Este programa vai apenas produzir 10 pulsos de 256us*200 no pino RA2 e criar um pulso no pino RA3 com o período de 256us*256.
O programa vai contar 200 incrementos do TIMER0 e troca o estado do pino RA2. A frequência de clock é 4MHz, mas como são precisos 4 pulsos para fazer uma instrução, a frequência de instrução é 1MHz.
O registo OPTION_REG foi definido para um percaller de 1:256 no Timer0, quer dizer que é preciso 256us para cada incremento do timer e 65.536ms para o overflow do mesmo.
Após isso, configurei o registo INTCON, para "desmascarar" todas as interrupções (global), para activar a interrupção do TIMER0 e ainda para activar a flag de interrupção do TIMER0. Esta última é muito importante para que seja chamado o programa da interrupção.
Uma das coisas que também não estava habituado era de que todas as interrupções entrarem no "mesmo programa". O "void interrupt blabla()" é chamado sempre que ocorrer uma interrupção e dentro dele tem de ser feita a distinção de qual foi a origem da interrupção.
Como foi activada a flag de overflow do Timer0, no incio de "void interrupt INT" faz-se a seguinte verificação:
void interrupt INT(void){if (TMR0IE && TMR0IF){bla bla bla.....}}
A "pergunta" que é feita pelo "if (TMR0IE && TMR0IF)" é se ocorreu a interrupção (aparecimento da flag) e se a interrupção estava activa (definida pelo programador).
Verificando estas duas condições, entra no programa e faz o que tem a fazer...
IMPORTANTE: Não esquecer de no final limpar a flag da interrupção para que se houver outra, não haver enganos, ou seja, se for gerada uma interrupção por uma alteração no porto B, não ser executado o programa da interrupção do timer, por exemplo.
O código:
// PIC16F88 Configuration Bit Settings#include <xc.h>__CONFIG(FOSC_INTOSCIO & WDTE_OFF & PWRTE_OFF & MCLRE_OFF & BOREN_OFF & LVP_OFF & CPD_OFF & WRT_OFF & CCPMX_RB0 & CP_OFF);__CONFIG(FCMEN_OFF & IESO_OFF);#define _XTAL_FREQ 4000000char a;void interrupt INT(void){if (TMR0IE && TMR0IF){if(a<10){RA3=1;}else{RA3=0;INTCONbits.GIE=0;INTCONbits.TMR0IE=0;}a++;INTCONbits.TMR0IF=0;}}void main(){char conta;//***** PortosTRISA = 0b00000000;TRISB = 0b00000000;PORTA = 0;PORTB = 0;//***** OsciladorOSCCONbits.IRCF = 0b110;OSCCONbits.OSTS = 1;OSCCONbits.IOFS = 1;OSCCONbits.SCS = 0b00;//***** TIMER0OPTION_REGbits.PS =0b111;OPTION_REGbits.PSA =0;OPTION_REGbits.T0SE=0;OPTION_REGbits.T0CS=0;//**** Led a piscar com leitura de Timer0__delay_ms(1000);conta=0;while(conta<10){TMR0=0;RA2=1;while(TMR0<200);RA2=0;TMR0=0;while(TMR0<200);conta++;}//**** Led a piscar com leitura de Timer0 + interrupçãoINTCONbits.GIE=1;INTCONbits.TMR0IE=1;INTCONbits.TMR0IF=0; //interrupção não ocorreu aindaa=1;}
Saída de RA2 e RA3 |
Amigo,
Estou começando a usar este compilador, mas tenho uma dúvida sobre interrupções. Li alguns materiais e vi que para mid-range só pode ser usado uma interrupção, você pode confirmar esta informação
Só pode ser usada uma interrupção?
Como assim?
Podes usar as interrupções todas que quiseres...
Prova disso é que tenho um sistema aqui ao lado que tem 4/5 interrupções.
Olá, preciso fazer um pwm, quero girar e parar um servo nas seguintes posições 90º e 0º apenas, vai e volta, já li e vi vários vídeos, mas ainda não cheguei ao resultado que preciso.
Uso o MPLAB e Proteus.
Gostaria de sua ajuda para criar a programação.
Muito obrigado!!
Olá.
Para um simples servo, é preferível (se ele não ficar em esforço), fazer um pequeno ciclo para repetir os pulsos, num pino, para o fazer mover...
PWM também se pode fazer, recorrendo ao módulo de CCP do micro ;)
Entendi, já imaginava que ele não deveria ficar em esforço mesmo.
Talvez elevando o pino para 1 e depois para 0 comandado por um delay não é?
Muito obrigado por responder.
Sim....
É simples e rápido de colocar em prática ;).
Outra forma poderá ser usando o periférico CCP, ou então configurando a interrupção de um timer e ir alterando os valores com os quais carrega os registos de timer.