Ir ao conteúdo

Calibrar Timer0


cezar.opaleiro

Posts recomendados

Postado

Olá galera!

Me deem uma luz! :)

Quero calibrar o timer0, para que eu consiga medir 500ms. Eu fiz os seguintes cálculos:

Clock do PIC: 4Mhz

Janela de tempo: 500ms = 500000us

Prescaler: 1:64

500000/64 ~= 7812

7812/36 = 217

TMR0 = 256-36 = 220 (256 estoura e gera 1 interrupção)

Cada interrupção counter + 1

counter = 217 = 500ms

Código resumido:


void interrupt()
{
TMR0 = 220;
counter++; // Incrementa valor de counter a cada Interrupção.
INTCON = 0b00100000; // Seta T0IE (bit 5) e Limpa T0IF (bit 2).
}

void main()
{
while(1)
{
if(counter >= 217)
{
segundos = segundos+1;
}
Lcd_out(1,6,segundos);
}

}

Tá certo???

No projeto a contagem fico lenta, acho que ta incrementando a cada 1500ms.

Alguém pode me ajudar pelo menos com a teoria??

Obrigado!

Postado

Veja se ajuda o que fiz agora:

O PIC trabalhando com cristal de 4Mhz, internamente ele trabalha a FOSC/4, ou
seja, a 1Mhz.

Se utilizarmos o TIMER0 e o prescaler de 256, o TIMER0 trabalhará a uma frquência
de 1Mhz/256=3906,25Hz. Com essa freq. temos um período de 256uS(Micro-segundos).

o que isso quer dizer? Cada incremento do TIMER0 leva 256uS.

O TIMER0 é de 8 bits, ele vai de 0 a 255. Dessa forma, ele leva:

1 incremento ------------> 256uS
255 incrementos ------------> X

Multiplicando cruzado, temos X = 0.06528 segundos = 15.3Hz mais ou menos para
que ele estoure. Mas precisamos calcular 1 segundo, certo?

Ora, se o timer está estourando 15 vezes por segundo, apenas fazemos uma rotina
que englobe isso. Algo do tipo:

interrupção()
{
contador++;
if (contador == 15)
{
temos 1 segundo aqui;
}

set_timer0(preload); //sempre no final
}

Obs: Veja que a frequencia do TIMER0 é de 15.3 e não 15. Esses 0.3Hz podem atrapalhar
seu projeto. Dessa forma, é necessário ajustar o PRELOAD do TIMER0.

você coloca um valor e refaz a regra de 3 até ajustar para uma frequncia exata.

Dúvidas? pergunte!

Falou

Postado
Veja se ajuda o que fiz agora:

O PIC trabalhando com cristal de 4Mhz, internamente ele trabalha a FOSC/4, ou
seja, a 1Mhz.

Se utilizarmos o TIMER0 e o prescaler de 256, o TIMER0 trabalhará a uma frquência
de 1Mhz/256=3906,25Hz. Com essa freq. temos um período de 256uS(Micro-segundos).

o que isso quer dizer? Cada incremento do TIMER0 leva 256uS.

O TIMER0 é de 8 bits, ele vai de 0 a 255. Dessa forma, ele leva:

1 incremento ------------> 256uS
255 incrementos ------------> X

Multiplicando cruzado, temos X = 0.06528 segundos = 15.3Hz mais ou menos para
que ele estoure. Mas precisamos calcular 1 segundo, certo?

Ora, se o timer está estourando 15 vezes por segundo, apenas fazemos uma rotina
que englobe isso. Algo do tipo:

interrupção()
{
contador++;
if (contador == 15)
{
temos 1 segundo aqui;
}

set_timer0(preload); //sempre no final
}

Obs: Veja que a frequencia do TIMER0 é de 15.3 e não 15. Esses 0.3Hz podem atrapalhar
seu projeto. Dessa forma, é necessário ajustar o PRELOAD do TIMER0.

você coloca um valor e refaz a regra de 3 até ajustar para uma frequncia exata.

Dúvidas? pergunte!

Falou

Olá Mateus, obrigado pela aula!

Bacana, mas para calibrar para 1/2 segundo (500ms)?

Seria 0.06528 / 2?

O preload seria sempre 256-15 = 241?

valeu!!

Postado

Nao, nao.

O timer0 nao consegue gerar uma interrupção de 0.5segundos. Ele estoura antes.

Para isso terá que utilizar o TIMER 1 como o colega disse acima.

Mas para calcular 1 segundo qualquer timer serve. Só fazer a jogadinha que comentei.

Falou

Postado
Nao, nao.

O timer0 nao consegue gerar uma interrupção de 0.5segundos. Ele estoura antes.

Para isso terá que utilizar o TIMER 1 como o colega disse acima.

Mas para calcular 1 segundo qualquer timer serve. Só fazer a jogadinha que comentei.

Falou

valeu Mateus!

Bom e se eu fizer essa gambiarra hehe

ao invés de 15 coloco 8 + um Delay

0.06528 x 8 = 0,52224

acrescento um Delay_ms(22)

Dá certo?

Postado

Exemplo para o Timer1 ~2hz ou ~500ms:

/*

* Example Source Code For PIC Timers

* THis blinks LEDs on PORTB to show interrupt rates

*

* Example only! Use any code at your own risk.

*/

// Interrupt Handler

void interrupt()

{

// Timer1 Interrupt - Freq = 1.99 Hz - Period = 0.502968 seconds

if (PIR1.TMR1IF == 1) // timer 1 interrupt flag

{

PORTB.F1 = ~PORTB.F1; // Toggle PORTB bit1 LED

PIR1.TMR1IF = 0; // interrupt must be cleared by software

PIE1.TMR1IE = 1; // reenable the interrupt

TMR1H = 10; // preset for timer1 MSB register

TMR1L = 105; // preset for timer1 LSB register

}

}

// code starts here...

void main()

{

// setup portb to show the interrupts by blibking LEDs

TRISB = 0x00; // PORT is all output...to show the interrupts

PORTB = 0; // start with all outputs low

//Timer1 Registers Prescaler= 8 - TMR1 Preset = 2665 - Freq = 1.99 Hz - Period = 0.502968 seconds

T1CON.T1CKPS1 = 1; // bits 5-4 Prescaler Rate Select bits

T1CON.T1CKPS0 = 1; // bit 4

T1CON.T1OSCEN = 1; // bit 3 Timer1 Oscillator Enable Control bit 1 = on

T1CON.T1SYNC = 1; // bit 2 Timer1 External Clock Input Synchronization Control bit...1 = Do not synchronize external clock input

T1CON.TMR1CS = 0; // bit 1 Timer1 Clock Source Select bit...0 = Internal clock (FOSC/4)

T1CON.TMR1ON = 1; // bit 0 enables timer

TMR1H = 10; // preset for timer1 MSB register

TMR1L = 105; // preset for timer1 LSB register

// Interrupt Registers

INTCON = 0; // clear the interrpt control register

INTCON.TMR0IE = 0; // bit5 TMR0 Overflow Interrupt Enable bit...0 = Disables the TMR0 interrupt

PIR1.TMR1IF = 0; // clear timer1 interupt flag TMR1IF

PIE1.TMR1IE = 1; // enable Timer1 interrupts

INTCON.TMR0IF = 0; // bit2 clear timer 0 interrupt flag

INTCON.GIE = 1; // bit7 global interrupt enable

INTCON.PEIE = 1; // bit6 Peripheral Interrupt Enable bit...1 = Enables all unmasked peripheral interrupts

while(1) //endless loop

{

}

}

O exemplo acima, foi retirado da seguinte calculadora online:

http://eng-serve.com/pic/pic_timer.html

Dependendo o modelo do microcontrolador, os nomes de alguns registradores podem mudar um pouco. Consulte o datasheet, ou retorne. O exemplo acima atende a série 18. Para uso com 16 deverá mudar como já mencionado.

Abç.

Postado

Em primeiro lugar obrigado a todos!!

Shunt...valeu pelo código...na simulação do proteus fico certinho, filé! Mas no projeto físico a amostragem no LCD fico de aprox. uns 2 seg.

Veja como eu coloquei o código, veja se eu entendi direito...

a variável counter faz a contagem as interrupções do TMR1. (500ms cada)


void interrupt()
{
// Timer1 Interrupt - Freq = 1.99 Hz - Period = 0.502968 seconds
if (PIR1.TMR1IF == 1) // timer 1 interrupt flag
{
counter++;
PIR1.TMR1IF = 0; // interrupt must be cleared by software
PIE1.TMR1IE = 1; // reenable the interrupt
TMR1H = 10; // preset for timer1 MSB register
TMR1L = 105; // preset for timer1 LSB register
}

}// interrupt



void ContaInt()
{
IntToStr(counter,AUX3); //converte de INT para STR

Lcd_out(1,4,"Interrupcoes");
Lcd_out(2,4,AUX3);
}

void main()
{
ANSEL = 0b01111111; //CONFIGURA RA0/AN0 COMO I/O ANALOGICO
ADCON0 = 0b11000101; //MODULO ADC LIGADO COM FOSC/32 E CANAL0;
ADCON1 = 0b01000000;
OSCCON = 01100110;
TRISB = 0b00000000; // RA7,6,5,4,3,2,1,0 nessa ordem
PORTB = 0b00000000; // RA7,6,5,4,3,2,1,0 nessa ordem

//Timer1 Registers Prescaler= 8 - TMR1 Preset = 2665 - Freq = 1.99 Hz - Period = 0.502968 seconds
T1CON.T1CKPS1 = 1;
T1CON.T1CKPS0 = 1;
T1CON.T1OSCEN = 1;
T1INSYNC_bit = 1;
T1CON.TMR1CS = 0;
T1CON.TMR1ON = 1;
TMR1H = 10;
TMR1L = 105;

// Interrupt Registers
INTCON = 0;
INTCON.TMR0IE = 0;
PIR1.TMR1IF = 0;
PIE1.TMR1IE = 1;
INTCON.TMR0IF = 0;
INTCON.GIE = 1;
INTCON.PEIE = 1;


Lcd_Init(); // Initialize LCD
Delay_ms(10);
Lcd_Cmd(_LCD_CLEAR); // Clear display
Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off


while(1)
{
ContaInt();
}

}

Não sei se tem haver mas o clock do PIC que to usando é de 4Mhz.

valeu!

Postado

Cesar:

° O código completo ajudaria mais.

° O microcontrolador usado, igualmente.

° Qual versão do mikroC utiliza?

Esta função IntToStr se usada em pic 16 consome algum tempo.

Precisa tratar sua variavel counter. Quando ela atingir o valor 255 (por ser int) o que acontece?

Abç.

Postado
Cesar:

° O código completo ajudaria mais.

° O microcontrolador usado, igualmente.

° Qual versão do mikroC utiliza?

Esta função IntToStr se usada em pic 16 consome algum tempo.

Precisa tratar sua variavel counter. Quando ela atingir o valor 255 (por ser int) o que acontece?

Abç.

Shunt, o resto do código é apenas declaração de variáveis.

Microcontrolador que uso é o PIC16F88

MikroC v4.6

A IntToStr consome na casa de (us), não causaria mudanças na casa dos (ms) creio eu...

Eis minha dúvida, quando eu fico sabendo que ocorreu os 500ms??

Pelo que eu entendi era quando PIR1.TMR1IF == 1 é verdadeiro, é isso?

Preciso saber o momento, porque nesse momento eu incrementaria uma variável e mostraria ela no LCD.

Abrs!

Postado

Jogue a rotina que trata o lcd dentro da interrupção. Assim saberá quando ela ocorreu.

Outra coisa importante é para variaveis modificadas ou acessadas por interrupções, declare como:

volatile "tipo" "nome" = 0; //valor é opcional neste caso.

onde "tipo" = int, float, long, char ...

Postado
Jogue a rotina que trata o lcd dentro da interrupção. Assim saberá quando ela ocorreu.

Outra coisa importante é para variaveis modificadas ou acessadas por interrupções, declare como:

volatile "tipo" "nome" = 0; //valor é opcional neste caso.

onde "tipo" = int, float, long, char ...

valeu Shunt!

Mas o compilador não permiti colocar funções dentro da função de interrupção.

Quando declaro como volatile, qual a diferença?

Postado
o compilador não permiti colocar funções dentro da função de interrupção.

Desculpe Cesar, foi um engano ... ao procurar o exemplo para postar, vi não ser o que "pensava". Tentei compilar e verifiquei o erro.

Quando declaro como volatile, qual a diferença?

No help tem explicação quanto ao uso. Certa vez escrevi um código que funcionava no proteus e na pratica hora sim, hora não ... Mudei tudo o que pude e não corrigia o erro. Depois de uma olhada no help e uma consulta em livros de linguagem C, encontrei que para variáveis modificadas sem intervenção do usuario ou mesmo fluxo normal do programa, deveriam ser declaradas como volatile, pois assim o compilador não iria otimiza-las. Retornando ao primeiro código, coloquei o modificador volatile na variável tratada pela interrupção ... e até hoje a coisa funciona muito bem por aqui ...

--

Voltando ao seu problema, percebi que enquanto a interrupção não ocorre, a variavel é convertida para string e enviadas as duas linhas na função o tempo todo entre uma interrupção e outra. Pergunto: Não existe um tempo mínimo para que o display possa interpretar os comandos vindos do microcontrolador? E estes mesmos estão fora das especificações recomendadas pelo fabricante?

Acho que um delay dentro da função não vai atrapalhar. Tente qualquer valor entre 100 e 400ms, pois cada interrupção acontece a cada 500ms. O que acha?

Abç.

Postado
Desculpe Cesar, foi um engano ... ao procurar o exemplo para postar, vi não ser o que "pensava". Tentei compilar e verifiquei o erro.

No help tem explicação quanto ao uso. Certa vez escrevi um código que funcionava no proteus e na pratica hora sim, hora não ... Mudei tudo o que pude e não corrigia o erro. Depois de uma olhada no help e uma consulta em livros de linguagem C, encontrei que para variáveis modificadas sem intervenção do usuario ou mesmo fluxo normal do programa, deveriam ser declaradas como volatile, pois assim o compilador não iria otimiza-las. Retornando ao primeiro código, coloquei o modificador volatile na variável tratada pela interrupção ... e até hoje a coisa funciona muito bem por aqui ...

--

Voltando ao seu problema, percebi que enquanto a interrupção não ocorre, a variavel é convertida para string e enviadas as duas linhas na função o tempo todo entre uma interrupção e outra. Pergunto: Não existe um tempo mínimo para que o display possa interpretar os comandos vindos do microcontrolador? E estes mesmos estão fora das especificações recomendadas pelo fabricante?

Acho que um delay dentro da função não vai atrapalhar. Tente qualquer valor entre 100 e 400ms, pois cada interrupção acontece a cada 500ms. O que acha?

Abç.

Sem problemas amigo!

Pensei nisso também mas dentro da função interrupção o compilador não deixa nenhuma outra função ser executada...e o Delay é uma função...

Delay_ms(100);

Abrs!

Postado

Me referia:

void ContaInt()

{

IntToStr(counter,AUX3); //converte de INT para STR

Lcd_out(1,4,"Interrupcoes");

Lcd_out(2,4,AUX3);

Delay_ms(400);

}

O restante não modifique. Acima compila sem problemas.

Abç.

  • 1 ano depois...
Postado
Veja se ajuda o que fiz agora:

O PIC trabalhando com cristal de 4Mhz, internamente ele trabalha a FOSC/4, ou
seja, a 1Mhz.

Se utilizarmos o TIMER0 e o prescaler de 256, o TIMER0 trabalhará a uma frquência
de 1Mhz/256=3906,25Hz. Com essa freq. temos um período de 256uS(Micro-segundos).

o que isso quer dizer? Cada incremento do TIMER0 leva 256uS.

O TIMER0 é de 8 bits, ele vai de 0 a 255. Dessa forma, ele leva:

1 incremento ------------> 256uS
255 incrementos ------------> X

Multiplicando cruzado, temos X = 0.06528 segundos = 15.3Hz mais ou menos para
que ele estoure. Mas precisamos calcular 1 segundo, certo?

Ora, se o timer está estourando 15 vezes por segundo, apenas fazemos uma rotina
que englobe isso. Algo do tipo:

interrupção()
{
contador++;
if (contador == 15)
{
temos 1 segundo aqui;
}

set_timer0(preload); //sempre no final
}

Obs: Veja que a frequencia do TIMER0 é de 15.3 e não 15. Esses 0.3Hz podem atrapalhar
seu projeto. Dessa forma, é necessário ajustar o PRELOAD do TIMER0.

você coloca um valor e refaz a regra de 3 até ajustar para uma frequncia exata.

Dúvidas? pergunte!

Falou

Matheus, estou tentando contar 1s com um PIC 16F877A e cristal de 20MHz, mas não estou conseguindo acertar a conta do Preloader, pode me ajudar

[]

Samuka

Postado

Se você fizer as contas. Verá que com o prescaler de 256, nunca dará 1 segundo certinho. Ainda mais em C fica muito diícil 1 segundos exato.

Ali em cima cometi um erro em dizer que ele conta 255 vezes. Na verdade é 256 vezes. Ele estoura de 255 -> 0. então sao 256 incrementos.

No caso, com o prescaler de 256 consegui 1.009906 segundos, ajustando:

#include <16F877A.h>

#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //Crystal osc > 4mhz
#FUSES PUT //Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NODEBUG //No Debug mode for ICD
#FUSES BROWNOUT //Reset when brownout detected
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection

#use delay(clock=20000000) //meu clock

#define prescaler 0

int16 q;

#int_timer0
void TIMER0_isr (void)
{
q++;
if (q == 77)
{
output_toggle (PIN_B0);
q=0;
}
set_timer0(prescaler);
}

void main()
{
SETUP_TIMER_0 (RTCC_INTERNAL|RTCC_DIV_256); //Configurar timer1 para clock iterno/8
set_timer0 (prescaler);
enable_interrupts (INT_TIMER0); //Habilitar Interrupções
enable_interrupts (global);

while (TRUE);
}

Com prescaler de 8, deu um tempo de 1.001512 segundos. ajustando.

#include <16F877A.h>

#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //Crystal osc > 4mhz
#FUSES PUT //Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NODEBUG //No Debug mode for ICD
#FUSES BROWNOUT //Reset when brownout detected
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection

#use delay(clock=20000000) //meu clock

int16 q;

#int_timer0
void TIMER0_isr (void)
{
q++;
if (q == 2500)
{
output_toggle (PIN_B0);
q=0;
}
set_timer0(11);
}

void main()
{
SETUP_TIMER_0 (RTCC_INTERNAL|RTCC_DIV_8); //Configurar timer1 para clock iterno/8
set_timer0 (11);
enable_interrupts (INT_TIMER0); //Habilitar Interrupções
enable_interrupts (global);

while (TRUE);
}

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

LANÇAMENTO!

eletronica2025-popup.jpg


CLIQUE AQUI E BAIXE AGORA MESMO!