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 4000000


char 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;

//***** Portos
                 TRISA = 0b00000000;
                 TRISB = 0b00000000;
                 PORTA = 0;
                 PORTB = 0;
           
//***** Oscilador
                 OSCCONbits.IRCF = 0b110;
                 OSCCONbits.OSTS = 1;
                 OSCCONbits.IOFS = 1;
                 OSCCONbits.SCS  = 0b00;

//***** TIMER0
             OPTION_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ção
            INTCONbits.GIE=1;
            INTCONbits.TMR0IE=1;
            INTCONbits.TMR0IF=0;        //interrupção não ocorreu ainda
            a=1;
}

Saída de RA2 e RA3

6 Responses so far.

  1. 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

  2. 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.

  3. 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!!

  4. 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 ;)

  5. 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.

  6. 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.

Enviar um comentário