Časove hodiny RTC + GSM

Wiring, C++, C, Java, ...
Pravidla fóra
Toto subfórum slouží k řešení obecných otázek kolem programování (konstrukce, knihovny, alokace paměti, ...)
Odpovědět
ChCP
Příspěvky: 3
Registrován: 27 srp 2017, 18:11

Časove hodiny RTC + GSM

Příspěvek od ChCP » 27 srp 2017, 19:33

Dobrý deň,

najprv uvediem aký je zámer. Pomocou Arduino Mega 2560 , DS1307 RTC a modulu SIM900 urobiť časove hodiny ktoré spínajú relé. Ich funkcia by mala byt nasledovná:
- spínať relé podľa času s RTC
- pomocou zavolania zapnúť a vypnúť relé
- raz za mesiac nastaviť RTC čas s GSM modulu
Prikladám aj to čo som zatiaľ napísal. Viem, že to nie je krásne napísané a asi niekto by to napísal lepšie, ale takto je to pre mňa zrozumiteľné a verím že bude funkčné . Pri písaní kódu som ale narazil na problém , ktorý sa mi nedari vyriešiť a preto spolieham na rady skúsenejších.
Ak pustím samotný časovač s čítaním RTC, časovač funguje podľa mojich predstáv a spína relé ako ma na sekundu presne. V tom momente ako som pridal podmienku na čakanie hovoru prestal cely časovač fungovať korektne. Aj na výpise v terminály je vidieť odozva každých <5 sek. Musel som s podmienok času vymazať sekundy. Ak sa to netrafilo do sekúnd tak sa stav relé nezmenil (čo je logické). Zmena stavu pomocou zavolania funguje korektne. Ako dosiahnuť aby čas išiel ako ma, aby som ohol spínať na sekundy?
Mám ešte ďalší problém, ale to je ďalšia časť kde po načítaní času s GSM pomocou AT+CCLK? spôsob ako s toho dostať formát, ktorý by bol použiteľný do príkazu RTC.adjust(DateTime(__DATE__, __TIME__)).
A ešte mám jednu zaujímavosť. Ak k modulu DS1307 pripojím GND pin tak prestane fungovať.

Ďakujem!
Přílohy
CAS_CALL.ino
(5.71 KiB) Staženo 304 x

zbysek
Site Admin
Příspěvky: 125
Registrován: 22 úno 2017, 15:18

Re: Časove hodiny RTC + GSM

Příspěvek od zbysek » 27 srp 2017, 20:46

Dobrý den, zkusím nadhodit pár myšlenek, třeba některé budou užitečné :)

Nesprávné časování
Problém
Jestli dobře chápu popis problému, tak část, která kód zdržuje je:

Kód: Vybrat vše

if(sim900.isCallActive(telCislo)) {
Zkuste napsat samostatný program, ve kterém vypíšete přes sériovou linku čas (millis()) před a po zavolání funkce sim900.isCallActive(telCislo). Uvidíte, jak dlouho provádění této funkce přibližně trvá.
Podle mě totiž tato funkce na delší dobu "zdrží" procesor. Proto ten výpadek cca 5s.

Řešení 1
Napadají mě dvě řešení. První z nich je upravit kód tak, aby mu toto zdržení nevadilo. Nevím, jestli je kód kritický natolik, že 5s zdržení vadí. Pokud ne, mohlo by toto být řešení.

Problém je asi způsob testování času:

Kód: Vybrat vše

if (now.hour() == 16 && now.minute() == 30 && now.dayOfTheWeek() == 1  )
Zde je problém v tom, že když se program netrefí do konkrétní minuty, nedojde k sepnutí/vypnutí.
Navrhuji si čas převést něco na způsob zjednodušeného timestamp. To bude udávat počet vteřin, které uběhly od začátku dne (00:00) ve vteřinách.

Kód: Vybrat vše

unsigned long time = now.hour() * 60 * 60 +  now.minute() * 60;
pokud byste chtěl ještě přidat vteřiny, můžete řádek upravit na

Kód: Vybrat vše

unsigned long time = now.hour() * 60 * 60 +  now.minute() * 60 + now.second();
Pokud dobře koukám do kódu, tak každý den v 16:30 relé zapínáte a 8:30 vypínáte.
Nemusíte mít podmínku pro každý den, ale jen pro konkrétní časy - slovy: "když je více než 16:30 a je relé vypnuto, zapni ho" a "když je více než 8:30 a je relé zapnuto, vypni ho". Když to přepíšeme do kódu, tak:

Kód: Vybrat vše

unsigned long time8_30 = 8 * 60 * 60 + 30 * 60;
unsigned long time16_30 = 16 * 60 * 60 + 30 * 60;

if(time >= time16_30 && StatusRelay == 0){
	Serial.print(" Start ");
	StatusRelay = 1;
}
else if(time >= time8_30 && StatusRelay == 1){
	Serial.print(" Stop ");
	StatusRelay = 0; 
}
To by mělo vyřešit problém způsobený zpožděním.

Řešení 2
Druhou možností, která mě napadá je využít přerušení. Jestli se nepletu, tak některé RTC moduly mají vyhrazený pin, na kterém každou vteřinu vyšlou pulz. Na tento pulz by mohlo Arduino reagovat pomocí přerušení a zkontrolovat aktuální čas. Do tohoto řešení bych se ale nepouštěl, pokud bude Řešení 1 dostačující :)

Převod formátu data
Na převod dat z formátu do formátu vás odkáži na dvě funkce sscanf (http://www.cplusplus.com/reference/cstdio/sscanf/) a sprintf(http://www.cplusplus.com/reference/cstdio/sprintf/).
Pomocí sscanf načtete data z řetězce získaného z AT+CCLK? do proměnných a ty pak dosadíte do správného tvaru funkcí sprintf.

ChCP
Příspěvky: 3
Registrován: 27 srp 2017, 18:11

Re: Časove hodiny RTC + GSM

Příspěvek od ChCP » 27 srp 2017, 22:24

Dobrý deň,

ďakujem za myšlienky a rozšírenie obzoru!
Áno, v tejto podmienke sa to asi niekde zastaví/spomalí.

Kód: Vybrat vše

if(sim900.isCallActive(telCislo)) {
Nie že by 5 sekúnd bol problém, ale zaujíma ma to z princípu prečo to je tak.
Kvôli tomu som upravil kód tak, aby sekundy nebral do úvahy. Nie som žiaden programátor, ale skúsim zmerať ten čas.

Dôvodom prečo sú všade aj dni ten, že 4 krát sa to spúšťa o 16.30 a vypne o 8.30, ale 1 krat sa to zapne 16.30 a vypne o 8.30 avšak o 2 dni (beží to kontinuálne od piatka poobedia až do pondelka rana). Ak by to bolo pravidelne tiež by som to riešil len jednou podmienkou. Skúsim implementovať funkciu

Kód: Vybrat vše

unsigned long time = now.hour() * 60 * 60 +  now.minute() * 60 + now.second();
či sa niečo zmení.

Ďakujem za funkcie. Skúsim ich použiť, ale zatiaľ som nedostal z AT+CCLK? výstup do premennej ktorú by som rozložil.

zbysek
Site Admin
Příspěvky: 125
Registrován: 22 úno 2017, 15:18

Re: Časove hodiny RTC + GSM

Příspěvek od zbysek » 28 srp 2017, 09:18

Dobrý den,
provedení různých funkcí trvá různě dlouho. Záleží na tom, jak je funkce komplexní a jak moc časově náročné věci vykonává. Když třeba vytvoříme funkci

Kód: Vybrat vše

function dlouhaFunkce(){
	delay(5000);
}
tak bude trvat cca 5s a to vlastně nic nedělá.

V sim900.isCallActive(telCislo) je tedy asi něco, co trvá dlouho (komunikace s modulem, ...). Jistý si ale úplně nejsem.

To měření času může být třeba takovéto:

Kód: Vybrat vše

unsigned long before, after;
//zde přidejte vložení knihoven apod.

void setup(){
	before = millis();
	sim900.isCallActive(telCislo);
	after = millis();
	
	Serial.begin(9600);
	Serial.print("Before: ");
	Serial.println(before);
	Serial.print("After: ");
	Serial.println(after);
	Serial.print("Duration: ");
	Serial.println(after - before);
}
void loop(){}
Pardon, toho přeskočení dvou dní jsem si nevšiml. Můžete to ale udělat podobně, jen do time přidáte ještě dny.

Kód: Vybrat vše

unsigned long time = now.dayOfTheWeek() * 24 * 60 * 60 + now. now.hour() * 60 * 60 +  now.minute() * 60 + now.second();
Time je potom počet vteřin od začátku týdne.

Podmínku sestavíte tak, že si vytvoříte timestamp pro jednotlivé časy - třeba pondělí 8:30, pondělí 16:30 atd. A budete je testovat OD NEJVĚTŠÍHO (jinak by podmínka uspěla vždy při pondělním timestamp, i když by byl pátek apod.). Tedy:

Kód: Vybrat vše

if(time > patek16_30 && StatusRelay == 0){
	StatusRelay = 1;
} 
else if(time > patek8_30 && StatusRelay == 1){
	StatusRelay = 0;
}
else if(time > ctvrtek16_30 && StatusRelay == 0){...}
.
.
.
K tomu AT+CCLK? - podařilo se vám získat z modulu nějaký čas a jen nevíte, jak se tento čas uloží do proměnné, nebo jen víte, že existuje příkaz AT+CCLK? a nevíte, jak ho použít?

ChCP
Příspěvky: 3
Registrován: 27 srp 2017, 18:11

Re: Časove hodiny RTC + GSM

Příspěvek od ChCP » 29 srp 2017, 15:10

Dobrý deň,

ešte raz ďakujem za snahu a nasmerovanie.
Mali ste absolútnu pravdu. Váš program vypísal trvanie funkcie presne 5145ms.
Potom som pozeral do súboru sim900.h kde je hneď na začiatku toto:

Kód: Vybrat vše

#ifndef __SIM900_H__
#define __SIM900_H__

#include <SoftwareSerial.h>
#include <Arduino.h>

#define DEFAULT_TIMEOUT     		 5   //seconds
#define DEFAULT_INTERCHAR_TIMEOUT 1500   //miliseconds

enum DataType {
    CMD     = 0,
    DATA    = 1,
};
T.j. dôvod prečo to ide každých 5sek. je jasný.

S tým AT+CCLK? som len v začiatkoch skúmania. Pri tom ako som preveroval knižnice tak som narazil na súbor GPRS_Shield_Arduino.cpp a tam som našiel funkciu GPRS::getDateTime.

Kód: Vybrat vše

bool GPRS::getDateTime(char *buffer)
{
	//If it doesn't work may be for two reasons:
	//		1. Your carrier doesn't give that information
	//		2. You have to configurate the SIM900 IC.
	//			- First with SIM900_Serial_Debug example try this AT command: AT+CLTS?
	//			- If response is 0, then it is disabled.
	//			- Enable it by: AT+CLTS=1
	//			- Now you have to save this config to EEPROM memory of SIM900 IC by: AT&W
	//			- Now, you have to power down and power up again the SIM900 
	//			- Try now again: AT+CCLK?
	//			- It should work
	
	//AT+CCLK?						--> 8 + CR = 9
	//+CCLK: "14/11/13,21:14:41+04"	--> CRLF + 29+ CRLF = 33
	//								
	//OK							--> CRLF + 2 + CRLF =  6

    byte i = 0;
    char gprsBuffer[50];
    char *p,*s;
	sim900_flush_serial();
    sim900_send_cmd("AT+CCLK?\r");
    sim900_clean_buffer(gprsBuffer,50);
    sim900_read_buffer(gprsBuffer,50,DEFAULT_TIMEOUT);
    if(NULL != ( s = strstr(gprsBuffer,"+CCLK:"))) {
        s = strstr((char *)(s),"\"");
        s = s + 1;  //We are in the first phone number character 
        p = strstr((char *)(s),"\""); //p is last character """
        if (NULL != s) {
            i = 0;
            while (s < p) {
              buffer[i++] = *(s++);
            }
            buffer[i] = '\0';            
        }
        return true;
    }  
    return false;
}
Asi ju skúsim použiť.

Odpovědět

Kdo je online

Uživatelé prohlížející si toto fórum: Žádní registrovaní uživatelé a 2 hosti