Ir ao conteúdo
  • Cadastre-se

PIC Gerar Pulsos de baixa frequência com PIC12F675


Posts recomendados

Saudações a todos, atualmente me deparei com o seguinte problema, estou tentando gerar pulsos de baixa frequência com um PIC12F675, o algoritmo para gerar a frequência eu copie do seguinte post:

, a questão é a seguinte, um potenciômetro é utilizado para variar a frequência do pulso, que começa em aproximadamente 16Hz e vai até  aproximadamente 130hz, esse potenciômetro esta ligado ao conversor A/D do Pic, quando ele é variado a frequência também varia.

 Quando eu simulo no ISIS, se o potenciômetro estiver entre 1% a 70% os pulsos acontecem normalmente, acima disso eles entram em desordem.

O código que fiz é esse:  

int leitura = 0x00;						//Variavel auxiliar para receber valor do conversor A/D
int new_value = 0x00;					//Variavel auxiliar para mudar valor da frequencia		
int freq = 230;							//Varia que contem valor inicial da frequencia


void interrupt()
{
 static int pulse;						//Variavel que controla periodo do pulso
 
 if(T0IF_bit)
 {
  T0IF_bit   = 0x00;                    //Limpa a flag de estouro do TMR0
  TMR0       = 0x01;                    //Reinicia o TMR0
  
  --freq;
  
  if(freq == 0x00)
  {
   freq = new_value;
   pulse = freq/2;
  }
  if(pulse)
  {
   GPIO.F1   = 0x01;                    //Leva o GPIO.F1 a nivel logico 1
   --pulse;                             //Decrementa a variavel pulse
  }else
  {
   GPIO.F1  = 0x00;                     //Leva o GPIO.F1 a nivel logico 0
  }
 }
}

void main() 
{
 CMCON          = 0x07;                 //Desabilta os comparadores
 OPTION_REG     = 0x88;                 //0b10001000 Pull-ups desablitadas prescalaer adicionado ao WDT 1:1
 ANSEL          = 0x01;                 //RA0 como entrada do conversor A/D frequencia Fosc/2
 GIE_bit        = 0x01;                 //Habilita as interrupções globais
 PEIE_bit       = 0x01;                 //Habilita as interrupções dos perifericos
 T0IE_bit       = 0x01;                 //Habilita interrupção por estouro do TMR0
 TMR0           = 0x01;                 //Inicia TMR0 em 1 para estouro a cada 256us
 
 TRISIO         = 0x01;                 //Habilita GPIO 0 como entrada
 GPIO           = 0x00;                 //Inicia tudo em low

 while(1)
 {
  leitura = ADC_Read(0);

  if(leitura > 0) new_value = 230;      //16Hz
  if(leitura > 75) new_value = 150;   
  if(leitura > 150) new_value = 120;    
  if(leitura > 225) new_value = 94;    
  if(leitura > 300) new_value = 78;   
  if(leitura > 375) new_value = 67;    
  if(leitura > 450) new_value = 58;
  if(leitura > 525) new_value = 52;     
  if(leitura > 600) new_value = 47;
  if(leitura > 675) new_value = 43;
  if(leitura > 750) new_value = 39;
  if(leitura > 825) new_value = 36;
  if(leitura > 900) new_value = 33;
  if(leitura > 975) new_value = 30;		//130Hz
 }
}

 

protheus 2.png

Protheus.png

Link para o comentário
Compartilhar em outros sites

É porque você juntou intervalos ai em cima... ai ele faz a leitura do interrupt lê um valor... vai de novo para o interrupt e lê outro valor... no mesmo valor de resistência lida... ou seja fica variando... você tem que colocar intervalos...

 

Já que esse tópico me forçou a fazer a simulação para ver o problema vou deixar a parte do código modificado... mas não costumo fazer isso lol aqui pelo menos resolveu...

 

ah sobre o pino MCLR ou você desabilita ele via Projet edite ou você colocar um resistor de 10k ligado ele aos 5V...

int leitura = 0x00;						//Variavel auxiliar para receber valor do conversor A/D
int new_value = 0x00;					//Variavel auxiliar para mudar valor da frequencia
int freq = 230;							//Varia que contem valor inicial da frequencia


void interrupt()
{
 static int pulse;						//Variavel que controla periodo do pulso

 if(T0IF_bit)
 {
  T0IF_bit   = 0x00;                    //Limpa a flag de estouro do TMR0
  TMR0       = 0x01;                    //Reinicia o TMR0

  --freq;

  if(freq == 0x00)
  {
   freq = new_value;
   pulse = freq/2;
  }
  if(pulse)
  {
   GPIO.F1   = 0x01;                    //Leva o GPIO.F1 a nivel logico 1
   --pulse;                             //Decrementa a variavel pulse
  }else
  {
   GPIO.F1  = 0x00;                     //Leva o GPIO.F1 a nivel logico 0
  }
 }
}

void main()
{
 CMCON          = 0x07;                 //Desabilta os comparadores
 OPTION_REG     = 0x88;                 //0b10001000 Pull-ups desablitadas prescalaer adicionado ao WDT 1:1
 ANSEL          = 0x01;                 //RA0 como entrada do conversor A/D frequencia Fosc/2
 GIE_bit        = 0x01;                 //Habilita as interrupções globais
 PEIE_bit       = 0x01;                 //Habilita as interrupções dos perifericos
 T0IE_bit       = 0x01;                 //Habilita interrupção por estouro do TMR0
 TMR0           = 0x01;                 //Inicia TMR0 em 1 para estouro a cada 256us

 TRISIO         = 0x01;                 //Habilita GPIO 0 como entrada
 GPIO           = 0x00;                 //Inicia tudo em low

 while(1)
 {
  leitura = ADC_Read(0);

  if(leitura > 0&& leitura <=75) new_value = 230;      //16Hz
  if(leitura > 75&& leitura <=150) new_value = 150;
  if(leitura > 150&& leitura <=225) new_value = 120;
  if(leitura > 225&& leitura <=300) new_value = 94;
  if(leitura > 300&& leitura <=375) new_value = 78;
  if(leitura > 375&& leitura <=450) new_value = 67;
  if(leitura > 450&& leitura <=525) new_value = 58;
  if(leitura > 525&& leitura <=600) new_value = 52;
  if(leitura > 600&& leitura <=675) new_value = 47;
  if(leitura > 675&& leitura <=750) new_value = 43;
  if(leitura > 750&& leitura <=825) new_value = 39;
  if(leitura > 825&& leitura <=900) new_value = 36;
  if(leitura > 900&& leitura <=975) new_value = 33;
  if(leitura > 975) new_value = 30;		//130Hz
 }
}

 

adicionado 2 minutos depois

Minha falta de experiência já deveria ter visto de cara que era eram os intervalos e não ficar simulando aqui... mas enfim...

adicionado 35 minutos depois

Já ia me esquecendo... você simplesmente poderia colocar uma função para tirar os valores assim não trabalharia com intervalos...

Tipo

new_value=leitura*(função do primeiro grau qualquer)

e colocar intervalos de funcionamento

if(leitura > 0&& leitura <=975)  {new_value=leitura*(função do primeiro grau qualquer) ;}

Pronto com poucas linhas você consegue fazer até melhor... Ou você pode usar um "For" para fazer isso... e por ai vai...

 

Enfim... melhore teu código...

Link para o comentário
Compartilhar em outros sites

  • Membro VIP
7 horas atrás, Bommu Perneta disse:

melhore teu código...

Algo como...

unsigned char const tabela={230,150,120,94,78.....39,36,33};
...
for (;;)
{
leitura = ADC_Read(0); new_value=tabela[leitura/75];
}

Estás a fazer um pianinho?

 

Tem como reduzir a parte da interrupt também mas to com preguiça de pensar agora

Link para o comentário
Compartilhar em outros sites

Muito obrigado, Bommu Perneta, e Isadora Ferraz, fantástico quantas linhas foram poupadas apenas melhorando o código, estou aprendendo aos poucos a programar e suas dicas foram muito valiosas.

12 horas atrás, Bommu Perneta disse:

Enfim... melhore teu código...

Eu o refiz da seguinte forma, seguindo as suas orientações:

unsigned const char tabela[]={230,150,120,94,78,67,58,52,47,43,39,36,33,30};	
int leitura = 0x00;
int new_value = 0x00;
int freq = 230;

void interrupt()
{
 static int pulse;
 
 if(T0IF_bit)
 {
  T0IF_bit = 0x00;
  TMR0 = 0x01;
  
  if(!--freq)
  {
   freq = new_value; pulse = freq/2;
  }
  if(pulse)
  {
   GPIO.F1 = 0x01; --pulse;
  }else GPIO.F1 = 0x00;
 }
}

void main()
{
 CMCON          = 0x07;                 //Desabilta os comparadores
 OPTION_REG     = 0x88;                 //0b10001000 Pull-ups desablitadas prescalaer adicionado ao WDT 1:1
 ANSEL          = 0x01;                 //RA0 como entrada do conversor A/D frequencia Fosc/2
 GIE_bit        = 0x01;                 //Habilita as interrupções globais
 PEIE_bit       = 0x01;                 //Habilita as interrupções dos perifericos
 T0IE_bit       = 0x01;                 //Habilita interrupção por estouro do TMR0
 TMR0           = 0x01;                 //Inicia TMR0 em 1 para estouro a cada 256us

 TRISIO         = 0x01;                 //Habilita GPIO 0 como entrada
 GPIO           = 0x00;                 //Inicia tudo em low

 while(1)
 {
   for(;;)
   {
    leitura = ADC_Read(0);
    new_value = tabela[leitura/75];
   }
 }

}

 

5 horas atrás, Isadora Ferraz disse:

Estás a fazer um pianinho?

 

Não, é um pulsador para eletro injetor automotivo.

 

5 horas atrás, Isadora Ferraz disse:

Tem como reduzir a parte da interrupt também mas to com preguiça de pensar agora

 

Tem como reduzir mais que isso ? :

void interrupt()
{
 static int pulse;
 
 if(T0IF_bit)
 {
  T0IF_bit = 0x00;
  TMR0 = 0x01;
  
  if(!--freq)
  {
   freq = new_value; pulse = freq/2;
  }
  if(pulse)
  {
   GPIO.F1 = 0x01; --pulse;
  }else GPIO.F1 = 0x00;
 }
}

 Mais uma vez muito obrigado a todos. 

Link para o comentário
Compartilhar em outros sites

  • Membro VIP

De fato se a proposta é gerar uma forma de onda quadrada com frequência variável em função do resultado do ad, , penso em algo minimalista assim...
 

void interrupt()
//{
//if(T0IF_bit) //nem precisa quando se tem só uma interrupt
{
T0IF_bit = 0x00; TMR0 = 0x01;
if(!--freq) GPIO.F1^=1;
}
//}

e no loop
 

for(;;) //ou while(1)
{
leitura = ADC_Read(0);
freq=tabela[leitura/75];
while(freq);//sincronizado com a interrupt
}

 

Mas isso é só pra quando fosse um mc tipo pic10F com 256 bytes e flash. No seu caso nem precisa pois o mc tem memória de sobra.

Ah o 10f não tem ad? você é que pensa...

adicionado 6 minutos depois

ah sim. Acredite se quiser mas tem como reduzir ainda + beirando às raias de duas linhas de programa. Mas não quero lhe causar indigestão...

Link para o comentário
Compartilhar em outros sites

7 horas atrás, Isadora Ferraz disse:

De fato se a proposta é gerar uma forma de onda quadrada com frequência variável em função do resultado do ad, , penso em algo minimalista assim...
 


void interrupt()
//{
//if(T0IF_bit) //nem precisa quando se tem só uma interrupt
{
T0IF_bit = 0x00; TMR0 = 0x01;
if(!--freq) GPIO.F1^=1;
}
//}

e no loop
 


for(;;) //ou while(1)
{
leitura = ADC_Read(0);
freq=tabela[leitura/75];
while(freq);//sincronizado com a interrupt
}

 

Mas isso é só pra quando fosse um mc tipo pic10F com 256 bytes e flash. No seu caso nem precisa pois o mc tem memória de sobra.

Ah o 10f não tem ad? você é que pensa...

adicionado 6 minutos depois

ah sim. Acredite se quiser mas tem como reduzir ainda + beirando às raias de duas linhas de programa. Mas não quero lhe causar indigestão...

 

Nossa... Show !!

 

7 horas atrás, Isadora Ferraz disse:

ah sim. Acredite se quiser mas tem como reduzir ainda + beirando às raias de duas linhas de programa. Mas não quero lhe causar indigestão...

:D:D Resolvido, muito obrigado por sanarem minhas duvidas.

Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

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

 

GRÁTIS: ebook Redes Wi-Fi – 2ª Edição

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!