Go Down

Topic: Armazenar temperatura máxima e minima (Read 7557 times) previous topic - next topic

NJPinheiro

Boas Pll,
Mais uma vez tenho de recorrer aqui ao forum, que me tem ajudado muito na construção do meu projecto, para o forum e para os seus membros, (eu incluído  :) ), um Bem Haja!

O seu "hardware" é:
- Arduino Mega;
- Teclado Matricial 4x4;
- RTC DS1307;
- LCD 16x2;
- Sensor de temperatura DS18B20;
- Placa de 8 Reles;

Necessitava de "armazenar" na Arduíno as temperaturas máxima e mínima que ele ler no dia, e também se possível a máxima e mínima de sempre.

Depois ter qualquer coisa do tipo :

Code: [Select]

.......
{switch (Key)
                    {case 'A' :
                                  Lcd.clear();
                                  lcd.setCursor (0,0);
                                  lcd.print ("mostrava a temperatura máxima do dia");
                                  lcd.setCursor(0,1);
                                  lcd.print("mostrava a temperatura mínima do dia");
                                  break;
                      case 'B' :
                                  Lcd.clear();
                                  lcd.setCursor (0,0);
                                  lcd.print ("mostrava a temperatura máxima de sempre");
                                  lcd.setCursor(0,1);
                                  lcd.print("mostrava a temperatura mínima de sempre");
                                  break;


O meu problema é que não sei fazer o código para "armazenar" valores na memória do Arduíno, nem depois ir ler os valores.

Alguém me pode dar uma ideia de como fazer isto?

PS: indico para o meu código fonte caso "desperte" o interesse de alguém:
          lhttps://googledrive.com/host/0B-Pv876wR5B1OVFDdF9rYjZ6UFkink

NJPinheiro

bubulindo

A que memoria te referes??? RAM ou EEPROM?

Para fazer na RAM, e simples...

Code: [Select]

float max_temp_mes = 0.0;
float max_temp_ever = 0.0;
float min_temp_mes = 3000.0;
float min_temp_ever = 3000.0;
unsigned char flag_temp = 0;

if (temperatura > max_temp_mes) max_temp_mes = temperatura;
if (temperatura < min_temp_mes) min_temp_mes = temperatura;

if (day == 1 && flag_temp == 0) { //novo mes que inicia...
    max_temp_mes = 0.0;
    min_temp_mes = 3000.0;
    flag_temp =1;
}


A logica para os valores de sempre e semelhante.

Se queres guardar isto na EEPROM, apenas tens de guardar os dados la com as funcoes do arduino ou da AVRlib.
Uma coisa que deves ter em mente e que ao iniciar tens de ver se os dados guardados na EEPROM fazem sentido. Outra coisa a ter em conta e minimizar ao maximo o numero de escritas na EEPROM, pois ela tem um numero finito de escritas/leituras.

Tirando isso... esta tudo na boa.
This... is a hobby.

luisilva

Eu, e respondendo também ao bubulindo, não faria nem na memória RAM, nem na memória EEPROM... faria numa mistura das duas! É confuso, por isso vou explicar. Se não me engano, o RTC deve ter uma zona de RAM que fica "protegida" por bateria (para quando a alimentação é desligada, não se perder a hora actual), como os registos necessários para armazenar a data+hora normalmente não são muitos, o usuário, costuma ter alguns registos que pode utilizar.
Penso que esta memória é ideal para guardar os máximos e mínimos absolutos. Para a máxima e mínima do dia, a ideia é a mesma. Vendo melhor o código, e a ref do RTC esse é um dos que têm a tal RAM disponível. Eu aconselho o uso (ou pelo menos a consulta) de uma biblioteca que já faça a leitura/escrita de valores nessa zona de memória (não é muito diferente da leitura/escrita de data/hora).
O resto o bubulindo já explicou como se faz, apenas é necessário a escrita do novo valor máximo/mínimo na memória depois do cálculo.

bubulindo

#3
Aug 30, 2014, 04:26 pm Last Edit: Aug 30, 2014, 04:31 pm by bubulindo Reason: 1
Tens razao... essa e outra possibilidade.

pelas minhas contas, assim por alto, daria para guardar 13 floats... logo suficiente para os min/max de sempre/ano/mes.

Provavelmente (para nao dizer quase de certeza), uma funcao (ou metodo) teria de ser implementado para aceder a essa area de memoria e tambem para serializar os dados por forma a guardar byte a byte, mas nao seria nada de extraordinariamente dificil.

vi agora uma biblioteca que tem a funcao para escrever na NVRam implementada.

https://github.com/adafruit/RTClib

This... is a hobby.

FernandoGarcia

Olá!

Meu comentário não está relacionado com a sua questão mas, acho que vale a informação.

Não sei exatamente o quanto isso influência em termos de consumo de memória e desempenho mas, deixa o código mais limpo no meu ponto de vista.

Acho este tipo de método desnecessário.

Code: [Select]

const byte ROWS = 4;
const byte COLS = 4;  

char keys[ROWS][COLS] =
{
 ...
}

byte rowPins[ROWS] = { 22, 23, 24, 25 };

byte colPins[COLS] = {26, 27, 28, 29};

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );



Poderia usar apenas:

Code: [Select]

char keys[4][4] =
{
 ...
}

byte rowPins[4] = { 22, 23, 24, 25 };

byte colPins[4] = {26, 27, 28, 29};

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, 4, 4 );


Assim teria 2 variáveis a menos no código.

Abraço.
Fernando Garcia.

bubulindo

Ja andamos a ver isto, mas esqueco-me sempre do resultado...

Se nao me engano, ao definir como const, existe espaco de memoria que e utilizado. Se fizer um #define consegue o mesmo proposito sem aumento de espaco de memoria/programa.
This... is a hobby.

FernandoGarcia

Sim, eu me lembro.

A questão é que não vejo necessidade de criar 2 variáveis para usá-las apenas em 3 lugares no começo do código.

Code: [Select]

const byte ROWS = 4;
const byte COLS = 4;

NJPinheiro

Olá pll,
começo por agradecer a ajuda :)

...mas se eu já estava baralhado, agora ainda mais estou :~

vamos por partes,


A que memoria te referes??? RAM ou EEPROM?


Com essa é que me "Li#as-%e" RAM, EEPROM, HELP!!!

Quando "enviamos" um código para o Arduíno estamos a escrever aonde?
(julgo que seja na EEPROM, será?) Qual a diferença de uma para a outra?

Conforme já deve ter dado para reparar, eu ainda estou muito "verde" nesta área dos Arduínos !!
Podes explicar melhor o valor 3000.0? (já dei voltas à cabeça para perceber...mas não chego a nenhuma conclusão :~ )

O exemplo que dás é para mês em que eu substituiria o mês por dia, mas e depois esta parte?
Code: [Select]
if (day == 1 && flag_temp == 0) { //novo mes que inicia...
    max_temp_mes = 0.0;
    min_temp_mes = 3000.0;
    flag_temp =1;
}


Que julgo que o que faz é "limpar" a memória "mensal"quando muda o mês, então e para o dia? Seria assim?
Code: [Select]
if (hora == 0 && flag_temp == 0) { //novo mes que inicia...
    max_temp_mes = 0.0;
    min_temp_mes = 3000.0;
    flag_temp =1;



A logica para os valores de sempre e semelhante.


Mas para este caso, (Maxima/Minima temperatura de sempre), já não é necessário a parte do:
"if (day, blá, blá, blá), certo?


Se queres guardar isto na EEPROM, apenas tens de guardar os dados la com as funcoes do arduino ou da AVRlib.
Uma coisa que deves ter em mente e que ao iniciar tens de ver se os dados guardados na EEPROM fazem sentido. Outra coisa a ter em conta e minimizar ao maximo o numero de escritas na EEPROM, pois ela tem um numero finito de escritas/leituras.


Desculpa, podes explicar melhor? (admito que a tua explicação esteja explicita, mas eu com os poucos conhecimentos que tenho não estou a entender o que queres dizer com:
"...apenas tens de guardar os dados la com as funcoes do arduino ou da AVRlib.
....ao iniciar tens de ver se os dados guardados na EEPROM fazem sentido."

Quanto ao numero finito de escritas, espero que seja bastante  grande, pois estou "farto" de "carregar" o meu código :(

Luisilva, eu sei que a intenção é boa, mas se eu já ando "a apanhar balões" com o que o bubulindo escreveu, com o que escreves-te então estou mesmo a "lestes do paraiso", se puderes (e tiveres paciência), podes clarificar? (mas uma vez, acredito que o teu post esteja claro...eu é que....não chego lá!


Olá!
Meu comentário não está relacionado com a sua questão mas, acho que vale a informação.
Não sei exatamente o quanto isso influência em termos de consumo de memória e desempenho mas, deixa o código mais limpo no meu ponto de vista.


Todos os comentários são bem vindos, principalmente para quem como eu ainda tem muito que aprender!!

Testei o código com a sua dica, e em termos de memória é igual, (20.352 bytes), no desempenho não notei diferença.
Em todo o caso, obrigado pela dica.
Optei por deixar como está simplesmente porque para quem ainda não domina, (o meu caso), parece-me mais "fácil de perceber" o código como tenho, só por isso.



luisilva

OK. Não tinha noção disso. Penso que sendo assim, é melhor começar com algumas definições e a partir daí talvez de para perceber melhor o que tentei explicar (e o que perguntou o bubulindo).

ROM - Read Only Memory (memória só de leitura, portanto não consegue ser escrita, normalmente é escrita uma vez durante a produção do chip).
RAM - Ramdom Access Memory (memória de acesso aleatório - não sei bem qual é a origem das iniciais, mas penso que tenha sido "uma brincadeira" para ser parecida com ROM, mas esta é uma memória de escrita e leitura).

Outra diferença que existe entre as duas, é que, na RAM, quando a energia é desligada, os dados são perdidos.
As memória ROM, hoje em dia não têm grande utilização. Elas serviam principalmente para guardar os programas, mas por exemplo no Arduino, nós queremos poder apagar os programas e escrever outros, para fazer experiências etc. Sendo assim, a tecnologia foi evoluindo e foram criadas outro tipo de ROM's. Uma delas a EEPROM.

EEPROM - Electric Erasable "ROM" (isto é, é uma memória "só de leitura", mas que pode ser apagada!?)

Este "nonsense" pode ser explicado pelo facto de ser memória só de leitura numa óptica de os dados não serem perdidos quando a energia desaparece (ou seja, quando o equipamento é desligado). O programa que é descarregado para o Arduino é guardado numa memória deste tipo (que do ponto de vista tecnológico é diferente, por isso recebe outro nome: Flash Memory), mas do ponto de vista lógico funciona da mesma forma, isto é, é não volátil (os dados não desaparecem quando a energia desaparece) e pode ser apagada (e gravada) electricamente (não por processos mecânicos nem químicos, o que não dava muito jeito).

Portanto, para guardar os valores máximo e mínimo de sempre deve ser usado um tipo de memória em que não seja perdido o seu conteúdo quando a energia é perdida (pelo menos, não seria assim que eu faria, porque nesse caso, não seriam os valores "de sempre", mas os valores de sempre desde que o equipamento está ligado).

Daí a pergunta do bubulindo, que "trocando por miúdos" basicamente quer dizer: "Mas o que queres fazer? Podes perder os valores ou não?"

Uma coisa que eu ainda não disse acerca das memórias EEPROM é que elas normalmente têm um tempo limitado de vida. Apenas podem ser escritas/apagadas um determinado número de vezes (normalmente são valores muito altos, na casa das 100.000 ou 1.000.000), por isso se o programa estiver constantemente a escrever um novo valor naquele local da memória, essa zona da memória pode ficar danificada (e o resto em bom estado). Por isso, para coisas que possam variar muito, convém não usar EEPROM para armazenar esses valores.

Aqui chegamos à parte do RTC. O RTC tem os seus valores a variar constantemente (1 vez por segundo), estes valores são mantidos (e continuam a ser alterados) mesmo quando o equipamento é desligado. Isto acontece, porque estes valores são mantidos em memória RAM, mas o chip continua a ser alimentado por uma pilha de botão.

Sendo assim, o que eu tentei dizer no meu post é que se no projecto existe já este dispositivos disponível, ele é o candidato ideal a armazenar estes valores máximos e mínimos.


A questão dos 3000.0, tem uma explicação muito fácil. Antes de saber quais serão as primeiras temperaturas máximas e mínimas, é necessário garantir que o sistema começa a trabalhar. Como é que o sistema vai calcular (ou verificar) a temperatura máxima? Seguido o procedimento seguinte:

- mede a temperatura actual;
- a temperatura actual é maior que a temperatura máxima?
- se sim, a temperatura actual é a nova temperatura máxima.


portanto, antes de isto iniciar, tem que haver uma valor guardado na variável "temperatura máxima" que tem que ser suficientemente pequeno, para que a a primeira temperatura que seja medida passe a ser a temperatura máxima. Por isso o bubulindo fez:
Code: [Select]
    max_temp_mes = 0.0;

para a temperatura mínima, é a mesma coisa, mas o processo inverso:

- mede a temperatura actual;
- a temperatura actual é MENOR que a temperatura MÍNIMA?
- se sim, a temperatura actual é a nova temperatura MÍNIMA.


portanto, o processo tem que começar com um valor suficientemente alto na temperatura mínima para que a primeira temperatura medida passe a ser a nova temperatura mínima. (neste caso o bubulindo escolheu 3000.0, assim como poderia ter escolhido, 60.0, por exemplo, uma vez que se for medida a temperatura ambiente, por muito calor que esteja, esta nunca chegará aos 60.0)

NJPinheiro

Agora sim  :) ...explicado assim até parece fácil ;)

Se bem percebi,

Os valores devem ser gravados na memoria RAM do RTC, e gora como é que eu escrevo na memoria RAM do RTC?


PS:Já implementei a dica do bubulindo, alterando o mês para dia e parece-me estar a funcionar, ainda só não consegui testar se ele apaga os valores máximos e minimos quando muda o dia, vamos ver se consigo testar amanhã :)

Obg
NJPinheiro



FernandoGarcia

#10
Aug 31, 2014, 05:04 pm Last Edit: Aug 31, 2014, 05:07 pm by FernandoGarcia Reason: 1
Olá !

Quote
Testei o código com a sua dica, e em termos de memória é igual, (20.352 bytes), no desempenho não notei diferença.


Eu estava me referindo à memória RAM. Esse número é da memória FLASH.

Você pode usar este código para testar a memória livre.

Code: [Select]

int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}


Code: [Select]
Serial.println(freeRam());


Code: [Select]

const byte ROWS = 4;
const byte COLS = 4; 

char keys[ROWS][COLS] =
{
  ...
}



Code: [Select]

char keys[4][4] =
{
  ...
}


Esses códigos fazem a mesma coisa porém, no primeiro você tem duas variáveis para guardar o número 4, que na minha opinião é inútil.

Só vale a pena criar uma variável quando ela for usada muitas vezes no código ou que mude com o tempo.

Se tivesse essa variável em vários lugares seria bom usá-la pois, se precisasse mudar o valor não teria que correr o código inteiro para ficar mudando os valores. No seu caso são apenas 3 lugares e no começo do código. :)

Abraço.

bubulindo

Peço desculpa.... A temperatura máxima devia ser comparada a -3000 ou algo igualmente irrealista.

0 graus é irrealista apenas em algumas zonas. :$
This... is a hobby.

luisilva

@bubulindo: por acaso reparei que não fazia muito sentido o " 0 ", quando o outro extremo era 3000, mas como o código vai funcionar correctamente, por isso não disse nada.

@FernandoGarcia: discordo completamente daquilo que diz, mas o pior penso que é ensinar "maus vícios" a quem está a começar a programar. Na minha opinião, isto:
Code: [Select]
char keys[4][4] =
{
  ...
}

byte rowPins[4] = { 22, 23, 24, 25 };

byte colPins[4] = {26, 27, 28, 29};

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, 4, 4 );


é um bom exemplo de mau estilo de programação. Os programas não têm só que funcionar e ser leves e ocupar pouca memória, etc., também têm se perceber bem (agora e daqui por 5 anos) e têm que permitir ser facilmente alteráveis de forma a permitir uma rápida e fácil manutenção/ampliação. Quanto muito, a alteração que sugere, poderia ser feita da seguinte forma:
Code: [Select]

#define ROWS  4;
#define COLS  4

char keys[ROWS][COLS] =
{
  ...
}

byte rowPins[ROWS] = { 22, 23, 24, 25 };

byte colPins[COLS] = {26, 27, 28, 29};

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

Até da muito menos trabalho a fazer, que aquela que sugere, o efeito é exactamente o mesmo, mas tem a vantagem de poder ser facilmente alterável e identificável (agora percebe-se o significado do 4º parametro do contrutor Keypad()).
A única coisa que concordo, daquilo que diz, é que o assunto "não está relacionado com a sua questão", por isso para continuar-mos esta discussão, deve ser melhor criar-mos um novo tópico em vez de estar-mos a baralhar ainda mais o OP.

FernandoGarcia

#13
Sep 01, 2014, 04:37 pm Last Edit: Sep 01, 2014, 04:41 pm by FernandoGarcia Reason: 1
Luis, seu comentário é desnecessário visto que no post anterior eu deixei bem explicado as condições de uso da minha sugestão.

E o que sugeres é trocar 6 por meia dúzia.

Se for seguir seu raciocínio é melhor criar uma variável para cada número do código.

Para estes por exemplo:

Code: [Select]
{ 22, 23, 24, 25 }

bubulindo

#define não cria variáveis.... Cria um simbolo logico que ira ser substituido pelo valor a ser definido pelo pré-processador do compilador. Desta forma o #define não ocupa memória e permite alterar um valor apenas num local do código.

O que o Luis referiu está completamente correcto. É a práctica correcta de programação para aquele caso... Pensava que já dominavas estes pormenores depois da luta no teu projecto.

Usar o const serve apenas quando queremos uma variavel constante no código de forma a apenas termos de mudar um local e não 30.
This... is a hobby.

Go Up