Interrupções para LED e Frequencímetro

Software e Hardware para uC PIC

Moderadores: andre_luis, 51, guest2003, Renie

Interrupções para LED e Frequencímetro

Mensagempor picman62 » 13 Fev 2015 07:15

Olá pessoal, bom dia.
Gostaria da ajuda de vocês para solucionar um problema que ainda não consegui resolver.

Na minha programação para o PIC 16F877A estou incluindo um frequencímetro no pino C0 utilizando TIMER1. Acontece que quando uma determinada frequência é lida nesse pino, um LED deve piscar no pino C1. Quando fui fazer a programação na função main sem utilizar interrupções, não deu certo. O LED não piscava devido aos delays que sobrecarregam o processador quando é acionado juntamenteo com a função para o frequencimetro. Então coloquei essa instrução do LED em uma interrupção de TIMER0 e mantive o frequencimetro na função 'main'. Ocorre que o frequencimetro utiliza um delay de 1000ms para a leitura e quando as duas funções são iniciadas, mesmo com o LED na interrupção, há um offset na leitura do frequencimetro de 60 a 80 Hz para mais, o que é incaceitável. Isso é comprovado com um gerador de função conectado no pino C0.
Não encontrei nenhum frequencimetro na internet que utilize os ticks ao invés dos delays para fazer esse papel, para o compilador CCS que utilizo. Somente para o MIKROC. Sou iniciante em programação e não sei converter esse código ainda. No entanto, achei uma solução que pareceu resolver o meu problema em termos. Não achei para o TIMER0 mas achei um código para o LED ser colocado em uma interrupção de TIMER2 e fiz algumas modificações. O frequencimetro é utilizado na função main com o TIMER1, mas também utiliza o TIMER2 do led para o 'count'.
Aqui está o código da interrupção do LED:

cpp code
#define PER_SECOND 126 //valor que calculei para a correta leitura do frequencimetro baseado no timer2 
#int_timer2
void TimerLED()
{
static int8 led_count;//=(PER_SECOND)
// a instrução original era PER_SECOND -1 para o LED piscar em cada 1s.
if (led_count)
--led_count;
else
{
output_toggle(PIN_C1);
led_count=(6); // 126 - (PER_SECOND = 120)
}
if (count)
--count;


O frequencimetro na função main:
cpp code
{     
setup_timer_2(T2_DIV_BY_16,249,10); //seria 125 interrupções p/ segundo, mas na prática o valor de 126 é o correto
setup_timer_1(t1_external | T1_DIV_BY_1);
count=1;
while (count) ; //wait for interrupt
count=(PER_SECOND-1);
set_timer1(0);//start the count

while(count)
; //wait for one second
setup_timer_1(T1_DISABLED);
value=get_timer1(); }


Tudo está funcionando. Mas o meu problema é que possuo 3 condições para a piscada do LED. De acordo com a frequencia que é lida, ele pisca mais rápido para a frequência certa, mais lento para um offset de mais ou menos um valor e mais lento ainda quando esse valor é ainda maior. Acontece que não estou conseguindo uma instrução para utilizar na função main como 'if' que faça isso.
Ou seja, ele já inicia o 'rate' de piscada no valor (6) que já está dentro da interrupção. Esse valor será o utilizado para piscar mais rápido, juntamente com os valores 16 e 32 para piscar mais lento. Já tentei colocar uma variável lá e trazer os valores para a condição 'if' na função main, mas não funciona, ele pisca aleatoriamente lento além do que o frequencimetro fica com leitura alterada com offset gigantesco.

Como esse código dentro da interrupção deve ser escrito para que eu consiga na função main, controlar a taxa de piscada do LED em 3 condições diferentes e que também não afete a leitura do frequencimetro?

Obrigado e abraços.
picman62
Nibble
 
Mensagens: 53
Registrado em: 21 Dez 2014 08:40

Re: Interrupções para LED e Frequencímetro

Mensagempor RobL » 13 Fev 2015 08:10

Antes de analisar o soft (programador) devemos fazer a pergunta se não seria um problema do analista.
1- Preciso medir frequência. Tenho um periférico para medir f ?
Se sim, posso medir essa f com certo período que me atenda e o resultado ficar armazenado em uma variável.
Por ser um periférico, este poderá estar sempre medindo sem afetar outras tarefas. Viva os periféricos.
Por exemplo, posso medir essa f a cada segundo( ou com outra taxa), visto que um led será visto por olhos humanos que são muito lentos.

2- De acordo com o resultado desta variável, preciso fazer um led piscar em certa cadência.
Posso verificar o valor da frequência na variável dela e se dentro de certa faixa, tomar decisão de piscar rápido, outra faixa, lento, etc.

Ninguém vai ficar esperando pelo outro, ou seja, enquanto no loop do led o valor da var f for f1, o led vai piscar com período p1, se mudar para f2, pisca com p2 ...
De outra maneira, no loop principal, enquanto a var f não mudar não muda a cadência do led. Uma interrupção, altera o valor da var f. No loop principal o novo valor de f mudará a cadência do led.
Certamente, existem mil formas de resolver um problema.
RobL
Dword
 
Mensagens: 1546
Registrado em: 20 Fev 2007 17:56

Re: Interrupções para LED e Frequencímetro

Mensagempor picman62 » 13 Fev 2015 09:04

Obrigado pela resposta RobL.
Se entendi corretamente, seria assim?
Código: Selecionar todos
#int_timer2
void TimerLED()
{
  static int8 led_count;//=(PER_SECOND);

  int16 f1;
  int16 f2;
  int16 f3;
 
  if (led_count)
       --led_count;
   
  else
{
      output_toggle(PIN_C1);
 
       if (f1)
       led_count=(6);
       if (f2)
       led_count=(16);
       if (f3)
       led_count=(24);
}
   
   
   if (count)
      --count;
}


E na condição no loop principal poderia por por exemplo:

Código: Selecionar todos
 
int16 contador=5000;
if(value>=contador-(10) && value<=contador+(10))//intervalo de offset de freq lida 4990 e 5010
     {     
      f1;
      output_toggle(pin_c1);
      }   


Está correto?
picman62
Nibble
 
Mensagens: 53
Registrado em: 21 Dez 2014 08:40

Re: Interrupções para LED e Frequencímetro

Mensagempor ze » 13 Fev 2015 09:08

Tentemos...Confira se minha bola de cristal não está muito enferrujada... Basicamente voce quer fazer led piscar de acordo com a frequência. é isso?
Por partes...
a essência do frequencímetro é simples. Vamos ler <50,<100 e >100 Hz e fazer o led piscar de acordo com o valor. Deixe a entrada num contador TRM0 com prescaler 1:1 p.ex.(vai ter que ler o d.s. pra ver se é possível. Não dói nada) e deixe rodando livre. PaciênciaParePenseProduzaPratiquePercebaProgrida
Ajuste o TIMER1 pra uma interrupção de 1Hz. de novo, o indolor d.s. PPPPPPP
Uma variável global freq
Na interrupt:
Código: Selecionar todos
freq=TMR0; //só...
TMR0=0; //...isso

No main() vc já vai ter a freq prontinha e automática com zero esforço. O hw fez o trabalho sujo (PPPPPPP)
Agora o pisca led
Código: Selecionar todos
for(;;)
{
if (freq<50) {led^=1;delayms(500);} //1Hz p.ex.
if ((freq>50) && (freq<100) {led^=1;delayms(200);} //5Hz
if (freq>100) {led^=1;delayms(100);} //10Hz
}

bom, como disse foi só a essência que obviamente pode ser melhorada (como p.ex. usar TMR1H e L pra controlar o delay e um monte de etc).
ccs não vai rolar e ainda continuo insistindo que passe os olhos pelo d.s. pois além de sua mente, abrir-se-ão muitas portas

Talvez não seja nada disso... Mas dá um tempo pow. Este burro está ficando velho (não necessariamente nesta ordem). Vc pode tentar uma das outras 999 "formas de resolver um problema."
Avatar do usuário
ze
Dword
 
Mensagens: 1655
Registrado em: 05 Jun 2007 14:32

Re: Interrupções para LED e Frequencímetro

Mensagempor picman62 » 13 Fev 2015 09:21

Grande Ze!
Que bom que está por aqui e ainda não foi experimentar a sua fantasia de escola de samba. :mrgreen:
Pelo que entendi do que voce disse, o frequencimetro não mais fica 'dependente' do LED no timer2, e esse último agora tem um TIMER0 dedicado, certo?
Vou 'montar' a sua sugestão e dou um retorno.
picman62
Nibble
 
Mensagens: 53
Registrado em: 21 Dez 2014 08:40

Re: Interrupções para LED e Frequencímetro

Mensagempor ze » 13 Fev 2015 10:08

tipo isso sim meu fíi...
A contagem do Timer0 tem acesso pelo pino e vc pode dividir antes de aplicar na contagem (o 'ilegível' prescaler). Pra freq grande isso é legal (e obrigatório) pois TMR0=8 bits (vc já viu o d.s.?!!ah sim tem desenho viu!), pro seu caso de led isso não é empecilho.
Resumindo: TIMER0=contador, TIMER1=base de tempo (não necessariamente 1 segundo)
TIMER2 tem funções mais "nobres" e por isso gosto de "não usá-lo"

Alternativamente e ainda mais simplista, vc pode aplicar um bit da contagem direto no pino e nem precisa de TIMER1. Caso a freq varie a largos passos, vc pode perceber. Se for gradual, só com olhos muito muito muitooooô treinados mesmo

tipo assim:
Código: Selecionar todos
#define led RC0
...
led=TMR0>>5;// divide por 32

De fato já fiz algo assim pra "ouvir" um sinal de ultrasom

carnaval? pra mim tem valor nulo. o phoda é que nem é feriado esta merd@. e no país do carnaval hein...

sexta 13, mesmo assim... boa sorte!
Avatar do usuário
ze
Dword
 
Mensagens: 1655
Registrado em: 05 Jun 2007 14:32

Re: Interrupções para LED e Frequencímetro

Mensagempor picman62 » 13 Fev 2015 10:51

Já tinha passado uma olhada no datasheet. O timer0 do 16f é 8 bits. Na realidade, está perfeito para o caso do LED. Só preciso evitar delays com ele e usar só ticks de contagem, pois só quero ele piscando em certa taxa para frequencias especificas e delays arrebentam com a programação dos PICs...
O importante é ter uma suficiente precisão no frequencimetro para ler as frequencias corretas.
O que estava(está) ocorrendo é que quando o LED e o frequencimetro são acionados, ambos são afetados, ou o LED pisca errado muito lentamente ou o frequencimetro mostra leitura incorreta com offsets grandes.
Concordo também e não quero utilizar o timer2 para isso, porque ainda tem O PWM que irei fazer uso ligando e desligando um determinado pulso.

Só relembrando. São 3 frequencias que estou trabalhando. 5KHz, 8,KHz e 15KHz. Por isso o frequencimetro tem que ser no TIMER1 16 bits.
picman62
Nibble
 
Mensagens: 53
Registrado em: 21 Dez 2014 08:40

Re: Interrupções para LED e Frequencímetro

Mensagempor MOR_AL » 13 Fev 2015 19:02

picman62!
Atenção para o detalhe.
Um frequencímetro em linguagem diferente de assembly Não vai medir a frequência corretamente. Sempre vai medir um pouco mais ou um pouco menos.
Você está comparando sua frequência medida com três valores (o que está errado, porque é quase certo que estes valores não coincidirão com o valor medido).
Já o Zé está fazendo a verificação corretamente, pois ele está verificando se a frequência medida se encontra dentro de TRÊS FAIXAS. Qualquer medida com pequena percentagem de erro ainda assim cairá dentro de um dos ifs. No seu caso, é quase certo que nenhum if será escolhido.
Você informou que para ler até 15kHz precisa ser o timer1, porque tem 16 bits. Tudo bem, mas também pode ser um timer com apenas 8 bits, caso ele possua um prescaler que possa armazenar (dividir) a frequência de entrada por 64, 128 ou 256.
Outro detalhe é que para conhecer a frequência, você não precisa medir durante 1 segundo. Pode, por exemplo, medir durante 1/8 de segundo e multiplicar o resultado por 8. Melhor ainda. Nem precisa multiplicar o resultado por 8 (neste exemplo). Basta comparar o valor da frequência medida com as novas faixas 5k/8, 10k/8 e 15k/8.
MOR_AL
"Para o triunfo do mal só é preciso que os bons homens não façam nada." Edmund Burke.
"Nunca discutas com pessoas estúpidas. Elas irão te arrastar ao nível delas e vencê-lo por possuir mais experiência em ser ignorante". Mark Twain
Avatar do usuário
MOR_AL
Dword
 
Mensagens: 2934
Registrado em: 19 Out 2006 09:38
Localização: Mangaratiba - RJ

Re: Interrupções para LED e Frequencímetro

Mensagempor ze » 14 Fev 2015 17:33

moris, 1/2 offtopic mas... depende do compilador. ccs desconheço mas hitech-c pode ficar tão otimizado como se fosse feito em asm. Não só isso...: mesmo se programador asm = mediano tende a ficar a ficar ainda menor. experiência própria quando me considerava mediano em asm e fiz o mesmo projeto em c. Não cheguei ao nível avançado portanto não tenho como comparar +. (asm x c : desnecessário re-polemizar ok?)
em comum: tudo a ver prescaler, e /8
abç
Avatar do usuário
ze
Dword
 
Mensagens: 1655
Registrado em: 05 Jun 2007 14:32

Re: Interrupções para LED e Frequencímetro

Mensagempor RobL » 14 Fev 2015 21:08

Nem precisa fazer toda essa operação.
Poderia usar captura e comparar o valor do timer diretamente.
Para simplificar poderia zerar o timer antes de iniciar uma captura, devido a medida ser de baixa f. Teria que adequar o prescaler.
RobL
Dword
 
Mensagens: 1546
Registrado em: 20 Fev 2007 17:56

Re: Interrupções para LED e Frequencímetro

Mensagempor RobL » 14 Fev 2015 21:19

Por captura tanto faz ser em C ou qualquer linguagem, pois o valor medido estará esperando no timer para ser lido e comparado. A captura independe da linguagem é um processo totalmente eletrônico e atômico ( ou seja uma vez iniciado vai até o final sem interrupção).
Nos Pics, especialmente para a linha 16F, há muita diferença entre as soluções em C e Assembler, pois o mesmo não possui hardware adequado(pilhas, etc) nem instruções que facilite o uso de C.
Não haveria diferença no resultado dos periféricos em função da linguagem utilizada a não ser em algo muito especializado.
RobL
Dword
 
Mensagens: 1546
Registrado em: 20 Fev 2007 17:56


Voltar para PIC

Quem está online

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

x