[Resolvido] Comparar horário RTC e aplicar função

Olá pessoal. Estou com um código de RTC, e já está rodando no meu arduino corretamente.
O que eu queria fazer agora, é comparar o horário e caso seja o horário desejado, aplicar-lhe um if, para acender um led/acionamento de uma carga

// Programa : Data e Hora com DS1307
// Autor : Arduino e Cia

#include "Wire.h"

#define DS1307_ADDRESS 0x68

byte zero = 0x00; 

int led = 8;

void setup()
{
  pinMode(led, OUTPUT);
  Wire.begin();
  Serial.begin(9600);
  //A linha abaixo pode ser retirada apos setar a data e hora
//SelecionaDataeHora(); 
}

void loop()
{
  Mostrarelogio();
  delay(1000);
}

void SelecionaDataeHora()   //Seta a data e a hora do DS1307
{
  byte segundos = 42; //Valores de 0 a 59
  byte minutos = 46; //Valores de 0 a 59
  byte horas = 11; //Valores de 0 a 23
  byte diadasemana = 5; //Valores de 0 a 6 - 0=Domingo, 1 = Segunda, etc.
  byte diadomes = 10; //Valores de 1 a 31
  byte mes = 10; //Valores de 1 a 12
  byte ano = 14; //Valores de 0 a 99
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(zero); //Stop no CI para que o mesmo possa receber os dados

  //As linhas abaixo escrevem no CI os valores de 
  //data e hora que foram colocados nas variaveis acima
  Wire.write(ConverteParaBCD(segundos));
  Wire.write(ConverteParaBCD(minutos));
  Wire.write(ConverteParaBCD(horas));
  Wire.write(ConverteParaBCD(diadasemana));
  Wire.write(ConverteParaBCD(diadomes));
  Wire.write(ConverteParaBCD(mes));
  Wire.write(ConverteParaBCD(ano));
  Wire.write(zero); //Start no CI
  Wire.endTransmission(); 
}

byte ConverteParaBCD(byte val){ //Converte o número de decimal para BCD
  return ( (val/10*16) + (val%10) );
}

byte ConverteparaDecimal(byte val)  { //Converte de BCD para decimal
  return ( (val/16*10) + (val%16) );
}

void Mostrarelogio()
{
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(zero);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_ADDRESS, 7);
  int segundos = ConverteparaDecimal(Wire.read());
  int minutos = ConverteparaDecimal(Wire.read());
  int horas = ConverteparaDecimal(Wire.read() & 0b111111); 
  int diadasemana = ConverteparaDecimal(Wire.read()); 
  int diadomes = ConverteparaDecimal(Wire.read());
  int mes = ConverteparaDecimal(Wire.read());
  int ano = ConverteparaDecimal(Wire.read());
  //Mostra a data no Serial Monitor
  Serial.print("Data: ");
  Serial.print(diadomes);
  Serial.print("/");
  Serial.print(mes);
  Serial.print("/");
  Serial.print(ano);
  Serial.print(" ");
  Serial.print("Hora : ");
  Serial.print(horas);
  Serial.print(":");
  Serial.print(minutos);
  Serial.print(":");
  Serial.print(segundos);
  switch(diadasemana)
    {
      case 0:Serial.println(", Domingo");
      break;
      case 1:Serial.println(", Segunda");
      break;
      case 2:Serial.println(", Terca");
      break;
      case 3:Serial.println(", Quarta");
      break;
      case 4:Serial.println(", Quinta");
      break;
      case 5:Serial.println(", Sexta");
      break;
      case 6:Serial.println(", Sabado");
    }
}

Este é o código. Tentei para minha aplicação o seguinte:

if(horas = "12" && minutos = "10"){
      digitalWrite(led, HIGH);
    }

Coloquei dentro do void Mostrarelogio() abaixo do switch(diadasemana){....}

Aparece-me este erro:

RTC.ino: In function 'void Mostrarelogio()':
RTC:103: error: lvalue required as left operand of assignment

Tentei isto:

if(horas == "12" && minutos == "10"){
      digitalWrite(led, HIGH);
    }

e me apareceu isto:

RTC.ino: In function 'void Mostrarelogio()':
RTC:103: error: ISO C++ forbids comparison between pointer and integer
RTC:103: error: ISO C++ forbids comparison between pointer and integer

Há outra forma de fazer esta comparação?
Obrigado.

if(horas = "12" && minutos = "10"){
digitalWrite(led, HIGH);
}

Isto é uma atribuiçao e nao uma comparação!

if(horas == "12" && minutos == "10"){
digitalWrite(led, HIGH);
}

Isto tenta comparar um inteiro com uma string e obviamente o compilador gera erro!
Nao podes querer comparar batatas com feijões!

Há outra forma de fazer esta comparação?

A biblioteca tem uma estrutura com todos os campos que tu queres.

tmElements_t tm;

Podes actualizar essa estrutura fazendo o RTC.read passando como parametro a estrutura.
Depois podes ler cada campo da estrutura para obteres os dados que queres e posteriormente compara-los.Nota que cada campo é um byte portanto tens de fazer a comparaçao com inteiros e nao como strings

typedef struct {
uint8_t Second;
uint8_t Minute;
uint8_t Hour;
uint8_t Wday; // day of week, sunday is day 1
uint8_t Day;
uint8_t Month;
uint8_t Year; // offset from 1970;
} tmElements_t, TimeElements, *tmElementsPtr_t;

Aqui podes ver todos os campos da estrutura
Senao me engano existe uma biblioteca adicional Time que faz os alarmes como tu queres.

Certo, vou tentar fazer isto.
Seu segundo quote na verdade era para aparecer isto

if(strcmp(horas == "12" && minutos == "10")){
      digitalWrite(led, HIGH);
    }

Mas acho que mesmo assim deverei alterar a estrutura.

Esse pedaco de codigo que colocaste nao faz sentido e nao vai compilar.

Os membros das estruturas nao sao strings... como tal para comparar deves usar 12 em vez de "12"...

Mais uma vez, o teu problema esta me nao saberes as bases mais essenciais de C... Perder um pouco de tempo para ler sobre o essencial ou pesquisar na net sobre as funcoes (strcmp, por exemplo) seria o melhor que tens a fazer se realmente queres aprender algo sobre isto.

Passei a usar isto

// Modificated by SoBraL - mr.sobral@hotmail.com
// Font: http://arduino.cc/forum/index.php/topic,8833.0.html

#include <WProgram.h> //é um recurso para referenciar a biblioteca Wiring
#include <Wire.h> //inclui a biblioteca Wire necessaria para comunicaçao i2c
#include <DS1307.h> //inclui a biblioteca de comandos do DS1307 utilizada neste programa. Necessário baixá-la no link acima
int rtc[6];
int led = 7;

void setup()
{
Serial.begin(9600);
for (int pino = 9; pino <= 13; pino++) { // configura pinos 10 ao 13 como saída
pinMode(pino, OUTPUT); 
digitalWrite(pino, LOW); // desliga pinos 10 ao 13
pinMode(led, OUTPUT);
}

//Esta sequencia de comandos deve ser escrita apenas uma vez, para 
//configurar a hora do Shield RTC 1307. Troque os numeros pela hora atual
/*
RTC.stop();
RTC.set(DS1307_SEC,7); //define o segundo rtc[0]
RTC.set(DS1307_MIN,35); //define o minuto rtc[1]
RTC.set(DS1307_HR,2); //define a hora rtc[2]
RTC.set(DS1307_DOW,6); //define o dia da semana rtc[3]
RTC.set(DS1307_DATE,11); //define o dia rtc[4]
RTC.set(DS1307_MTH,10); //define o mes rtc[5]
RTC.set(DS1307_YR,14); //define o ano rtc[6]
RTC.start();
RTC.get(rtc,true);
*/
}

void MudaDispositivo(byte dispositivo, byte estado, byte hora, byte minuto, byte segundo, int* rtc) {
if ( rtc[2] == hora && rtc[1] == minuto && rtc[0] == segundo )
digitalWrite(dispositivo, estado);
}
void loop()
{

RTC.get(rtc,true);

MudaDispositivo(led, HIGH, 2, 38, 0, rtc);
MudaDispositivo(led, LOW, 2, 40, 0, rtc);
MudaDispositivo(led, HIGH, 3, 0, 0, rtc);
MudaDispositivo(led, LOW, 3, 1, 0, rtc);
MudaDispositivo(led, HIGH, 3, 02, 0, rtc);
MudaDispositivo(led, LOW, 3, 03, 0, rtc);



for(int i=0; i<=6; i++){
Serial.print(rtc[i]);
Serial.print(" ");
}
}

E já está funcionando.

Penso que usar os segundos como referência não é boa ideia, principalmente quando se tem um programa com muitas funções.

Dê uma olhada neste tópico.

http://forum.arduino.cc/index.php?topic=265253.msg1871127#msg1871127

Quais problemas poderiam acarretar? Preferes que eu use como referência o RTC?

Desta forma passou a funcionar, mas caso tenha alguma desvantagem usar assim, me explique por favor.

Além do que já foi feito, gostaria de implementar um status, por exemplo, quando deu horário para ligar:

MudaDispositivo(rele, LOW, 16, 6, 0, rtc);

ele definisse um boolean inserido no setup, como false ou true. Mas não estou conseguindo fazê-lo.

Alguma solução usando a estrutura atual?

Obrigado

O problema de usares os segundos e que em programas muito grandes ou com delays (lembras-te de perguntar acerca se podias usar delay? Ca esta uma razao), pode acontecer que esse pedaco de codigo nao chegue a correr durante o segundo que vai activar o alarme.

Imagina que o programa demora 1.01 segundos a correr... esse codigo corre uma vez as xx:xx:59.9 e quando correr outra vez pode ja ser xx:xx:01. Nesta situacao o alarme nao ia activar ou desactivar.

unsigned char led_status = 0;

void MudaDispositivo(byte dispositivo, byte estado, byte hora, byte minuto, byte segundo, int* rtc) {
if ( rtc[2] == hora && rtc[1] == minuto && rtc[0] == segundo )
digitalWrite(dispositivo, estado);
led_status = estado; 
}

referes-te a isto?

bubulindo:

unsigned char led_status = 0;

void MudaDispositivo(byte dispositivo, byte estado, byte hora, byte minuto, byte segundo, int* rtc) {
if ( rtc[2] == hora && rtc[1] == minuto && rtc[0] == segundo )
digitalWrite(dispositivo, estado);
led_status = estado;
}



referes-te a isto?

Não, este estado refere-se ao estado de led.
Estava pensando em usar um boolean statusLuz = false;
e fazer que quando o rtc fosse usado, ele passasse a ser true. Pois assim, quando estiver em função do RTC, os sensores LDR não atuam, e quando chegar no estado LOW, que encerra o uso do RTC, statusLuz passa a ser false novamente, e o estado do led passa a ser controlado por sensor.

Algo como:

MudaDispositivo(led, LOW, 2, 0, 0, rtc){ //Quando entras no RTC deve alterar para true (Quando der 2:00:00 da manhã, ele //desligue o led independentemente do valor de sensores ldr)
statusLuz = true;
}

MudaDispositivo(led, HIGH, 4, 21, 0, rtc){ //Quando sai do RTC deve alterar para false (Quando der 3:00:00 da manhã, ele //passe a controlar o led através do valor de sensores ldr)
statusLuz = false;
}

if(ldr<100 && statusLuz == 0){
    digitalWrite(led, HIGH);
  }
  if(ldr>100 && statusLuz == 0){
    digitalWrite(led, LOW);
  }

Obviamente que este:

MudaDispositivo(led, LOW, 2, 0, 0, rtc){
statusLuz = true;
}

é impossível, apenas foi feito para exemplificar meu pensamento.

Desculpa... estas a gozar?

Se meteres o codigo todo certamente que o conselho dado vai estar correcto... se estas a falar duma coisa e pedes conselhos sobre algo que ninguem sabe que estas a fazer esperas o que??

Se colocares esse codigo a funcionar, prepara-te para teres uma discoteca em casa... ou lampadas fundidas. :] Como tu estas num modo Top Secret, fica aqui o termo que deves procurar para entender isto da discoteca:

Histerese

Boa sorte.

Vou explicar melhor:

A ideia inicial do tópico era saber como eu poderia usar o RTC para ligar cargas em determinados horários.

O que estou fazendo agora, são pra iluminação externa. Quando a luminosidade é baixa, ativa o relé, quando for alta, desliga relé.

Quando der 2:00, desliga relé independente da luminosidade. E quando der 5:00 liga relé, voltando a ser dependente da luminosidade.

Queria ver como fazer isso sem utilizar de uma chave geral pra ativar e desativar as chaves secundárias (relés das lâmpadas).

Desculpe se te fiz mal, mas saiba que tenho muito respeito pelo senhor, e que me ajudaste muito em menos de um mês.

Como já disse, um dia vou ter tempo para estudar, por enquanto estou muito no básico e aprendendo lentamente.

Tudo muito bem que queiras fazer algo diferente... mas toma cuidado em explicar o que pretendes fazer e acima de tudo mostrar o que fizeste e onde esta o problema.
Tu pediste para guardar o estado dum bit e foi isso que te foi mostrado. Se queres fazer algo completamente diferente nao esperes que as pessoas adivinhem o que isso e...

Ja experimentaste o codigo que colocaste aqui? O controlo de tempo e por lampada ou e para todas?

Ja pesquisaste por histerese??

bubulindo:
Ja experimentaste o codigo que colocaste aqui? O controlo de tempo e por lampada ou e para todas?

Já testei o código, porém não funcionou. Ou ele não respeita o horário (apenas a luminosidade), ou só respeita o horário e não a luminosidade.

O controle será para todas as lâmpadas. Serão 4 relés, um para cada lâmpada, que serão ativadas com a mesma luminosidade, desativadas no mesmo horário (2:00), e ativadas novamente as 5:00.

Como disse, poderia eu utilizar de uma chave geral, que funcionasse apenas com o RTC, e os demais, com os relés, funcionando com a luminosidade.

Qual deles acha mais recomendado?
Pegar uma chave geral que desliga às 2 e liga as 5 ou descartar a chave geral, fazendo que ao desligar às 2, muda o status pra 1, para que não caia nesta condição:

if(ldr<100 && statusLuz == 0){
    digitalWrite(led, HIGH);
  }

bubulindo:
Ja pesquisaste por histerese??

Pesquisei sim, vi um exemplo onde um termostato pode acionar um aquecedor somente quando a temperatura for inferior a A graus e só desligará quando for superior a B graus.
Basicamente, filtrar sinais fazendo com que a saída deste reaja de maneira retardada à entrada do sinal.

Ele pega um pouco da saída e joga na entrada.
Uma tensão entra no positivo e outra que quero comparar, entra na negativa. Quando aumento o valor da tensão no negativo, a tensão que entra no positivo é diferente, portanto, ele compara a tensão sempre com valores diferentes, nunca ficando instável entre 0 e 1.

Correto?

Neste pedaco:

MudaDispositivo(led, LOW, 2, 0, 0, rtc){ //Quando entras no RTC deve alterar para true (Quando der 2:00:00 da manhã, ele //desligue o led independentemente do valor de sensores ldr)
statusLuz = true;
}

Tens de ligar a luz com o digitalWrite... e no outro desligar juntamente com o statusLuz... so assim e que o programa funciona.
Se a luz foi ligada com o RTC entre as duas e as cinco, nada a desliga. Se nao esta ligada, a luz fica dependente da LDR.

A histerese serve para evitar que a luz ande a ligar e desligar em intervalos curtos... conviria tambem pensares um pouco no que vai acontecer as luzes quando uma nuvem passar por cima da LDR.

Certo, portanto, creio que essas alterações são necessárias:

//unsigned char status_Luz = 0;

void MudaDispositivo(byte hora, byte minuto, byte segundo, int* rtc) { //RETIREI O BYTE DISPOSITIVO E BYTE ESTADO
  (rtc[2] == hora && rtc[1] == minuto && rtc[0] == segundo);
}
void loop()
{
  int valorLDR = analogRead(0);
  ldr = (valorLDR);

  Serial.println(ldr);
  delay(500);


  RTC.get(rtc,true);

  MudaDispositivo(14, 20, 0, rtc);
  {
    statusLuz = true; //AQUI PASSA A SER ATIVADO POR DIGITALWRITE JUNTAMENTE COM O STATUSLUZ
    digitalWrite(led, LOW);
  }
  
  MudaDispositivo(14, 25, 0, rtc);
  {
    statusLuz = false;
    digitalWrite(led, HIGH);
  }



  if(ldr<100 && statusLuz == 0){
    digitalWrite(led, HIGH);
  }

  if(ldr>100 && statusLuz == 0){
    digitalWrite(led, LOW);
  }

Apesar de não ter acusado erro, sei que isso não está certo:

  MudaDispositivo(14, 20, 0, rtc);
  {
    statusLuz = true; //AQUI PASSA A SER ATIVADO POR DIGITALWRITE JUNTAMENTE COM O STATUSLUZ
    digitalWrite(led, LOW);
  }

Não tem como converter o MudaDispositivo(14, 20, 0, rtc) para bool. Estou confuso neste quesito. Devo entrar nesta condição após receber este horário, mas como?

bubulindo:
A histerese serve para evitar que a luz ande a ligar e desligar em intervalos curtos... conviria tambem pensares um pouco no que vai acontecer as luzes quando uma nuvem passar por cima da LDR.

Neste caso, a intenção é que a luz acenda do mesmo jeito. Se está escuro, acenda, se não, apague. Para economia é que estou usando o RTC, pois normalmente, se acendem as lâmpadas a noite e apagam o primeiro que acordar, rs...

Minhas alterações estão corretas? Retirei algumas coisas para fazer como me disse, acionar através do digitalWrite, sendo desnecessário o uso do estado e dispositivo.

Não sei que linguagem é essa... Mas não é C. O pensamento não está errado, mas a sintaxe está toda errada.

Tens ; a mais, estás a tentar definir funções dentro de funções ou estás a esquecer-te de if's.

Eu sai há pouco do trabalho e estou no iPad... Amanhã, se alguém não fizer primeiro, corrijo isso.

Aquela palavra void a frente das funções quer dizer algo e pode ser trocada por uma multitude de palavras como char, int, boolean, unsigned log, float, double, char* entre outras.... Tenta ver o que significa isso.

Ah e explica-me o que fazes com o valor analogico lido... Os parentesis não são uma função.

Tentei resolver o código por conta, não foi 100%, mas acho que ficou mais próximo de ser corrijido:

int MudaDispositivo(byte hora, byte minuto, byte segundo, int* rtc) { //Alterei aqui para int
  (rtc[2] == hora && rtc[1] == minuto && rtc[0] == segundo);
}

void loop()
{
  int valorLDR = analogRead(0);
  ldr = (valorLDR);

  Serial.println(ldr);
  delay(500);
 
  RTC.get(rtc,true);


  if(MudaDispositivo(23, 54, 0, rtc)) //sendo Int, pensei que funcionaria esta condição, mas já não funciona, pois nem mesmo o Serial.print aparece
  {
    statusRTC = true;
    digitalWrite(led, LOW);
    Serial.print("Horário ativo"); //Confirma que entrou no horário, sendo assim, mudou o statusRTC e do led
    delay(500);
  }
  
  if(MudaDispositivo(23, 55, 0, rtc))
  {
    statusRTC = false;
    digitalWrite(led, HIGH);
    Serial.print("Horário inativo");
    delay(500);
  }


  if(ldr < 100 && statusRTC == 0){
    digitalWrite(led, HIGH);
    Serial.println("Baixa luminosidade");
    delay(500);
  }

  if(ldr > 100 && statusRTC == 0){
    digitalWrite(led, LOW);
    Serial.println("Alta luminosidade");
    delay(500);
  }

Alterei statusLuz para statusRTC, pois condiz melhor, já que é o RTC que vai alterar o status, por exemplo, se entrar no horário tal, muda statusRTC, informando que o RTC entrou em ação, e quando chegar no horário final, altera novamente. É a mesma coisa, apenas com o nome alterado.

Quanto ao valor analógico lido, estás a falar disto:

int valorLDR = analogRead(0);
  ldr = (valorLDR);

Pego o valor lido para aplicar uma condição, que são as duas últimas condições do código acima.

Ok...

A meio de ver esse pedaco de codigo desisti porque isso esta uma salgalhada e nao se percebe sequer o que queres.

Tu queres que a luz seja controlada por uma LDR e que entre determinadas horas a LDR nao funcione?

Ou queres controlar as horas em que a LDR funciona?

Olhando aos ultimos pedacos de codigo, tu nem tao pouco dominas o conceito de funcao e neste momento estas a atirar variaveis e simbolos na esperanca que algo funcione.
Isto nao funciona assim...

Primeiro defines o que queres fazer na sua totalidade.
Depois divides tudo isso em pedacos pequenos.
Fazes um pedaco de cada vez e separadamente.
Comecas a adicionar um pedaco ao outro de cada vez ate teres tudo junto.

Por exemplo:

Eu quero um sistema com 5 nos interligados a um no "master" por radio com nRF24L01. O no "master" vai estar ligado a internet e vai enviar dados para um servidor. O no master vai ter um sensor de pressao.
2 dos nos vao ter sensores DHT11 para medir humidade e temperatura.
2 dos nos vao ter sensores 18B20 para medir so temperatura.
1 dos nos vai medir luminosidade e tambem os impulsos do contador de electricidade.

Com esta definicao eu sei que tenho de fazer os seguintes passos (sem nenhuma ordem em especial):

  • comunicar entre dois dispositivos com o nRF24L01.
  • aumentar a rede de 2 para 6 dispositivos em rede.
  • enviar dados pela internet para um servidor.
  • ver a influencia do interface com a internet e com o radio no "master".
  • utilizar o sensor DHT11.
  • utilizar o sensor barometrico.
  • utilizar o sensor 18B20.
  • testar o interface da LDR.
  • medir os pulsos do contador de electricidade com LDR ou com um IR receptor.

Depois adiciono um pedaco ao outro ate ter o sistema completo que propus no inicio.

quando olhas para o codigo que tens de fazer, tens de pensar da mesma forma... mas a uma escala menor. Ou seja, tens de saber as horas.
Tens de saber se a hora actual esta no horario ON ou horario OFF.
Se estiver ON, fazes o que tens a fazer, etc...

Neste momento nao fazes nada disto. :confused: para um pouco, define exactamente o que queres e vais ver que sera mais simples. E, mais importante ainda, estuda C... porque sabes muito pouco!!!

Tens razão. Devido a longa espera que vou ter para a chegada dos componentes, não custa nada dar uma pausa ao projeto e estudar um pouco rs...

Enfim, quanto a organização do projeto, será algo assim:

Um arduino uno deverá medir a luminosidade e usar funções de tempo com RTC:

  • o LDR deve obter valores de luminosidade para então, entrar nas condições das luzes (acesso ou apagado)
  • o RTC, deverá em determinado horário (horário inicial), desativar o LDR (apenas mudando o status para 'statusRTC = true' será o suficiente) e no determinado horário final, reativar o LDR (mudando 'statusRTC = false')

É só isso mesmo, pois o restante do projeto não está ligado a ele por comunicação, este é independente.

Quanto ao estudo, escolhi estas fontes:

http://goo.gl/iv3jgP (PDF)

http://www.mtm.ufsc.br/~azeredo/cursoC/aulas-main.html

http://www.ic.unicamp.br/~mc102/introducao-ao-curso-de-c.html

http://www.unipacto.com.br/ (necessita cadastro)

Estou pensando em ver por exemplo:

Introdução - Vejo a introdução de todos os links
Variáveis, Constantes, Operadores e Expressões - Vejo de todos os links
...
Dessa forma, qualquer coisa que um omitiu, posso saber através do outro..

Alguma outra sugestão?

E a lampada fica em que estado???