Página 1 de 2

Como melhorar precisão do pic

MensagemEnviado: 05 Jul 2015 20:15
por rosiley
Boa noite pessoal, estou com dificuldades em acertar a precisão do meu projeto.

Estou usando como base do meu projeto o livro "CRIAÇÃO DE SISTEMAS SUPERVISÓRIOS EM MICROSOFT VISUAL C# 2010 EXPRESS - CONCEITOS BÁSICOS, VISUALIZAÇÃO E CONTROLES". Estou o compilador CCS C, só que não consigo realizar a leitura dos valores com precisão apesar de estar utilizando um processador de 12 bits e ao mesmo tempo não tenho a informação em tempo real no aplicativo e tem mais eu preciso que os valores sejam informado com o sinal (.) pois alguns dos valores são representados em milivolts, segue abaixo o código para a análise de voces.
Informo tambem que estou utilizando uma referencia de 5volts.

cpp code
#include<18F4553.h>           //Inclui arquivo header do PIC 18F4553
#device ADC = 12 //Define 12 bits para o resultado da conversão AD
#use delay (clock=20000000) /*Definição da frequência do cristal para cálculo
..dos delays*/
#fuses HS, NOWDT, PUT,BROWNOUT, NOLVP //Configuração dos bits de controle

//Definições para a comunicação serial
#use RS232 (Baud=9600, enable = PIN_C5, xmit = PIN_C6, rcv = PIN_C7)
#include <2432.c>
#include <DS1307.c>
//#include <RS485.c>

//variáveis para armazenamento da conversão

int32 AN; // AN
int32 AN1; // AN1
int32 AN4; // AN4
int32 AN5; // AN5
int32 AN6; // AN6
int32 AN7; // AN7
int32 AN8; // AN8

int display = 0; //variáveis de controle para o display de leds

/******************************************************************************
variáveis de controle:
temperatura;
agua;
cont = controle de índice para recepção serial;
tempo = informação de tempo em 2 segundos
*******************************************************************************/
int temperatura = 0, agua=0, cont=0, tempo=0;

int1 tmp = 0; /*variável de controle de tempo em 2 segundos para
alterarção das informações no LCD*/
int rec[5]; //Variável de recepção de dados pela serial

#INT_RDA //Diretiva de identficação p/ int. pela recepção serial
void rec_serial() //Funçõa de tratamento da recepção de dados
{
rec[cont] = getc(); /*Lê o dado vindo pela serial e o armazena em
rec na posição (índice) informado por cont*/

if (rec[cont] == 0x0D) //Verifica se o dado recebido é igual a CR (0x0D)
{
//Liga O Display de Leds
if (rec[0]=='L') //Verifica se os primeiros caracteres são 'L'
{
display = 1; //controle do display de leds = 1
output_bit(PIN_D0,display); //Liga o display conectado ao pino RD0
}

//Desliga o display de Leds
if (rec[0]=='D') //Verifica se os primeiros caracteres são 'D'
{
display = 0; //controle do display de leds = 0
output_bit(PIN_D0,Display); //Desliga o display conectado ao pino RD0
}

/*Após recebido todos os dados da serial, faz a limpeza de toda a
variável rec e retorna o controle de índices cont em 0*/
for(cont = 0; cont < 5; cont++) rec[cont] = '\0';
cont = 0;
}
else
/*Se ainda não foram recebidos todos os dados de controle, incrementa
a variável de índice cont*/
cont++;
}

#INT_TIMER0 //Diretiva de indetificação da int. do Timer 0

void PiscaLED()
{
static boolean PiscaLed; //para piscar o led.
static int contador; //para contar o tempo de 1/2 segundo.
set_timer0(61-get_timer0());
contador++;
if(contador == 64) //Se contou 64 (1/2 segundo).
{
contador=0; //zera contagem.
PiscaLed = !PiscaLed; //Inverte bit;
output_bit(pin_C0, PiscaLed); //Liga/desliga LED.
}
}

void Trata_t0() //Função para tratamento do Timer 0
{
tempo++; //Incrementa a variável tempo a cada 25ms
if (tempo >= 80) //Se tempo >= 80 <=> 2 segundos?
{
tmp = 1; //Variável de controle de tempo 2 seg vai para 1
tempo = 0; //Retorna a variável tempo em 0
}
SET_TIMER0(61); //Retorna o valor inicial ao Timer 0
}

//Formato do protocolo = AN0:0000:TMP:0000:00000000
void escreve_serial() //Função de envio do protocolo para a serial
{
printf("AN0:%04lu",AN * 5000/4095); //Envia dados de conversão A/D
printf(":"); //Controle do protocolo
printf("AN1:%04lu",AN1 * 5000/4095); //Envia dados de conversão A/D
printf(":"); //Controle do protocolo
printf("AN4:%04lu",AN4 * 5000/4095); //Envia dados de conversão A/D
printf(":"); //Controle do protocolo
printf("AN5:%04lu",AN5 * 5000/4095); //Envia dados de conversão A/D
printf(":"); //Controle do protocolo
printf("AN6:%04lu",AN6 * 5000/4095); //Envia dados de conversão A/D
printf(":"); //Controle do protocolo
printf("AN7:%04lu",AN7 * 24000/4095); //Envia dados de conversão A/D
printf(":"); //Controle do protocolo
printf("AN8:%04lu",AN8 * 5000/4095); //Envia dados de conversão A/D
printf(":"); //Controle do protocolo
/******************************************************************************
Envia dados referentes ao circuito de aquecimento, ventoinha e leds
0: desligado
1: ligado
******************************************************************************/
printf("%d%d00%d\r\n",agua, temperatura, display);

}

void main() //Função principal
{
//Configura as entradas analógicas AN0 a AN8
SETUP_ADC_PORTS(AN0_TO_AN8|VREF_VREF); //Utiliza o clock interno para tempo de aquisição
//Utiliza o clock externo para tempo de aquisição
SETUP_ADC(ADC_CLOCK_DIV_32);
//Habilita interrupção global
Enable_Interrupts(GLOBAL);
//Habilita interrupção por recepção de dados na serial
Enable_Interrupts(INT_RDA);
//Habilita interrupção pelo overflow do Timer 0
ENABLE_INTERRUPTS(INT_TIMER0);
/*Configura Timer 0 para incremento pelo ciclo de máquina
Prescaler de 1:256 e modo de operação em 8 bits*/
SETUP_TIMER_0(RTCC_INTERNAL | RTCC_DIV_256 | RTCC_8_BIT);
//Inicia o Timer 0 com o valor 61 - Interrupção a cada 25ms
SET_TIMER0(61);


output_D(0x00); //Faz toda a porta D = 0

display = input_state(PIN_D0); //armazena em display o estado do pino RD0

/*Faz a limpeza de toda a variável rec e faz o controle de índices cont em 0*/
for(cont = 0; cont < 5; cont++) rec[cont] = '\0';
cont = 0;

while(true) //Loop principal
{
if (!input(PIN_B4)) //Se chave conectada ao pino RB3 for pressionada
{
agua = 1; //Faz controle da detecção de água = 1
}
else
{
agua = 0; //Faz controle da detecção de água = 0
}

SET_ADC_CHANNEL(0); //Configura o canal de leitura 0
delay_us(100); //Tempo de ajuste do canal (necessário)
AN = READ_ADC(); //Faz a conversão AD e a salva na variável ad0

SET_ADC_CHANNEL(1); //Configura o canal de leitura 1
delay_us(100); //Tempo de ajuste do canal (necessário)
AN1 = READ_ADC(); //Faz a conversão AD e a salva na variável ad0

SET_ADC_CHANNEL(4); //Configura o canal de leitura 4
delay_us(100); //Tempo de ajuste do canal (necessário)
AN4 = READ_ADC(); //Faz a conversão AD e a salva na variável ad0

SET_ADC_CHANNEL(5); //Configura o canal de leitura 5
delay_us(100); //Tempo de ajuste do canal (necessário)
AN5 = READ_ADC(); //Faz a conversão AD e a salva na variável ad0

SET_ADC_CHANNEL(6); //Configura o canal de leitura 6
delay_us(100); //Tempo de ajuste do canal (necessário)
AN6 = READ_ADC(); //Faz a conversão AD e a salva na variável ad0

SET_ADC_CHANNEL(7); //Configura o canal de leitura 7
delay_us(20); //Tempo de ajuste do canal (necessário)
AN7 = READ_ADC(); //Faz a conversão AD e a salva na variável ad0

SET_ADC_CHANNEL(8); //Configura o canal de leitura 8
delay_us(20); //Tempo de ajuste do canal (necessário)
AN8 = READ_ADC(); //Faz a conversão AD e a salva na variável ad0


if (AN4>=200) //Se tempint >= 200 (aprox. 25 graus)
{
temperatura = 1; //Faz controle da temperatura = 1
}

if (AN4<=170) //Se tempint <= 170 (aprox. 20 graus)
{
temperatura = 0; //Faz controle da temperatura = 0;
}

escreve_serial(); //Envia dados pela serial

delay_ms(300); //Atraso de 100ms
}
}

Re: Como melhorar precisão do pic

MensagemEnviado: 05 Jul 2015 20:39
por xultz
Se possível, cole o código usando as tags Code, ou cola teu código no site codeviewer.org e coloca o endereço aqui, porque analisar código sem indentação é osso.

Re: Como melhorar precisão do pic

MensagemEnviado: 05 Jul 2015 22:11
por EvandrPic
Conversor AD de 12 bits...
rosiley escreveu:... apesar de estar utilizando um processador de 12 bits...

Re: Como melhorar precisão do pic

MensagemEnviado: 05 Jul 2015 22:51
por andre_luis
Que valores estão aparcendo ?

Re: Como melhorar precisão do pic

MensagemEnviado: 06 Jul 2015 08:20
por EDSONCAN
Vamos la,

Se o seu ruido não vem de problemas de pcb ou dos CI operacionais de entrada que da para ver com o osciloscópio, aumenta os delays e usa uma referencia de tensão externa para o AD estabilizada em temperatura, cuidado com o GND, separe o digital do analógico sempre.

Em controle de processo se trabalha por varredura, ou seja, tem que completar um ciclo de leitura e ação dentro de um determinado tempo e se prioriza alguma tarefas em função de outras, para isso se usa núcleos de tempo real, seu programa é linear, portanto vai ter limitações, quando quiser colocar mais coisas funcionando.

Eu não uso getc, recebo por int na serial, evita que dois caracteres sejam transmitidos e o sistema não pegue devido a algum processo que demore.

Abraços

Re: Como melhorar precisão do pic

MensagemEnviado: 06 Jul 2015 09:12
por rosiley
Bom dia.

Peço desculpas pelo erro em postar o código.

Consegui resolver o problema da precisão em partes, os valores abaixo de 4.5 volts aparecem beleza sem problema algum mas quando o valor ultrapassa os 4.5 volts ele fica marcando os mesmos 4.5 v estou utilizando referencia externa de 5 volts ajustado em 4.997 mv. Pois precisarei utilizar toda a escala do processador pois um dos sensores tem o seu fundo de escala em 5v.

Outro problema é que utilizando o hyperterminal para verificar o funcionamento o mesmo hora ou outra aparece caracteres que não condiz com o valor a ser mostrado.

Re: Como melhorar precisão do pic

MensagemEnviado: 06 Jul 2015 12:53
por andre_luis
Poderia postar aqui o diagrama esquematico do circuito ?

Re: Como melhorar precisão do pic

MensagemEnviado: 06 Jul 2015 16:12
por ze
chutar pode?
chute 1...
experimente fazer
Código: Selecionar todos
(AN*5000)/4095;

onde está
Código: Selecionar todos
AN * 5000/4095

a não ser que int32 seja o mesmo que float

chute 2...
Com relação ao hyperterminal, pode ser que a interrupt do led esteja zoando o barraco

Agora sério... para ad de 12 bis e medir sinal bem baixo, suas referências (+5, gnd) deve ter um layout bem feito além de ter boa estabilidade e precisão. P.ex. não aconselho usar o +5 da alimentação do mc e etc. Mas isso vc ainda vai sentir na pele. Por hora nada a ver com seu problema...

Re: Como melhorar precisão do pic

MensagemEnviado: 06 Jul 2015 16:58
por rosiley
ze escreveu:chutar pode?
chute 1...
experimente fazer
Código: Selecionar todos
(AN*5000)/4095;

onde está
Código: Selecionar todos
AN * 5000/4095

a não ser que int32 seja o mesmo que float

chute 2...
Com relação ao hyperterminal, pode ser que a interrupt do led esteja zoando o barraco

Agora sério... para ad de 12 bis e medir sinal bem baixo, suas referências (+5, gnd) deve ter um layout bem feito além de ter boa estabilidade e precisão. P.ex. não aconselho usar o +5 da alimentação do mc e etc. Mas isso vc ainda vai sentir na pele. Por hora nada a ver com seu problema...


Amigo boa tarde.

Verifiquei o circuito utilizando as suas observações e que por sinal me ajudar a enxergar o problema.
Retirei a tensão de referência dos 5v e coloquei diretamente na alimentação principal de cara a precisão e os sinais estranhos desapareceram, tendo uma leitura homogenea e estavel, retirei tambem tambem os leds que fazem a monitoração dos dados enviados e recebidos, a velocidade de recepção aumentou em muito.

Agora vou partir para a confecção de um circuito de referencia com boa estabilidade.

Obrigado pela ajuda, vou fazer os testes e verificar se está tudo do jeito que quero e posto o resultado aqui.

Re: Como melhorar precisão do pic

MensagemEnviado: 29 Jul 2015 19:58
por rosiley
Boa noite pessoal, volto aqui mais uma vez para pedir a ajuda a vocês.

É o seguinte, fiz as modificações no meu código com as instruções de vocês mas me deparei com um problema que não consigo resolver ou não consigo entender, montei todo o circuito na pci que mandei fabricar e funciona perfeitamente mais só que os valores do meu adc está variando muito, encontrei um código em outro fórum mas não entendi como fazer. Segue parte do código abaixo

Código: Selecionar todos
#include <18F4520.h>
#device adc=10

float Media,sinal,sinal2,OFFSET=1.71;

float conversao(){

   Media = 0;
   for(y=0;y<=38;y++){
            delay_us(100);
            Media = Media + read_adc();         
       }
   sinal = (media / 38);     
   sinal2 = (sinal*5.0)/1023;
   return ((sinal2-OFFSET)*8);

Re: Como melhorar precisão do pic

MensagemEnviado: 30 Jul 2015 12:27
por ze
Se só entender lhe basta, então tentemos...O código faz a média de 38 leituras. De fato é melhor fazer media de numeros base 2 por ser binário. No caso 32 e não precisa ser float pois o valor da conversão é int. Algo assim...
Código: Selecionar todos
unsigned int conversao()
{
unsigned char y;
unsigned int media=0;
for (y=0;y<32;y++) {media+=adcread();delay(xxx);}
return media/32;
}

e no programa principal
Código: Selecionar todos
float sinal2;
sinal2 = (conversao()*5.0)/1023;

Também acho que não demos muita bola ao último parágrafo do meu post anterior. Há probabilidade de ser problema de layout. Publique o esquema e o desenho do layout (pra eu copiar seu projeto e ficar milionário... isso foi engraçado? ... sqn)

Re: Como melhorar precisão do pic

MensagemEnviado: 30 Jul 2015 12:42
por rosiley
Ze, obrigado pela ajuda.

Agora se isto que estou fazendo vai me deixar milionário, tenho que correr antes que outro fique. rsrsrsrsr
Mais obrigado de novo, vou ler e reler o que você escreveu e aplicar nos testes, como falei anteriormente tudo está funcionando, só me resta mesmo é fazer com que o valor do ad fique estável pois tenho bastante variação, estou usando um lm 324 como amplificador de sinal na simulação via proteus tudo funciona mais na prática tenho essas variações.

Re: Como melhorar precisão do pic

MensagemEnviado: 30 Jul 2015 13:13
por rosiley
Segue anexo o ckt de amplificação do sinal.

Re: Como melhorar precisão do pic

MensagemEnviado: 30 Jul 2015 14:24
por ze
seu circuito tá 1/2 estranho. certeza que é assim mesmo? bom... tem algumas variáveis que se devem definir
-que tipo de sinal é? de onde vem? quantos v? mV? uV? é dc, claro.
-qual o valor do ganho - em quantas vezes pretendeu amplificar?
-qual a proposta final do projeto?
-o layout é crítico. aquele gnd p.ex não pode ir pro regulador de voltagem e sim pro pino gnd do mc. O vcc-vdd preferencialmente outro que não seja o mesmo do mc.
-o mc usa ser turrão quando troca de um canal pra outro. Vc deve dar um tempo e as vezes até mesmo deixar as outras entradas como digital pra ler a "analógica do momento"
-etc
Mostre o desenho do layout.
Cogite no futuro migrar para avr. Alguns têm amplificador

Re: Como melhorar precisão do pic

MensagemEnviado: 30 Jul 2015 16:35
por MOR_AL
Meu amiguinho. Acho que você está com um problema.
Para poder analisar o circuito:
1 - Quais são os limites de tensão dos sinais fornecidos por J1, pinos 1, 2 e 3?
2 - Quais são os limites de frequência dos mesmos sinais?
3 - Você conhece as impedâncias de saída dos sinais fornecidos por J1, pinos 1, 2 e 3? Quais seriam? Mesmo uma ordem de grandeza bastaria.

Informações adicionais:
1 - O LM324, assim como muitos ou todos os amplificadores operacionais (AO) possuem limitações de tensão máxima comum de entrada. Em outras palavras; a saída não responde (como deveria) se a diferença de tensão entre o sinal e a tensão de alimentação for inferior a um determinado valor. Ex. Vcc ou Vdd = +5V e Vsinal de pico em 4,5V. A diferença é de 0,5V. Acho que para p LM324 essa diferença não pode ser inferior a 1,5V. Pelo menos é o que consta no manual, mas em determinadas condições gerais. Em alguns casos especiais esta diferença não pode ser maior que 2V e em outros casos esta diferença é menor. Mas independente das condições, a tensão de modo comum [(Ventrada positiva + Ventrada negativa) /2] não pode alcançar a tensão de alimentação (Vcc, ou Vdd).
2 - Os AO reais também possuem limitações quanto à faixa de tensão de saída. Para este operacional, a tensão mínima de saída pode ir até 5mV (típico) ou 20mV (máximo). Isso para Vcc = 5V e RL = 10k ohms.
Já a tensão máxima de saída, em boas condições, pois vai depender da corrente de saída, é de no mínimo 1V abaixo de Vcc ou Vdd. Isso quer dizer que, se a sua fonte for de 5V, o AO não DEVE funcionar corretamente com tensões de saída superiores a 4V.
3 - Este AO em especial, possui um circuito para reduzir o consumo da corrente de alimentação. Para isso ele pode funcionar ou em Classe A, ou em Classe B. Vai depender da tensão de saída. Em alguns casos, para prevenir a distorção de Cross-Over, que ocorre com sinais de saída inferiores a 1V, é necessário incluir um resistor da saída ao terra.

4 - Como você está usando um CAD com 12 bits de resolução, este (e muitos AO) não servirão para o seu projeto.
Explico:
Um conversor de 12 bits possui 2 elevado a 12 valores, ou 4096 valores, certo?
Isso quer dizer que, para um sinal que pode variar entre 0V e +5V, você terá degraus mínimos de tensão de 5.000mV / 4096 = 1,2207mV.
1 - O AO não vai possuir esta precisão toda. Teria que usar AO com duas fontes de tensão. Uma positiva e outra negativa para que seu sinal não se aproxime das tensões de alimentação.
2 - A sua tensão de referência teria que ter a precisão referente a uma tensão de meio bit menos significativo, ou 5.000mV / (2 x 4096) = 0,61uV (micro volts). ISSO EM TODA A FAIXA DE TEMPERATURA QUE O CIRCUITO DEVE FUNCIONAR. A própria tensão de referência TERIA que ser EXCELENTE. Não é fácil se obter esta precisão. 4,999.39V <= Vref <= 5,000.61V.

Sinceramente.
Eu não acredito que você precise de toda esta precisão, qualquer que seja este seu circuito. Em outras palavras. Acredito que você poderia reduzir o número de bits do seu CAD. Isso facilitaria, um pouco, a sua vida. Tanto na tensão de referência, como na escolha do AO, como na rapidez do programa.

Finalmente:
1 - Não entendi porque você colocou capacitores diretamente conectados ao seu sinal em J1 (pinos 1, 2 e 3).
2 - Os seus filtros (como R5 e C5) poderiam ser melhorados.
R4 também deveria ter um valor compatível com a impedância de saída dos sinais em J1 (pinos 1, 2 e 3).

São estes os meus comentários.
Bons projetos.
MOR_AL