Ir ao conteúdo
  • Cadastre-se

Arduino Código para leitura de sensores com Arduino.


Posts recomendados

Boa noite pessoal, estou continuando a saga dos meus tópicos anteriores onde o objetivo é fazer com que o arduino MEGA faça a leitura dos sensores do carro e envie para um Tablet. Demorei para continuar porque estava esperando mais componentes chegarem da China, chegaram a alguns dias e alguns sensores já consegui fazer funcionar, agora peço a ajuda de vocês para que possamos continuar o projeto, alguns sensores estão sendo bem mais complicados do que eu imaginei, pedi ajuda ao chatGPT e ajudou em algumas coisas mas tem coisa que ele se complica demais e não funcionam bem.

 

A programação do tablet também é complicada, por isso consegui um display I2C 16x4 e vou utilizar ele, depois que a leitura de todos os sensores estiverem funcionando bem no display então passarei a programação com o tablet.

 

A leitura do primeiro sensor que peço ajuda é o da sonda lambda que faz a leitura dos gases do escapamento, junto com a sonda  comprei um gerenciador de sonda que faz a leitura da mesma e controla o aquecedor interno que a sonda possuí, o gerenciador exibe a temperatura e a leitura da sonda em um lcd pequeno e também tem algumas saídas para injeção eletrônica.

 

O sensor exibe a leitura da sonda no fator lambda que vai de 0,68 até 1,36 onde:

 

0,68    tem combustível demais e pouco ar.

1,36    tem pouco combustível e muito ar.

1,00    ideal, o ar e o combustível estão na mesma proporção.

 

O gerenciador vem com essa informação na conexão dos fios:

 

image.thumb.png.0661476567949bae9eaf54ea56cf70e4.png

 

Na saída 4 tem uma tensão linear correspondente a leitura da sonda e vai de 0 a 5v ou seja ideal para o arduino fazer a leitura, e aí está o problema, tentei fazer a leitura com a função MAP no arduino e não funcionou de jeito nenhum, se colocar de 0 até 100 por exemplo a função map funciona, mas se colocar de 0,68  até  1,36 fica travado marcando 0,0   tentei me acertar com o chatGPT e ele me disse que a função MAP é indicada para fazer a relação de valores lineares, no meu caso ela não se aplica, enviei meu código ele sugeriu usar uma tal de interpolação linear alterou  o código e ficou assim:

 

#include <LiquidCrystal_I2C.h>



// Inicializa o display no endereço 0x27

LiquidCrystal_I2C lcd(0x27, 16, 4);



const int lambdaPin = A3; // Pino analógico utilizado para ler a tensão do gerenciador de sonda lambda

float voltageToLambda(float voltage);



void setup()

{

  Serial.begin(9600); // Inicializa a comunicação serial

  lcd.init();

  lcd.setBacklight(HIGH);

  lcd.setCursor(0, 0);

  lcd.print("V=       L=");

}



void loop()

{float voltage = analogRead(lambdaPin) * (5.0 / 1023.0); // Leitura da tensão em volts

  float lambda = 0.68 + (voltage - 0.0) * (1.36 - 0.68) / (5.0 - 0.0);



    lcd.setCursor(3, 0);

  lcd.print(voltage, 2); // Exibe a tensão com 2 casas decimais

  lcd.setCursor(13, 0);

  lcd.print(lambda, 2); // Exibe o fator lambda com 2 casas decimais



    Serial.print("Voltage: ");

Serial.println(voltage);

Serial.print("Lambda: ");

Serial.println(lambda);



delay(1000);

}

 

 

 

De fato este código funcionou, mas não está 100% fiel ao que o gerenciador da sonda exibe, quando ligo o gerenciador até ele aquecer a sonda para ter uma leitura correta ele exibe o valor 1,02 por alguns segundos depois vai subindo até 1,36 porque o motor está desligado logo não tem combustível nenhum, mas utilizando este código quando acabo de ligar comparando as leituras ficam assim:

 

gerenciador     arduino

     1,02              1,02

     1,03              1,07

     1,11              1,09

     1,36              1,36

 

parece que a leitura do arduino é meio aproximada tanto para mais quanto para menos, elas só ficam iguais quando o gerenciador fica com o mesmo valor por um tempinho, tanto que quando acabo de ligar ambos ficam em 1,02 e quando a sonda termina de aquecer ambos ficam em 1,36 a leitura só fica meio doida no meio do caminho.

 

Será que isso é por causa da tal interpolação linear que o GPT sugeriu?

 

Pensei que a função MAP seria ideal para executar essa função mas ela simplesmente não funcionou, será que é uma faixa muito pequena ela não consegue ser executada corretamente e isso faz ela não funcionar?

 

 

Link para o comentário
Compartilhar em outros sites

1 hora atrás, GustavoH93 disse:

float lambda = 0.68 + (voltage - 0.0) * (1.36 - 0.68) / (5.0 - 0.0);

a parte da expressão  (1.36 - 0.68) / (5.0 - 0.0) será executada antes da multiplicação pela voltage. Pode parecer bobagem, com uma boa calculadora (muitas casas) a ordem desses fatores não altera nada mas se pensar numa calculadora limitada a coisa muda de figura.

Tente substituir a expressão

float lambda = 0.68 + (voltage - 0.0) * (1.36 - 0.68) / (5.0 - 0.0);

por

float lambda = (voltage - 0.0) * (1.36 - 0.68);

float lambda = 0.68 + lambda / (5.0 - 0.0);

 

O truque está em ir ao número máximo antes de entrar com a divisão. 

Link para o comentário
Compartilhar em outros sites

Lendo melhor o código, substitua

{float voltage = analogRead(lambdaPin) * (5.0 / 1023.0); // Leitura da tensão em volts

  float lambda = 0.68 + (voltage - 0.0) * (1.36 - 0.68) / (5.0 - 0.0);

por

{voltage = analogRead(lambdaPin);

float lambda = voltage * (1.36 - 0.68);

float lambda = 0.68 + lambda / 1023;

declare voltage como unsigned int

Uma dúvida: a discrepância entre as 2 tabelas se refere à variável lambda ou voltage?

A simplificação de fómula que fiz melhora o resultado de lambda mas altera o voltage. Caso queira exibir a tensão lida o valor lido está intacto, ainda dá para para executar após o cálculo do lambda

voltage = voltage * 5;

float voltage2 = voltage /1023;

e na impressão substitua

Serial.println(voltage);

por

Serial.println(voltage2);

Link para o comentário
Compartilhar em outros sites

3 horas atrás, .if disse:

O -0.0 está me doendo.

 

Para mim também .... mas eu faria tudo com variáveis de 16 bits e converteria no final......

 

A função MAP funciona sim, já ví muita gente usar ela. Até criei uma equivalente no Bascom para facilitar as conversões.

 

O que eu estou gostando de ver é  uso do ChatGPT  para auxiliar nos códigos básicos ...

 

Paulo 

 

 

Link para o comentário
Compartilhar em outros sites

@.if@aphawk

Fiz meus primeiros códigos no tempo do TK80 e similares. Depois passei décadas fora disso. Retornei recentemente.

Tem uma coisa que me incomoda nas bibliotecas. Por não saber procurar, quando vejo algo novo que utiliza uma biblioteca aprendo os códigos utilizados no exemplo. Sinto falta de um readme que mostre as sintaxes disponíveis na biblioteca e seus detalhes. Certamente esse tipo de informação está disponível. Onde encontrar?

Link para o comentário
Compartilhar em outros sites

  • Membro VIP
Em 23/05/2023 às 15:57, Sérgio Lembo disse:

bibliotecas. Por não saber procurar, quando vejo algo novo que utiliza uma biblioteca aprendo os códigos utilizados no exemplo

As arduínas? Bem.. é meio óbvio d+ mas com menos de 1 clique você acha referências em...

https://www.arduino.cc/reference/en/

Já em c puro nem tem como linkar nada (além do google) pois são muitos depende.. o principal é do hw.

 

Em tempo.. agora há pouco perdi muitos minutos tentando gerar tom num pino... Com o mesmo fonte c de um pic que deu certo , tentei gerar no atmega.. É muito simples.. algo como (fonte 100% original de uma era sem net)

tom(char t)

{

int tmp,f=1000;

while (f--) { PORTB0⁼^1; tmp=t; while (tmp--); }

}

não deu nem foo dendo. Suspeitei de bug no compilador arduino. Minutos perdidos depois me deparei com a função tone().... afff fala śerio.

 

 

  • Haha 1
Link para o comentário
Compartilhar em outros sites

fiz o que pediu Sérgio e o código ficou assim:

#include <LiquidCrystal_I2C.h>



// Inicializa o display no endereço 0x27

LiquidCrystal_I2C lcd(0x27, 16, 4);



const int lambdaPin = A3; // Pino analógico utilizado para ler a tensão do gerenciador de sonda lambda

//float voltageToLambda(float voltage);

unsigned int voltage;



void setup()

{

  Serial.begin(9600); // Inicializa a comunicação serial

  lcd.init();

  lcd.setBacklight(HIGH);

  lcd.setCursor(0, 0);

  lcd.print("V=       L=");

}



void loop()

//{float voltage = analogRead(lambdaPin) * (5.0 / 1023.0); // Leitura da tensão em volts

  //float lambda = 0.68 + (voltage - 0.0) * (1.36 - 0.68) / (5.0 - 0.0);

  {voltage = analogRead(lambdaPin);



float lambda = voltage * (1.36 - 0.68);

float lambda = 0.68 + lambda / 1023;






  lcd.setCursor(3, 0);

  lcd.print(voltage, 2); // Exibe a tensão com 2 casas decimais

  lcd.setCursor(13, 0);

  lcd.print(lambda); // Exibe o fator lambda com 2 casas decimais



Serial.print("Voltage: ");

Serial.println(voltage);

Serial.print("Lambda: ");

Serial.println(lambda);



delay(300);

}

 

 

Compilation error: redeclaration of 'float lambda'

 

Está dizendo que a lambda foi declarada duas vezes, mas isso é estranho porque na linha:     float lambda = voltage * (1.36 - 0.68);     ele declara a variável local lambda e na linha a baixo: float lambda = 0.68 + lambda / 1023; ele atualiza a variável declarada anteriormente não cria uma nova variável, ou estou entendendo errado?🤔

 

Em 22/05/2023 às 21:59, Thiago Miotto disse:

E se ao invés de usar float, usar o map com inteiro de 68 até 136?

tentei, adicionei a linha de comando:

 

int lambda = map(voltage, 0.0, 5.0, 68, 136); // Mapeia a tensão para o intervalo correspondente de fator lambda

 

por incrível que pareça a leitura ficou mais estranha, parece que ficou um buraco utilizei um potenciômetro e veja de 95 ela pula para 108 com menos de 0,10v de diferença:

 

Citação

Voltage: 2.95
Lambda: 95
Voltage: 3.04
Lambda: 108
Voltage: 3.09
Lambda: 108
Voltage: 3.07
Lambda: 108
Voltage: 2.97
Lambda: 95
Voltage: 2.90
Lambda: 95
Voltage: 2.91
Lambda: 95
Voltage: 3.02

 

Em 23/05/2023 às 11:19, aphawk disse:

A função MAP funciona sim, já ví muita gente usar ela. Até criei uma equivalente no Bascom para facilitar as conversões.

Acho que a função MAP junto com as funções if, else são umas das primeiras que apresentam nos cursinhos de arduino do youtube, é bem fácil utilizar com resultados bem interessantes, não sei porque não está funcionando adequadamente aqui, estou suspeitando se a saída do gerenciador pode não ser tão linear assim...

 

Em 23/05/2023 às 11:19, aphawk disse:

O que eu estou gostando de ver é  uso do ChatGPT  para auxiliar nos códigos básicos

Olha realmente o GPT está ajudando muita gente na programação ele cria o básico e ajuda no aprendizado, eu mesmo já troquei mais de uma centena de mensagens com ele sobre programação e os poucos vou aprendendo.

 

No começo estava achando que usar ele seria uma "trapaça" porque eu não iria criar os códigos totalmente do zero mas agora estou achando que usando ele ou não estou aprendendo também, porque acabamos aprendendo quais funções usar, por exemplo executar uma tarefa usamos if se algo acontecer, se não acontecer usamos else, se quisermos mapear uma leitura usamos MAP...

 

Acho interessante aprender as funções mesmo não sabendo escrever totalmente só de saber o que precisamos fazer qual função usar já é uma forma de aprender, e mesmo usando o GPT temos que ter o "desconfiometro" também tem umas coisas que acontecem de forma errada lá, seja por ele não entender o objetivo ou porque simplesmente comete erros, de qualquer forma é uma ferramenta que pode ser muito util.

 

Em 23/05/2023 às 16:16, .if disse:

não deu nem foo dendo. Suspeitei de bug no compilador arduino. Minutos perdidos depois me deparei com a função tone().... afff fala śerio.

essa é uma das primeiras funções que usei no arduino, para simular o sensor hall do motor, pedia para gerar tom de frequência baixa ali perto dos 60hz para ver se a leitura que eu iria fazer com outro arduino  estava correta kkkkk (baita gambiarra e pra variar gerar o tom funcionou, agora a leitura do meu código ficou uma porcaria)😅

Link para o comentário
Compartilhar em outros sites

  • Membro VIP
10 horas atrás, GustavoH93 disse:

Compilation error: redeclaration of 'float lambda'

 

Está dizendo que a lambda foi declarada duas vezes,

Não poderia ser mais explícito, né? Pois declare 1x só uai.

 

10 horas atrás, GustavoH93 disse:

a função MAP junto com as funções if, else são umas das primeiras que apresentam nos cursinhos de arduino do youtube

Não misture as coisas. if/else são comandos nativos do c e o tal map foi criação posterior. Aliás nem mesmo o tradicional prinft do hello world não é c. Se o c tiver meia dúzia de comandos é muito... sendo o principal como já percebeste .. if 😁

 

10 horas atrás, GustavoH93 disse:

a leitura ficou mais estranha, parece que ficou um buraco

Isso é porque int não é fracionável. Aliás o mc nem trabalha diretamente com frações. Pra ele tudo é inteiro. Por isso que com a maior relutância ele cria sim ponto flutuante artificialmente mas de cobra caro... mesmo.

 

Pra tornar o buraco menor: por enquanto* multiplique por 10 (ou 100 1000)

c=(a*10)/b. Coloque o . artificialmente como já te expliquei

*depois de dominar a técnica use base 2 o que torna mais rápido pro mc

 

 

Link para o comentário
Compartilhar em outros sites

12 horas atrás, .if disse:

Isso é porque int não é fracionável. Aliás o mc nem trabalha diretamente com frações. Pra ele tudo é inteiro. Por isso que com a maior relutância ele cria sim ponto flutuante artificialmente mas de cobra caro... mesmo.

mas a tensão teria que ser float, ou seria int e trabalhariamos diretamente com o 0 até o 1023 para exibir no lcd? Se bem que a tensão só quero saber  para ver se o resultado da sonda está fazendo sentido, não vou utilizar a tensão futuramente...

 

12 horas atrás, .if disse:

Pra tornar o buraco menor: por enquanto* multiplique por 10 (ou 100 1000)

c=(a*10)/b. Coloque o . artificialmente como já te expliquei

*depois de dominar a técnica use base 2 o que torna mais rápido pro mc

Tive que ir lá nos tópicos antigos para relembrar, consegui fazer parecido mas não tá funcionando totalmente com certeza tô fazendo alguma coisa errada, @.if  o seu truque de colocar o ponto artificialmente tá quase funcionando só que no lugar do micro quem não tá executando bem sou eu kkkk dá uma olhadinha por favor, atualmente está assim o código:

 

Citação

#include <LiquidCrystal_I2C.h>

 

// Inicializa o display no endereço 0x27

LiquidCrystal_I2C lcd(0x27, 16, 4);

 

const int lambdaPin = A3; // Pino analógico utilizado para ler a tensão do gerenciador de sonda lambda


 

void setup()

{

  Serial.begin(9600); // Inicializa a comunicação serial

  lcd.init();

  lcd.setBacklight(HIGH);

  lcd.setCursor(0, 0);

  lcd.print("V=       L=");

}

 

void loop()

{float voltage = analogRead(lambdaPin) * (5.0 / 1023.0); // Leitura da tensão em volts

 int lambda=map(analogRead(lambdaPin),0,1023,68,136);

 

int resultadoInteiro =  (lambda * 10) / 10;

int resultadoRestante = (lambda * 10) % 10 ;        <------   acho que aqui está o pepino, mas não consegui acertar

 

  lcd.setCursor(3, 0);

  lcd.print(voltage, 2); // Exibe a tensão com 2 casas decimais

  lcd.setCursor(13, 0);

  lcd.print(resultadoInteiro);

  lcd.setCursor(14, 0);

  lcd.print(".");

  lcd.setCursor(15, 0);

  lcd.print(resultadoRestante);


 

Serial.print("Voltage: ");

Serial.println(voltage);

Serial.print("Lambda: ");

Serial.println(lambda);

 

delay(300);

}

 

 

@.if passei perto faltou pouco para acertar né?😅

Link para o comentário
Compartilhar em outros sites

  • Membro VIP

O retorno da função adcread é int. Adotar float nela não é muito inteligente mas claro é mais conveniente pra jovens preguiçosos. O desafio de transformar 0 a 1023 pra 0 a 5.00 .. algo como...

unsigned int v=adcread()*64;

v/=131;
printf("%d",v%10);
v/=10;
printf("%d",v%10);
printf("%s",".");
v/=10;
printf("%d",v);

 

Pronto.. eis seu 99.4 <----   (se vira 🤔🙃) pra resultado 0x3ff dos 10 bits do adc. Algo me diz que, sem a gulosa printf, ocupa menos recurso do que qualquer operação com float. Mas só testando mesmo

 

Em tempo.. isso é nostalgia da velharada (😁). Só vale a pena se realmente houver escassez de recursos. Deixe o mc sofrer com fração .. se fô da vontade dele 🤔.. 😜

  • Obrigado 1
  • Haha 1
Link para o comentário
Compartilhar em outros sites

Em meu cálculo da temperatura de termopar, tive que fazer duas coisas:

 

Para linearizar a função não linear...

 

1 - Peguei a curva do termopar e dividi em diversas retas. Fiz a interpolação linear "no braço". Usei o Matlab (poderia ser outro qualquer) para fornecer o erro entre a reta e o trecho selecionado da função. Fiquei satisfeito quando o erro ficava menor ou igual a 1/2 bit menos significativo do CAD.

Não usei operações em ponto flutuante, usei apenas as quatro operações e variáveis inteiras ... acho que com 16 bits, não me lembro.

Um detalhe. Para que usar interpolação, se o sensor informa que a função é linear (já é uma reta). 

 

2 - Monitorei as operações antes de usá-las no firmware. Achava os limites envolvidos nas parcelas (a equação da reta possui duas parcelas). Nas equações das retas eu até multipliquei alguns valores das parcelas por 1000 ou 10.000, para que os valores não dessem muito pequenos. Depois compensei nos resultados. Com isso obtém-se mais casas decimais corretas. Até aproximei a última casa decimal usando esse método.

Acho que o que está ocorrendo com você é que alguns resultados intermediários dão muito baixo (algo como 0,00000123) e com isso você perde precisão.

Outro detalhe:

Entendi que no pino do item 4, já é fornecida a faixa de 0v a 5v. Você que retornar para os limites entre 0,68 e 1,36?

MOR_AL

Link para o comentário
Compartilhar em outros sites

  • Membro VIP
9 horas atrás, MOR_AL disse:

temperatura de termopar,

9 horas atrás, MOR_AL disse:

Para linearizar a função não linear...

Acho que já registrei mas senti vontade registrar de novo. Com zero regras matemáticas, há alguns anos eu fiz assim por insight prum atmega8

//********************************************************
unsigned const int g16[]= //16 faixas com base em 1024
{
1024,1058,1071,1082,1090,1095,1102,1107,1110,1113,1115,1117,1118,1118,1119,1120
};
//--------------------------------------------------------------------------------------------------
unsigned int termopar, temperatura;
temperatura=read_ac();

void lineariza(void)
{
//16 faixas até 512º: 2048 unidades de ad 2048/16=128     ......->..........16 faixas
termopar=((unsigned long int)temperatura*g16[temperatura/128])/4096;//2048/128=16 faixas. 4096: 12 bits que saem do resultado até 1023º 
if (termopar>999) termopar=999;//pra não zoar o barraco se abrir termopar
}

Perceba a contramão da apelação temporária pra um long int 😁

 

temperatura é o resultado saído diretamente de leitura adc 12bits de um caro pacarái max31855. Usei temperatura como índice da tabela pra localizar o multiplicador linearizador por faixas. Ideota 100% original e com sucesso. Se prestar muita atenção vai perceber que a medida que sobe temperatura, sobe também nos 16 passos do index

 

Foi bom enquanto durou. Logo em seguida descobri o mcp9600 mais barato, sai em °C, digital i2c, linearizado, compensado, vários tipos de termopares e etc.

Em tempo.. descobri também um erro no d.s. do mcp que me custou dias. Notifiquei a microchip... os f d p  corrigiram e nem me deram bola.😡

Link para o comentário
Compartilhar em outros sites

Em 23/05/2023 às 21:00, GustavoH93 disse:

Está dizendo que a lambda foi declarada duas vezes, mas isso é estranho porque na linha:     float lambda = voltage * (1.36 - 0.68);     ele declara a variável local lambda e na linha a baixo: float lambda = 0.68 + lambda / 1023; ele atualiza a variável declarada anteriormente não cria uma nova variável, ou estou entendendo errado?

Está não, me deixei levar pelo controlC controlV. Dizer que uma variável é unsigned int varA ou float varB só se faz na declaração. Declarados os tipos é ir usando o varA e o varB sem se preocupar. A razão pela qual não acusou esse erro no código inicial é que a expressão float foi usada uma única vez num recurso avançado do C no qual se declara a variável e já se coloca para trabalhar.Na forma mais clássica teria sido:

float lambda

lambda = ..................(a conta que se segue)

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

18 horas atrás, .if disse:

O retorno da função adcread é int. Adotar float nela não é muito inteligente mas claro é mais conveniente pra jovens preguiçosos. O desafio de transformar 0 a 1023 pra 0 a 5.00 .. algo como...

Não duvido que a a função map do Arduino cria algo semelhante a isso. Claro, como deve prever situações meio foras da curva, vai ter meia dúzia de If a mais, mas como dito, deixa o mc sofrer por nós.

 

Ao invés disso:

Em 24/05/2023 às 20:42, GustavoH93 disse:

{float voltage = analogRead(lambdaPin) * (5.0 / 1023.0); // Leitura da tensão em volts

Eu faria o seguinte:

{int voltage = map(analogRead(lambdaPin); 0; 1023; 0; 500);; // Leitura da tensão em volts com base 500 
 
  Lcd.print(voltage/100); // Exibe a tensão inteira
  Lcd.print(","); // Exibe a virgula
  Lcd.print(voltage%100); // Exibe a virgula



 

Link para o comentário
Compartilhar em outros sites

  • Membro VIP

A map pelo que deduzo é bem legal: transforma uma faixa em outra. Mas de fato parece ser linear.. algo como transformar mm em pol ou °C em °F . Para o termopar que é algo como começa com 40uV/°C e vai até 60uV/°C (pesquise tabela de termopar) penso que ela não pode ser usada diretamente. E sim no início usei if pra ajustar algumas faixas mas ficou bem pobre. Enriqueci com o supramencionado sem if. Mas teorizo que existe matemática pra isso que claro exige conhecimentos adicionais.

Já que mapeou de 0 a 500, que tal se a gente colocar uma casa decimal a+?

...

..🤔

..

... depois eu penso 1 jeito 😁

Link para o comentário
Compartilhar em outros sites

  • Membro VIP

Não amigo.. se considerarmos que o código supramencionado roda num pic10f200. Também entendamos que um programador "normal" vai querer rodar função mastigada da lib como a propria printf() ou inttostr() ou sprintf() que por si já ocupam centenas ou milhares de bytes.

O mais econômico é mesmo fracionar o número em unidades e enviar uma a uma pra saída.

Olha mais uma fofura minha 100% original do início deste século...

#define un s[0] 
#define dez s[1]
#define cen s[2]
#define mil s[3]
#define dmil s[4]

unsigned char s[5]; //global
void separa(unsigned int dado)
{
unsigned char i=0;
un=dez=cen=mil=dmil=0; // variáveis globais: DEVEM ser zeradas
while(dado)
	{
	s[i]=dado%10;
	dado/=10;
	i++;
	}	
}

se fizer

separa(12345); //pode rodar num pic10f200.. qualquer dia eu tento...

Depois de rodar teremos em bytes separados dmil=1;...un=5.. facim pra enviar uma a uma pro display ou serial usando apenas o hw do mc. .. sem usar as gulosas printf("%s", 12345) ou ldc.print(12345);

 

Portanto a [minha] ideia secular é [era] usar zero lib pronta devido à minha pobreza do passado sempre presente. Mas de novo, hoje em dia tem mc cheio de recurso e barato... mas pra mim ainda é "coisa de rico" 😁

 

 

Pois mostra pra nós uai...! Não se acanhe nem [se] esconda. .. compartilhe ! Ninguém vai rir. [além de mim] ninguém tem autorização pra te zoar 😁

 

7 minutos atrás, aphawk disse:

Fiz exatamente isso também , muito parecido

🤪

Link para o comentário
Compartilhar em outros sites

6 horas atrás, .if disse:

Olha mais uma fofura minha 100% original do início deste século...

 

Fiz exatamente isso também , muito parecido kkkkkk :

 

off-topic : a pedido do @.if e um bom exemplo de como conseguir cálculos com números decimais usando aritmética de 16 bits ...

 

Parte em negrito para observar kkkkkk

'----------------------------------------------------------------------

' PROGRAMA MULTIPLEX 5 - Implementa um voltímetro que pode medir

' tensão entre 0 e 5 volts, e mostra com até 3 casas depois da vírgula

' Usaremos agora o MAX7219

' os displays estão numerados assim  D4-D3-D2-D1

' Este programa utiliza aritmética de 16 bits apenas !

'----------------------------------------------------------------------



$crystal = 8000000

'vamos usar o clock interno que é de 8 MHz.

$regfile = "m328Pdef.dat"

' vamos compilar para o ATMEGA328P

$hwstack = 40

$swstack = 32

$framesize = 52



Dim Digitos(4) As Byte

' nosso display terá 4 dígitos

Dim Dp_position As Byte

Dim Numero As Word

Dim I As Byte



Const Reg_decode_mode = &B1111100111111111

Const Reg_scan_limit = &B1111101111111011

Const Reg_intensity = &B1111101011111111

Const Reg_shutdown = &B1111110011111111





Dim Resultado As Word

' RESULTADO tem de apresentar numeros não inteiros

Dim Resultado1 As Word

' MAIS UMA VARIÁVEL PARA OS CÁLCULOS





Config Portc.0 = Output                                     'data

Config Portc.1 = Output                                     'load

Config Portc.2 = Output                                     'clock



Max_data Alias Portc.0

Max_load Alias Portc.1

Max_clock Alias Portc.2



Digitos(1) = 0

Digitos(2) = 0

Digitos(3) = 0

Digitos(4) = 0

Max_load = 1







Config Adc = Single , Prescaler = Auto , Reference = Avcc

Start Adc

' aqui configuramos o conversor a/d para fazer uma leitura

' apenas quando pedirmos, vai usar como referencia 5V





Enable Interrupts

' aqui habilitamos as interrupções definidas no programa







Dp_position = 4

' ponto decimal sempre no primeiro dígito



'vamos agora inicializar o MAX7219



Numero = Reg_shutdown

Gosub Sai_max

Numero = Reg_decode_mode

Gosub Sai_max

Numero = Reg_intensity

Gosub Sai_max

Numero = Reg_scan_limit

Gosub Sai_max



'já configurado !



Do

   Waitms 100

   Numero = 0

   For I = 1 To 49

     Numero = Numero + Getadc(5)

   Next I



' vamos calcular a media, somando 49 ezes a leitura. Porque 49 ?

' se multiplicarmos 49 x 1023, teremos 50.127, que ultrapassa em pouco 50.000

' SE DIVIDIRMOS 50127/50.000 = 1,00254, que é 2,54% maior do que queremos,

' agora, temos um valor que ultrapassa 50.000 em 0,254% . Vamos portanto subtrair

' esses 0,254% !



   Resultado1 = Numero

   Resultado1 = Resultado1 / 500                            ' 0,2%

   Numero = Numero - Resultado1

   Resultado1 = Numero

   Resultado1 = Numero / 2000                               '0,05 %

   Numero = Numero - Resultado1

   Resultado1 = Numero

   Resultado1 = Resultado1 / 25000                          ' 0,004 %

   Numero = Numero - Resultado1



' FINALMENTE SUBTRAIMOS 2,54%

' VAMOS AGORA DIVIDIR POR 10 PARA CHEGARMOS NA ESCALA QUE QUEREMOS.

   Numero = Numero / 10



   Resultado1 = Numero / 1000

   Digitos(4) = Low(resultado1)

   Resultado = Digitos(4) * 1000

   Numero = Numero - Resultado



   Resultado1 = Numero / 100

   Digitos(3) = Low(resultado1)

   Resultado = Digitos(3) * 100

   Numero = Numero - Resultado



   Resultado1 = Numero / 10

   Digitos(2) = Low(resultado1)

   Resultado = Digitos(2) * 10

   Numero = Numero - Resultado



   Digitos(1) = Low(numero)



' prontinho... não precisamos utilizar matemática de ponto flutuante, que

' sempre faz o programa ficar bem maior. Veremos no final a redução do programa.





   For I = 4 To 1 Step -1

     Numero = Digitos(i)

     If Dp_position = I Then

       Numero = Numero Or &B1111000010000000

    End If

     Select Case I

       Case 1

         Numero = Numero Or &B1111010000000000

       Case 2

         Numero = Numero Or &B1111001100000000

       Case 3

         Numero = Numero Or &B1111001000000000

       Case 4

         Numero = Numero Or &B1111000100000000

     End Select

     Gosub Sai_max

   Next I



Loop



Sai_max:

  Max_data = 0

  Max_clock = 0

  Max_load = 0

  Shiftout Max_data , Max_clock , Numero , 1

  Max_load = 1

Return





End

 

 

 

Este programa compilado tem 1.474 bytes, tratando o Max 7219 na unha.

 

Paulo

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

  • Membro VIP
17 horas atrás, aphawk disse:
Resultado1 = Numero / 1000

   Digitos(4) = Low(resultado1)

   Resultado = Digitos(4) * 1000

   Numero = Numero - Resultado



   Resultado1 = Numero / 100

   Digitos(3) = Low(resultado1)

   Resultado = Digitos(3) * 100

   Numero = Numero - Resultado



   Resultado1 = Numero / 10

   Digitos(2) = Low(resultado1)

   Resultado = Digitos(2) * 10

   Numero = Numero - Resultado



   Digitos(1) = Low(numero)

Fiz exatamente isso em c na versão alpha do programa.😁

unsigned int mil,cen,dez,un;
mil=dado/1000;
cen=(dado-mil*1000)/100;
dez=(dado-mil*1000-cen*100)/10;
un=dado-mil*1000-cen*100-dez*10;

... antes de descobrir que o loop com resto % lá de cima ficava mais enxuto...pelo menos no fonte.

Ainda estou digerindo o lance do..

17 horas atrás, aphawk disse:
um valor que ultrapassa 50.000 em 0,254% . Vamos portanto subtrair

' esses 0,254% !

 

Estou de molho com reação à vacina... talvez eu tente algo como...

17 horas atrás, aphawk disse:
um voltímetro que pode medir

' tensão entre 0 e 5 volts, e mostra com até 3 casas depois da vírgula

' Usaremos agora o MAX7219

Me bate a curiosidade se ocuparia...

17 horas atrás, aphawk disse:

1.474 bytes,

 

você diz na unha mas não achei a função Shiftout  ... por acaso é implementação do hw? tipo spi?

Link para o comentário
Compartilhar em outros sites

Em 26/05/2023 às 03:31, Thiago Miotto disse:

Eu faria o seguinte:

{int voltage = map(analogRead(lambdaPin); 0; 1023; 0; 500);; // Leitura da tensão em volts com base 500 
 
  Lcd.print(voltage/100); // Exibe a tensão inteira
  Lcd.print(","); // Exibe a virgula
  Lcd.print(voltage%100); // Exibe a virgula

funcionou muito bem, tentei aplicar o mesmo sistema na exibição da sonda no LCD mas não dá certo, imagino que é porque de 68 até 136 não dá pra dividir por 100 e ter o resultado exato, ou estou enganado? 

 

O código ficou assim:

 

Citação

#include <LiquidCrystal_I2C.h>

 

// Inicializa o display no endereço 0x27

LiquidCrystal_I2C lcd(0x27, 16, 4);

 

const int lambdaPin = A3; // Pino analógico utilizado para ler a tensão do gerenciador de sonda lambda


 

void setup()

{

  Serial.begin(9600); // Inicializa a comunicação serial

  lcd.init();

  lcd.setBacklight(HIGH);

  lcd.setCursor(0, 0);

  lcd.print("V=       L=");

}


 

void loop()

{

  int voltage = map(analogRead(lambdaPin), 0, 1023, 0, 500); // Leitura da tensão em volts com base 500

  int lambda = map(analogRead(lambdaPin), 0, 1023, 68, 136); // Mapeia voltage com lambda

 

  lcd.setCursor(3, 0);

  lcd.print(voltage/100); // Exibe a tensão inteira

  lcd.print(","); // Exibe a virgula

  lcd.setCursor(5, 0);

  lcd.print(voltage%100);  // Exibe o resultado após a virgula

 

  lcd.setCursor(12, 0);

  lcd.print(lambda/100); // Exibe a tensão inteira

  lcd.print(","); // Exibe a virgula

  lcd.setCursor(14, 0);

  lcd.print(voltage%100);

 

  Serial.print("Voltage: ");

  Serial.println(voltage);

  Serial.print("Lambda: ");

  Serial.println(lambda);

 

  delay(300);

}

 

 

 

lambda e voltage vejo no monitor serial que está funcionando direitinho, mas no LCD só voltage aparece corretamente, a sonda 0, ou 1, aparece normal mas depois da virgula dá uma leitura absurda como 1,99 e na serial vejo que está 136.

 

Em 25/05/2023 às 09:12, .if disse:
unsigned int v=adcread()*64;

v/=131;
printf("%d",v%10);
v/=10;
printf("%d",v%10);
printf("%s",".");
v/=10;
printf("%d",v);

 

Pronto.. eis seu 99.4 <----   (se vira 🤔🙃) pra resultado 0x3ff dos 10 bits do adc. Algo me diz que, sem a gulosa printf, ocupa menos recurso do que qualquer operação com float. Mas só testando mesmo

 

Em tempo.. isso é nostalgia da velharada (😁). Só vale a pena se realmente houver escassez de recursos. Deixe o mc sofrer com fração .. se fô da vontade dele 🤔.. 😜

mesmo sendo curto eu as vezes não entendo 100% do que tá escrito aí tento decifrar o que a @.if escreve kkkk de qualquer forma em alguns casos não tem como terei que usar float, mas como vou colocar um monte de funções no arduino quanto menos coisas nele melhor.

 

Em 25/05/2023 às 20:44, Sérgio Lembo disse:

Está não, me deixei levar pelo controlC controlV. Dizer que uma variável é unsigned int varA ou float varB só se faz na declaração. Declarados os tipos é ir usando o varA e o varB sem se preocupar. A razão pela qual não acusou esse erro no código inicial é que a expressão float foi usada uma única vez num recurso avançado do C no qual se declara a variável e já se coloca para trabalhar.Na forma mais clássica teria sido:

float lambda

lambda = ..................(a conta que se segue)

agora entendi, vou tentar alterar aqui e ver como fica, a função MAP como o @Thiago Miotto  sugeriu está funcionando bem, não estou conseguindo exibir o valor da sonda no LCD mas quando conseguir vou usar a conta que sugeriu Sérgio, é bom porque testando no sensor e funcionando poderemos escolher qual ocupa menos recursos do micro.

 

 

Link para o comentário
Compartilhar em outros sites

44 minutos atrás, GustavoH93 disse:

lambda e voltage vejo no monitor serial que está funcionando direitinho, mas no LCD só voltage aparece corretamente, a sonda 0, ou 1, aparece normal mas depois da virgula dá uma leitura absurda como 1,99 e na serial vejo que está 136.

Estranho.
Cogitei ser pelos 2 números após a casa (quando o resto for 9, ele deve escrever 09, esqueci de prever isso), mas segundo o que você falou de resultado, não faz sentido.

 

Dá p/ fazer por if, ou escrevendo dígito a dígito. Acho a segunda opção mais fácil:

 

 lcd.setCursor(3, 0);

  lcd.print(voltage/100); // Exibe a tensão inteira

  lcd.print(","); // Exibe a virgula

  lcd.setCursor(5, 0);

  
  lcd.print((voltage%100)/10);  // Exibe o 1º digito  após a virgula

  lcd.print(voltage%10);  // Exibe o 2º digito após a virgula



 

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

Ebook grátis: Aprenda a ler resistores e capacitores!

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!