• Welcome to LusoRobótica - Robótica em Português.
 

Routina de 1ms com o tmr0

Started by Electropepper, 02 de November de 2014, 18:20

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Electropepper

Ok, o que eu quero para já é aprender a fazer uma rotina de 1ms com precisão, dai eu posso tirar 1s, 1m ou seja o que for para poder aplicar de futuro noutros projectos, segundo o meu projecto é alimentar este pic com uma pilha CR2032 de 3v que vou ligar a um daqueles modulos pequenos de RF315Khz, dai eu querer usar o oscilador interno e tambem o mais lento possivel, não demasiado lento porque vou ter que usar a USART tambem.
Mas se de futuro eu quiser usar por exemplo o protocolo OneWire preciso de precisão ao milisegundo.
Portanto para já tenho um led com a respectiva resistencia de 220 no pino 5 do 12f1822 ou RA2, mais nada.

Electropepper

Já agora Asena, quando começei isto tinha as subrotinas em assembly, no final o resultado foi igualzinho a este, por isso decidi usar apenas C.

Sérgio_Sena

- Para 1-Wire precisas de precisao ao micro-segundo. O protocolo eh apertado mas permite algum erro.

- Ainda escrevo em ASM qd preciso de precisao em termos de poder controlar os ciclos todos do programa. Posso-te garantir que eh possivel fazer as rotinas q quiseres, a demorar o tempo q quiseres !! :)

Cumprimentos,
Sérgio Sena

Electronic Gear for Musicians

Instagram

Electropepper

Vou procurar e já te mostro.  :)

Electropepper

Asena, não encontrei mas fiz aqui uma rapidamente.
Continua impreciso na mesma.
Usei o Code generator.


#include <pic12f1822.h>


/* Setup chip configuration */
__code int __at(_CONFIG1) __CONFIG = _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF;

void setup(void);
void delay_ms(int milis);



void main(void) {

    setup();


    while(1) {

        delay_ms(1000);
        LATA |= (1<<2);
        delay_ms(1000);
        LATA &= ~(1<<2);
    }

}

void setup(void) {

    OSCCON = 0b01011000; // 1MHZ internal clock
    LATA = 0;
    TRISA = 0x00;
    PORTA = 0x00;
__asm
cblock 0x20
d1
endc
__endasm;

}

void delay_ms(int milis) {

    while (milis--) {
    __asm
        movlw   0x51
        movwf   d1
        Delay_0:
        decfsz  d1, f
        goto    Delay_0
    __endasm;
    }
}

Dave

Assim, de forma rápida, no XC8...

Tenta lá o *.hex do anexo.

Não deve dar um erro assim tão grande...
Já usei esse micro e é brutal para aplicações pequenas. Nunca tive grande problemas com coisas destas...

Tem um pequeno desvio... mas deve ser alguma coisa a rondar os ~700uS por cada minuto, segundo o simulador...

O LED vai ficar 1min ligado, 1min desligado, e assim sucessivamente...


#include <xc.h>

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable (PWRT enabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON        // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF       // PLL Enable (4x PLL enabled)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)

#define _XTAL_FREQ 1000000

unsigned char seg = 0;
unsigned int cont = 0;

void interrupt isr (void)
{
    if(INTCONbits.T0IF)
    {
        TMR0 += 6;

        cont++;

        if(cont>=1000)
        {
            seg++;
            cont = 0;
        }

        if(seg>=60)
        {
            seg = 0;
            LATAbits.LATA2 = !LATAbits.LATA2;
        }

        INTCONbits.T0IF = 0; 
    }

}


void init_osc(void)         //1MHz
{
    OSCCONbits.SPLLEN = 0;
    OSCCONbits.IRCF = 0b1011;
    OSCCONbits.SCS = 0;
}

void init_port(void)
{
    TRISA   = 0;
    LATA    = 0;
    ANSELA  = 0;
}

void interrup(void)
{
    INTCONbits.T0IF = 0;
    INTCONbits.T0IE = 1;
    INTCONbits.GIE = 1;
}

void init_timer0(void)
{
    OPTION_REGbits.TMR0CS = 0;
    OPTION_REGbits.T0SE = 0;
    OPTION_REGbits.PSA = 1;
    TMR0 = 0;
}

void main(void)
{
    init_osc();
    init_port();
    init_timer0();
    interrup();

    LATAbits.LATA2 = 1;
    TMR0 = 6;

    while(1);
}


David Martins
Eng. Electrotécnica e de Computadores, UBI

Electropepper

Sim está bem perto de um minuto  :).
Mas tenho de esperimentar isto com 1s ai é que se vê claramente com um cronometro ao lado.
O código que postei acima com a rotina em assembly tambem está igualmente perto.
Já agora o XC da microchip não traz rotinas de delay ? ou outro tipo de libs ?

Dave

Sim tras... mas no caso usar vários delays para fazer 1 min vai dar num grande erro também...
David Martins
Eng. Electrotécnica e de Computadores, UBI

Dave

#23
Quote from: Electropepper on 02 de November de 2014, 23:55
Mas tenho de esperimentar isto com 1s ai é que se vê claramente com um cronometro ao lado.
Isso é relativo... vais ter imensa dificuldade em cronometrar manualmente o tempo certo.

Tenta o *.hex em anexo para 1segundo.

O LED vai ter um comportamento semelhante ao de 1min, mas agora a cada segundo.

Segundo o simulador dá um erro de ~12uS...
David Martins
Eng. Electrotécnica e de Computadores, UBI

Sérgio_Sena

Quote from: Electropepper on 02 de November de 2014, 23:15
Asena, não encontrei mas fiz aqui uma rapidamente.
Continua impreciso na mesma.
Usei o Code generator.


#include <pic12f1822.h>


/* Setup chip configuration */
__code int __at(_CONFIG1) __CONFIG = _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF;

void setup(void);
void delay_ms(int milis);



void main(void) {

    setup();


    while(1) {

        delay_ms(1000);
        LATA |= (1<<2);
        delay_ms(1000);
        LATA &= ~(1<<2);
    }

}

void setup(void) {

    OSCCON = 0b01011000; // 1MHZ internal clock
    LATA = 0;
    TRISA = 0x00;
    PORTA = 0x00;
__asm
cblock 0x20
d1
endc
__endasm;

}

void delay_ms(int milis) {

    while (milis--) {
    __asm
        movlw   0x51
        movwf   d1
        Delay_0:
        decfsz  d1, f
        goto    Delay_0
    __endasm;
    }
}




O facto de teres uma parte do codigo em ASM nao significa q as temporizacoes estao certas.

Estahs a ter em conta os saltos para entrar e sair da funcao?
O teu loop While estahs a ser convertido para ASM de q forma?

Trabalhar com tempos precisos tem algumas nuances pois no Arduino as brincadeiras nao teem importancia se atrasarem, mas em trabalhos com plataformas a serio as coisas mudam de figura e tem q se "escrever" tudo como se quer.

Cumprimentos,
Sérgio Sena

Electronic Gear for Musicians

Instagram

Sérgio_Sena

Quote from: Dave on 03 de November de 2014, 00:20
Quote from: Electropepper on 02 de November de 2014, 23:55
Mas tenho de esperimentar isto com 1s ai é que se vê claramente com um cronometro ao lado.
Isso é relativo... vais ter imensa dificuldade em cronometrar manualmente o tempo certo.

Tenta o *.hex em anexo para 1segundo.

O LED vai ter um comportamento semelhante ao de 1min, mas agora a cada segundo.

Segundo o simulador dá um erro de ~12uS...


Querias dizer ~12 mili-segundos ?   pela imagem do simulador eh o q lah esta.

Cumprimentos,
Sérgio Sena

Electronic Gear for Musicians

Instagram

Sérgio_Sena

Quote from: Dave on 02 de November de 2014, 23:34
Assim, de forma rápida, no XC8...

Tenta lá o *.hex do anexo.

Não deve dar um erro assim tão grande...
Já usei esse micro e é brutal para aplicações pequenas. Nunca tive grande problemas com coisas destas...

Tem um pequeno desvio... mas deve ser alguma coisa a rondar os ~700uS por cada minuto, segundo o simulador...

O LED vai ficar 1min ligado, 1min desligado, e assim sucessivamente...


#include <xc.h>

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable (PWRT enabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON        // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF       // PLL Enable (4x PLL enabled)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)

#define _XTAL_FREQ 1000000

unsigned char seg = 0;
unsigned int cont = 0;

void interrupt isr (void)
{
    if(INTCONbits.T0IF)
    {
        TMR0 += 6;

        cont++;

        if(cont>=1000)
        {
            seg++;
            cont = 0;
        }

        if(seg>=60)
        {
            seg = 0;
            LATAbits.LATA2 = !LATAbits.LATA2;
        }

        INTCONbits.T0IF = 0; 
    }

}


void init_osc(void)         //1MHz
{
    OSCCONbits.SPLLEN = 0;
    OSCCONbits.IRCF = 0b1011;
    OSCCONbits.SCS = 0;
}

void init_port(void)
{
    TRISA   = 0;
    LATA    = 0;
    ANSELA  = 0;
}

void interrup(void)
{
    INTCONbits.T0IF = 0;
    INTCONbits.T0IE = 1;
    INTCONbits.GIE = 1;
}

void init_timer0(void)
{
    OPTION_REGbits.TMR0CS = 0;
    OPTION_REGbits.T0SE = 0;
    OPTION_REGbits.PSA = 1;
    TMR0 = 0;
}

void main(void)
{
    init_osc();
    init_port();
    init_timer0();
    interrup();

    LATAbits.LATA2 = 1;
    TMR0 = 6;

    while(1);
}




O facto de teres a rotina de Interrupcao cheia de codigo, eh propositadamente educativo? ou eh naturalmente como programas?

A funcao de interrupcao nao deve ter nada a nao ser Set/Clear de Flags. Qq codigo extra atrasa todo o processo em curso no Main.

Assim estaria mais correcto ::


void interrupt isr (void)
{
    if(INTCONbits.T0IF)
    {
        INTCONbits.T0IF = 0; 

        TMR0 += 6;

        FLAG-TMR0 = 1;
    }
}


Main:
   if (FLAG-TMR0)
   {
        cont++;

        if(cont>=1000)
        {
            seg++;
            cont = 0;
        }

        if(seg>=60)
        {
            seg = 0;
            LATAbits.LATA2 = !LATAbits.LATA2;
        }
    }




Eh mais ou menos isto q estava a falar.
E mesmo aquele TMR0 += 6 ali, da-me arrepios :D

Crias uma estrutura so com registos de Flags e podes usar isso por todo o programa.
Cumprimentos,
Sérgio Sena

Electronic Gear for Musicians

Instagram

Dave

#27
Quote from: asena on 03 de November de 2014, 08:21

Querias dizer ~12 mili-segundos ?   pela imagem do simulador eh o q lah esta.

Há dias lixados... xD

Sim ~12milisegundos :D

Quanto ao resto, não é comum. É um programa rápido para mostrar que funciona.
De qualquer forma, para o que o micro está a fazer, não há nada a correr no main e o timer não para, seja onde estiver. Por isso o resultado, neste caso, ia dar os mesmos tempos, quer da minha forma quer da tua, acho eu... mas tu é que és o mestre :D.


PS: Estava aqui a tentar ver melhor, "FLAG-TMR0" deveria ser "FLAG_TMR0"?
Se não for,  não consigo entender o objectivo. Se puderes, depois dá uma explicação ;)


Abraço.
David Martins
Eng. Electrotécnica e de Computadores, UBI

Sérgio_Sena

Quote from: Dave on 03 de November de 2014, 09:02
Quote from: asena on 03 de November de 2014, 08:21

Querias dizer ~12 mili-segundos ?   pela imagem do simulador eh o q lah esta.

Há dias lixados... xD

Sim ~12milisegundos :D

Quanto ao resto, não é comum. É um programa rápido para mostrar que funciona.
De qualquer forma, para o que o micro está a fazer, não há nada a correr no main e o timer não para, seja onde estiver. Por isso o resultado, neste caso, ia dar os mesmos tempos, quer da minha forma quer da tua, acho eu... mas tu é que és o mestre :D.


PS: Estava aqui a tentar ver melhor, "FLAG-TMR0" deveria ser "FLAG_TMR0"?
Se não for,  não consigo entender o objectivo. Se puderes, depois dá uma explicação ;)


Abraço.


Qual mestre LOL.... mestres somos todos uns dos outros ;)

FLAG-TMR0 eh apenas um pseudo nome.

Algo como isto talvez, quick examplenao formatado nem outras coisas:


typedef struct
{
    unsigned char   byState;

    unsigned        bTimerUsartRX:1;
    unsigned        bTimerComms:1;
    unsigned        bTimerAlarm:1;

}_TIMERS;

_TIMERS                 g_TIMERS;






void interrupt interrupcao(void)
{
    if ((TMR2IF) && (TMR2IE))
    {
        TMR2IF = 0;

        // Da indicacao q o timer rolou
        g_TIMERS.bTimerComms = 1;
    }

}


void interrupt interrupcao(void)
{

    if ((TMR2IF) && (TMR2IE))
    {
        TMR2IF = 0;

        // Da indicacao ah maquina de estados dos Timers do proximo passo
        g_TIMERS.byState = ST_Timers_TICK;
    }


}





void main (void)
{
...

if (g_TIMERS.bTimerComms)
{
// executar tarefa
}
}
Cumprimentos,
Sérgio Sena

Electronic Gear for Musicians

Instagram

Electropepper

Ok pessoal, já deu para tirar umas conclusões.
Usar a interrupção com apenas uma flag(state machine) a dar indicação que o timer rolou.
Ter em conta a chamada e saida para a função de delay assim como fazer o load do tmr0 com o respectivo valor.
Mais logo quando chegar a casa já esperimento isto outa vez.
E tenho de ver se arranjo um oscilóscpio para tirar as teimas.