LusoRobótica - Robótica em Português

Sistemas específicos => Arduino / AVR => Tópico iniciado por: AndréD. em 18 de Setembro de 2013, 11:31

Título: Contadores de minutos millis()
Enviado por: AndréD. em 18 de Setembro de 2013, 11:31
Boas Pessoal,

Desde ontem que ando a bater com a cabeça nisto, e não tenho ainda sequer uma solução à vista, por isso vos peço ajuda.

Eis o que necessito:
Tenho um sensor de Temperatura (Lm335) que quando passar dos 30º inicie uma contagem de 1 minuto, ao fim desse minuto se a temperatura continuar acima dos 30º activo uma saída e comece outro contador de 30 minutos em que durante os mesmos caso a temperatura seja maior que 30 o contador seja colocado a 0, caso contrario não faz nada e fica de novo á espera que passe os 30º. Ao fim dos 30 minutos o processo repete.


Situação N1:
A temperatura passa os 30º
Contador de 1 Minuto começa
Se a temperatura continuar nos 30º Depois desse minuto o Led Acende.
- Esta situação está Resolvida -

Situação N2:
A temperatura passa os 30º
Contador de 1 Minuto começa
Se a temperatura não passou dos 30 Depois desse minuto fica de novo á espera que passe os 30 para iniciar novamente o contador de 1 Minuto.
- Esta situação não Resolvida -

Problemas:

A temp passa os 30, o contador de 1 minuto começa, passado esse minuto (com temp abaixo dos 30), assim que a temp os passar invés de o contador de 1 minuto começar acende logo o Led.


Situação N3:
A temperatura passa os 30º
Contador de 1 Minuto começa
Se a temperatura continuar nos 30º Depois desse minuto o Led Acende.
Assim que a temperatura for menor que 30º começa um contador de 30 minutos e sempre que a temperatura subir para lá dos 30º o mesmo tem de reiniciar.
No fim desses 30 Minutos o processo repete-se de novo desde o inicio.
- Esta situação não Resolvida -

Problemas:
Não sei por onde começar.


Aqui fica o pedaço de código que já tenho feito. Espero que me possam dar umas luzes.

Código: [Seleccione]
int pinoLM35 = A15; // Pino Analogico onde vai ser ligado a pata do meio do LM35
int valorLido = 0; // Variavel onde se ira guardar o valor lido pelo LM53
int saida = 22; // Pino Do LED da Board Do Arduino
float temperatura = 0; //Variavel onde vai ser guardada a Temperatura
static unsigned long  tempHIT;
static unsigned long  startTime;
int flag = 0;
int flagTM =0;

void setup() {
  Serial.begin(9600);
  pinMode(saida, OUTPUT);
  startTime = millis();
  tempHIT = millis();
}

void loop() {

  if(CheckTemp() > 30 && flag==0){ //Verifica se a temperatura é maior que 20, e se for acende o Led Da Board do Arduino.
    Serial.println("Dentro do IF 1");
    tempHIT = millis();
    flag = 1;
    flagTM=0;
  }

  if(millis() - tempHIT >= 1UL*60UL*1000UL && CheckTemp() > 30 && flagTM==0) {
    Serial.println("Dentro do IF 2");
    digitalWrite(saida, HIGH); //Acende o led da board do Arduino
    flagTM =1;
    flag=0;

  }

}


float CheckTemp(){


  // delay(1000); // Espera um segundo.

  if(millis() - startTime >=1000){
    valorLido = analogRead(pinoLM35); //Coloca na Variavel valorLido o que está a ser lido pelo sensor.
    temperatura = (valorLido *  0.4887585532746823069403714565); ///
    //temperatura = temperatura / 9.31 *; /// Conversão do valor obtido atraves da porta analogica para um valor “usavel”
    Serial.print("Temperatura actual:"); // Imprime no Serial Monitor “Temperatura Actual:”
    Serial.println(temperatura); // Imprime no Serial monitor o valor da variavel temperatura

      startTime = millis();
  }

  return temperatura; // Retorna A temperatura
}

Desde já muito obrigado pelo tempo.
Os Melhores Cumprimentos
AndréD.
Título: Re: Contadores de minutos millis()
Enviado por: jm_araujo em 18 de Setembro de 2013, 12:04
O teu erro é que estás a querer verificar tudo ao mesmo tempo no teu segundo if.
Primeiro tens de esperar o minuto, e depois conforme a temperatura é que tomas a ação devida. Como tens o código, o segundo if fica bloqueado à espera que a temperatura passe dos 30º
Tem de ser algo do género:

Código: [Seleccione]
if( (millis()-tempHIT)>=1UL*60UL*1000UL && flagTM==0) { //Verifica se já passou 1 minuto
    // já

    if (CheckTemp() > 30)
        // ainda está a cima de 30º
        digitalWrite(saida, HIGH); //Acende o led da board do Arduino

    flagTM=1;
}

E como tens o código, no setup devias inicializar o flagTM a 1.
Título: Re: Contadores de minutos millis()
Enviado por: tarquinio em 18 de Setembro de 2013, 15:00
Boas. Não estou certo se percebi bem o que tu queres fazer, mas penso que o resultado esperado seja que o led acenda quando a temperatura for maior do que 30 durante mais de um minuto, e apague logo que baixe desse valor. Alem disso, quando o led apaga, só pode voltar a acender 30 minutos depois.
Assumindo que é isto, eu faria a coisa com uma pequena máquina de estados. Tambem poderias fazer com várias flags e verificar as várias condições de outras formas, mas pessoalmente eu sugeria fazer assim.
Há 4 estados possiveis para o sistema:
-Temperatura abaixo dos 30º
-Temperatura acima dos 30, mas à menos de 1 minuto
-Temperatura acima dos 30, à mais de 1 minuto
-Periodo de cooldown, onde vai esperar 30 minutos sem fazer nada

Eu cada um destes estados, basta fazer um ou dois testes simples e passar para o estado seguinte (as flags fazem +- o mesmo, mas acho que é mais simples pensar apenas num estado de cada vez, do que ter de olhar para 3 ou 4 flags ao mesmo tempo (porque ainda irias precisar de mais) para tomar as decisões.

O if proposto pelo jm_araujo só vai testar a temperatura no fim de passar o minuto, o que significa que se a temperatura baixar e voltar a subir durante esse minuto, o led acende à mesma no fim, e penso que isso não seja o pretendido...

Código: [Seleccione]
int pinoLM35 = A15; // Pino Analogico onde vai ser ligado a pata do meio do LM35
int valorLido = 0; // Variavel onde se ira guardar o valor lido pelo LM53
int saida = 22; // Pino Do LED da Board Do Arduino
float temperatura = 0; //Variavel onde vai ser guardada a Temperatura

#define TARGET_TEMPERATURE 30

#define BELOW_TEMP 1
#define ABOVE_TEMP_LESS_1_MINUTE 2
#define ABOVE_TEMP_MORE_1_MINUTE 3
#define COOLDOWN_30_MINUTES 4
byte state;

unsigned long minute_start;
unsigned long cooldown_start;

void setup() {
  Serial.begin(9600);
  pinMode(saida, OUTPUT);
  state = BELOW_TEMP;
}

void loop()
{
// Verifica os vários estados possíveis
switch(state)
{
// Se a temperatura anterior estava abaixo do valor pretendido
case BELOW_TEMP:
if (CheckTemp() >= TARGET_TEMPERATURE)
{
// Comeca a contar o minuto e regista a mudança de estado
minute_start = millis();
state = ABOVE_TEMP_LESS_1_MINUTE;
}
break;
// Se já passou o valor pretendido, mas à menos de 1 minuto
case ABOVE_TEMP_LESS_1_MINUTE:
// Se nesta fase a temperatura for abaixo do valor pretendido, volta ao estado inicial
if (CheckTemp() < TARGET_TEMPERATURE) state = BELOW_TEMP;
else
{
// Caso se mantenha acima do valor pretendido, vai testando se já passou 1 minuto
if (millis() - minute_start >= 1UL*60UL*1000UL)
{
// Se já passou o minuto, acende o led e passa ao estado activo
state = ABOVE_TEMP_MORE_1_MINUTE;
digitalWrite(saida, HIGH);
}
}
break;
// Se estamos na situação em que já passou o valor pretendido à mais de 1 minuto
case ABOVE_TEMP_MORE_1_MINUTE:
// Se nesta fase a temperatura for abaixo do valor pretendido, vai para o estado de cooldown
if (CheckTemp() < TARGET_TEMPERATURE)
{
//Quando a temperatura baixa do valor pretendido, apaga o led e inicia o periodo de cooldown
state = COOLDOWN_30_MINUTES;
cooldown_start = millis();
digitalWrite(saida, LOW);
{
break;
// Se estamos na situação em que o sistema está à espera de passar 30 minutos para activar outra vez
case COOLDOWN_30_MINUTES:
// A unica coisa a fazer aqui é ver se já passaram 30 minutos
if (millis() - cooldown_start >= 30UL*60UL*1000UL)
{
state = BELOW_TEMP; // Volta ao estado inicial
}
break;
{

}

float CheckTemp()
{
  if(millis() - startTime >=1000){
valorLido = analogRead(pinoLM35); //Coloca na Variavel valorLido o que está a ser lido pelo sensor.
temperatura = (valorLido *  0.4887585532746823069403714565); ///
//temperatura = temperatura / 9.31 *; /// Conversão do valor obtido atraves da porta analogica para um valor “usavel”
Serial.print("Temperatura actual:"); // Imprime no Serial Monitor “Temperatura Actual:”
Serial.println(temperatura); // Imprime no Serial monitor o valor da variavel temperatura

  startTime = millis();
  }
  return temperatura; // Retorna A temperatura
}
Título: Re: Contadores de minutos millis()
Enviado por: TigPT em 18 de Setembro de 2013, 15:12
Não era mais simples teres uma variável flag para saber a condição do teste anterior e mediante essa saber qual dos casos estas a testar?

Lembra-te da metodologia KISS
http://pt.wikipedia.org/wiki/Keep_It_Simple (http://pt.wikipedia.org/wiki/Keep_It_Simple)
Título: Re: Contadores de minutos millis()
Enviado por: jm_araujo em 18 de Setembro de 2013, 15:20
Tarquinio, fizeste a papinha toda ao rapaz, assim não aprende nada.

Ao menos a positiva ficou garantida, basta enfiar os fios nos buracos certos para ter uma boa nota ;)


PS:Tou só a ser mauzinho, não liguem. :D



Título: Re: Contadores de minutos millis()
Enviado por: senso em 18 de Setembro de 2013, 15:30
Os floats do arduino são só de 32 bits, isto:
0.4887585532746823069403714565

Não é preciso..
Título: Re: Contadores de minutos millis()
Enviado por: jm_araujo em 18 de Setembro de 2013, 16:03
Os floats do arduino são só de 32 bits, isto:
0.4887585532746823069403714565

Não é preciso..
E fica muito mais legível (e fácil de corrigir) se estiver na forma da fração original:
500/1023 = 0.4887585532746823069403714565

Título: Re: Contadores de minutos millis()
Enviado por: tarquinio em 18 de Setembro de 2013, 16:17
Tarquinio, fizeste a papinha toda ao rapaz, assim não aprende nada.
Ao menos a positiva ficou garantida, basta enfiar os fios nos buracos certos para ter uma boa nota ;)

Acordei, vi o post e tava com vontade de programar... E prontos gerou-se código! ;) Mas nem li em lado nenhum que era para um projecto académico, pensei que fosse algo para por a funcionar um projecto pessoal. Se soubesse que era para uma aula provávelmente teria dado só umas dicas tb.

Citação de: tig_pt

Não era mais simples teres uma variável flag para saber a condição do teste anterior e mediante essa saber qual dos casos estas a testar?
Aqui é mais uma questão de preferência, acho eu... Da maneira como eu penso, acho mais natural pensar numa máquina de estados com um valor diferente para cada estado, do que ter várias flags, cada uma para cada estado diferente, alterando cada uma delas separadamente. Seja como for, vais ter sempre de ter a noção do estado em que o sistema está. Fazendo a mesma coisa com várias flags, duvido que a coisa fosse ficar muito mais pequena... As condições a ser verificadas são as mesmas, só que podem ser feitas por uma ordem diferente. E de cada vez que eu mudo o estado no meu código, na versão equivalente usando flags teriam de ser alteradas uma ou mais flags. Por isso o código iria acabar por ter +- o mesmo tamanho, acho que aqui a maneira "correcta" é mesmo a maneira que cada programador preferir :)

Título: Re: Contadores de minutos millis()
Enviado por: TigPT em 18 de Setembro de 2013, 16:19
tens razão, mas quando vi o post não tinha visto sequer o teu reply e estava a ver se puxava a ideia das state machines.
Título: Re: Contadores de minutos millis()
Enviado por: tarquinio em 18 de Setembro de 2013, 21:14
Pronto então tava tudo a convergir para o mesmo... ;)
Mas ainda não percebi... A cena afinal é para um trabalho escolar ou para um projecto pessoal? :P
Se for para aprendizagem eu para a proxima slacko mais no código... :)
Título: Re: Contadores de minutos millis()
Enviado por: TigPT em 18 de Setembro de 2013, 22:22
Independentemente do objectivo final, embora estejamos todos aqui para nos ajudar-mos, gostamos de ensinar a pescar e orientar sem dar logo a papinha feita para que consigamos aprender uns com os outros.

Não é regra mas é quase uma opinião unanima.
Título: Re: Contadores de minutos millis()
Enviado por: tarquinio em 18 de Setembro de 2013, 22:32
Sim tens razão, aprende-se mais se se tiver que puxar mais pela cabeça... Eu tambem costumo dar mais respostas nesse sentido, em vez de fazer tudo. Hoje acho que foi mais por já ter saudades me programar no meu arduino que me deu para disparar o código todo :)
Título: Re: Contadores de minutos millis()
Enviado por: TigPT em 18 de Setembro de 2013, 23:56
Haha.

Estou a precisar de gente com essa vontade para um projeto que estou a fazer a prova de conceito antes de apresentar oficialmente. Se quiseres ajudar apita.
Título: Re: Contadores de minutos millis()
Enviado por: tarquinio em 19 de Setembro de 2013, 00:36
Tens algum sitio onde estejas a discutir esse projecto? Ou podes mandar-me PM se não quiseres estar a discutir num thread, nunca se sabe... :)
Título: Re: Contadores de minutos millis()
Enviado por: TigPT em 19 de Setembro de 2013, 10:35
Mandei PM
Título: Re: Contadores de minutos millis()
Enviado por: AndréD. em 19 de Setembro de 2013, 14:48
Boa Tarde Pessoal,

Antes de mais, muito obrigado pela ajuda e pelo vosso tempo. Como o TigPT disse, se nos fizerem o trabalho todo nunca aprendemos nada, e por essa razão agradeço muito o teu tempo tarquinio, mas não vou utilizar o teu código, ou melhor vou utilizar na medida em que me vou orientar por o mesmo.

Alguém falou por ai na minha nota, isto é um projecto pessoal por isso não vou receber nada com o mesmo. :P

Vou agora dar uns toques no pedaço de código que tinha, seguir mais ou menos a lógica do código do amigo tarquinio, e qualquer duvida eu vou colocando aqui.

Os Melhoes Cumprimentos
AndréD.
Título: Re: Contadores de minutos millis()
Enviado por: TigPT em 19 de Setembro de 2013, 14:51
Força AndréD ;)
Título: Re: Contadores de minutos millis()
Enviado por: tarquinio em 20 de Setembro de 2013, 15:08
Pois mesmo tendo feito overkill e posto logo o código todo, a minha idéia tambem nunca foi simplesmente por o código para fazeres copy-paste directo, daí ter posto os comentários por todo o lado para conseguires seguir bem a linha de pensamendo ;)

Força nisso, tens de acabar isso rápido que o verão está a acabar e depois para testares isso com temperaturas maiores de 30º tens de esperar até ao ano que vem! :P
Título: Re: Contadores de minutos millis()
Enviado por: andre_f_carvalho em 20 de Setembro de 2013, 19:10
Pois mesmo tendo feito overkill e posto logo o código todo, a minha idéia tambem nunca foi simplesmente por o código para fazeres copy-paste directo, daí ter posto os comentários por todo o lado para conseguires seguir bem a linha de pensamendo ;)

Força nisso, tens de acabar isso rápido que o verão está a acabar e depois para testares isso com temperaturas maiores de 30º tens de esperar até ao ano que vem! :P


a fogueira também deve servir xD
Título: Re: Contadores de minutos millis()
Enviado por: AndréD. em 21 de Setembro de 2013, 23:50
Boas...

Tens razão, tenho de me despachar senão depois não há temperaturas maiores que 30 :P :P :P

Mais uma vez peço aqui ao pessoal uma ajudinha, já andei a ler umas coisas sobre referencias e etc, mas fiquei na mesma.

É o seguinte, preciso de passar um array como parâmetro para uma função, isto para não estar a escrever 50 vezes a mesma coisa que seria:

Código: [Seleccione]
digitalWrite(Saidas[0],HIGH);
digitalWrite(Saidas[1],LOW);
digitalWrite(Saidas[2],LOW);
digitalWrite(Saidas[3],LOW);
digitalWrite(Saidas[4],LOW);
digitalWrite(Saidas[5],LOW);
digitalWrite(Saidas[6],LOW);

Então a ideia passa por fazer o seguinte, receber o array na função, passar por todos os elementos e verificar se os mesmos são 1 ou 0 e se forem 1 colocar a Saída respectiva a HIGH e se for 0 Colocar a respectiva a LOW.

Criei um array "temporario", para guardar os valores que quero.
Código: [Seleccione]
int Values[] = {0,0,0,0,0,0,0};
E depois quando quisesse chamar a função faria o seguinte:

Código: [Seleccione]
Values[] = (1,1,0,0,0,0,0);
    Saida(Values);

Código: [Seleccione]
void Saida(int cenas[]){

  for(int i = 0; i <=6; i++){
    if(cenas[i] == 1) {
      digitalWrite(Saidas[i],HIGH);
    }
    else {
      digitalWrite(Saidas[i],LOW);
    }
}
}

No entanto isto não funciona. Será que podem dar uma mãozinha?

Desde já muito Obrigado pelo tempo e Ajuda
Os Melhores Cumprimentos
AndréD.
Título: Re: Contadores de minutos millis()
Enviado por: tarquinio em 22 de Setembro de 2013, 00:06
Ok esta parte tá ok:
Código: [Seleccione]
int Values[] = {0,0,0,0,0,0,0};

Mas isto já n podes fazer:
Código: [Seleccione]
Values[] = (1,1,0,0,0,0,0);

tens de fazer posição a posição:
Código: [Seleccione]
Values[0] = 1;
Values[1] = 1;

E já agora, não é por aí que não funciona, mas podes simplificar o código da função sem precisar de ter o IF (porque ter High e Low é o mesmo que teres 0 ou 1)
Título: Re: Contadores de minutos millis()
Enviado por: AndréD. em 22 de Setembro de 2013, 00:36
Boas...

Pois, foi o que li também, que só se podiam atribuir valores individualmente, mas isso vou escrever uma carrada de linhas na mesma, fazer,

Código: [Seleccione]
values[0]=1;
values[1]=1;
etc..

é igual a fazer,

Código: [Seleccione]
digitalWrite(Saidas[0],HIGH);
digitalWrite(Saidas[1],LOW);
digitalWrite(Saidas[2],LOW);
digitalWrite(Saidas[3],LOW);
digitalWrite(Saidas[4],LOW);
digitalWrite(Saidas[5],LOW);
digitalWrite(Saidas[6],LOW);

Era isto é que queria evitar... :P Estou agora aqui a lembrar-me, não existe uma maneira de passar um conjunto de Bits, e depois trata-los 1 por um?

Algo deste género B1000000 e depois ir pegando nos mais à direita ou esquerda e colocar nas saídas os respectivos 1's e 0's?

Os Melhores Cumprimentos
AndréD.
Título: Re: Contadores de minutos millis()
Enviado por: tarquinio em 22 de Setembro de 2013, 01:09
Bem não sei exactamente o que é que pretendes fazer com a coisa... Mas tens várias opções.

A opção que disseste dá para fazer sim. Mas pelo que vejo ainda estás a aprender, e o projecto é é bastante simples, por isso sugeria talvez uma alternativa mais simples, que seria ter vários arrays para cada estado diferente, por exemplo:
Código: [Seleccione]
int estado_1[] = {0,0,0,0,0,0,0};
int estado_2[] = {1,0,1,0,1,0,1};

E depois é passares cada vector ao código que tu já tens. No fundo é igual à tua opção, so que passas vários conjuntos de bytes em vez de vários conjuntos de bits.
Título: Re: Contadores de minutos millis()
Enviado por: AndréD. em 22 de Setembro de 2013, 01:32
Boas,

Mais uma vez obrigado pela ajuda e pelo teu tempo tarquinio, mas é o seguinte se vou fazer um array para cada estado ainda fica mais "complicado" pois vou ter muitos estados possíveis nas saídas...

Vou continuando a pesquisar o assunto dos Bits, para ver se chego a alguma conclusão :P

Os Melhores Cumprimentos
AndréD.
Título: Re: Contadores de minutos millis()
Enviado por: tarquinio em 22 de Setembro de 2013, 02:13
Fazendo com bits a idéia é a mesma, só que em vez de passares N arrays diferentes tens de passar N conjuntos de bits diferentes. Tambem terás de fazer 1 variável diferente para cada estado, o código não fica mais simples por aí. Vais poupar alguma memória, mas a nivel de código a complexidade é a mesma...

Se quiseres mesmo usar bit masks, tens de aprender a usar os operadores de bits >>,  <<,  &  e |

Por exemplo em vez de escreveres
Código: [Seleccione]
if (a[3] == 1)
fica algo do tipo
Código: [Seleccione]
if (a>>3 & B00000001)

Não estou a dizer que seja mau usar, apenas que a sintaxe é mais estranha até uma pessoa se habituar, e não estou a ver nenhuma forma disso simplificar o código no teu caso..
Título: Re: Contadores de minutos millis()
Enviado por: AndréD. em 22 de Setembro de 2013, 02:19
Boas,

 :o Tinha uma ideia errada sobre o assunto...

Peço desculpa pelo tempo que te fiz perder e que eu perdi também, mas já vi que não vai adiantar de grande coisa e o código vai ficar mais confuso.

De qualquer das formas e mais uma vez obrigado pela ajuda.

Os Melhores Cumprimentos
AndréD.
Título: Re: Contadores de minutos millis()
Enviado por: tarquinio em 22 de Setembro de 2013, 02:24
Mas no meio disto tudo fiquei sem perceber... Isses outputs todos erm para controlar o que mesmo? :P
Pode ser que se arranje uma maneira alternativa mais simples se explicares mais especificamente o que queres fazer ;)
Título: Re: Contadores de minutos millis()
Enviado por: AndréD. em 22 de Setembro de 2013, 02:31
Boas,

Basicamente é para controlar um conjunto de reles...
São 7 outputs, que variam entre ON/OFF (HIGH/LOW) a certas horas do dia, e a certos dias.

Cumprimentos
AndréD.
Título: Re: Contadores de minutos millis()
Enviado por: tarquinio em 22 de Setembro de 2013, 03:16
Bem se usares as bitmasks consegues fazer coisas numa linha do tipo
Código: [Seleccione]
state = state | B10101010;

que activa logo as posições 7, 5, 3 e um de uma vez, por exemplo. E de forma parecida,
Código: [Seleccione]
state = state & B11111000;

que por exemplo desliga as posições 0, 1 e 2. Não sei se este tipo de coisas ajudará...