Ir ao conteúdo
  • Cadastre-se

Como medir corrente ac usando pic?


cart

Posts recomendados

Ok Mauroviana, também fiz isso, o vtrx passou a dica em um outro tópico. Eliminou uma boa parte do erro, mas continuou a oscilar (minimamente) mesmo sem corrente nenhuma.

Então POIN. eu postei a função da conversão, lembrando que fiz alterações como sugerida pelo mauroviana. Mas qual é a sua duvida exactamente? Não sei se posso postar o programa.

A conversão para o ACS712-30A, ficou assim:



////////////////////////////////////////////////////////////////////////////////
float conversao(){

int y;
Media = 0;
for(y=0;y<=120;y++){
delay_us(100);
Media = Media + read_adc();
}
sinal = (media / 120);
sinal2 = (sinal*5.0)/1023; //0-->5v
return ((sinal2-OFFSET)*12); //0--30A
}
float Media, sinal,sinal2;

Ola Leo, eu estou fazendo essa progamação no micro c, e estou tentando encaixar as devidas mudanças aqui do ccs para o micro c..

Uma duvida q eu tenho é em relaçao a saida do acs, como q você fez? você retificou o sinal alternado para depois colocar no pic, ou você ligou direto a saida no pic sem nenhum ajuste?

Brigadao você ta me ajundo muito

Link para o comentário
Compartilhar em outros sites

Obrigado Leo, pelo esclarecimento.

Cart, então, se entra AC e sai AC, não seria o caso de fazer um algoritmo que "capte" os valores de pico? Deste modo, você evitará amostrar médias (leituras fora dos 90º da senoide). A leitura do pico da senoide representará, portanto, a corrente máxima medida. Algo do tipo:

- Cria uma variável que guardará o valor de pico medido. Vou chamar de adc_max e inicializá-la em zero.

Em um loop:

início do loop

- Conversor AD faz aquisição.

- O valor da aquisição é maior do que o valor atual de adc_max?

-> sim - guarda o valor em adc_max.

-> não - não guarda o valor

volta ao início do loop

O loop faz várias leituras. O resultado, portanto, é que a variável adc_max terá guardado o maior valor medido no loop, que será o de pico e que você usará no seu projeto.

Talvez aproveites a ideia.

Bons trabalhos.

Link para o comentário
Compartilhar em outros sites

Faz alguns anos, eu brinquei com esse mesmo CI. Levei alguns bailes, e o que funcionou melhor foi fazer o máximo de amostragens do sinal, dentro do período correspondente a 60 hz, e calcular o valor RMS, como se fizesse a Integral da forma de onda.

Obtive com este método resultados muito bons, mas só conseguí me livrar das pequenas oscilações quando fiz a terceira versão do meu PCB, e mesmo assim, tive de trabalhar com 9 bits de resolução.

O curioso foi que o resultado era muito bom quando a carga era resistiva, mas quando a carga aplicada usava algum tipo de chaveamento, tipo controle de potência por Triac, os erros eram bem grandes....

Depois de queimar a cabeça, achei o causador do problema no datasheet : a resposta de frequência do CI é pequena, e quando a senóide é interrompida, são gerados harmônicos , e conforme sobe a frequência desses harmônicos , pior é a onda na saída do CI, perdendo a fidelidade com a onda na entrada do mesmo, e fazendo com que a medida da corrente seja bem inferior à real.

Paulo

Link para o comentário
Compartilhar em outros sites

boa noite senhores como vai Leo tranquilo ? esse exemplo de programa tava na net e talvez ajude

#include <16F876.H>
#DEVICE ADC=10
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, NOLVP
#use delay(clock=48000000)

#include "flex_lcd.c"

void main()
{

lcd_init(); // Always call this first.

int16 veri, veri2, counter, valADC, akimMin, akimMax, topAkim, topGerilim, gerilimMin, gerilimMax;
float gerilim,akim, guc, akimOrt, gerilimOrt;
setup_adc_ports(0); // ALL ANALOGS
setup_adc(ADC_CLOCK_DIV_32);
delay_ms(100);
while(1){
counter =0;

set_adc_channel(0); //Current Channel
veri=read_adc();
akimMax=veri;
akimMin=veri;

set_adc_channel(1); //Voltage Channel
veri2=read_adc();
gerilimMin=veri2;
gerilimMax=veri2;

for(counter=0;counter<20000;counter++){
set_adc_channel(0);
veri=read_adc();

if(veri>akimMax){ //determine the read max value
akimMax=veri;
}

if(veri<akimMin){ //determine the read min value
akimMin=veri;
}

delay_us(1);
set_adc_channel(1);
delay_us(1);
veri=read_adc();

if(veri>gerilimMax){ //determine the read max value
gerilimMax=veri;
}

if(veri<gerilimMin){ //determine the read min value
gerilimMin=veri;
}
delay_us(1);
}

akimOrt=(akimMax+akimMin)/2.; //verinin ortalama değeri denge gerilimini (2.5V) vermeli

gerilim=(gerilimMax*5./1024)*339.6/4.68; //R1=335.0k, R2=4,68k (Vadc*(R1+R2))/R2

akim=((akimMax-akimOrt)*5./1024)*(60/4); //The sensor outputs from 0.5V to 4.5V for -30A to 30A respectively. Lets take the steady state value (akimOrt) out of the max value of the current. That difference is caused by the current..
valADC=akimMax-akimMin;

//printf(lcd_putc,"\fI=%.3fA V=%.3fV\n",akim, gerilim);
printf(lcd_putc,"\fI=%.3fA V=%3.1fV",akim,gerilim);
printf(lcd_putc,"\nIM=%Lu VM=%Lu",akimMax,gerilimMax);

delay_ms(100);
output_toggle(PIN_C3);
}

}

Link para o comentário
Compartilhar em outros sites

Leo, segue o método que eu fiz.

Programei uma interrupção do timer para interromper na frequência de 60 * 72 = 4.320 Hz . Assim terei 72 interrupções em um único período equivalente a 60 Hz.

Criei duas variáveis para guardar as contas, uma é a soma dos valores medidos, e a outra é a soma dos quadrados dos valores medidos.

Em cada uma das interrupções, faço a leitura do A/D, calculo o quadrado do valor, e adiciono esses dois valores nas duas variáveis citadas acima. Ou seja, estou fazendo a somatória.

Quando isso se repetir 72 vezes, já tenho tudo o que preciso para fazer a conta do valor RMS.

Olha que simples :

Pego a variável que contém a soma das leituras, divido ela por 72, e assim tenho o valor correspondente à leitura do nível DC , pois sabemos que na saída do ACS712 temos um nivel DC ( próximo de 2,5 volts ) mais uma senóide em AC . E o que queremos saber é exatamente o valor RMS dessa senóide !

Mas não há garantias que esse valor na ausência de sinal é exatamente 2,5 Volts, assim eu prefiro fazer o cálculo, divido a somatória dos valores por 72 e pronto, tenho o nível DC médio. Isso funciona muito bem para sinais com periodicidade.

E calculo o quadrado desse valor, vou chamar isso de X .

Agora, o truque :

Pego a variável que contém a somatória dos quadrados dos valores, divido ela por 72. Este é o valor referente ao total , isto é, contém a parte referente ao nível DC médio mais o valor referente à senóide AC. Vou chamar isso de Y .

Olha que beleza :

(Valor RMS da senóide)^2 = Y - X

Ou seja, basta subtrair um do outro e depois tirar a raiz quadrada, e voce terá o valor RMS de sua leitura, basta fazer a conversão de escala para ter o valor RMS da corrente.

Com este método tive os melhores resultados.

Se quiser ver a teoria por trás, está aqui :

https://en.wikipedia.org/wiki/Root_mean_square#cite_note-1

Paulo

Link para o comentário
Compartilhar em outros sites

Obrigado pela contribuição pessoal, será útil pra mim e pra muita gente.

boa noite senhores como vai Leo tranquilo ? esse exemplo de programa tava na net e talvez ajude



#include <16F876.H>
#DEVICE ADC=10
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, NOLVP
#use delay(clock=48000000)

#include "flex_lcd.c"

void main()
{

lcd_init(); // Always call this first.

int16 veri, veri2, counter, valADC, akimMin, akimMax, topAkim, topGerilim, gerilimMin, gerilimMax;
float gerilim,akim, guc, akimOrt, gerilimOrt;
setup_adc_ports(0); // ALL ANALOGS
setup_adc(ADC_CLOCK_DIV_32);
delay_ms(100);
while(1){
counter =0;

set_adc_channel(0); //Current Channel
veri=read_adc();
akimMax=veri;
akimMin=veri;

set_adc_channel(1); //Voltage Channel
veri2=read_adc();
gerilimMin=veri2;
gerilimMax=veri2;

for(counter=0;counter<20000;counter++){
set_adc_channel(0);
veri=read_adc();

if(veri>akimMax){ //determine the read max value
akimMax=veri;
}

if(veri<akimMin){ //determine the read min value
akimMin=veri;
}

delay_us(1);
set_adc_channel(1);
delay_us(1);
veri=read_adc();

if(veri>gerilimMax){ //determine the read max value
gerilimMax=veri;
}

if(veri<gerilimMin){ //determine the read min value
gerilimMin=veri;
}
delay_us(1);
}

akimOrt=(akimMax+akimMin)/2.; //verinin ortalama değeri denge gerilimini (2.5V) vermeli

gerilim=(gerilimMax*5./1024)*339.6/4.68; //R1=335.0k, R2=4,68k (Vadc*(R1+R2))/R2

akim=((akimMax-akimOrt)*5./1024)*(60/4); //The sensor outputs from 0.5V to 4.5V for -30A to 30A respectively. Lets take the steady state value (akimOrt) out of the max value of the current. That difference is caused by the current..
valADC=akimMax-akimMin;

//printf(lcd_putc,"\fI=%.3fA V=%.3fV\n",akim, gerilim);
printf(lcd_putc,"\fI=%.3fA V=%3.1fV",akim,gerilim);
printf(lcd_putc,"\nIM=%Lu VM=%Lu",akimMax,gerilimMax);

delay_ms(100);
output_toggle(PIN_C3);
}

}

Pelo que deu pra ver esse programa faz varias leituras do sinal máximo e minimo, e depois calcula o valor medio, certo?

Paulo eu vou analisar o teu método e fazer os testes. Se haver alguma dúvida posto aqui.

Link para o comentário
Compartilhar em outros sites

  • 4 semanas depois...
preciso da sua ajuda quanto ao deslocador de sinais de 2,5 V para 5 V para o ADC do Pic.

Oi Pedro, não percebi a tua duvida. Contudo no post #23 postei a parte do codigo que faz a conversão.


float Media, sinal,sinal2;

////////////////////////////////////////////////////////////////////////////////
float conversao(){

int y;
Media = 0;
for(y=0;y<=120;y++){
delay_us(100);
Media = Media + read_adc();
}
sinal = (media / 120);
sinal2 = (sinal*5.0)/1023; //0-->5v
return ((sinal2-OFFSET)*12); //0--30A
}

Link para o comentário
Compartilhar em outros sites

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

 

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

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!