Olá,
Para esta semana preparei um exemplo que vale por 2, pois vou demonstrar como comunicar
via SPI com um microcontrolador que não possui hardware pra isso(ou seja vou emular)
outro detalhe é usar o chip max31855K.
O maior limitante deste projeto foi a memoria de programa pequena do microcontrolador para
fazer cálculos(tive que limitar o range de -25° a 300°c), por não conhecer o sensor termopar julguei
erradamente que o sinal seria totalmente linear foi não era linear,quando percebi que era necessário
montar um polinômio para que o resultado se aproxime do valor o mais próximo possível, então foi
montado varias equações para cobrir todo o range.
Logo depois percebi que conforme a temperatura ambiente muda isso interfere também na leitura
da temperatura,mas dai já havia montado as equações para uma temperatura ambiente de 25°C,então
foi montado a função "compensa_vari_ambiente() " para que a equação se comportasse de forma
dinâmica ou seja independente da temperatura e mesmo que o valor lido no sensor fosse variado a
temperatura sempre ficava próximo do esperado.A função "debugue(int val)" serve para visualizar
o pacote recebido do chip(para isso este bloco do programa deve ser descomentado e chamado).
O circuito montado para simulação foi este:
Depois de tudo funcionando no proteus coloquei o circuito pra funcionar na pratica e então
pra minha surpresa o valor lido era completamente diferente da simulação, embora a temperatura
ambiente tenha ficado correta.Enfim não sei se o termopar tipo K que estou usando é diferente
ou se o chip max31855K não está coerente, vou investigar para descobrir o que aconteceu.Mas
resolvi postar o código aqui para haver uma troca de experiencia e espero que de alguma forma
essas informações seja uteis pra alguém.
O código fonte:
/*
* sensor de temperatura termopar com max31855K
*
* Compilador : MPlabXC8
* Microcontrolador: 16F648A
* Autor: aguivone
* Versão: 1
* Data : 29/04/2016
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#define _XTAL_FREQ 4000000 // oscilador interno de 20 Mhz
#include <xc.h>
/////////////////////////////////////////////////////////configuraçôes//////////////////////////////////////////////////
#define SPI_DADOS PORTBbits.RB0
#define SPI_CLCK PORTBbits.RB3
#define SPI_CS PORTBbits.RB5
#define LED_STATUS PORTBbits.RB7
#define TEMPO_LED 1000
// CONFIG
#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = OFF // Brown-out Detect Enable bit (BOD disabled)
#pragma config LVP = OFF // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
unsigned long gulTempo_us=0;
unsigned long gulTempo_ms=0;
unsigned long gulLed_status_tempo=0;
unsigned long gulTempo_aux_ms=0;
unsigned long gulTemp_termopar=0;
unsigned long gulTemp_chip=0;
unsigned char gucSinal_termopar=' ';//se + não precisa de colocar nada
unsigned char gucSinal_termp_chip=' ';//se + não precisa de colocar nada
bit gbErro_ausente=0;
bit gbErro_curto_vcc=0;
bit gbErro_curto_gnd=0;
bit gbIndica_erro =0;
void interrupt interrupcao(void)//vetor de interrupção
{
if(T0IF)
{//interrupção do timer0 - estoura quando atinge 255(0XFF)
gulTempo_us++;
if(gulTempo_us == 13)
{ //acontece a cada 1ms
gulTempo_us =0;
gulLed_status_tempo++;
gulTempo_ms++;
if(gulTempo_aux_ms>0)
{ gulTempo_aux_ms--;}
if(gulTempo_ms == 1000)
{//acontece a cada 1s
gulTempo_ms = 0;
}
}
TMR0 = 254;//reinicia timer com o valor calculado
T0IF = 0;
//62.5us + os delay da rotinas = 75us
}
}
void inicializa_timer0()
{
OPTION_REG = 0X03;//timer0 com prescaler dividido por 16
T0IE = 1;//habilita interrupção do timer0
TMR0 = 254;//zera registrador de contagem
}
/////////////////////////////////funçoes usadas pela uart //////////////////////////////////////////////////////
void inicializa_RS232(long velocidade,int modo)
{////por padrão é usado o modo 8 bits e sem paridade, mas se necessario ajuste aqui a configuração desejada.
//verifique datasheet para ver a porcentagem de erro e se a velocidade é possivel para o cristal utilizado.
RCSTA = 0X90;//habilita porta serial,recepção de 8 bit em modo continuo,assincrono.
int valor;
if(modo == 1)
{//modo = 1 ,modo alta velocidade
TXSTA = 0X24;//modo assincrono,trasmissao 8 bits.
valor =(int)(((_XTAL_FREQ/velocidade)-16)/16);//calculo do valor do gerador de baud rate
}
else
{//modo = 0 ,modo baixa velocidade
TXSTA = 0X20;//modo assincrono,trasmissao 8 bits.
valor =(int)(((_XTAL_FREQ/velocidade)-64)/64);//calculo do valor do gerador de baud rate
}
SPBRG = valor;
RCIE = 0;//não habilita interrupção de recepção - se habilitar e não tratar a recpção trava o chip(se deixar o pino em aberto quando habilitado é pior))
TXIE = 0;//deixa interrupção de transmissão desligado(pois corre se o risco de ter uma interrupção escrita e leitura ao mesmo tempo)
}
void escreve_char(char valor)
{
TXIF = 0;//limpa flag que sinaliza envio completo.
TXREG = valor;
NOP();
NOP();//espera 2 ciclos
while(TXIF == 0);//espera enviar caracter
}
void imprime(const char frase[])
{
char indice = 0;
char tamanho = strlen(frase);
while(indice < tamanho ) ///veja que o programa pode travar se aqui não tiver as duas aspas
{
escreve_char(frase[indice]);
indice++;
}
}
void long_to_char(long ulQuant,int virgula)
{
char cTexto[4]={'0','0','0','0'};
/* char cTexto[5]={'0','0','0','0','0'};
while(ulQuant>=10000)
{
ulQuant=ulQuant-10000;
cTexto[4]++;
}
escreve_char(cTexto[4]);*/
if(virgula == 4){escreve_char(',');}
while(ulQuant>=1000)
{
ulQuant=ulQuant-1000;
cTexto[3]++;
}
escreve_char(cTexto[3]);
if(virgula == 3){escreve_char(',');}
while(ulQuant>=100)
{
ulQuant=ulQuant-100;
cTexto[2]++;
}
escreve_char(cTexto[2]);
if(virgula == 2){escreve_char(',');}
while(ulQuant>=10)
{
ulQuant=ulQuant-10;
cTexto[1]++;
}
escreve_char(cTexto[1]);
if(virgula == 1){escreve_char(',');}
while(ulQuant>=1)
{
ulQuant=ulQuant-1;
cTexto[0]++;
}
escreve_char(cTexto[0]);
}
void delay_ms(long tempo)
{
gulTempo_aux_ms = 2;//tempo pra garantir que chip está pronto
while(gulTempo_aux_ms>0);
}
/*
* usado para ver o pacote inteiro do pacote
* void debugue(int val)
{
switch(val)
{
case 14:
{
escreve_char('_');
}break;
case 16:
{
escreve_char('_');
}break;
case 28:
{
escreve_char('_');
}break;
}
if(SPI_DADOS == 1)
{
escreve_char('1');
}
else
{
escreve_char('0');
}
}*/
void Ler_sensor()
{//lê e já trata informação
SPI_CS = 0;
int contador=0;
long multiplicador =1;
delay_ms(2);
gbErro_ausente=0;///zera variaveis
gbErro_curto_vcc=0;
gbErro_curto_gnd=0;
gbIndica_erro =0;
gucSinal_termp_chip =' ';//se + não precisa de colocar nada
gucSinal_termopar =' ';//se + não precisa de colocar nada
gulTemp_termopar = 0;
gulTemp_chip=0;
while(contador < 32)
{
SPI_CLCK = 1;
delay_ms(20);
if(SPI_DADOS == 1)//só há processamento quando o bit é 1.
{//processa dados
if(contador == 0)
{//pega sinal da temperatura do termopar
gucSinal_termopar ='-';
}
else
{
if(contador <15)
{//pega temperatura do termopar
//2^12 = 4096, pois a contagem comeca em zero e 1 bit é o sinal
gulTemp_termopar = gulTemp_termopar + (4096/multiplicador);
multiplicador = multiplicador*2;
}
else
{
if((contador > 16)&&(contador < 29))
{//pega sinal da temperatura ambiente
//2^10 = 1024, pois a contagem comeca em zero e 1 bit é o sinal
gulTemp_chip = gulTemp_chip + (1024/multiplicador);
multiplicador = multiplicador*2;
}
if(contador == 16)
{//pega sina da temperatura do chip(temperatura ambiente)
gucSinal_termp_chip ='-';
multiplicador =1;//para pegar a segunda temperatura
}
if((gbIndica_erro == 1)&&(contador>28))
{//se tem erro checa estas possibilidades
switch(contador)
{
case 29:
{
gbErro_curto_gnd=1;
}break;
case 30:
{
gbErro_curto_vcc=1;
}break;
case 31:
{
gbErro_ausente=1;
}break;
}
}
else
{if(contador == 15)
{gbIndica_erro =1;}
}
}
}
}
else
{
if(contador == 16)
{
multiplicador =1;//para pegar a segunda temperatura
}
if(((contador > 0)&&(contador < 15))||((contador > 16)&&(contador < 29)))
{//pega temperatura do termopar
multiplicador = multiplicador*2;
}
}
///so pra testar o codigo, se quiser não precisa chamar essa função
// debugue(contador);
/////////////////////
SPI_CLCK = 0;
contador++;
}
SPI_CS = 1;
}
/*
* usado para simular
* void compensa_vari_ambiente()
{//essa função compensa a variação de temperatura da junta fria do sensor
long_to_char(gulTemp_termopar,0);
escreve_char('(');
if(gulTemp_chip>404)
{//maior que 25°C
gulTemp_termopar = gulTemp_termopar-((long)((gulTemp_chip - 404)*0.247));
long_to_char(gulTemp_termopar,0);
}
else
{//menor que 25°c
if(gulTemp_chip<404)
{
gulTemp_termopar = gulTemp_termopar+((long)((404 - gulTemp_chip)*0.247));
long_to_char(gulTemp_termopar,0);
}
}
escreve_char(')');
}*/
void compensa_vari_ambiente()
{//essa função compensa a variação de temperatura da junta fria do sensor
if(gulTemp_chip>404)
{//maior que 25°C
gulTemp_termopar = gulTemp_termopar-((long)((gulTemp_chip - 404)*0.247));
}
else
{//menor que 25°c
if(gulTemp_chip<404)
{gulTemp_termopar = gulTemp_termopar+((long)((404 - gulTemp_chip)*0.247));}
}
}
void trata_termopar()
{///funcionou de -25°C até 300°C - na simulação
compensa_vari_ambiente();;
if(gulTemp_termopar>100)
{
gulTemp_termopar = (long)(((gulTemp_termopar/0.395)-250)+ 3.5);//equação base
if((gulTemp_termopar>0)&&(gulTemp_termopar<69))//0 até 7
{
gulTemp_termopar = gulTemp_termopar - 2 ;
return;//isso garante que depois de processado vá executar os proximos passos
}
if((gulTemp_termopar>500)&&(gulTemp_termopar<1008))//50 até 100
{
gulTemp_termopar = (long)gulTemp_termopar*0.995;
return;//isso garante que depois de processado vá executar os proximos passos
}
/*
* para reduzir o numero de memoria usada juntei 2 intevalos num só
*
if((gulTemp_termopar>500)&&(gulTemp_termopar<900))//50 até 93
{
gulTemp_termopar = (long)gulTemp_termopar*0.998;
return;//isso garante que depois de processado vá executar os proximos passos
}
if((gulTemp_termopar>899)&&(gulTemp_termopar<1008))//93 até 100
{
gulTemp_termopar = (long)gulTemp_termopar*0.992;
return;//isso garante que depois de processado vá executar os proximos passos
}
*/
if((gulTemp_termopar>1007)&&(gulTemp_termopar<1500))//100 até 150passa
{
gulTemp_termopar = gulTemp_termopar-9;
return;//isso garante que depois de processado vá executar os proximos passos
}
if((gulTemp_termopar>1499)&&(gulTemp_termopar<1981))//150 até 200passa a ignorar o vem depois da virgula
{
gulTemp_termopar = (long)(gulTemp_termopar/10)*10;
return;//isso garante que depois de processado vá executar os proximos passos
}
if((gulTemp_termopar>2100)&&(gulTemp_termopar<2490))//200 até 250passa a ignorar o vem depois da virgula
{
gulTemp_termopar = gulTemp_termopar+4;
return;//isso garante que depois de processado vá executar os proximos passos
}
/*
* para reduzir o numero de memoria usada
* if((gulTemp_termopar>2490)&&(gulTemp_termopar<3500))//250 até 300passa a ignorar o vem depois da virgula
{
gulTemp_termopar = gulTemp_termopar+8;
return;//isso garante que depois de processado vá executar os proximos passos
}*/
}
else
{
if(gulTemp_termopar==99)
{
gulTemp_termopar = 0;
}
else
{
escreve_char('-');
gulTemp_termopar = (long)(251 - (gulTemp_termopar/0.395));//equação base
if((gulTemp_termopar>40)&&(gulTemp_termopar<96))//-1 até -8
{
gulTemp_termopar = gulTemp_termopar+2;
return;//isso garante que depois de processado vá executar os proximos passos
}
if((gulTemp_termopar>95)&&(gulTemp_termopar<126))//-8 até -13passa a ignorar o vem depois da virgula
{
gulTemp_termopar = gulTemp_termopar+4;
return;//isso garante que depois de processado vá executar os proximos passos
}
if((gulTemp_termopar>125)&&(gulTemp_termopar<300))//-13 até 150passa a ignorar o vem depois da virgula
{
gulTemp_termopar = gulTemp_termopar+8;
return;//isso garante que depois de processado vá executar os proximos passos
}
}
}
}
//////////////////////////////////////////////////////Rotina principal///////////////////////////////////////////////////////////////
void main(void)
{
TRISB = 0X03;//configura portB
TRISA = 0XFF;//configura portA
PORTB = 0; // limpar as portas que estão configuradas como saidas
PORTA = 0;
CMCON = 7;//desabilita comparadores
inicializa_RS232(9600,1);//modo de alta velocidade
inicializa_timer0();
PEIE = 1;//habilita interrupção de perifericos do pic
GIE = 1; //GIE: Global Interrupt Enable bit
SPI_CLCK = 0;
SPI_CS = 1;
for(;;)
{
if(gulLed_status_tempo > TEMPO_LED)
{
LED_STATUS = ~LED_STATUS;
gulLed_status_tempo = 0;
// imprime("\r\n Pacote recebido : \r\n "); ///so pra testar o codigo na aplicação pode ser removido essa linha
Ler_sensor();
imprime("\r\nT= ");
//////converte temperatura do termopar////////////////////////////////////////
/* if(gucSinal_termopar == '-')
{//não será usado aqui
// escreve_char('-');
}
else
{
trata_temp_positiva();
escreve_char('/');
} */
trata_termopar();
long_to_char(gulTemp_termopar,1);
imprime(" °C\r\nChip= ");
///converte temperatura do chip //////////////////////////////////
if(gucSinal_termp_chip == '-')
{//converte a parte negativa da temperatura
gulTemp_chip = (long)gulTemp_chip*6.2;
gulTemp_chip =(long) 12698 - gulTemp_chip;
escreve_char('-');
}
else
{
gulTemp_chip = (long)gulTemp_chip*6.2;
}
long_to_char(gulTemp_chip,2);
///////////////////////////////////////////////////////////////////
imprime(".");
if(gbIndica_erro)
{//tem erro
imprime("\r\n Falha:");
if(gbErro_ausente)
{imprime("\r\n Sensor aberto ou inexistente!");}
if(gbErro_curto_vcc)
{imprime("\r\n Sensor em curto com o gnd!");}
if(gbErro_curto_gnd)
{imprime("\r\n Sensor em curto com o vcc!");}
}
}
}//loop infinito
}
Nenhum comentário :
Postar um comentário
olá,digite aqui seu comentário!