Contador com PIC 16F628A

Software e Hardware para uC PIC

Moderadores: andre_luis, 51, guest2003, Renie

Contador com PIC 16F628A

Mensagempor Mixicus » 20 Mai 2009 19:20

Ola pessoal.
Sou novo aqui no forum e iniciante em programacao.
Tenho um projeto q consiste em captar o tempo em que uma onda quadrada fica em nivel 0 e mandar para um LCD assim que ela entrar em nivel 1.
A contagem teria que ser de 10us em 10us.
Exemplo:
Nivel 0 = 2,50ms
Nivel 1 = 10 ms
Assim que a onda entrar em nivel 1, terei que pegar o tempo em que ela ficou em nivel 0 e mandar pro LCD.
Alguem tem uma ideia de como eu poderia fazer isto?
Programo em C com o MikroC.
A ideia que tive foi:
- Assim que a onda entrar em nivel 0 acionar o TIMER para iniciar uma contagem e quando a onda subir para nivel 1 parar o TIMER e pegar o valor dele e mandar para uma variavel e depois para um LCD.
Espero que possam me ajudar.
Abraço.[/b]
Mixicus
Bit
 
Mensagens: 20
Registrado em: 11 Mai 2009 20:03
Localização: Brusque - SC

Mensagempor lpagano » 21 Mai 2009 08:35

Mixicus,

Primeiramente seja benvindo ao nosso fórum.

Quanto à sua dúvida essa idéia do timer é boa mas como ele conta ciclos de máquina dividido pelo seu prescaler você teria que pegar o valor do timer ao final do nível 0, tirar do valor inicial (diferença entre início e fim do timer) e multiplicar por um fator que dê o tempo em ms. Aí você quarda esse valor numa variável e o joga no LCD.
O MikroC tem bibliotecas prontas e bem eficientes para trabalhar com LCD

É uma resumo simples mas espero ter ajudado.


Valeu!
lpagano
Byte
 
Mensagens: 393
Registrado em: 06 Nov 2006 14:23

Re: Contador com PIC 16F628A

Mensagempor Djalma Toledo Rodrigues » 21 Mai 2009 09:07

Mixicus escreveu:...A contagem teria que ser de 10us em 10us.
Exemplo:
Nivel 0 = 2,50ms
Nivel 1 = 10 ms
Assim que a onda entrar em nivel 1, terei que pegar o tempo em que ela ficou em nivel 0 e mandar pro LCD.

Bom , vamos verificar antes se isso é viável.
Nivel 0 = 2,50ms mais Nivel 1 = 10 ms dá um periodo igual a 12,5 ms
Logo haverá atualização do Display 1 / 0,0 125s ou 80 vezes por segundo

Demasiado rápido não lhe parece ?
.
Avatar do usuário
Djalma Toledo Rodrigues
Dword
 
Mensagens: 2334
Registrado em: 03 Ago 2008 13:22

Mensagempor ze » 21 Mai 2009 09:49

Uma alternativa seria fazer (depois de configurar o timer1 como contador clock interno, zerado e etc e timer0 como timeout)
Código: Selecionar todos
#define pino RB0 //ex.
uint captura();
{
...
TMR0IF=TMR1H=TMR1L=0;
TMR1ON=1;
While(pino && !TMR0IF); //timer 0 pra timeout e não travar aqui na ausência de sinal ...ops... nível 0 então !pino.
TMR1ON=0;
return TMR1H*256 + TMR1L; // o 'tempo' está em TMR1H e TMR1L.
}
Tem um pic que tem um pino que controla se o oscilador oscila ou não. Skeci kualé. Tende a ser + eficiente. Atualize o display a cada 1/4 segundo pra resolver a questão do dj.
abç
Avatar do usuário
ze
Dword
 
Mensagens: 1655
Registrado em: 05 Jun 2007 14:32

Mensagempor Mixicus » 21 Mai 2009 17:46

lpagano escreveu:Mixicus,

Primeiramente seja benvindo ao nosso fórum.

Quanto à sua dúvida essa idéia do timer é boa mas como ele conta ciclos de máquina dividido pelo seu prescaler você teria que pegar o valor do timer ao final do nível 0, tirar do valor inicial (diferença entre início e fim do timer) e multiplicar por um fator que dê o tempo em ms. Aí você quarda esse valor numa variável e o joga no LCD.
O MikroC tem bibliotecas prontas e bem eficientes para trabalhar com LCD

É uma resumo simples mas espero ter ajudado.


Valeu!


Olá...
Estava tentando montar um esboço para praticar o prescaler do TIMER0, mas quando diminuo ele de 5 para 3 (OPTION_REG=5 para OPTION_REG=3), o valor do contador não é mais mostrado no LCD.
Este programa serve apenas para ver se o prescaler esta funcionando para começar a trabalhar com o TIMER0.
Como disse, sou iniciante em programação e desculpe qualquer besteira no programa hehe.
Gostaria de que me ajudassem a descobrir qual o problema do programa para dar continuidade à ele.
Abraços.

Segue abaixo o programa q fiz:

//INCLUSÕES DE ARQUIVOS FONTE
#include <C:\Arquivos de programas\Mikroelektronika\mikroC\Uses\ceprob.c>
#include <C:\Arquivos de programas\Mikroelektronika\mikroC\Uses\lcd.c>

//****************************************************************

//DEFINIÇÕES DAS ENTRADAS
#define chave RA7

//****************************************************************

//DEFINIÇÕES DAS SAÍDAS


//****************************************************************

// VARIÁVEIS GLOBAIS
char contador; // Variável de 8 bits
unsigned tempo; // Variável de 16 bits


//****************************************************************
void interrupt() // Início da rotina de interrupção
{
if(T0IF) // Verifica se a interrupção foi do Timer0
{
T0IF=0; // Se foi, limpa o flag de indicação
if(TMR0==0) // Quando o TIMER0 estourar sua contagem...
{ // ...terá passado 64us x 125 = 8ms
tempo--; // A cada 8ms decrementa o "tempo"
if(tempo==0) // Quando o "tempo" chegar a "zero"...
{ // ...terá passado 8ms x 125 = 1 segundo
contador++; // Incrementa o contador
if(contador==10) // Se o contador chegar a 10...
{
contador=0; // ...zera o contador
}
tempo=125; // O "tempo" é recarregado com 125
}
TMR0=131; // O TIMER0 é recarregado com 131
}
}
}


//****************************************************************

//ROTINA PRINCIPAL
void main() // Início do programa principal
{
TRISB = 0b00000000; // Todos os pinos do PortB como saída
PORTB = 0b00000000; // PortB é carregado
CMCON = 0x07; // Desabilita os comparadores de tensão
GIE=1; // Habilitação geral das interrupções
T0IE=1; // Habilitação da interrupção do Timer0
OPTION_REG=0x83; // Prescaler do Timer0 em 1:64
TMR0=131; // Carrega o Timer 0 para que ocorra uma interrupção a cada 8ms
tempo=125; // Carrega o tempo com 125
contador=0; // Contador inicia com o valor 0
lcd_inicia(); // Rotina para iniciar o LCD
lcd_limpa(); // Limpa o LCD

//****************************************************************

while(1)
{
lcd_posiciona(1,1); // Posiciona o cursor na linha 1 e coluna 1
lcd_valor(contador); // Imprimi o valor do contador no LCD
}
} // Fim do programa principal
Mixicus
Bit
 
Mensagens: 20
Registrado em: 11 Mai 2009 20:03
Localização: Brusque - SC

Mensagempor Mixicus » 25 Mai 2009 16:19

Alguem ai tem alguma dica para me ajudar a descobrir o q esta errado no programa acima?
Mixicus
Bit
 
Mensagens: 20
Registrado em: 11 Mai 2009 20:03
Localização: Brusque - SC

Mensagempor RobL » 25 Mai 2009 16:34

Quando você altera o valor do OPTION_REG de 5 para 3, está alterando um monte de bits que atuam no prescaler e dependendo do valor do OPTION_REG modifica outras bits em diferentes áreas.
Os 3 primeiros bits tem relação com o prescaler <2,0> <PS2,PS1,PS0>.
Quando o valor está em 5 (0x5) somente o bit zero e o bit 2 estão setados , dando um certo tempo de estouro no seu TMR0. Quando com 3 somente PS0 e PS1 estão setados gerando outro tempo no seu TMR0, bem menor que com 5 (1/16 e 1/64 veja no manual).
Não verifiquei se esta é a causa do problema na sua rotina. Verifique se com 1/16 dá algum problema em sua rotina ou passa a atropelar o tempo de algum hardware (lcd ou outro que esteja usando).
Se estiver usando pullup na porta para contar se OPTION_REG não tiver o bit 7 setado o pullup será desligado e não conta.
O OPTION_REG deveria ser 0x85 ou 0x83 e não 0x5 e 0x3. A não ser que não esteja usando pullup.
Editado pela última vez por RobL em 25 Mai 2009 16:44, em um total de 1 vez.
RobL
Dword
 
Mensagens: 1546
Registrado em: 20 Fev 2007 17:56

Mensagempor Mixicus » 25 Mai 2009 16:42

RobL escreveu:Quando você altera o valor do OPTION_REG de 5 para 3, está alterando um monte de bits que atuam no prescaler e dependendo do valor do OPTION_REG modifica outras bits em diferentes áreas.
Os 3 primeiros bits tem relação com o prescaler <2,0> <PS2,PS1,PS0>.
Quando o valor está em 5 (0x5) somente o bit zero e o bit 2 estão setados , dando um certo tempo de estouro no seu TMR0. Quando com 3 somente PS0 e PS1 estão setados gerando outro tempo no seu TMR0, bem menor que com 5 (1/16 e 1/64 veja no manual).
Não verifiquei se esta é a causa do problema na sua rotina. Verifique se com 1/16 dá algum problema em sua rotina.


Olá RobL, obrigado pela dica.
Eu recentemente comprei o livro DESBRAVANDO O PIC 16F628 e no APÊNDICE A vi que tem isto que você falou, mas gostaria de saber o porquê do meu porgrama não funcionar com o prescalar em 3, porque quando eu botava OPTION_REG=5 e OPTION_REG=4 ele funcionava, claro q com o valor 4 ele contava mais rapido porque diminuia o tempo de estouro do TIMER0, mas quando diminuo para 3 ou menos não vejo mais ele contar no meu LCD.
Se puder me ajudar agradeço.
Abraço.
Mixicus
Bit
 
Mensagens: 20
Registrado em: 11 Mai 2009 20:03
Localização: Brusque - SC

Mensagempor RobL » 25 Mai 2009 16:46

Veja lá em cima que eu estava editando quando você escreveu.
Veja se tem relação com pullup.
Na sua rotina você ligou o pullup bit 7.
RobL
Dword
 
Mensagens: 1546
Registrado em: 20 Fev 2007 17:56

Mensagempor Mixicus » 25 Mai 2009 20:19

RobL escreveu:Veja lá em cima que eu estava editando quando você escreveu.
Veja se tem relação com pullup.
Na sua rotina você ligou o pullup bit 7.


Olá RobL.
Testei de varias formas o prescaler nos suegintes valores:
OPTION_REG=0x5 (funcionou)
OPTION_REG=0x85 (funcionou)
OPTION_REG=0x4 (funcionou)
OPTION_REG=0x84 (funcionou)
OPTION_REG=0x3 (não funcionou)
OPTION_REG=0x83 (não funcionou)
OPTION_REG=0x2 (não funcionou)
OPTION_REG=0x82 (não funcionou)
OPTION_REG=0x1 (não funcionou)
OPTION_REG=0x81 (não funcionou)
OPTION_REG=0x0 (não funcionou)
OPTION_REG=0x80 (não funcionou)
Resolvi retirar o LCD e fazer ele contar no PORT com leds nos bits 0, 1, 2 e 3 e nos bits 4, 5, 6 e 7, mas o problema não foi resolvido.
Gostaria de que me ajudassem a descobrir o q pode ter de errado no programa.
Grato.
Mixicus
Bit
 
Mensagens: 20
Registrado em: 11 Mai 2009 20:03
Localização: Brusque - SC

Mensagempor RobL » 26 Mai 2009 10:13

Como lhe disse, não lí o seu programa, nem notei que esta fazendo a contagem direto pelo tmr0 e o pullup não vai interferir.
void interrupt() // Início da rotina de interrupção
{
if(T0IF) // Verifica se a interrupção foi do Timer0
{
T0IF=0; // Se foi, limpa o flag de indicação
if(TMR0==0) // Quando o TIMER0 estourar sua contagem...
{ // ...terá passado 64us x 125 = 8ms


Experimente colocar no lugar de :
Código: Selecionar todos
if(TMR0==0) use (TMR0>=0)


Deve funcionar. Neste caso o que ocorre é que com o prescaler menor (maior divisão do clock) se passam mais ciclos até o TMR0 sair do zero para 1. Para ficar claro, suponha o prescaler com valor de 1/1. A cada ciclo, após a interrupção, haverá um incremento do TMR0 e até chegar nesta linha na qual o valor do TMR0 é avaliado (se = 0) seu valor já não é zero.
Com uma divisão maior, pelo prescaler, ao testar essa linha, o valor do TMR0 ainda se encontra em zero, quando testado (if TMR0 == 0 ).
Acrescento, não há necessidade desse teste visto que a interrupção já tem esse teste embutido.
RobL
Dword
 
Mensagens: 1546
Registrado em: 20 Fev 2007 17:56

Mensagempor Mixicus » 26 Mai 2009 18:05

RobL escreveu:Como lhe disse, não lí o seu programa, nem notei que esta fazendo a contagem direto pelo tmr0 e o pullup não vai interferir.
void interrupt() // Início da rotina de interrupção
{
if(T0IF) // Verifica se a interrupção foi do Timer0
{
T0IF=0; // Se foi, limpa o flag de indicação
if(TMR0==0) // Quando o TIMER0 estourar sua contagem...
{ // ...terá passado 64us x 125 = 8ms


Experimente colocar no lugar de :
Código: Selecionar todos
if(TMR0==0) use (TMR0>=0)


Deve funcionar. Neste caso o que ocorre é que com o prescaler menor (maior divisão do clock) se passam mais ciclos até o TMR0 sair do zero para 1. Para ficar claro, suponha o prescaler com valor de 1/1. A cada ciclo, após a interrupção, haverá um incremento do TMR0 e até chegar nesta linha na qual o valor do TMR0 é avaliado (se = 0) seu valor já não é zero.
Com uma divisão maior, pelo prescaler, ao testar essa linha, o valor do TMR0 ainda se encontra em zero, quando testado (if TMR0 == 0 ).
Acrescento, não há necessidade desse teste visto que a interrupção já tem esse teste embutido.


Valeu RobL, funcionou certinho o prescaler com a dica que você me passou, agora voi poder dar continuidade ao meu projeto, brigadão.
Vê se surge alguma dica. Meu objetivo era usar o TMR0 para que a cada 10us aproximadamente ele incrementasse uma variável enquanto uma onda quadrada estivesse em nivel 0. Assim que ela subisse para nível 1, parasse de incrementar a variável e pegasse o valor dela e mandasse para um LCD.
A onda iria variar de 2ms ate 15ms apoximadamente, mas preciso de duas casas após a vírgula, por isso preciso incrementá-la a cada 10us.
Será que dará certo essa minha i´deia?
O LCD iria ser atualizado 4x por segundo.
Abraço e obrigado pelas dicas.
Mixicus
Bit
 
Mensagens: 20
Registrado em: 11 Mai 2009 20:03
Localização: Brusque - SC

Mensagempor RobL » 26 Mai 2009 18:26

Se você está querendo medir o tempo de um pulso use captura. Leia sobre o uso do timer1 (CCP). Há quem num pic já mediu tempos da ordem de dezenas de nano segundos, pois esses periféricos nos pics são muito rápidos.
RobL
Dword
 
Mensagens: 1546
Registrado em: 20 Fev 2007 17:56

Mensagempor Andre_Cruz » 27 Mai 2009 14:48

Experimenta usar a interupção por mudança de estado do RB0 !
Ou como o RobL disse CCP!

Abraço
André
Andre_Cruz
Word
 
Mensagens: 559
Registrado em: 03 Jan 2009 14:06


Voltar para PIC

Quem está online

Usuários navegando neste fórum: Nenhum usuário registrado e 1 visitante

x