diff --git a/arduino_proto_threads/tp_serre/pt.h b/arduino_proto_threads/tp_serre/pt.h new file mode 100644 index 0000000..ef90636 --- /dev/null +++ b/arduino_proto_threads/tp_serre/pt.h @@ -0,0 +1,76 @@ +#ifndef __PT_H__ +#define __PT_H__ + +typedef unsigned short lc_t; +#define LC_INIT(s) s = 0; // LC_INIT +#define LC_RESUME(s) switch(s) { case 0: // LC_RESUME +#define LC_SET(s) s = __LINE__; case __LINE__: // LC_SET line +#define LC_END(s) } // LC_END + +struct pt { lc_t lc; }; + +#define PT_WAITING 0 +#define PT_YIELDED 1 +#define PT_EXITED 2 +#define PT_ENDED 3 +#define PT_INIT(pt) LC_INIT((pt)->lc) // INIT +#define PT_THREAD(name_args) char name_args // THREAD +#define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1; LC_RESUME((pt)->lc) // BEGIN +#define PT_END(pt) LC_END((pt)->lc); \ + PT_YIELD_FLAG = 0; \ + PT_INIT(pt); return PT_ENDED; } // END +#define PT_WAIT_UNTIL(pt, condition) \ + do { \ + LC_SET((pt)->lc); \ + if(!(condition)) { \ + return PT_WAITING; \ + } \ + } while(0) // WAIT_UNTIL +#define PT_WAIT_WHILE(pt, cond) \ + PT_WAIT_UNTIL((pt), !(cond)) // WAIT_WHILE +#define PT_WAIT_THREAD(pt, thread) \ + PT_WAIT_WHILE((pt), PT_SCHEDULE(thread)) // WAIT_THREAD +#define PT_SPAWN(pt, child, thread) \ + do { \ + PT_INIT((child)); \ + PT_WAIT_THREAD((pt), (thread)); \ + } while(0) // SPAWN +#define PT_RESTART(pt) \ + do { \ + PT_INIT(pt); \ + return PT_WAITING; \ + } while(0) // RESTART +#define PT_EXIT(pt) \ + do { \ + PT_INIT(pt); \ + return PT_EXITED; \ + } while(0) // EXIT +#define PT_SCHEDULE(f) ((f) < PT_EXITED) // SCHEDULE +#define PT_YIELD(pt) \ + do { \ + PT_YIELD_FLAG = 0; \ + LC_SET((pt)->lc); \ + if(PT_YIELD_FLAG == 0) { \ + return PT_YIELDED; \ + } \ + } while(0) // YIELD +#define PT_YIELD_UNTIL(pt, cond) \ + do { \ + PT_YIELD_FLAG = 0; \ + LC_SET((pt)->lc); \ + if((PT_YIELD_FLAG == 0) || !(cond)) { \ + return PT_YIELDED; \ + } \ + } while(0) // YIELD_UNTIL +// checked for n calls in a thread : seems OK +#define PT_DELAY(pt, ms) \ + do { \ + static unsigned long _PTTTL_ ; \ + _PTTTL_ = millis() + (unsigned int)(ms); \ + PT_WAIT_UNTIL((pt), (millis() > _PTTTL_)); \ + } while(0) // DELAY +#define PT_SYNC(pt, mark, ms) \ + do { \ + PT_WAIT_UNTIL((pt), (millis() - (mark) > (ms) )); \ + } while(0) // SYNC +#endif /* __PT_H__ */ diff --git a/arduino_proto_threads/tp_serre/serialTrace.h b/arduino_proto_threads/tp_serre/serialTrace.h new file mode 100644 index 0000000..6211e67 --- /dev/null +++ b/arduino_proto_threads/tp_serre/serialTrace.h @@ -0,0 +1,103 @@ +/*------------------------------------------------------------------*/ +/* Projet: Dev Tools */ +/* File : serialTrace.h */ +/* Author: user@W500 08/28/20 */ +/*------------------------------------------------------------------*/ +// RCS CI/CO : Cx v v, terminate log : CcCc, view log : Cx v l +// TODO: all this should be in a class or a singleton class +// TODO: strings should be in Flash 32kb code +// #include + +#ifndef __SERIALTRACE_H__ +#define __SERIALTRACE_H__ +extern char *__brkval; +unsigned long freeMemory() { + char top; + return &top - (__brkval ? __brkval : __malloc_heap_start); +} + +void retard(unsigned long ms, int mini) { +#ifndef TEST + delay(ms); +#else + delay(mini); +#endif +} +// functions used for I/O using serial monitor +#ifndef IHM // if IHM undefined then just empty functions. +// So users don't need to change code, just define/undefine IHM. +// A bit of a waste, but main purpose is testing. +bool ttyAskN ( String prompt ) {} +bool ttyAskY ( String prompt ) {} +char ttyGetChar ( String prompt ) {} +int ttyGetInt ( String prompt ) {} +void ttyPutInt ( String prompt, int num ) {} +void ttyPutMem ( ) {} +void ttyPutStr ( String txt ) {} +void ttyPutUin ( String prompt, unsigned int num ) {} +void ttyPutFloat ( String prompt, float num ) {} +void ttySetIHM ( long baud ) {} +void ttyWipe ( short lines ) {} + +#else +void ttySetIHM(long baud) { + Serial.begin(baud); // WIP check if baud in correct values ? + for (int i=0;i<10;i++) Serial.print("\n") ; +} +void ttyPutStr(String txt) { Serial.println(txt); +} +void ttyPutMem() { + char buf[32]; + unsigned long octets = freeMemory(); + int k = octets / 1024 ; int o = octets % 1024; + sprintf(buf, "SRAM: %dKo%d free",k,o); + Serial.println (buf) ; +} +void ttyPutInt(String prompt, int num ) { + char buf[64]; + sprintf(buf, "%s %d", prompt.c_str(), num ) ; + Serial.println (buf) ; +} +void ttyPutUin(String prompt, unsigned int num ) { + char buf[64]; + sprintf(buf, "%s %d", prompt.c_str(), num ) ; + Serial.println(buf) ; +} +int ttyGetInt(String prompt) { + Serial.println(prompt); + while (Serial.available()==0) {} //Wait for user input + String val=Serial.readString(); + return val.toInt(); +} +void ttyPutFloat ( String prompt, float num ) { + Serial.print(prompt); + Serial.println (num) ; + } +void ttyPutFloatRound ( String prompt, float num ) { + char buf[64]; + sprintf(buf, "%s %d", prompt.c_str(), int(num) ) ; + Serial.println (buf) ; + } +char ttyGetChar(String prompt) { + Serial.println(prompt); + while (Serial.available()==0) {} //Wait for user input + return Serial.read(); +} +bool ttyAskY(String prompt){ + byte R = 223 & (byte)ttyGetChar(prompt); + if ('Y' == R ) return true; + else return false ; +} +bool ttyAskN(String prompt){ + byte R = 223 & (byte)ttyGetChar(prompt); + if ('N' == R ) return true; + return false ; +} +void ttyWipe (short lines) { +//const short ESC=27 ; KO in Arduino serial monitor, works with others tty +// Serial.write(ESC); Serial.print("[2J"); // cls +// Serial.write(ESC); Serial.print("[H"); // cursor to home + while (lines--) Serial.print("\n") ; // somehow overkill ! +} +#endif // IHM +#endif // __SERIALTRACE_H__ diff --git a/arduino_proto_threads/tp_serre/tp_serre.ino b/arduino_proto_threads/tp_serre/tp_serre.ino new file mode 100644 index 0000000..3b786c9 --- /dev/null +++ b/arduino_proto_threads/tp_serre/tp_serre.ino @@ -0,0 +1,158 @@ +/* Si la température est < 15°C, un cycle de chauffe. +Si la température > 25 °C, le ventilateur tourne en proportion. +Si l’Humidité < 50%, un cycle arrosage. +Si l’Humidité >70 %, le ventilateur tourne en proportion +*/ +#define JAUNE 13 // +#define BLEU 12 // +#define ROUGE 11 // +#define VERTE 9 // +#define APVCC 2 // +#define APGND 6 // +#define AP_H A0 // +#define AP_T A1 // + +#define IHM +#include "serialTrace.h" // infos / trace to serial monitor +#include "pt.h" +static struct pt ptT, ptH, ptV, ptC, ptE, ptN, ptA; // proto threads +int temp=0; int humi=0; +bool alarme = false; int nb_cycles = 0; +void log_acqui(char * msg, int va); +void ledPWM(int led, int ratio) { + int val=constrain(ratio,0,254); // limit to values [0..254] + analogWrite(led, val); +} +int acquis(int broche, int vmin, int vmax) { +// WIP + int val ; + val=analogRead(broche); // 1024 pts, 0 < U < 5V ==> 0 < val < 1023 + return map (val, 0, 1023, vmin, vmax ) ; +} +static int ptTemp(struct pt *pt, int repit) { +static unsigned long ttl = 0; + PT_BEGIN(pt); + while(1) { + ttl = millis() + repit ; + PT_WAIT_UNTIL(pt, millis() > ttl); + temp = acquis(AP_T, 0, 50); // pour ptHumi on a : humi = acquis(AP_T, 20, 80); + ttyPutInt ("temp: ", temp); + } + PT_END(pt); +} +static int ptHumi(struct pt *pt, int repit) { +static unsigned long ttl = 0; + PT_BEGIN(pt); + while(1) { + ttl = millis() + repit; + PT_WAIT_UNTIL(pt, millis() > ttl); + humi = acquis(AP_H, 20, 80); + ttyPutInt ("humi: ",humi); + } + PT_END(pt); +} +static int ptAlarme (struct pt *pt, int duree){ + static unsigned long ttl; + PT_BEGIN(pt); + while (alarme) { + ttl = millis() + duree; + PT_WAIT_UNTIL(pt, millis() > ttl); + digitalWrite(VERTE, !digitalRead(VERTE)); + } + PT_END(pt); +} +static int ptNiveau(struct pt *pt){ + static int nb_old = 0; int ratio; + PT_BEGIN(pt); + while (!alarme) { + nb_old = nb_cycles; + ratio = map(nb_cycles, 0, 100, 254, 0); + ledPWM(VERTE, ratio); + PT_WAIT_UNTIL(pt, nb_cycles > nb_old ); // attente nouvel arrosage + } + PT_END(pt); +} +static int ptChauffe(struct pt *pt, int actif, int inactif ){ +static unsigned long ttl = 0; + PT_BEGIN(pt); + while (1) { + PT_WAIT_UNTIL(pt, temp < 15); + digitalWrite(JAUNE, HIGH); + ttl = millis() + actif ; + PT_WAIT_UNTIL (pt, millis() > ttl); + digitalWrite(JAUNE, LOW); + ttl = millis() + inactif ; + PT_WAIT_UNTIL (pt, millis() > ttl); + } + PT_END(pt); +} // Chauffe +static int ptEau(struct pt *pt, int actif, int inactif ) { +static unsigned long ttl = 0; +PT_BEGIN(pt); + while (!alarme) { + PT_WAIT_UNTIL(pt, humi < 50); + digitalWrite(BLEU, HIGH); + ttl = millis() + actif ; + nb_cycles++; + alarme = ( nb_cycles > 100); + PT_WAIT_UNTIL (pt, millis() > ttl); + digitalWrite(BLEU, LOW); + ttl = millis() + inactif ; + PT_WAIT_UNTIL (pt, millis() > ttl); + } + PT_END(pt); +} // Eau +static int ptVenti(struct pt *pt) { + static int temp_old = 0, humi_old = 0; int t_ratio=0, h_ratio = 0, i ; + static unsigned long ttl = 0; + PT_BEGIN(pt); + while (1) { + if (temp < 25 && humi < 70) digitalWrite(ROUGE, LOW); + PT_WAIT_UNTIL(pt, temp > 25 || humi > 70); + temp_old = temp; + humi_old = humi ; + if (temp > 25) t_ratio = map(temp, 0, 50, 0,254); + if (humi > 70) h_ratio = map(humi, 30, 100, 0,254); + i = max(t_ratio , h_ratio ); + ledPWM(ROUGE, i) ; + PT_WAIT_UNTIL(pt, temp != temp_old || humi != humi_old ); + } + PT_END(pt); +} // Ventilateur + +void initIO() { + pinMode(ROUGE, OUTPUT); analogWrite(ROUGE, 0); + pinMode(JAUNE, OUTPUT); pinMode(BLEU, OUTPUT); + digitalWrite(JAUNE, LOW); digitalWrite(BLEU, LOW) ; + pinMode(VERTE, OUTPUT); analogWrite(VERTE, 254); // at max + pinMode(APVCC, OUTPUT); pinMode(APGND, OUTPUT); + digitalWrite(APVCC, HIGH); digitalWrite(APGND, LOW); +} +void setup() { + int val; + initIO(); // Setup: set LEDs & pots + // static struct pt ptT, ptH, ptV, ptC, ptE, ptN, ptA ; + PT_INIT(&ptT); PT_INIT(&ptH); PT_INIT(&ptV); PT_INIT(&ptC); + PT_INIT(&ptE); PT_INIT(&ptN); PT_INIT(&ptA); + + ttySetIHM(9600); + Serial.println(F("\nLog de " __FILE__ " du " __DATE__)); + val=analogRead(1); + ttyPutInt("Raw Temp = ",val); + val=analogRead(0); + ttyPutInt("Raw humi = ",val); + temp = acquis(1, 0, 100); + ttyPutInt("Temp = ",temp); + humi = acquis(0, 0, 100); + ttyPutInt("Humi = ",humi); +} + +void loop() { + ptTemp(&ptT,2000); // acquisition t° chaque 200ms + ptHumi(&ptH,4000); // acquisition % chaque 500ms + ptVenti(&ptV); // pilotage ventilation (LED Rouge) + ptChauffe(&ptC,5,10); // pilotage chauffage de 3s et inactivité de 3s (LED Jaune) + ptEau(&ptE,3,20); // pilotage arrosage de 3s et inactivité de 5s (LED Bleu) + ptNiveau(&ptN); // affichage niveau d’eau, PWM Verte de 254 à 0 (LED Verte) + ptAlarme(&ptA,500); // alarme réserve vide , clignote à 1Hz (LED Verte) +}