Boa tarde, Claudio!!
Acrescentei mais um LM35, no AN2... fiz algumas alterações no programa, para que mostrasse alternadamente uma temp do sensor 1 ora do sensor 2...
,mas estou obtendo exito. Sou iniciante em programação, e por isso estou solicitando um auxilio.
DEsde ja agradeço
Olá Thalis!
Em que eu poderia ajudar?
Opa, faltou a palavra não, de não estou obtendo êxito... Poderia me auxiliar para que o programa leia dois lm35 e indique a cada por exemplo 2 segundos a temperatura deles no display 7 segmento s de forma alternada...
Desde já agradeço
Olá Thalis!
Terá que alterar significativamente o programa para usar mais um port analógico (o pino 3 ) e ler o LM35 adicional. A rotina 'void le_lm35() ' terá que ser modificada para ler o sensor 1 ( o original) e também o sensor 2 (o novo sensor LM35).
Você vai ter um problema na prática: identificar nos displays qual dos LM35 está sendo lido em um dado momento.
Talvez tenha que usar um sinal antes de apresentar a leitura de um dos sensores como por ex. S1 (acendendo os seguimentos do display para formar a letra 'S' no display 2 e '1' no display 1) para identificar que a leitura é do sensor 1. E o mesmo com o sensor 2, escrevendo um 'S2' antes de mostrar o valor.
Não tem mais ports sobrando senão poderia ser usado um led para indicar qual dos sensores está sendo lido. Por ex. aceso= s1 e pagado = s2,
Com display de cristal do tipo 16x2 fica mais fácil a apresentação já que tem 2 linhas. Ficaria um resultado na linha superior e o outro na linha inferior.
Ola, sim fiz algumas alterações para o pic 16f870, na qual placa estou usando, tenho sim alguns pinos de i/o sobrando e ideia e´justamente quando mostrar uma temperatura acenda um led, indicando o sensor 1 e outro pino de i/o faça o mesmo para outra temperatura. Praticamente dobrei a rotina de rotina 'void le_lm35() ' e rotina 'void le_lm35() _2'... mas fiquei na duvida nos registradores ADRESH,ADRESL... ? tenho que ligar novamente o 'canal 1/ liga conversor'na segunda rotina le_lm35() _2 ? Não quando devo implementar o acedimento dos leds de indicação de temperatura...? A persitencia neste tipo de display de 7 segmentos , é que enchergamos as temperaturas a maiores distancias ,ser melhor para visualização .
Agradeço qualquer auxilio
SEgue o programa:
/******************************************************************************
* TERMOMETRO -50 a +100 ºC
*
* C/ PIC 16f818 visualizando em 3 displays de 7 seguimentos
* Utiliza DOIS sensores LM35
*
* Autor: Cláudio Larios
* site: http://larios.tecnologia.ws/iBlog/archives/7583
* Data: 04/09/2015
*
* ALTERADO POR: Thalis Mazzarino
* Data: 05/09/2019
* Indicar temperaturas na faixa de -50 até 100º Centigrados
* Resolução pós virgula de 0,5 graus.
* Escala negativa sem pós virgula (uso do sinal '-')
* Ajuste Voltagem de referência no pino 2 para 2,5 Volts
* Material didático apenas.
* Use compilador CCS C
*
* Arquivo integrante do blog Lários.Tecnologia.Ws
******************************************************************************/
/* Escolha aqui o tipo de display (catodo ou anodo comum */
#define ANODO_COMUM
//Descomente para anodo comum e comente para catodo comum
//==============================================================================
#include <16F870.h>
#device adc=10
#use delay(clock=4000000) //tempo por instrução=1us
#fuses HS, NOWDT, NOPUT, NOPROTECT, NOBROWNOUT, NOLVP //MCLR, //, NOCPD,CCPB2 ,INTRC_IO,
#use fast_io(a)
#use fast_io(b)
#ZERO_RAM
#byte PORTA = 0X5
#byte PORTB = 0X6
#byte PORTC = 0X07
#byte ADRESH = 0X1E
#byte ADRESL = 0X9E
#byte ADCON0 = 0X1F
#byte ADCON1 = 0X9F
//#byte OSCCON = 0X8F
#byte TRISA = 0X85
#byte TRISB = 0X86
#byte TRISC = 0x87
#byte OPTION_REG = 0X81
//#byte CCP1CON = 0X17
#bit GO_DONE = 0X1F.2
//#bit SSPEN = 0X14.5
#bit ADON = 0X1F.0
//defines
#bit k0 = 0X7.0 //catodo/anodo 0 pino C0
#bit k1 = 0X7.1 //catodo/anodo 1 pino C1
#bit k2 = 0X7.2 //catodo/anodo 1 pino C2
#bit ponto = 0X6.7 //seguimento 'p' pino RB7
#define fator 5 // vref=2,5volts x 2
#define N_AMOSTRA 1000 //amostras por apresentação
#define N_AMOSTRA2 1000 //amostras por apresentação
//variáveis globais
int1 f_ok,f_sel,f_neg,f_err;
int8 vez,dig0,dig1,dig2,dig0a,dig1a,dig2a;
int16 cnt,conv,cnt2,conv3;
int32 RES,RES1,RES2,RES3;
//constantes para conversão 7 seguimentos
// PGFEDCBA SEGUIMENTOS
// PORTB 76543210
int8 const num[] = { 0B00111111,//0
0B00000110,//1
0B01011011,//2
0B01001111,//3
0B01100110,//4
0B01101101,//5
0B01111101,//6
0B00000111,//7
0B01111111,//8
0B01101111,//9
0B01000000, //10 '-' traço
0B00000000, //11' ' apaga
0B11111001 //12'E' erro
};
void multiplexa(){
int8 a;
if(f_ok) {dig0=dig0a; dig1=dig1a;dig2=dig2a; f_ok=0;}
if(++vez>2)vez=0;
PORTC=0X0F;//desliga display
switch (vez){
case 0:{a= num[dig0];break;}//case 0:
case 1:{a= num[dig1];break;}//case 1:
case 2:{a= num[dig2];break;}//case 2:
}//switch (vez)
#ifdef ANODO_COMUM
PORTB=~a;
#else
PORTB=a;
#endif
switch (vez){
case 0: {k0=0; break;} //liga display 'UNIDADE'
case 1: {
if(!f_neg)
#ifdef ANODO_COMUM
ponto=0;
#else
ponto=1;
#endif
k1=0; break;}//liga display 'dezena'
case 2: {k2=0; break;}//liga display 'centena'
}
delay_ms(2);
} //void multiplexa()
void delay_ad(){delay_us(10);}
void le_lm35() {
if(GO_DONE) return; //utiliza o timer 0 para temporizar numero de comversão
if(!f_sel){
RES+=(int16) ADRESH<<8;
RES+=ADRESL; //obtem valor
f_sel=1;
ADCON0=0b11001001; //canal 1/ liga conversor
delay_ad();
}
else{
RES1+=(int16)ADRESH<<8;
RES1+=ADRESL; //obtem valor
f_sel=0;
ADCON0=0b11000001; //canal 0/ liga conversor
delay_ad();
}
if(++cnt<N_AMOSTRA){
GO_DONE=1; //inicia nova conversão
return;
}
if(RES>=RES1){
RES=RES-RES1;
f_neg=0;
}
else{
RES=RES1-RES;
f_neg=1;
}
conv=RES/N_AMOSTRA;
conv=conv* fator ;
if(conv>999){f_err=1;f_neg=0;}
cnt=0;
dig2a= conv /100;//digito das centenas
dig1a= (conv %100) /10;//digito das dezenas
dig0a=(conv %100) %10;//digito da unidade
if(f_neg){
dig0a=dig1a;
dig1a=dig2a;
dig2a=10; //traço
if(dig1a==0)dig1a=11;//apaga
}
else{
if(dig2a==0)dig2a=11; //apaga
}
if(f_err){
dig2a=12; //'E'
dig1a=12;//'E'
dig0a=12;//'E'
f_err=0;
}
f_sel=0;
f_ok=1;
RES=0;
RES1=0;
GO_DONE=1; //inicia nova conversão
}
void le_lm35_2() {
if(GO_DONE) return; //utiliza o timer 0 para temporizar numero de comversão
if(!f_sel){
RES2+=(int16) ADRESH<<8;
RES2+=ADRESL; //obtem valor
f_sel=1;
ADCON0=0b11001001; //canal 1/ liga conversor
delay_ad();
}
else{
RES3+=(int16)ADRESH<<8;
RES3+=ADRESL; //obtem valor
f_sel=0;
ADCON0=0b11000001; //canal 2/ liga conversor
delay_ad();
}
if(++cnt2<N_AMOSTRA2){
GO_DONE=1; //inicia nova conversão
return;
}
if(RES2>=RES3){
RES2=RES2-RES3;
f_neg=0;
}
else{
RES2=RES3-RES2;
f_neg=1;
}
conv3=RES2/N_AMOSTRA2;
conv3=conv* fator ;
if(conv3>999){f_err=1;f_neg=0;}
cnt2=0;
dig2a= conv3 /100;//digito das centenas
dig1a= (conv3 %100) /10;//digito das dezenas
dig0a=(conv3 %100) %10;//digito da unidade
if(f_neg){
dig0a=dig1a;
dig1a=dig2a;
dig2a=10; //traço
if(dig1a==0)dig1a=11;//apaga
}
else{
if(dig2a==0)dig2a=11; //apaga
}
if(f_err){
dig2a=12; //'E'
dig1a=12;//'E'
dig0a=12;//'E'
f_err=0;
}
f_sel=0;
f_ok=1;
RES2=0;
RES3=0;
GO_DONE=1; //inicia nova conversão
}
/**************************************************************************
Rotina Main
************************************************************************/
void main(){
OPTION_REG=0; //sem prescaller
// CCP1CON=0;
// SSPEN=0;//DESLIGA SSP
//OSCCON=0B01100100; //escolhe 4MHZ interno
ADCON0=0b11000001; //canal 0/ liga conversor
ADCON1=0b11000101; //frequencia para oscilador interno
PORTC=0x0F;//desliga display
TRISA= 0B00111111;//RA7,6 saidas
TRISB=0;//seguimentos
TRISC=0;
dig0=8;//teste de digitos
dig1=8;//idem
dig2=8;//idem
cnt=0;
RES=0;
RES1=0;
cnt2=0;
RES2=0;
RES3=0;
f_sel=0;
f_err=0;
ADON=1; //liga a/d
/***********************************************************************
Laço Principal de Repetição
***************************************************************************/
for(;;){
/* le_lm35();//le a tensão gerada pelo LM35
multiplexa();//apresentação nos displays
delay_ms(100);
*/ le_lm35_2();//le a tensão gerada pelo LM35
multiplexa();//apresentação nos displays
// delay_ms(100);
}
}
Olá Thalis!
A rotina dessa montagem foi feita de uma forma que chamarei de 'dinâmica'. O microcontrolador não pode ficar preso em rotinas de delay de valor alto como 100 milissegundos (alguns microssegundos não teria problema como no caso da espera de 10 microssegundos antes de iniciar a conversão após trocar de canal do ADC). Ela entra e sai em constante loop e a cada vez realiza alguma coisa ou simplesmente não faz nada. Isto é necessário pelo tipo de multiplexação que foi usada. Se colocar o delay de 100 milissegundos como você fez irá acender um display após outro de forma bem visível e desagradável.
Quanto a usar uma repetição da rotina ' le_lm35_2()' ela também não funcionará. Terá que alterar a rotina 'le_lm35()' para também fazer a leitura de um canal a mais. Se notar irá encontrar um flag nomeado de 'f_sel'. Se ele for setado irá ler o canal zero e se estiver resetado, o canal 1. Ele admite apenas 2 estados. Então terá que substitui-lo por um contador, para que conte mais estados.
Ex. contador=0 irá ler o canal 1.Salva valor no registrador RES. Ajusta contador=1.
contador=1 lerá o canal 0 (diodo). Salva valores no registrador RES1. Temos o resultado do sensor 1 se subtrairmos o valor maior do menor e ajustamos o flag de sinal. Após encaminha valores para conversão hec/decimal e apresenta no display. Contador de tempo (cnt) é resetado. Ajusta contador para 2.
contador=2 irá ler o canal 2 (o outro LM35). Salva valores no registrador RES2. Ajusta contador para 3.
contador=3 irá ler novamente o canal 0 para subtrair do canal 2 e apresenta-lo nos displays após conversão hex/decimal. Zera contador de tempo. Ajusta contador para 0.
Note que este 'contador' fará o papel de um gerenciador de tarefas. Conforme o seu valor o programa irá seguir um caminho. Neste caso é melhor usar a função interna do compilador chamada 'switch'.
Ex.
Switch (contador){
case 0:{ rotina de leitura do LM35 n1, etc);
case 2:{ rotina de leitura da tensão do diodo canal 0}
......(outras cases)
}
O valor do 'contador' pode ser usado para acionar o led indicador de qual LM35 está sendo visualizado.
Existem várias formas de fazer este programa. Por exemplo, poderia colocar a multiplexação em uma rotina de interrupção de algum timer a cada 1 a 2 milissegundos, para acionar sequencialmente os displays com seus respectivos valores. A rotina principal se encarregaria de ler os canais e preparar os resultados a serem visualizados pela rotina de multiplexação.