Ir ao conteúdo

Problema com Timer1 e RA4 - Mikroc - Pic16f628a


alexandrefdem

Posts recomendados

Postado

Olá senhores!

Quanto tempo não posto aqui... então. Retornei aos estudos do mikroc em arremesso, já adquirí 2 16f628 e estou no aguardo da chegada do gravador, enquanto isso ando fazendo testes no ISIS mesmo.

Qual o problema.

Escrevi um programa muito simples, pra testar o Timer1. Nesse programa, tentei criar um estouro de 1 segundo na variavel Segundo. O problema é que, ao rodar no ISIS, ele ta me dando um estouro de 100us, e não importa quantos registradores eu configure, desabilite modulos.... não consigo fazer o timer rodar correto.

Outro problema. A porta RA4 não quer ser output de forma nenhuma. Já desabilitei o Timer0 (ela é a porta de interrupção externa dele e i/o digital) e não dá jeito. Vou passar o código logo abaixo:


long int q = 0;
int segundo = 0;

void interrupt()
{
if(PIR1.TMR1IF==1)
{
PIR1.TMR1IF = 0;
TMR1L = 0xF0;
TMR1H = 0xD8;
q++;
if(q==15)
{
q=0;
segundo++;
}
}

}

void mudar()
{
if(segundo++)
{
Portb++;
Porta=~porta;
}
}

void main() {

TRISA = 0x00; //Todas porta como out
TRISB = 0X00; //Todas portb como out

PORTB =0X00; //Em estado inicial 0
PORTA= 0x00; //

INTCON.PEIE = 0; // Desative interrupções externas

PIE1.TMR1IE = 1; // Timer1 interrupt ativo
PIR1.TMR1IF = 0; // Timer1 limpe a flag
T1CON.T1CKPS1 = 0; //Prescaller 1:1 - Sem divisão

INTCON.T0IE = 0;
T1CON.T1CKPS0 = 0;
TMR1L = 0xF0; // Reset Timer1 lower 8 bits
TMR1H = 0xD8; // Reset Timer1 upper 8 bits
//conta a partir de 55536

INTCON.GIE = 1; // Ative as interrupções globais
OPTION_REG.T0CS = 0; //SET TIMER0 pra clock interno, livrando RA4

VRCON.VREN = 0; // Desativar VOLTAGE COMPARATOR MODULE
CCP1CON = 0b00000000; // CAPTURE/COMPARE/PWM OFF

//Percebam que eu tentei desativar TMR0, modulo de tensão
//modulo comparador, pwm... e nada com RA4.

do
{
mudar();
}
while(1);

}

Postado

O pino RA4 é do tipo dreno aberto, ele nunca consegue nível alto sozinho. Ele funciona somente como uma chave para o 0V. Se colocar um resistor de pull-up, já funciona, só tens que lembrar que ele é simplesmente ou uma chave ligando o pino ao 0V ou então uma chave aberta (ele só drena corrente), diferente dos outros pinos de I/O que são do tipo toten-pole, podendo ter saída em nível baixo e também em nível alto (tanto drena quanto fornece corrente).

Quanto ao timer, o ideal seria que você colocasse o valor do clock para que pudéssemos confirmar suas contas. Com o seu programa, com prescaler 1:1, você vai obter 1000 ciclos de máquina a cada estouro, o que com um clock de 4Mhz equivale a 1ms. Se você utilizou uma variável para contar até 15, então vais ter aproximadamente 15ms para estouro. Ainda estou tentando entender de onde vieram os 100ms, pois pra isso terias que utilizar uma freqüência bem baixa de oscilador.

Também é recomendável apagar o bit 0 (TMR1ON) do registrador T1CON antes de configurar o valor dos registradores TMR1H e TMR1L, e após configurar os valores setar o bit TMR1ON novamente.

Postado

Olá Zaqueu! Grato pela atenção!

Então, na mosca. Cristal de 4 Mhz. Encontrei essa fórmula para calcular o count(variavel de incremento num site que segue abaixo

Count = Fclk / 4 * Prescaller * (65536-TMR1) * Fout

Fout é a frequência que quero.

http://www.microcontrollerboard.com/pic-timer1-tutorial.html

E mesmo assim não obtive resultados.

Segue o código com suas recomendações:



int q = 0;
int segundo = 0;

void interrupt()
{
if(TMR1IF_bit)
{
q++;
TMR1IF_bit = 0;
TMR1L = 0x00;
TMR1H = 0x00;
}

}

void mudar()
{
if(segundo++)
{
Portb++;
Porta=~porta;
}
}

void seg()
{
if(q>=15)
{
segundo++;
q=0;
}
else if(segundo>=60)
{
segundo=0;
}
}

void main() {

TRISA = 0b11100000; //Todas porta como out
TRISB = 0X00; //Todas portb como out

PORTB =0X00; //Em estado inicial 0
PORTA= 0xfF; //



T1CON.TMR1ON = 0; // desabilitado Timer1
TMR1IF_bit = 0; // limpe a flag TMR1IF
INTCON = 0b11000000; // Habilitando interrupções
TMR1L = 0x00; // Reset Timer1 lower 8 bits
TMR1H = 0x00; // Reset Timer1 upper 8 bits
T1CON.TMR1CS = 0; // Sem o oscilador interno
TMR1IE_bit = 1; // enable Timer1 interrupt
T1CON.TMR1ON = 1; // habilitado TMR1


VRCON.VREN = 0; // Desativar VOLTAGE COMPARATOR MODULE
CCP1CON = 0b00000000; // CAPTURE/COMPARE/PWM OFF

//Percebam que eu tentei desativar TMR0, modulo de tensão
//modulo comparador, pwm... e nada com RA4.

do
{
seg();
mudar();
}
while(1);

}

Será que eu necessito configurar os pinos do cristal oscilador? Afinal eles são multiplexados com RA6 e RA7

Postado

Não é a maneira correta de se fazer/aprender um código, mas utilize a calculadora abaixo:

*

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

*

Ela configura corretamente os timers baseado no clock do cristal utilizado, e logo em seguida mostra um codigo funcional para o mikroC.

Com isso você pode colocar o projeto para funcionar mais rápido e tempo para estudar e entender a configuração dos registradores.

Espero que ajude.

Abç.

Postado

Cometi um erro no post acima, a sua conta está praticamente correta, basta alterar a contagem da variável "q" que você utilizou. Com prescaler 1:1, clock de 4Mhz e carregando 55535, você vai obter uma freqüência de (4000000/4/1/10000) = 100Hz, o que dá um período de 10ms. Então a sua variável "q" deve contar até 100 (100*0,010ms = 1s).

Acredito que você não tenha entendido o que eu falei acima sobre o reset do bit TMR1ON, responsável por ligar o timer1. Vou mandar uma sugestão de código para um tempo de 1s e comentar ao lado as modificações que sugeri:

long int q = 0;

int segundo = 0;

void interrupt()

{

if(PIR1.TMR1IF==1)

{

PIR1.TMR1IF = 0;

T1CON.TMR1ON = 0; //Desabilita o Timer1 temporariamente

TMR1L = 0xF0; //Pela sua conta, teremos um estouro a cada

TMR1H = 0xD8; //10ms

T1CON.TMR1ON = 1; //Habilita novamente após carregar o valor

q++;

if(q==100) //Verifica se já passaram 100 estouros (100*0,01=1)

{

q=0;

segundo++;

}

}

}

void mudar()

{

if(segundo++)

{

Portb++;

Porta=~porta;

}

}

void main() {

TRISA = 0x00; //Todas porta como out

TRISB = 0X00; //Todas portb como out

PORTB =0X00; //Em estado inicial 0

PORTA= 0x00; //

INTCON.PEIE = 0; // Desative interrupções externas

PIE1.TMR1IE = 1; // Timer1 interrupt ativo

PIR1.TMR1IF = 0; // Timer1 limpe a flag

T1CON.T1CKPS1 = 0; //Prescaller 1:1 - Sem divisão

INTCON.T0IE = 0;

T1CON.T1CKPS0 = 0;

TMR1L = 0xF0; // Reset Timer1 lower 8 bits

TMR1H = 0xD8; // Reset Timer1 upper 8 bits

//conta a partir de 55536

T1CON.TMR1ON = 1; //Habilita novamente após carregar o valor

INTCON.GIE = 1; // Ative as interrupções globais

OPTION_REG.T0CS = 0; //SET TIMER0 pra clock interno, livrando RA4

VRCON.VREN = 0; // Desativar VOLTAGE COMPARATOR MODULE

CCP1CON = 0b00000000; // CAPTURE/COMPARE/PWM OFF

//Percebam que eu tentei desativar TMR0, modulo de tensão

//modulo comparador, pwm... e nada com RA4.

//OBS.: Lembre-se do resistor de pull-up no pino para obter nível alto!

do

{

mudar();

}

while(1);

}

Postado

Senhores, agradeço muito pelas respostas, realmente me ajudaram a tentar entender o que estava acontecendo.

Sem a duvida de que o Timer1 estava configurado corretamente, corrí atrás de outros problemas e acabei percebendo que ao usar funções como if(segundo++), de alguma forma, eu estava sem conseguir fazer com que a função executasse apenas no incremento de segundo, e sim sempre que o interrupt estourasse, ainda não entendí porque... comprovei isso por experimento mudando o código.

Segue o código funcionando. Nova configuração do timer1 - interrupt em 2Hz (pela calculadora que o nosso colega postou acima) Portb incrementa a cada segundo, porta inverte o estado a cada 2 segundos.



/*
* Example Source Code For PIC Timers
* THis blinks LEDs on PORTB to show interrupt rates
*
* Barton Dring
* Dring Engineering Services
* www.eng-serve.com
*
* Example only! Use any code at your own risk.
*/


// Interrupt Handler

short q;
short seg;

void interrupt()
{
if(PIR1.TMR1IF==1)
{
PIR1.TMR1IF = 0;
T1CON.TMR1ON = 0; //Desabilita o Timer1 temporariamente
TMR1L = 38; //Pela sua conta, teremos um estouro a cada
TMR1H = 12; //10ms
T1CON.TMR1ON = 1; //Habilita novamente após carregar o valor
q++;

}

}

void funcao()
{
if(q==2) //Verifica se já passaram os estouros(rodando a 2Hz)
{
q=0;
portb++;
seg++;
}
if(seg==2)
{
porta=~porta;
seg=0;
}
}


// code starts here...
void main()
{

// setup portb/porta to show the interrupts by blibking LEDs
TRISA = 0;
PORTA = 0xFF;
TRISB = 0x00; // PORT is all output...to show the interrupts
PORTB = 0; // start with all outputs low

//Timer1 Registers Prescaler= 8 - TMR1 Preset = 53094 - Freq = 10.05 Hz - Period = 0.099536 seconds
T1CON.T1CKPS1 = 1; // bits 5-4 Prescaler Rate Select bits
T1CON.T1CKPS0 = 1; // bit 4
T1CON.T1OSCEN = 0; // bit 3 Timer1 Oscillator Enable Control bit 1 = on
T1CON.TMR1CS = 0; // bit 1 Timer1 Clock Source Select bit...0 = Internal clock (FOSC/4)
TMR1H = 0x12; // preset for timer1 MSB register
TMR1L = 0x38; // preset for timer1 LSB register
T1CON.TMR1ON = 1; // bit 0 enables timer

// Interrupt Registers
INTCON = 0; // clear the interrpt control register
INTCON.T0IE = 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.T0IF = 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

//Do as funções que quero em loop infinito
do
{
funcao();
}

while(1); //endless loop

}

Não modifiquei todas as notas no código, confiem no escrito acima

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