Compare commits
	
		
			8 Commits
		
	
	
		
			88a936198e
			...
			8c7c12178a
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 8c7c12178a | ||
|  | 240bfe370c | ||
|  | 7381d6d6e1 | ||
|  | a79db84f16 | ||
|  | ebba78c49b | ||
|  | 44e40b8ab3 | ||
|  | 3a3c01186c | ||
|  | 182901d5bc | 
							
								
								
									
										98
									
								
								lib/LTC2439Lib/LTC2439.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								lib/LTC2439Lib/LTC2439.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,98 @@ | ||||
| #include "LTC2439.h" | ||||
| #include <math.h> | ||||
| 
 | ||||
| #define DEBUG | ||||
| 
 | ||||
| LTC2439::LTC2439(uint8_t csPin, uint8_t sdoPin, double vref) :_csPin(csPin), _statusPin(sdoPin), _sampleTriggered(false), _vref(vref), _adcRes(16), _quantum(_vref / (pow(2, _adcRes)-1)), | ||||
| _channelMap{0,8,1,9,2,10,3,11,4,12,5,13,6,14,7,15}, | ||||
| _SPIsettings(500000, MSBFIRST,SPI_MODE0) | ||||
| { | ||||
|   pinMode(_csPin, OUTPUT); | ||||
|   digitalWrite(_csPin, HIGH); | ||||
|   SPI.begin(); | ||||
| } | ||||
| 
 | ||||
| void LTC2439::setVref(double vref) | ||||
| { | ||||
|   _vref = vref; | ||||
|   _quantum = _vref / (pow(2, _adcRes) - 1); | ||||
| } | ||||
| 
 | ||||
| void LTC2439::startAsyncSample(uint8_t channel, boolean sgl, boolean force) | ||||
| { | ||||
|   if(!_sampleTriggered || force) | ||||
|   { | ||||
|     //On envoie la demande de conversion
 | ||||
|     //On sélectionne l'adc
 | ||||
|     pinMode(_statusPin, INPUT); | ||||
|     digitalWrite(_csPin, LOW); | ||||
|     while(digitalRead(_statusPin)); | ||||
|     uint8_t commande = 0b10100000; | ||||
|     commande |= sgl << 4; | ||||
| 	 | ||||
| 	SPI.beginTransaction(_SPIsettings); | ||||
|     SPI.transfer(commande | _channelMap[channel]); | ||||
|     SPI.endTransaction(); | ||||
| 	 | ||||
|     digitalWrite(_csPin, HIGH); | ||||
|     _sampleTriggered = true; | ||||
| 	 | ||||
| 	//restoreRadioSpi();
 | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| boolean LTC2439::asyncResultAvailable() | ||||
| { | ||||
|   //On désactive le bus SPI
 | ||||
|   SPI.end(); | ||||
|   //On regarde si la valeur est prête à être lue:
 | ||||
|   pinMode(_statusPin, INPUT); | ||||
|   digitalWrite(_csPin, LOW); | ||||
|   boolean ready = !digitalRead(_statusPin); //Si la pin sdo est à l'état haut, c'est que la conversion n'est pas terminée.
 | ||||
|   digitalWrite(_csPin, HIGH); | ||||
|   //On réactive le bus SPI
 | ||||
|   SPI.begin(); | ||||
|   return ready; | ||||
| } | ||||
| 
 | ||||
| double LTC2439::convertToVoltage(int32_t value) | ||||
| { | ||||
|   value += 32767; | ||||
|   value *= _quantum; | ||||
|   return value; | ||||
| } | ||||
| 
 | ||||
| int32_t LTC2439::getAsyncValue() | ||||
| { | ||||
|   if(!_sampleTriggered) | ||||
|     return -1; | ||||
|      | ||||
|   digitalWrite(_csPin, LOW); | ||||
|    | ||||
|   SPI.beginTransaction(_SPIsettings); | ||||
|   int8_t bitsleft = 19; | ||||
|   long result = 0;  | ||||
|   while(bitsleft > 0)  | ||||
|   { | ||||
|     result <<= 8; | ||||
|     result |= SPI.transfer(0); | ||||
|     bitsleft -= 8; | ||||
|   } | ||||
|   SPI.endTransaction(); | ||||
|    | ||||
|   digitalWrite(_csPin, HIGH); | ||||
|      | ||||
|   result >>= -bitsleft; | ||||
|   int pos = (result & 0b10000000000000000)>> 16; | ||||
|   unsigned long mask = 0b1111111111111111; | ||||
|   result &= mask; | ||||
|      | ||||
|   if(!pos && result != 0) | ||||
|   { | ||||
|     result = result | (~mask); | ||||
|   } | ||||
| 
 | ||||
|   _sampleTriggered = false; | ||||
| 
 | ||||
|   return result; | ||||
| } | ||||
							
								
								
									
										43
									
								
								lib/LTC2439Lib/LTC2439.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								lib/LTC2439Lib/LTC2439.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | ||||
| /**
 | ||||
| * Anatole SCHRAMM-HENRY | ||||
| * Tim THUREL | ||||
| * Projet température de la ruche GROUPE 3 | ||||
| * Driver pour le LTC2439 fonctionne avec l'ESP8266 | ||||
| * Méthodes asynchrones disponibles | ||||
| * | ||||
| * Tout droits réservés | ||||
| */ | ||||
| 
 | ||||
| #ifndef LTC2439_H | ||||
| #define LTC2439_H | ||||
| 
 | ||||
| #include <Arduino.h> | ||||
| #include <SPI.h> | ||||
| 
 | ||||
| class LTC2439 | ||||
| { | ||||
|   public:            | ||||
|     LTC2439(uint8_t csPin, uint8_t sdoPin, double vref = 3300); | ||||
|     void setVref(double vref); | ||||
|     double getVref(){return _vref;}; | ||||
|     int32_t sampleValue(uint8_t channel, boolean sgl = true); | ||||
|     int32_t sampleValue(); | ||||
|     double sampleVoltage(uint8_t channel, boolean sgl = true); | ||||
|     double sampleVoltage(); | ||||
|     //Methodes asynchrones
 | ||||
|     void startAsyncSample(uint8_t channel, boolean sgl = true, boolean force = false); | ||||
|     boolean asyncResultAvailable(); | ||||
|     double convertToVoltage(int32_t value); | ||||
|     int32_t getAsyncValue(); | ||||
|   protected: | ||||
|   private: | ||||
|     uint8_t _csPin, _statusPin; | ||||
|     boolean _sampleTriggered; | ||||
|     double _vref; //Delta de tension de la plage : vref-gnd en mV
 | ||||
|     uint8_t _adcRes; | ||||
|     double _quantum; | ||||
|     const uint8_t _channelMap[16]; | ||||
| 	const SPISettings _SPIsettings; | ||||
| }; | ||||
| 
 | ||||
| #endif //LTC2439_H
 | ||||
							
								
								
									
										23
									
								
								lib/LTC2439Lib/examples/LTC2439Lib/LTC2439Lib.ino
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								lib/LTC2439Lib/examples/LTC2439Lib/LTC2439Lib.ino
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| #include "LTC2439.h" | ||||
| 
 | ||||
| LTC2439 adc(2,12); | ||||
| uint8_t channel(0); | ||||
| 
 | ||||
| void setup() | ||||
| { | ||||
|   Serial.begin(115200); | ||||
|   Serial.println("Starting setup"); | ||||
|   Serial.println("End setup"); | ||||
| } | ||||
| 
 | ||||
| void loop() | ||||
| { | ||||
|   adc.startAsyncSample(channel); | ||||
|    | ||||
|   if(adc.asyncResultAvailable()) | ||||
|   { | ||||
|     int32_t raw = adc.getAsyncValue(); | ||||
|     Serial.printf("Conversion done, result for channel %u : %d, tension : %.2f\n", channel, raw, adc.convertToVoltage(raw)); | ||||
|     channel = channel == 15 ? 0 : channel + 1; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										22
									
								
								lib/LTC2439Lib/keywords.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								lib/LTC2439Lib/keywords.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| ####################################### | ||||
| # Syntax Coloring Map LTC2439Lib | ||||
| ####################################### | ||||
| 
 | ||||
| ####################################### | ||||
| # Datatypes (KEYWORD1) | ||||
| ####################################### | ||||
| LTC2439	KEYWORD1 | ||||
| 
 | ||||
| ####################################### | ||||
| # Methods and Functions (KEYWORD2) | ||||
| ####################################### | ||||
| setVref	KEYWORD2 | ||||
| startAsyncSample	KEYWORD2 | ||||
| asyncResultAvailable	KEYWORD2 | ||||
| convertToVoltage	KEYWORD2 | ||||
| getAsyncValue	KEYWORD2 | ||||
| getVref	KEYWORD2 | ||||
| ####################################### | ||||
| # Constants (LITERAL1) | ||||
| ####################################### | ||||
| 
 | ||||
| @ -1,7 +1,10 @@ | ||||
| #include "LoRaRadio.h" | ||||
| 
 | ||||
| boolean _transmitted = false; | ||||
| 
 | ||||
| lmic_pinmap lmic_pins = {0}; | ||||
| void (*LoRaRadio::downlinkHandler)(u1_t, u1_t, u1_t*) = NULL; | ||||
| void (*LoRaRadio::sendCompleteHandler)(void) = NULL; | ||||
| 
 | ||||
| LoRaRadio::LoRaRadio(PinMap pinMap, dr_t dataRate, s1_t txPower) :_pinMap(pinMap), _dataRate(dataRate), _txPower(txPower) | ||||
| { | ||||
| @ -46,7 +49,7 @@ void LoRaRadio::setRadioEUChannels() | ||||
| } | ||||
| 
 | ||||
| void LoRaRadio::send(u1_t port, uint8_t *data, uint8_t length, u1_t confirmed) | ||||
| { | ||||
| {  | ||||
|   if (LMIC.opmode & OP_TXRXPEND)  | ||||
|   { | ||||
|     //Serial.println(F("OP_TXRXPEND, not sending"));
 | ||||
| @ -69,6 +72,11 @@ void LoRaRadio::setDownlinkHandler(void (*funcP)(u1_t, u1_t, u1_t*)) | ||||
|   downlinkHandler = funcP; | ||||
| } | ||||
| 
 | ||||
| void LoRaRadio::setSendCompleteHandler(void (*funcP)(void)) | ||||
| { | ||||
|   sendCompleteHandler = funcP; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Here, we declare the onEvent function required by the LMIC | ||||
|  */ | ||||
| @ -78,6 +86,9 @@ void onEvent(ev_t ev) | ||||
|   { | ||||
|     case EV_TXCOMPLETE: | ||||
|       //Event telling us that the data was transmitted
 | ||||
| 	  if(LoRaRadio::sendCompleteHandler != NULL) | ||||
|           (*LoRaRadio::sendCompleteHandler)(); | ||||
| 	   | ||||
|       //It is also here that we check for downlinks
 | ||||
|       if(LMIC.dataLen) | ||||
|       { | ||||
|  | ||||
| @ -1,3 +1,13 @@ | ||||
| /**
 | ||||
| * Anatole SCHRAMM-HENRY | ||||
| * Tim THUREL | ||||
| * Projet température de la ruche GROUPE 3 | ||||
| * Wrapper C++ afin d'utiliser la LMIC (en C) façon objets. | ||||
| * Commenté en anglais pour le plaisir des yeux. | ||||
| * | ||||
| * Tout droits réservés | ||||
| */ | ||||
| 
 | ||||
| #ifndef LORARADIO_H | ||||
| #define LORARADIO_H | ||||
| 
 | ||||
| @ -5,9 +15,10 @@ | ||||
| #include <hal/hal.h> | ||||
| #include <SPI.h> | ||||
| #include <Arduino.h> | ||||
| /*
 | ||||
|  * Here, we define the onEvent function required by the LMIC | ||||
|  */ | ||||
| /**
 | ||||
| * Here, we define the onEvent function required by the LMIC | ||||
| **/ | ||||
| 
 | ||||
| void onEvent(ev_t ev); | ||||
| 
 | ||||
| class PinMap | ||||
| @ -37,12 +48,14 @@ class LoRaRadio | ||||
|     void send(u1_t port, uint8_t *data, uint8_t length, u1_t confirmed = false); | ||||
|     void run(); | ||||
|     void setDownlinkHandler(void (*funcP)(u1_t, u1_t, u1_t*)); | ||||
| 	void setSendCompleteHandler(void (*funcP)(void)); | ||||
|     void disableEUChannel(u1_t channel); | ||||
|     void disableAllEUChannelsBut(u1_t channel); | ||||
| 
 | ||||
|     //Function pointers used to interact with events
 | ||||
|     //Parameters : dataLen, dataBeg, dataBuffer
 | ||||
|     static void (*downlinkHandler)(u1_t, u1_t, u1_t*); | ||||
| 	static void (*sendCompleteHandler)(void); | ||||
|   protected: | ||||
|   private: | ||||
|     dr_t _dataRate; | ||||
|  | ||||
| @ -21,6 +21,7 @@ run	KEYWORD2 | ||||
| setDownlinkHandler	KEYWORD2 | ||||
| disableEUChannel	KEYWORD2 | ||||
| disableAllEUChannelsBut	KEYWORD2 | ||||
| setSendCompleteHandler	KEYWORD2 | ||||
| 
 | ||||
| ####################################### | ||||
| # Constants (LITERAL1) | ||||
|  | ||||
							
								
								
									
										201
									
								
								lib/MeasureUnit_ESP8266/MeasureUnit_ESP8266.ino
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								lib/MeasureUnit_ESP8266/MeasureUnit_ESP8266.ino
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,201 @@ | ||||
| /**
 | ||||
|  * Cet exemple correspond à l'application de test de la bibliothèque MeasureUnit qui | ||||
|  * permet de calculer la température qui est fonction de la résistance d'une matrice de thermistance  | ||||
|  *  | ||||
|  * Anatole SCHRAMM-HENRY | ||||
|  * 17/12/2019 | ||||
|  */ | ||||
| #include <Wire.h> | ||||
| #include <ESP8266WiFi.h> | ||||
| #include <RTClib.h> | ||||
| #include "PayloadFormatter.h" | ||||
| #include "LoRaRadio.h" | ||||
| #include "ThermistorSetting.h" | ||||
| #include "AdcSetting.h" | ||||
| #include "STS21.h" | ||||
| 
 | ||||
| //#define RADIO_ENABLED
 | ||||
| #define PUSH_BUTTON 0 | ||||
| 
 | ||||
| uint8_t analogInput[] = {0,1,2,3,4,5,6,7}; | ||||
| double tempArray[8] = {21.58,21.65,21.54,21.48,21.68,21.75,21.54,21.59}; | ||||
| 
 | ||||
| /*
 | ||||
|  * Liste des offsets trouvés | ||||
|  * |  -0.49  |  0.36  |  -0.29  |  0.38  |  0.44  |  -0.35  |  -0.21  |  0.14  | | ||||
|  * |  -0.72  |  0.07  |  -0.52  |  -0.01  |  2.38  |  -0.65  |  -0.44  |  -0.11  | | ||||
|  * |  -0.99  |  -0.06  |  -0.74  |  2.24  |  0.73  |  -0.86  |  -0.68  |  0.35  | | ||||
|  * |  -0.53  |  -0.49  |  -0.27  |  1.17  |  0.07  |  0.14  |  -0.02  |  -0.08  | | ||||
|  * |  -0.62  |  -0.73  |  1.58  |  0.42  |  -0.27  |  0.09  |  -0.25  |  -0.21  | | ||||
| 
 | ||||
|  *  | ||||
|  */ | ||||
| 
 | ||||
| //Objet de calcule de la temperature
 | ||||
| ThermistorSetting thermistorSetting(3380, 10000); | ||||
| //ThermistorSetting thermistorSetting(3650, 470);
 | ||||
| //AdcSetting adcSetting(3300.0, 12, 310, 3);
 | ||||
| AdcSetting adcSetting(3310, 15, 6, 10); | ||||
| //MeasureUnit measureUnit(analogInput, 8, 99, thermistorSetting, adc);
 | ||||
| //Objet de création des trames LoRa
 | ||||
| PayloadFormatter payloadFormatter(2,4); | ||||
| 
 | ||||
| RTC_DS1307 rtc; | ||||
| DateTime payloadDate; | ||||
| STS21 sts21; | ||||
| 
 | ||||
| boolean data(false); | ||||
| uint8_t *payload(NULL), _timeCounter(0), size(0), _channel(0); | ||||
| boolean calibrer(false); | ||||
| unsigned long _time(0); | ||||
| /*
 | ||||
|  * Radio Part | ||||
| */ | ||||
| void os_getArtEui (u1_t* buf) { } | ||||
| void os_getDevEui (u1_t* buf) { } | ||||
| void os_getDevKey (u1_t* buf) { } | ||||
| 
 | ||||
| static u1_t NWKSKEY[16] = { 0x1F, 0x9E, 0xE2, 0x7A, 0xC8, 0xBA, 0xE8, 0xEA, 0xF5, 0xC2, 0x5E, 0x47, 0x5D, 0xE0, 0x77, 0x55 }; | ||||
| static u1_t APPSKEY[16] = { 0x3B, 0x89, 0x86, 0x96, 0xBB, 0xAA, 0x38, 0x1E, 0x1F, 0xC4, 0xAD, 0x03, 0xEF, 0x3F, 0x56, 0x12 }; | ||||
| static u4_t DEVADDR = 0x260113D3;//0x03FF0001 ; // <-- Change this address for every node!
 | ||||
| 
 | ||||
| u1_t dio[3] = {15,3,LMIC_UNUSED_PIN}; | ||||
| PinMap pinMap(2, LMIC_UNUSED_PIN, 0, dio); | ||||
| LoRaRadio radio(pinMap); | ||||
| 
 | ||||
| void downlinkHandler(u1_t length, u1_t dataBeg, u1_t *data) | ||||
| { | ||||
|   Serial.println("Downlink received : "); | ||||
|   for(uint8_t i(0); i < length; i++) | ||||
|   { | ||||
|     Serial.printf("%u -> %d\n",i,data[dataBeg + i]); | ||||
|   } | ||||
|   Serial.println(); | ||||
| 
 | ||||
|   //Action en fonction de l'octet de commande
 | ||||
|   switch(data[dataBeg+0]) | ||||
|   { | ||||
|     case 0x01://Mise à jour de l'heure
 | ||||
|       //Octets suivants:
 | ||||
|       //2 jour 3 mois 4 année 5 heures 6 minutes
 | ||||
|       if(length == 6) | ||||
|       { | ||||
|         Serial.printf("dd: %u, m: %u, yyyy: %d, hh: %u, mm: %u\n", data[dataBeg+1], data[dataBeg+2], data[dataBeg+3]+2000, data[dataBeg+4], data[dataBeg+5]); | ||||
|       } | ||||
|       else | ||||
|         Serial.println("Action réglage RTC : paramètres insuffisants"); | ||||
|       break; | ||||
|     case 0x02: | ||||
|       /*memcpy(screenTxt,(data+dataBeg+1), length-1);
 | ||||
|       screenTxt[length-1] = '\0'; | ||||
|       display.stopscroll(); | ||||
|       display.clearDisplay(); | ||||
|       display.setTextColor(WHITE); | ||||
|       display.setCursor(0,15); | ||||
|       display.setTextSize(2); | ||||
|       display.print(screenTxt); | ||||
|       display.display(); | ||||
|       display.startscrollleft(0,16);*/ | ||||
|       break; | ||||
|     default: | ||||
|       Serial.println("Action inconnue"); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void setup() { | ||||
|   Serial.begin(115200); | ||||
|   delay(1000); | ||||
|   Serial.println("Start setup"); | ||||
|   WiFi.mode(WIFI_OFF); | ||||
|   //Partie concernant l'initialisation de la radio
 | ||||
|   #ifdef RADIO_ENABLED | ||||
|   radio.init(); | ||||
|   radio.setTTNSession(0x1, DEVADDR, NWKSKEY, APPSKEY); | ||||
|   radio.setRadioEUChannels(); | ||||
|   /*
 | ||||
|    * La directive setMCUClockError() permet de laisser une fenêtre plus grande pour le slot de | ||||
|    * réception (Downlink). En effet ce slot doit durer 2 secondes et il peut durer moins en raison | ||||
|    * d'imprécisions d'horloge. | ||||
|    */ | ||||
|   //radio.setMCUClockError(50);
 | ||||
|   radio.setDownlinkHandler(&(downlinkHandler)); | ||||
|   #endif | ||||
|   _time = millis(); | ||||
|    | ||||
|   if(rtc.begin()) | ||||
|     Serial.println("RTC Ok!"); | ||||
|   else | ||||
|     Serial.println("RTC Fail!"); | ||||
| 
 | ||||
|   if(sts21.begin()) | ||||
|   { | ||||
|     Serial.println("Sensor present !"); | ||||
|     sts21.setResolution(STS21::RES_14); | ||||
|   } | ||||
|   else | ||||
|     Serial.println("Sensor missing !"); | ||||
|    | ||||
|   Serial.println("End setup"); | ||||
|   Serial.println("|   T1    |   T2    |   T3    |   T4    |   T5    |   T6    |   T7    |   T8    |"); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void loop() { | ||||
|   //Version asynchrone :
 | ||||
| 
 | ||||
|   //On peut tester si la conversion est terminée avec :
 | ||||
|    | ||||
|   //measureUnit.getAsyncTemperatures() renvoie NULL si la recupération de la température n'est pas terminée
 | ||||
|   //tempArray = //measureUnit.getAsyncTemperatures();
 | ||||
|   double temp = sts21.getTemperature(); | ||||
|   if(tempArray != NULL) | ||||
|   { | ||||
|     Serial.print("|"); | ||||
|     for(int i(0); i < 8; i++) | ||||
|     { | ||||
|       if(i != 7) | ||||
|       { | ||||
|         Serial.print("  ");Serial.print(tempArray[i],2);Serial.print("  |"); | ||||
|       } | ||||
|       else | ||||
|       { | ||||
|         Serial.print("  ");Serial.print(tempArray[i],2);Serial.print("  |"); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     //On affiche la trame associée:
 | ||||
|     payloadFormatter.startSession(1); | ||||
|     payloadDate = rtc.now(); | ||||
|     size = payloadFormatter.buildPayload(&payload, &payloadDate, 22.5,tempArray); | ||||
|     if(size != 0) | ||||
|     { | ||||
|       //Serial.print("LoRa packet --> ");Serial.print("size : ");Serial.print(size);Serial.println(" bytes");
 | ||||
|       for(int i(0); i < size; i++) | ||||
|       { | ||||
|         payload[i] <= 0x0F ? Serial.print("0") : Serial.print(""); Serial.print(payload[i], HEX); Serial.print(" "); | ||||
|       } | ||||
|       Serial.printf("|%u-%u-%u %u:%u ext temp : %.2f \n", payloadDate.day(),payloadDate.month(),payloadDate.year(),payloadDate.hour(),payloadDate.minute(), temp); | ||||
|     } | ||||
|     else | ||||
|       Serial.print("Failed to build LoRa packet"); | ||||
|      | ||||
|     payloadFormatter.endSession(); | ||||
|      | ||||
|     #ifdef RADIO_ENABLED | ||||
|     if(_timeCounter == 30 && size != 0) | ||||
|     { | ||||
|       _timeCounter = 0; | ||||
|       Serial.printf("Sending data\n"); | ||||
|       radio.send(1, payload, size); | ||||
|     } | ||||
|      | ||||
|     _timeCounter++; | ||||
|     delay(1000); | ||||
|     #endif | ||||
|   } | ||||
| 
 | ||||
|   //On effectue la calibration
 | ||||
|   #ifdef RADIO_ENABLED | ||||
|   radio.run(); | ||||
|   #endif | ||||
| } | ||||
							
								
								
									
										19
									
								
								lib/MeasureUnit_ESP8266_LTC2439/AdcSetting.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								lib/MeasureUnit_ESP8266_LTC2439/AdcSetting.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| #include "AdcSetting.h" | ||||
| 
 | ||||
| AdcSetting::AdcSetting(double vref,  | ||||
| uint8_t adcResolution,  | ||||
| uint8_t measureIteration,  | ||||
| uint16_t delayBetweenIteration) : _vref(vref), _adcResolution(adcResolution), _measureIteration(measureIteration), _delayBetweenIteration(delayBetweenIteration), _quantum(vref/(pow(2.0,(double) adcResolution)-1)) | ||||
| { | ||||
|    | ||||
| } | ||||
| 
 | ||||
| uint8_t AdcSetting::getMeasureIteration() | ||||
| { | ||||
|   return _measureIteration; | ||||
| } | ||||
| 
 | ||||
| double AdcSetting::getQuantum() | ||||
| { | ||||
|   return _quantum; | ||||
| } | ||||
							
								
								
									
										25
									
								
								lib/MeasureUnit_ESP8266_LTC2439/AdcSetting.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								lib/MeasureUnit_ESP8266_LTC2439/AdcSetting.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| #ifndef ADCSETTING_H | ||||
| #define ADCSETTING_H | ||||
| #include <Arduino.h> | ||||
| #include <math.h> | ||||
| 
 | ||||
| class AdcSetting | ||||
| { | ||||
|   public: | ||||
|     AdcSetting(double vref, uint8_t adcResolution, uint8_t measureIteration = 5, uint16_t delayBetweenIteration = 5); | ||||
|     ~AdcSetting(){} | ||||
|      | ||||
|     uint8_t getMeasureIteration(); | ||||
|     uint16_t getDelayBetweenIteration(){ return  _delayBetweenIteration;} | ||||
|     double getQuantum(); | ||||
|     double getVref(){return _vref;} | ||||
|   protected: | ||||
|   private: | ||||
|     double _vref; | ||||
|     uint8_t _adcResolution; | ||||
|     double _quantum; | ||||
|     uint8_t _measureIteration; | ||||
|     uint16_t _delayBetweenIteration; | ||||
| }; | ||||
| 
 | ||||
| #endif //ADCSETTING_H
 | ||||
							
								
								
									
										183
									
								
								lib/MeasureUnit_ESP8266_LTC2439/MeasureUnit.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								lib/MeasureUnit_ESP8266_LTC2439/MeasureUnit.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,183 @@ | ||||
| #include "MeasureUnit.h" | ||||
| //#define DEBUG
 | ||||
| 
 | ||||
| MeasureUnit::MeasureUnit(uint16_t thermistorCount,  | ||||
| uint64_t precResistor,  | ||||
| ThermistorSettings thermistorSettings,  | ||||
| LTC2439 &adc) : _thermistorCount(thermistorCount),  | ||||
| _precResistor(precResistor), | ||||
| _thermistorSettings(thermistorSettings),  | ||||
| _adc(adc),  | ||||
| _globalOffset(0),  | ||||
| _error(OK),  | ||||
| _state(IDLING), | ||||
| _channel(0), | ||||
| _offsetComputeIte(7), | ||||
| _offsetCounter(7), | ||||
| _courant{0.0, 0.0}, | ||||
| _triggerLevelOff(false) | ||||
| { | ||||
|   //Allocation dynamique des différent tableaux
 | ||||
|   _temperatures = (double*) calloc(_thermistorCount, sizeof(double)); | ||||
|   _rOffsetMap = (double*) calloc(_thermistorCount, sizeof(double)); | ||||
|   _resistanceMap = (double*) malloc(_thermistorCount * sizeof(double)); | ||||
|   _rOffsetBuffer = (double*) malloc(_thermistorCount * sizeof(double)); | ||||
| 
 | ||||
|   if(_temperatures == NULL || _rOffsetMap == NULL || _resistanceMap == NULL || _rOffsetBuffer == NULL) | ||||
|   { | ||||
|     _error = MALLOC_ERR; | ||||
|     _temperatures != NULL ? free(_temperatures):(void)_temperatures; | ||||
|     _rOffsetMap != NULL ? free(_rOffsetMap):(void)_rOffsetMap; | ||||
|     _resistanceMap != NULL ? free(_resistanceMap):(void)_resistanceMap; | ||||
|     _rOffsetBuffer != NULL ? free(_rOffsetBuffer):(void)_rOffsetBuffer; | ||||
| 
 | ||||
|     _temperatures = NULL; | ||||
|     _rOffsetMap = NULL; | ||||
|     _resistanceMap = NULL; | ||||
|     _rOffsetBuffer = NULL; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| MeasureUnit::~MeasureUnit() | ||||
| { | ||||
|   if(_error != MALLOC_ERR) | ||||
|   { | ||||
|     free(_temperatures); | ||||
|     free(_rOffsetMap); | ||||
|     free(_resistanceMap); | ||||
|     free(_rOffsetBuffer); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void MeasureUnit::run() | ||||
| { | ||||
|   switch(_state) | ||||
|   { | ||||
|     case MEASURING: | ||||
|       _adc.startAsyncSample(_channel); | ||||
|        | ||||
|       if(_adc.asyncResultAvailable()) | ||||
|       { | ||||
|         _resistanceMap[_channel] = _adc.convertToVoltage(_adc.getAsyncValue()); | ||||
|        #ifdef DEBUG | ||||
|        Serial.printf("Voltage %u  : %.2f\n", _channel, _resistanceMap[_channel]); | ||||
|        #endif | ||||
|        _channel++; | ||||
|       } | ||||
|        | ||||
|       //Fin de la partie d'acquisition
 | ||||
|       if(_channel == _thermistorCount) | ||||
|       { | ||||
|         _state = COMPUTING; | ||||
|       } | ||||
|       break; | ||||
|     case COMPUTING : | ||||
|       //Ici nous calculons les temperatures des thermistances (8 à la fois)
 | ||||
|       _courant[0] = _resistanceMap[0] / (double) _precResistor; | ||||
|       for(int i(0); i < 8; i++) | ||||
|       { | ||||
|         //Calcule de delta :
 | ||||
|         if(i < 7) | ||||
|           _resistanceMap[i] = _resistanceMap[i+1] - _resistanceMap[i]; | ||||
|         else | ||||
|           _resistanceMap[i] = _adc.getVref() - _resistanceMap[i]; | ||||
|         #ifdef DEBUG | ||||
|         Serial.printf("Debug voltage delta : %u -> %.2f\n",i,_resistanceMap[i]); | ||||
|         #endif | ||||
|       } | ||||
| 
 | ||||
|       _courant[1] = _resistanceMap[8] / (double) _precResistor; | ||||
|       for(int i(8); i < 16; i++) | ||||
|       { | ||||
|         //Calcule de delta :
 | ||||
|         if(i < 15) | ||||
|           _resistanceMap[i] = _resistanceMap[i+1] - _resistanceMap[i]; | ||||
|         else | ||||
|           _resistanceMap[i] = _adc.getVref() - _resistanceMap[i]; | ||||
|         #ifdef DEBUG | ||||
|         Serial.printf("Debug voltage delta : %u -> %.2f\n",i,_resistanceMap[i]); | ||||
|         #endif | ||||
|       } | ||||
| 
 | ||||
|       //Calcule de la température (8 à la fois) :
 | ||||
|       for(int i(0); i < 8; i++) | ||||
|       { | ||||
|         _resistanceMap[i] /= _courant[0]; | ||||
|         _temperatures[i] = computeTemperature(_thermistorSettings.getBeta(), _resistanceMap[i], _thermistorSettings.getRat25()); | ||||
|         _temperatures[i] += _rOffsetMap[i] + _globalOffset; | ||||
| 
 | ||||
|         #ifdef DEBUG | ||||
|         Serial.printf("Temperature %u -> %.2f\n", i, _temperatures[i]); | ||||
|         #endif | ||||
|       } | ||||
| 
 | ||||
|       for(int i(8); i < 16; i++) | ||||
|       { | ||||
|         _resistanceMap[i] /= _courant[1]; | ||||
|         _temperatures[i] = computeTemperature(_thermistorSettings.getBeta(), _resistanceMap[i], _thermistorSettings.getRat25()); | ||||
|         _temperatures[i] += _rOffsetMap[i] + _globalOffset; | ||||
| 
 | ||||
|         #ifdef DEBUG | ||||
|         Serial.printf("Temperature %u -> %.2f\n", i, _temperatures[i]); | ||||
|         #endif | ||||
|       } | ||||
|        _state = MEASUREMENT_READY; | ||||
|       break; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| double MeasureUnit::computeTemperature(double beta, double resistance, double rAt25) | ||||
| { | ||||
|   return (((25.0+273.15) * beta) / (beta + (25.0+273.15)*log(resistance / rAt25))) - 273.15; | ||||
| } | ||||
| 
 | ||||
| void MeasureUnit::setGlobalTempOffset(double offset) | ||||
| { | ||||
|   _globalOffset = offset; | ||||
| } | ||||
| 
 | ||||
| double MeasureUnit::getGlobalTempOffset() | ||||
| { | ||||
|   return _globalOffset; | ||||
| } | ||||
| 
 | ||||
| double *MeasureUnit::getROffsetMap() | ||||
| { | ||||
|   return _rOffsetMap; | ||||
| } | ||||
| 
 | ||||
| boolean MeasureUnit::startTemperatureMeasurement() | ||||
| { | ||||
| 
 | ||||
|   if(_state == IDLING) | ||||
|   { | ||||
|     _state = MEASURING; | ||||
|     _channel = 0; | ||||
|     return true; | ||||
|   } | ||||
| 
 | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| boolean MeasureUnit::isMeasurementReady() | ||||
| { | ||||
|   return _state == MEASUREMENT_READY; | ||||
| } | ||||
| 
 | ||||
| double *MeasureUnit::getAsyncTemperatures() | ||||
| { | ||||
|   double *p(NULL); | ||||
| 
 | ||||
|   if(_state == MEASUREMENT_READY) | ||||
|   { | ||||
|     p = _temperatures; | ||||
|     _state = IDLING; | ||||
|   } | ||||
|    | ||||
|   return p; | ||||
| } | ||||
| 
 | ||||
| void MeasureUnit::init() | ||||
| { | ||||
|    | ||||
| } | ||||
							
								
								
									
										50
									
								
								lib/MeasureUnit_ESP8266_LTC2439/MeasureUnit.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								lib/MeasureUnit_ESP8266_LTC2439/MeasureUnit.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,50 @@ | ||||
| #ifndef MEASUREUNIT_H | ||||
| #define MEASUREUNIT_H | ||||
| #include <LTC2439.h> | ||||
| #include "ThermistorSettings.h" | ||||
| 
 | ||||
| class MeasureUnit | ||||
| { | ||||
|   public: | ||||
|     enum ERROR {OK = 0, MALLOC_ERR = 1}; | ||||
|     MeasureUnit(uint16_t thermistorCount, uint64_t precResistor, ThermistorSettings thermistorSettings, LTC2439 &adc); | ||||
|     ~MeasureUnit(); | ||||
|     void init(); | ||||
|     void run(); | ||||
|      | ||||
|     void setGlobalTempOffset(double offset); | ||||
|     double getGlobalTempOffset(); | ||||
|     double *getROffsetMap(); | ||||
| 
 | ||||
|     //Async methods
 | ||||
|     enum STATE {IDLING, MEASURING, COMPUTING, MEASUREMENT_READY}; | ||||
|     boolean startTemperatureMeasurement(); | ||||
|     boolean isMeasurementReady(); | ||||
|     double *getAsyncTemperatures(); | ||||
|     //End of assync methods
 | ||||
| 
 | ||||
|     ERROR getError(){return _error;} | ||||
|      | ||||
|   protected: | ||||
|   private: | ||||
|     double computeTemperature(double beta, double resistance, double rAt25); | ||||
|      | ||||
|     double _globalOffset; //Correspond à l'offset global nécessaire afin d'avoir une température qui corresponde à la réalité
 | ||||
|     double *_temperatures; //Tableau contenant toutes les températures
 | ||||
|     double *_rOffsetMap,*_rOffsetBuffer; //Tableau qui contient les offsets individuels pour chaque thermistance
 | ||||
|     double *_resistanceMap; //Tableau qui contient les resistances associées aux thermistances (pour debug seulement)
 | ||||
|     uint16_t _thermistorCount; | ||||
|     uint64_t _precResistor; | ||||
|     ERROR _error; | ||||
| 
 | ||||
|     LTC2439 &_adc; | ||||
|     ThermistorSettings _thermistorSettings; | ||||
|      | ||||
|     //Async part
 | ||||
|     STATE _state; | ||||
|     uint8_t _channel, _offsetComputeIte,_offsetCounter; | ||||
|     double _courant[2]; | ||||
|     boolean _triggerLevelOff; //Attribut permettant de savoir si un étalonnage a été demandé
 | ||||
| }; | ||||
| 
 | ||||
| #endif //MEASUREUNIT_H
 | ||||
							
								
								
									
										198
									
								
								lib/MeasureUnit_ESP8266_LTC2439/MeasureUnit_ESP8266_LTC2439.ino
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								lib/MeasureUnit_ESP8266_LTC2439/MeasureUnit_ESP8266_LTC2439.ino
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,198 @@ | ||||
| /**
 | ||||
|  * Cet exemple correspond à l'application de test de la bibliothèque MeasureUnit qui | ||||
|  * permet de calculer la température qui est fonction de la résistance d'une matrice de thermistance  | ||||
|  *  | ||||
|  * Anatole SCHRAMM-HENRY | ||||
|  * Tim THUREL | ||||
|  * Version compatible avce le LTC2439 | ||||
|  * 10/05/2020 | ||||
|  */ | ||||
| #include <ESP8266WiFi.h> | ||||
| #include <RTClib.h> | ||||
| #include <PayloadFormatter.h> | ||||
| #include <LoRaRadio.h> | ||||
| #include <LTC2439.h> | ||||
| #include "MeasureUnit.h" | ||||
| #include "ThermistorSettings.h" | ||||
| #include <STS21.h> | ||||
| 
 | ||||
| //#define RADIO_ENABLED
 | ||||
| #define PUSH_BUTTON 0 | ||||
| 
 | ||||
| /*
 | ||||
|  * Liste des offsets trouvés | ||||
|  * |  -0.49  |  0.36  |  -0.29  |  0.38  |  0.44  |  -0.35  |  -0.21  |  0.14  | | ||||
|  * |  -0.72  |  0.07  |  -0.52  |  -0.01  |  2.38  |  -0.65  |  -0.44  |  -0.11  | | ||||
|  * |  -0.99  |  -0.06  |  -0.74  |  2.24  |  0.73  |  -0.86  |  -0.68  |  0.35  | | ||||
|  * |  -0.53  |  -0.49  |  -0.27  |  1.17  |  0.07  |  0.14  |  -0.02  |  -0.08  | | ||||
|  * |  -0.62  |  -0.73  |  1.58  |  0.42  |  -0.27  |  0.09  |  -0.25  |  -0.21  | | ||||
| 
 | ||||
|  *  | ||||
|  */ | ||||
| 
 | ||||
| //Objet de calcule de la température
 | ||||
| LTC2439 adc(2,12); | ||||
| 
 | ||||
| ThermistorSettings thermistorSettings(3380, 10000); | ||||
| MeasureUnit measureUnit(16, 1000, thermistorSettings, adc); | ||||
| //Objet de création des trames LoRa
 | ||||
| PayloadFormatter payloadFormatter(1,16); | ||||
| 
 | ||||
| RTC_DS1307 rtc; | ||||
| DateTime payloadDate; | ||||
| STS21 sts21; | ||||
| 
 | ||||
| boolean data(false); | ||||
| uint8_t *payload(NULL), _timeCounter(0), size(0), _channel(0); | ||||
| boolean calibrer(false); | ||||
| unsigned long _time(0); | ||||
| double *tempArray = NULL; | ||||
| /*
 | ||||
|  * Radio Part | ||||
| */ | ||||
| void os_getArtEui (u1_t* buf) { } | ||||
| void os_getDevEui (u1_t* buf) { } | ||||
| void os_getDevKey (u1_t* buf) { } | ||||
| 
 | ||||
| static u1_t NWKSKEY[16] = { 0x1F, 0x9E, 0xE2, 0x7A, 0xC8, 0xBA, 0xE8, 0xEA, 0xF5, 0xC2, 0x5E, 0x47, 0x5D, 0xE0, 0x77, 0x55 }; | ||||
| static u1_t APPSKEY[16] = { 0x3B, 0x89, 0x86, 0x96, 0xBB, 0xAA, 0x38, 0x1E, 0x1F, 0xC4, 0xAD, 0x03, 0xEF, 0x3F, 0x56, 0x12 }; | ||||
| static u4_t DEVADDR = 0x260113D3;//0x03FF0001 ; // <-- Change this address for every node!
 | ||||
| 
 | ||||
| u1_t dio[3] = {15,3,LMIC_UNUSED_PIN}; | ||||
| PinMap pinMap(2, LMIC_UNUSED_PIN, 0, dio); | ||||
| LoRaRadio radio(pinMap); | ||||
| 
 | ||||
| void downlinkHandler(u1_t length, u1_t dataBeg, u1_t *data) | ||||
| { | ||||
|   Serial.println("Downlink received : "); | ||||
|   for(uint8_t i(0); i < length; i++) | ||||
|   { | ||||
|     Serial.printf("%u -> %d\n",i,data[dataBeg + i]); | ||||
|   } | ||||
|   Serial.println(); | ||||
| 
 | ||||
|   //Action en fonction de l'octet de commande
 | ||||
|   switch(data[dataBeg+0]) | ||||
|   { | ||||
|     case 0x01://Mise à jour de l'heure
 | ||||
|       //Octets suivants:
 | ||||
|       //2 jour 3 mois 4 année 5 heures 6 minutes
 | ||||
|       if(length == 6) | ||||
|       { | ||||
|         Serial.printf("dd: %u, m: %u, yyyy: %d, hh: %u, mm: %u\n", data[dataBeg+1], data[dataBeg+2], data[dataBeg+3]+2000, data[dataBeg+4], data[dataBeg+5]); | ||||
|       } | ||||
|       else | ||||
|         Serial.println("Action réglage RTC : paramètres insuffisants"); | ||||
|       break; | ||||
|     case 0x02: | ||||
|       /*memcpy(screenTxt,(data+dataBeg+1), length-1);
 | ||||
|       screenTxt[length-1] = '\0'; | ||||
|       display.stopscroll(); | ||||
|       display.clearDisplay(); | ||||
|       display.setTextColor(WHITE); | ||||
|       display.setCursor(0,15); | ||||
|       display.setTextSize(2); | ||||
|       display.print(screenTxt); | ||||
|       display.display(); | ||||
|       display.startscrollleft(0,16);*/ | ||||
|       break; | ||||
|     default: | ||||
|       Serial.println("Action inconnue"); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void setup() { | ||||
|   Serial.begin(115200); | ||||
|   delay(1000); | ||||
|   Serial.println("Start setup"); | ||||
|   WiFi.mode(WIFI_OFF); | ||||
|   //Partie concernant l'initialisation de la radio
 | ||||
|   #ifdef RADIO_ENABLED | ||||
|   radio.init(); | ||||
|   radio.setTTNSession(0x1, DEVADDR, NWKSKEY, APPSKEY); | ||||
|   radio.setRadioEUChannels(); | ||||
|   /*
 | ||||
|    * La directive setMCUClockError() permet de laisser une fenêtre plus grande pour le slot de | ||||
|    * réception (Downlink). En effet ce slot doit durer 2 secondes et il peut durer moins en raison | ||||
|    * d'imprécisions d'horloge. | ||||
|    */ | ||||
|   //radio.setMCUClockError(50);
 | ||||
|   radio.setDownlinkHandler(&(downlinkHandler)); | ||||
|   #endif | ||||
|   _time = millis(); | ||||
|    | ||||
|   if(rtc.begin()) | ||||
|     Serial.println("RTC Ok!"); | ||||
|   else | ||||
|     Serial.println("RTC Fail!"); | ||||
| 
 | ||||
|   if(sts21.begin()) | ||||
|   { | ||||
|     Serial.println("Sensor present !"); | ||||
|     sts21.setResolution(STS21::RES_14); | ||||
|   } | ||||
|   else | ||||
|     Serial.println("Sensor missing !"); | ||||
|    | ||||
|   Serial.println("End setup"); | ||||
|   Serial.println("|   T1    |   T2    |   T3    |   T4    |   T5    |   T6    |   T7    |   T8    |   T9    |   T10   |   T11   |   T12   |   T13   |   T14   |   T15   |   T16   |"); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void loop() { | ||||
|   //Version asynchrone :
 | ||||
|   measureUnit.startTemperatureMeasurement(); | ||||
| 
 | ||||
|   //On peut tester si la conversion est terminée avec :
 | ||||
|   //if(measureUnit.isMeasurementReady())
 | ||||
|    | ||||
|   //measureUnit.getAsyncTemperatures() renvoie NULL si la recupération de la température n'est pas terminée
 | ||||
|   tempArray = measureUnit.getAsyncTemperatures(); | ||||
|    | ||||
|   double temp = sts21.getTemperature(); | ||||
|    | ||||
|   if(tempArray != NULL) | ||||
|   { | ||||
|     Serial.print("|"); | ||||
|     for(int i(0); i < 16; i++) | ||||
|     { | ||||
|       Serial.print("  ");Serial.print(tempArray[i],2);Serial.print("  |"); | ||||
|     } | ||||
| 
 | ||||
|     //On affiche la trame associée:
 | ||||
|     payloadFormatter.startSession(1); | ||||
|     payloadDate = rtc.now(); | ||||
|     size = payloadFormatter.buildPayload(&payload, &payloadDate, 22.5,tempArray); | ||||
|     if(size != 0) | ||||
|     { | ||||
|       //Serial.print("LoRa packet --> ");Serial.print("size : ");Serial.print(size);Serial.println(" bytes");
 | ||||
|       for(int i(0); i < size; i++) | ||||
|       { | ||||
|         payload[i] <= 0x0F ? Serial.print("0") : Serial.print(""); Serial.print(payload[i], HEX); Serial.print(" "); | ||||
|       } | ||||
|       Serial.printf("|%u-%u-%u %u:%u ext temp : %.2f \n", payloadDate.day(),payloadDate.month(),payloadDate.year(),payloadDate.hour(),payloadDate.minute(), temp); | ||||
|     } | ||||
|     else | ||||
|       Serial.print("Failed to build LoRa packet"); | ||||
|      | ||||
|     payloadFormatter.endSession(); | ||||
|      | ||||
|     #ifdef RADIO_ENABLED | ||||
|     if(_timeCounter == 30 && size != 0) | ||||
|     { | ||||
|       _timeCounter = 0; | ||||
|       Serial.printf("Sending data\n"); | ||||
|       radio.send(1, payload, size); | ||||
|     } | ||||
|      | ||||
|     _timeCounter++; | ||||
|     delay(1000); | ||||
|     #endif | ||||
|   } | ||||
| 
 | ||||
|   //On effectue la calibration
 | ||||
|   #ifdef RADIO_ENABLED | ||||
|   radio.run(); | ||||
|   #endif | ||||
|   measureUnit.run(); | ||||
| } | ||||
							
								
								
									
										21
									
								
								lib/MeasureUnit_ESP8266_LTC2439/ThermistorSettings.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								lib/MeasureUnit_ESP8266_LTC2439/ThermistorSettings.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| #include "ThermistorSettings.h" | ||||
| 
 | ||||
| ThermistorSettings::ThermistorSettings(uint16_t beta, uint64_t rAt25) : _beta(beta), _rAt25(rAt25) | ||||
| { | ||||
|    | ||||
| } | ||||
| 
 | ||||
| ThermistorSettings::~ThermistorSettings() | ||||
| { | ||||
|    | ||||
| } | ||||
| 
 | ||||
| uint16_t ThermistorSettings::getBeta() | ||||
| { | ||||
|   return _beta; | ||||
| } | ||||
| 
 | ||||
| uint64_t ThermistorSettings::getRat25() | ||||
| { | ||||
|   return _rAt25; | ||||
| } | ||||
							
								
								
									
										18
									
								
								lib/MeasureUnit_ESP8266_LTC2439/ThermistorSettings.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								lib/MeasureUnit_ESP8266_LTC2439/ThermistorSettings.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| #ifndef THERMISTORSETTINGS_H | ||||
| #define THERMISTORSETTINGS_H | ||||
| #include <Arduino.h> //Necessaire afin d'avoir les types : uintxx_t | ||||
| 
 | ||||
| class ThermistorSettings | ||||
| { | ||||
|   public: | ||||
|     ThermistorSettings(uint16_t beta, uint64_t rAt25); | ||||
|     ~ThermistorSettings(); | ||||
|     uint16_t getBeta(); | ||||
|     uint64_t getRat25(); | ||||
|   protected: | ||||
|   private: | ||||
|     uint16_t _beta; | ||||
|     uint64_t _rAt25; | ||||
| }; | ||||
| 
 | ||||
| #endif //THERMISTORSETTINGS_H
 | ||||
							
								
								
									
										34
									
								
								lib/MeasureUnit_ESP8266_LTC2439/keywords.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								lib/MeasureUnit_ESP8266_LTC2439/keywords.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| ####################################### | ||||
| # Syntax Coloring Map MeasureUnit | ||||
| ####################################### | ||||
| 
 | ||||
| ####################################### | ||||
| # Datatypes (KEYWORD1) | ||||
| ####################################### | ||||
| ThermistorSettings	KEYWORD1 | ||||
| AdcSetting	KEYWORD1 | ||||
| MeasureUnit	KEYWORD1 | ||||
| OK	KEYWORD1 | ||||
| MALLOC_ERR	KEYWORD1 | ||||
| 
 | ||||
| ####################################### | ||||
| # Methods and Functions (KEYWORD2) | ||||
| ####################################### | ||||
| getBeta	KEYWORD2 | ||||
| getRat25	KEYWORD2 | ||||
| getMeasureIteration	KEYWORD2 | ||||
| getDelayBetweenIteration	KEYWORD2 | ||||
| getQuantum	KEYWORD2 | ||||
| getVref	KEYWORD2 | ||||
| setGlobalTempOffset	KEYWORD2 | ||||
| getGlobalTempOffset	KEYWORD2 | ||||
| getROffsetMap	KEYWORD2 | ||||
| startTemperatureMeasurement	KEYWORD2 | ||||
| isMeasurementReady	KEYWORD2 | ||||
| getAsyncTemperatures	KEYWORD2 | ||||
| getError	KEYWORD2 | ||||
| 
 | ||||
| ####################################### | ||||
| # Constants (LITERAL1) | ||||
| ####################################### | ||||
| ERROR	LITERAL1 | ||||
							
								
								
									
										43
									
								
								lib/MeasureUnit_TTGO/Adc.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								lib/MeasureUnit_TTGO/Adc.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | ||||
| #include "Adc.h" | ||||
| 
 | ||||
| Adc::Adc() : _lastChannel(0), _adcSetting(0,0), _state(IDLING), _sampledValue(0), _numOfSamples(0), _elapsedTime(0) | ||||
| { | ||||
|   //Serial.println("Adc constructor called");
 | ||||
| } | ||||
| 
 | ||||
| Adc::~Adc() | ||||
| { | ||||
|    | ||||
| } | ||||
| 
 | ||||
| void Adc::setAdcSetting(AdcSetting adcSetting) | ||||
| { | ||||
|   _adcSetting = adcSetting; | ||||
| } | ||||
| 
 | ||||
| AdcSetting Adc::getAdcSetting() | ||||
| { | ||||
|   return _adcSetting; | ||||
| } | ||||
| 
 | ||||
| boolean Adc::isSampleReady() | ||||
| { | ||||
|   return _state == RESULT_READY; | ||||
| } | ||||
| 
 | ||||
| double Adc::getQuantum() | ||||
| { | ||||
|   return _adcSetting.getQuantum(); | ||||
| } | ||||
| 
 | ||||
| double Adc::getSampleValue() | ||||
| { | ||||
|   double ret(0); | ||||
|   if(_state == RESULT_READY) | ||||
|   { | ||||
|     ret = _sampledValue; | ||||
|     _state = IDLING; | ||||
|   } | ||||
|    | ||||
|   return ret; | ||||
| } | ||||
							
								
								
									
										42
									
								
								lib/MeasureUnit_TTGO/Adc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								lib/MeasureUnit_TTGO/Adc.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| #ifndef ADC_H | ||||
| #define ADC_H | ||||
| #include "AdcSetting.h" | ||||
| 
 | ||||
| class Adc | ||||
| { | ||||
|   public: | ||||
|     virtual ~Adc() = 0; | ||||
| 
 | ||||
|     virtual void begin() = 0; | ||||
|     virtual double getQuantum(); | ||||
|     virtual double sampleValue(int16_t channel, boolean sgl = true) = 0; | ||||
|     virtual double sampleValue() = 0; | ||||
|     virtual double sampleVoltage(int16_t channel, boolean sgl = true) = 0; | ||||
|     virtual double sampleVoltage() = 0; | ||||
| 
 | ||||
|     //Async methods
 | ||||
|     enum STATE {STARTED = 0, RESULT_READY, IDLING, SAMPLING}; | ||||
|     virtual void startSample(int16_t channel, boolean sgl = true) = 0; | ||||
|     virtual void startSample() = 0; | ||||
|     virtual double getSampleVoltage() = 0; | ||||
|      | ||||
|     boolean isSampleReady(); | ||||
|     double getSampleValue(); | ||||
|     //End of async methods
 | ||||
| 
 | ||||
|     void setAdcSetting(AdcSetting adcSetting); | ||||
|     AdcSetting getAdcSetting(); | ||||
|   protected: | ||||
|     Adc(); | ||||
|      | ||||
|     int16_t _lastChannel; | ||||
|     AdcSetting _adcSetting; | ||||
|     //Async part
 | ||||
|     STATE _state; | ||||
|     double _sampledValue; | ||||
|     uint8_t _numOfSamples; | ||||
|     unsigned long _elapsedTime; | ||||
|   private: | ||||
| }; | ||||
| 
 | ||||
| #endif //ADC_H
 | ||||
							
								
								
									
										19
									
								
								lib/MeasureUnit_TTGO/AdcSetting.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								lib/MeasureUnit_TTGO/AdcSetting.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| #include "AdcSetting.h" | ||||
| 
 | ||||
| AdcSetting::AdcSetting(double vref,  | ||||
| uint8_t adcResolution,  | ||||
| uint8_t measureIteration,  | ||||
| uint16_t delayBetweenIteration) : _vref(vref), _adcResolution(adcResolution), _measureIteration(measureIteration), _delayBetweenIteration(delayBetweenIteration), _quantum(vref/(pow(2.0,(double) adcResolution)-1)) | ||||
| { | ||||
|    | ||||
| } | ||||
| 
 | ||||
| uint8_t AdcSetting::getMeasureIteration() | ||||
| { | ||||
|   return _measureIteration; | ||||
| } | ||||
| 
 | ||||
| double AdcSetting::getQuantum() | ||||
| { | ||||
|   return _quantum; | ||||
| } | ||||
							
								
								
									
										25
									
								
								lib/MeasureUnit_TTGO/AdcSetting.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								lib/MeasureUnit_TTGO/AdcSetting.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| #ifndef ADCSETTING_H | ||||
| #define ADCSETTING_H | ||||
| #include <Arduino.h> | ||||
| #include <math.h> | ||||
| 
 | ||||
| class AdcSetting | ||||
| { | ||||
|   public: | ||||
|     AdcSetting(double vref, uint8_t adcResolution, uint8_t measureIteration = 5, uint16_t delayBetweenIteration = 5); | ||||
|     ~AdcSetting(){} | ||||
|      | ||||
|     uint8_t getMeasureIteration(); | ||||
|     uint16_t getDelayBetweenIteration(){ return  _delayBetweenIteration;} | ||||
|     double getQuantum(); | ||||
|     double getVref(){return _vref;} | ||||
|   protected: | ||||
|   private: | ||||
|     double _vref; | ||||
|     uint8_t _adcResolution; | ||||
|     double _quantum; | ||||
|     uint8_t _measureIteration; | ||||
|     uint16_t _delayBetweenIteration; | ||||
| }; | ||||
| 
 | ||||
| #endif //ADCSETTING_H
 | ||||
							
								
								
									
										127
									
								
								lib/MeasureUnit_TTGO/Ads1115.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								lib/MeasureUnit_TTGO/Ads1115.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,127 @@ | ||||
| #include "Ads1115.h" | ||||
| #define ADS_DEBUG | ||||
| 
 | ||||
| Ads1115::Ads1115() : ads1(0x48), ads2(0x49) | ||||
| { | ||||
|   #ifdef ADS_DEBUG | ||||
|   Serial.println("Ads1115 constructor called"); | ||||
|   #endif | ||||
|   //We set the adcs up:
 | ||||
|   ads1.setGain(GAIN_ONE); | ||||
|   ads2.setGain(GAIN_ONE); | ||||
| } | ||||
| 
 | ||||
| Ads1115::~Ads1115() | ||||
| { | ||||
|    | ||||
| } | ||||
| 
 | ||||
| void Ads1115::begin() | ||||
| { | ||||
|   #ifdef ADS_DEBUG | ||||
|   Serial.println("Ads1115 : begin"); | ||||
|   #endif | ||||
|   ads1.begin(); | ||||
|   ads2.begin(); | ||||
| } | ||||
| 
 | ||||
| double Ads1115::getQuantum() | ||||
| { | ||||
|   return 0.125; | ||||
| } | ||||
| 
 | ||||
| double Ads1115::sampleValue(int16_t channel, boolean sgl) | ||||
| { | ||||
|   double total(0); | ||||
|   for(int i(0); i < getAdcSetting().getMeasureIteration(); i++) | ||||
|   { | ||||
|     delay(getAdcSetting().getDelayBetweenIteration()); | ||||
|     total += getReading(channel, sgl); | ||||
|   } | ||||
| 
 | ||||
|   //We divide
 | ||||
|   total /= (double)getAdcSetting().getMeasureIteration(); | ||||
|    | ||||
|   //We return
 | ||||
|   return total; | ||||
| } | ||||
| 
 | ||||
| double Ads1115::sampleValue() | ||||
| { | ||||
|   return sampleValue(-1); | ||||
| } | ||||
| 
 | ||||
| double Ads1115::sampleVoltage(int16_t channel, boolean sgl) | ||||
| { | ||||
|   return sampleValue(channel, sgl)*0.125; | ||||
| } | ||||
| 
 | ||||
| double Ads1115::sampleVoltage() | ||||
| { | ||||
|   return sampleValue()*0.125; | ||||
| } | ||||
| 
 | ||||
| uint16_t Ads1115::getReading(int16_t channel, boolean sgl) | ||||
| { | ||||
|   int16_t chan(channel == -1 ? _lastChannel : channel); | ||||
| 
 | ||||
|   _lastChannel = chan > 8 ? 0 : chan; | ||||
| 
 | ||||
|   if(chan < 4) | ||||
|   { | ||||
|     return ads1.readADC_SingleEnded(chan); | ||||
|   } | ||||
|   else if(chan < 8) | ||||
|   { | ||||
|     return ads2.readADC_SingleEnded(chan - 4); | ||||
|   } | ||||
|   else return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| //Async part
 | ||||
| void Ads1115::startSample(int16_t channel, boolean sgl) | ||||
| { | ||||
|   switch(_state) | ||||
|   { | ||||
|     case IDLING: | ||||
|       _state = SAMPLING; | ||||
|       _elapsedTime = millis(); | ||||
|       _sampledValue = 0.0; | ||||
|       _numOfSamples = 0; | ||||
|       //We set the last channel attribute
 | ||||
|       if(channel != -1) | ||||
|       { | ||||
|         _lastChannel = channel > 8 ? _lastChannel : channel; | ||||
|       } | ||||
|        | ||||
|       break; | ||||
|     case SAMPLING: | ||||
|       //If enough time elapsed, we can sample a value again
 | ||||
|       if(millis() - _elapsedTime > getAdcSetting().getDelayBetweenIteration()) | ||||
|       { | ||||
|         _sampledValue += getReading(channel, sgl); | ||||
|         _elapsedTime = millis(); | ||||
|         _numOfSamples ++; | ||||
|       } | ||||
| 
 | ||||
|       //All samples are done:
 | ||||
|       if(_numOfSamples == getAdcSetting().getMeasureIteration()) | ||||
|       { | ||||
|         _sampledValue /= (double)_numOfSamples; | ||||
|         _sampledValue += channel > 3 ? 82.0 : 0.0; | ||||
|         _state = RESULT_READY; | ||||
|       } | ||||
|       break; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void Ads1115::startSample() | ||||
| { | ||||
|   startSample(-1); | ||||
| } | ||||
| 
 | ||||
| double Ads1115::getSampleVoltage() | ||||
| { | ||||
|   return getSampleValue() * 0.125; | ||||
| } | ||||
							
								
								
									
										31
									
								
								lib/MeasureUnit_TTGO/Ads1115.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								lib/MeasureUnit_TTGO/Ads1115.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| #ifndef ADS1115_H | ||||
| #define ADS1115_H | ||||
| #include "Adc.h" | ||||
| #include <Wire.h> | ||||
| #include <Adafruit_ADS1015.h> | ||||
| 
 | ||||
| class Ads1115 : public Adc | ||||
| { | ||||
|   public: | ||||
|     Ads1115(); | ||||
|     ~Ads1115(); | ||||
| 
 | ||||
|     virtual void begin(); | ||||
|     virtual double getQuantum(); | ||||
|     virtual double sampleValue(int16_t channel, boolean sgl = true); | ||||
|     virtual double sampleValue(); | ||||
|     virtual double sampleVoltage(int16_t channel, boolean sgl = true); | ||||
|     virtual double sampleVoltage(); | ||||
| 
 | ||||
|     //Async methods
 | ||||
|     virtual void startSample(int16_t channel, boolean sgl = true); | ||||
|     virtual void startSample(); | ||||
|     virtual double getSampleVoltage(); | ||||
|     //End of async methods
 | ||||
|   protected: | ||||
|   private: | ||||
|     uint16_t getReading(int16_t channel = -1, boolean sgl = true); | ||||
|     Adafruit_ADS1115 ads1, ads2; | ||||
| }; | ||||
| 
 | ||||
| #endif //ADS1115_H
 | ||||
							
								
								
									
										134
									
								
								lib/MeasureUnit_TTGO/Ads1115V2.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								lib/MeasureUnit_TTGO/Ads1115V2.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,134 @@ | ||||
| #include "Ads1115V2.h" | ||||
| #define ADSV2_DEBUG | ||||
| 
 | ||||
| Ads1115V2::Ads1115V2() : ads1(ADS1115_ADDRESS_ADDR_GND), ads2(ADS1115_ADDRESS_ADDR_VDD) | ||||
| { | ||||
|   #ifdef ADSV2_DEBUG | ||||
|   Serial.println("Ads1115 constructor called"); | ||||
|   #endif | ||||
| } | ||||
| 
 | ||||
| Ads1115V2::~Ads1115V2() | ||||
| { | ||||
|    | ||||
| } | ||||
| 
 | ||||
| void Ads1115V2::begin() | ||||
| { | ||||
|   #ifdef ADSV2_DEBUG | ||||
|   Serial.println("Ads1115V2 : begin"); | ||||
|   #endif | ||||
|   Wire.begin(); | ||||
|   //We set the adcs up:
 | ||||
|   ads1.initialize(); | ||||
|   ads2.initialize(); | ||||
|   ads1.setMode(ADS1115_MODE_SINGLESHOT); | ||||
|   ads2.setMode(ADS1115_MODE_SINGLESHOT); | ||||
|   ads1.setRate(ADS1115_RATE_250); | ||||
|   ads2.setRate(ADS1115_RATE_250); | ||||
|   ads1.setGain(ADS1115_PGA_4P096); | ||||
|   ads2.setGain(ADS1115_PGA_4P096); | ||||
| } | ||||
| 
 | ||||
| double Ads1115V2::getQuantum() | ||||
| { | ||||
|   return 0.125; | ||||
| } | ||||
| 
 | ||||
| double Ads1115V2::sampleValue(int16_t channel, boolean sgl) | ||||
| { | ||||
|   double total(0); | ||||
|   for(int i(0); i < getAdcSetting().getMeasureIteration(); i++) | ||||
|   { | ||||
|     delay(getAdcSetting().getDelayBetweenIteration()); | ||||
|     total += getReading(channel, sgl); | ||||
|   } | ||||
| 
 | ||||
|   //We divide
 | ||||
|   total /= (double)getAdcSetting().getMeasureIteration(); | ||||
|    | ||||
|   //We return
 | ||||
|   return total; | ||||
| } | ||||
| 
 | ||||
| double Ads1115V2::sampleValue() | ||||
| { | ||||
|   return sampleValue(-1); | ||||
| } | ||||
| 
 | ||||
| double Ads1115V2::sampleVoltage(int16_t channel, boolean sgl) | ||||
| { | ||||
|   return sampleValue(channel, sgl)*0.125; | ||||
| } | ||||
| 
 | ||||
| double Ads1115V2::sampleVoltage() | ||||
| { | ||||
|   return sampleValue()*0.125; | ||||
| } | ||||
| 
 | ||||
| uint16_t Ads1115V2::getReading(int16_t channel, boolean sgl) | ||||
| { | ||||
|   int16_t chan(channel == -1 ? _lastChannel : channel); | ||||
| 
 | ||||
|   _lastChannel = chan > 8 ? 0 : chan; | ||||
| 
 | ||||
|   if(chan < 4) | ||||
|   { | ||||
|     ads1.setMultiplexer(chan+4); | ||||
|     return ads1.getConversion(true); | ||||
|   } | ||||
|   else if(chan < 8) | ||||
|   { | ||||
|     ads2.setMultiplexer(chan); | ||||
|     return ads2.getConversion(true); | ||||
|   } | ||||
|   else return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| //Async part
 | ||||
| void Ads1115V2::startSample(int16_t channel, boolean sgl) | ||||
| { | ||||
|   switch(_state) | ||||
|   { | ||||
|     case IDLING: | ||||
|       _state = SAMPLING; | ||||
|       _elapsedTime = millis(); | ||||
|       _sampledValue = 0.0; | ||||
|       _numOfSamples = 0; | ||||
|       //We set the last channel attribute
 | ||||
|       if(channel != -1) | ||||
|       { | ||||
|         _lastChannel = channel > 8 ? _lastChannel : channel; | ||||
|       } | ||||
|        | ||||
|       break; | ||||
|     case SAMPLING: | ||||
|       //If enough time elapsed, we can sample a value again
 | ||||
|       if(millis() - _elapsedTime > getAdcSetting().getDelayBetweenIteration()) | ||||
|       { | ||||
|         _sampledValue += getReading(channel, sgl); | ||||
|         _elapsedTime = millis(); | ||||
|         _numOfSamples ++; | ||||
|       } | ||||
| 
 | ||||
|       //All samples are done:
 | ||||
|       if(_numOfSamples == getAdcSetting().getMeasureIteration()) | ||||
|       { | ||||
|         _sampledValue /= (double)_numOfSamples; | ||||
|         _sampledValue += channel > 3 ? 82.0 : 0.0; | ||||
|         _state = RESULT_READY; | ||||
|       } | ||||
|       break; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void Ads1115V2::startSample() | ||||
| { | ||||
|   startSample(-1); | ||||
| } | ||||
| 
 | ||||
| double Ads1115V2::getSampleVoltage() | ||||
| { | ||||
|   return getSampleValue() * 0.125; | ||||
| } | ||||
							
								
								
									
										31
									
								
								lib/MeasureUnit_TTGO/Ads1115V2.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								lib/MeasureUnit_TTGO/Ads1115V2.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| #ifndef ADS1115V2_H | ||||
| #define ADS1115V2_H | ||||
| #include "Adc.h" | ||||
| #include <Wire.h> | ||||
| #include <ADS1115x.h> | ||||
| 
 | ||||
| class Ads1115V2 : public Adc | ||||
| { | ||||
|   public: | ||||
|     Ads1115V2(); | ||||
|     ~Ads1115V2(); | ||||
| 
 | ||||
|     virtual void begin(); | ||||
|     virtual double getQuantum(); | ||||
|     virtual double sampleValue(int16_t channel, boolean sgl = true); | ||||
|     virtual double sampleValue(); | ||||
|     virtual double sampleVoltage(int16_t channel, boolean sgl = true); | ||||
|     virtual double sampleVoltage(); | ||||
| 
 | ||||
|     //Async methods
 | ||||
|     virtual void startSample(int16_t channel, boolean sgl = true); | ||||
|     virtual void startSample(); | ||||
|     virtual double getSampleVoltage(); | ||||
|     //End of async methods
 | ||||
|   protected: | ||||
|   private: | ||||
|     uint16_t getReading(int16_t channel = -1, boolean sgl = true); | ||||
|     ADS1115 ads1, ads2; | ||||
| }; | ||||
| 
 | ||||
| #endif //ADS1115V2_H
 | ||||
							
								
								
									
										375
									
								
								lib/MeasureUnit_TTGO/MeasureUnit.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										375
									
								
								lib/MeasureUnit_TTGO/MeasureUnit.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,375 @@ | ||||
| #include "MeasureUnit.h" | ||||
| //#define DEBUG
 | ||||
| 
 | ||||
| MeasureUnit::MeasureUnit(uint8_t *analogInput,  | ||||
| uint16_t thermistorCount,  | ||||
| uint64_t precResistor,  | ||||
| ThermistorSetting thermistorSetting,  | ||||
| Adc &adc) : _analogInput(analogInput), | ||||
| _thermistorCount(thermistorCount),  | ||||
| _precResistor(precResistor), | ||||
| _thermistorSetting(thermistorSetting),  | ||||
| _adc(adc),  | ||||
| _globalOffset(0),  | ||||
| _error(OK),  | ||||
| _state(IDLING), | ||||
| _channel(0), | ||||
| _offsetComputeIte(7), | ||||
| _offsetCounter(7), | ||||
| _courant(0.0), | ||||
| _tension(0.0), | ||||
| _triggerLevelOff(false) | ||||
| { | ||||
|   //Allocation dynamique des différent tableaux
 | ||||
|   _temperatures = (double*) calloc(_thermistorCount, sizeof(double)); | ||||
|   _rOffsetMap = (double*) calloc(_thermistorCount, sizeof(double)); | ||||
|   _resistanceMap = (double*) malloc(_thermistorCount * sizeof(double)); | ||||
|   _rOffsetBuffer = (double*) malloc(_thermistorCount * sizeof(double)); | ||||
| 
 | ||||
|   if(_temperatures == NULL || _rOffsetMap == NULL || _resistanceMap == NULL || _rOffsetBuffer == NULL) | ||||
|   { | ||||
|     _error = MALLOC_ERR; | ||||
|     _temperatures != NULL ? free(_temperatures):(void)_temperatures; | ||||
|     _rOffsetMap != NULL ? free(_rOffsetMap):(void)_rOffsetMap; | ||||
|     _resistanceMap != NULL ? free(_resistanceMap):(void)_resistanceMap; | ||||
|     _rOffsetBuffer != NULL ? free(_rOffsetBuffer):(void)_rOffsetBuffer; | ||||
| 
 | ||||
|     _temperatures = NULL; | ||||
|     _rOffsetMap = NULL; | ||||
|     _resistanceMap = NULL; | ||||
|     _rOffsetBuffer = NULL; | ||||
|   } | ||||
| 
 | ||||
|   _adc.begin(); | ||||
| } | ||||
| 
 | ||||
| MeasureUnit::~MeasureUnit() | ||||
| { | ||||
|   if(_error != MALLOC_ERR) | ||||
|   { | ||||
|     free(_temperatures); | ||||
|     free(_rOffsetMap); | ||||
|     free(_resistanceMap); | ||||
|     free(_rOffsetBuffer); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void MeasureUnit::run() | ||||
| { | ||||
|   switch(_state) | ||||
|   { | ||||
|     case MEASURING: | ||||
|       _adc.startSample(_channel); | ||||
|        | ||||
|       if(_channel == 0) //Calcule du courant
 | ||||
|       { | ||||
|         if(_adc.isSampleReady()) | ||||
|         { | ||||
|           _tension = _adc.getSampleVoltage(); | ||||
|           _courant =  _tension / (double) _precResistor; | ||||
|           #ifdef DEBUG | ||||
|           Serial.print("Tension prec : ");Serial.println(_tension); | ||||
|           #endif | ||||
|            _channel++; | ||||
|         } | ||||
|       } | ||||
|       else //Calcule des niveaux de tensions
 | ||||
|       { | ||||
|         if(_adc.isSampleReady()) | ||||
|         { | ||||
|           _resistanceMap[_channel-1] = _adc.getSampleVoltage(); | ||||
|           #ifdef DEBUG | ||||
|           Serial.print("Tension thermistances : ");Serial.println(_resistanceMap[_channel-1]); | ||||
|           #endif | ||||
|           _channel++; | ||||
|         } | ||||
|       } | ||||
|        | ||||
|       //Fin de la partie d'acquisition
 | ||||
|       if(_channel == _thermistorCount) | ||||
|       { | ||||
|         _state = COMPUTING; | ||||
|         _resistanceMap[_channel-1] = _adc.getAdcSetting().getVref(); | ||||
|       } | ||||
|       break; | ||||
|     case COMPUTING : | ||||
|       //Ici nous calculons les temperatures
 | ||||
|       for(int i(_thermistorCount-1); i > 0; i--) | ||||
|       { | ||||
|         //Calcule de delta :
 | ||||
|         _resistanceMap[i] -= _resistanceMap[i-1]; | ||||
|         #ifdef DEBUG | ||||
|         Serial.printf("Debug voltage delta : %u -> ",i);Serial.println(_resistanceMap[i]); | ||||
|         #endif | ||||
|       } | ||||
| 
 | ||||
|       //Ne pas oublier de déduire la chute de tension de la resistance de precision pour la première thermistance
 | ||||
|       _resistanceMap[0] -= _tension; | ||||
|       #ifdef DEBUG | ||||
|       Serial.printf("Debug voltage delta : 0 -> ");Serial.println(_resistanceMap[0]); | ||||
|       #endif | ||||
|        | ||||
|       for(int i(0); i < _thermistorCount; i++) | ||||
|       { | ||||
|         //3) Nous en déduisons la résistance
 | ||||
|         //Serial.print("Resistance ");Serial.print(i);Serial.print(" ");Serial.println(_resistanceMap[i]);
 | ||||
|         _resistanceMap[i] /= _courant; | ||||
|         //4) Nous en déduisons la temperature
 | ||||
|         _temperatures[i] = computeTemperature(_thermistorSetting.getBeta(), _resistanceMap[i], _thermistorSetting.getRat25()); | ||||
| 
 | ||||
|         //On effectue un étalonnage
 | ||||
|         if(_triggerLevelOff) | ||||
|         { | ||||
|           double averageTemp(0); | ||||
|           //We reset the offset
 | ||||
|           for(int i(0); i < _thermistorCount; i++) | ||||
|           { | ||||
|             _rOffsetMap[i] = 0; | ||||
|           } | ||||
|            | ||||
|           for(int i(0); i < _thermistorCount; i++) | ||||
|           { | ||||
|             averageTemp += _temperatures[i]; | ||||
|           } | ||||
|          | ||||
|           averageTemp /= (double)_thermistorCount; | ||||
|          | ||||
|           for(int i(0); i < _thermistorCount; i++) | ||||
|           { | ||||
|             _rOffsetMap[i] = averageTemp - _temperatures[i]; | ||||
|           } | ||||
|           _triggerLevelOff = false; | ||||
|         } | ||||
|          | ||||
|         _temperatures[i] += _rOffsetMap[i] + _globalOffset; | ||||
|         #ifdef DEBUG_TEMP | ||||
|         Serial.print("Temperature ");Serial.print(i);Serial.print(" : ");Serial.println(_temperatures[i]); | ||||
|         #endif | ||||
|       } | ||||
|        _state = MEASUREMENT_READY; | ||||
|       break; | ||||
|   } | ||||
|    | ||||
|   if(_offsetCounter < _offsetComputeIte && isMeasurementReady()) | ||||
|   { | ||||
|     //We reset the offset array
 | ||||
|     if(_offsetCounter == 0) | ||||
|     { | ||||
|       Serial.printf("Initiating average \n"); | ||||
|       for(int i(0); i < _thermistorCount; i++) | ||||
|       { | ||||
|         _rOffsetBuffer[i] = 0; | ||||
|         _rOffsetMap[i] = 0; | ||||
|       } | ||||
|     } | ||||
|     else if(_offsetCounter == _offsetComputeIte-1) | ||||
|     { | ||||
|       double averageTemp(0); | ||||
|        | ||||
|       for(int i(0); i < _thermistorCount; i++) | ||||
|       { | ||||
|         _rOffsetBuffer[i] += _temperatures[i]; | ||||
|       } | ||||
|       //We compute the average for each thermistor:
 | ||||
|       for(int i(0); i < _thermistorCount; i++) | ||||
|       { | ||||
|         _rOffsetBuffer[i] /= _offsetCounter; | ||||
|         averageTemp += _rOffsetBuffer[i]; | ||||
|       } | ||||
|        | ||||
|       averageTemp /= _thermistorCount; | ||||
|       for(int i(0); i < _thermistorCount; i++) | ||||
|       { | ||||
|         _rOffsetMap[i] = averageTemp - _rOffsetBuffer[i]; | ||||
|       } | ||||
| 
 | ||||
|       Serial.println("Offset done"); | ||||
|       Serial.print("|"); | ||||
|       for(int i(0); i < _thermistorCount; i++) | ||||
|       { | ||||
|         if(i != 7) | ||||
|         { | ||||
|           Serial.print("  ");Serial.print(_rOffsetMap[i],2);Serial.print("  |"); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|           Serial.print("  ");Serial.print(_rOffsetMap[i],2);Serial.print("  |"); | ||||
|         } | ||||
|       } | ||||
|       Serial.println(""); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|       for(int i(0); i < _thermistorCount; i++) | ||||
|       { | ||||
|         _rOffsetBuffer[i] += _temperatures[i]; | ||||
|       } | ||||
|     } | ||||
|      | ||||
|     _offsetCounter++; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void MeasureUnit::setOffsetIteration(uint8_t iteration) | ||||
| { | ||||
|   _offsetComputeIte = iteration; | ||||
|   _offsetCounter = iteration; | ||||
| } | ||||
| 
 | ||||
| void MeasureUnit::startOffsetComputing() | ||||
| { | ||||
|   _offsetCounter = 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Methode permettant d'effectuer les mesures de température et de les récupérer | ||||
|  */ | ||||
| double *MeasureUnit::getTemperatures() | ||||
| { | ||||
|   double courant(0), rPrecTension(0); | ||||
|   //1) Nous calculons le courant présent dans la branche grace à la résistance de précision
 | ||||
|   #ifdef DEBUG | ||||
|   Serial.println("-------------"); | ||||
|   #endif | ||||
|   rPrecTension = _adc.sampleVoltage(0); | ||||
|   #ifdef DEBUG | ||||
|   Serial.println("-------------"); | ||||
|   Serial.print("R prec voltage mV : ");Serial.println(rPrecTension,6); | ||||
|   #endif | ||||
|    | ||||
|   courant = rPrecTension / (double) _precResistor; | ||||
|   #ifdef DEBUG | ||||
|   Serial.print("R prec current mA : ");Serial.println(courant,6); | ||||
|   #endif | ||||
|    | ||||
|    | ||||
|   //2) Nous calculons le delta de tensions pour chaque thermistances
 | ||||
|   for(int i(1); i < _thermistorCount; i++) | ||||
|   {   | ||||
|     _resistanceMap[i-1] = _adc.sampleVoltage(_analogInput[i]); | ||||
|     #ifdef DEBUG | ||||
|     Serial.print("Voltage steps ");Serial.print(i-1);Serial.print(" : ");Serial.println(_resistanceMap[i-1]); | ||||
|     #endif | ||||
|   } | ||||
|   _resistanceMap[7] = _adc.getAdcSetting().getVref(); | ||||
|   #ifdef DEBUG | ||||
|   Serial.print("Voltage steps 7 : ");Serial.println(_resistanceMap[7]); | ||||
|   #endif | ||||
|    | ||||
|   for(int i(_thermistorCount-1); i > 0; i--) | ||||
|   { | ||||
|     //Calcule de delta :
 | ||||
|     _resistanceMap[i] -= _resistanceMap[i-1]; | ||||
|     #ifdef DEBUG | ||||
|     Serial.print("Debug voltage delta : ");Serial.println(_resistanceMap[i]); | ||||
|     #endif | ||||
|   } | ||||
| 
 | ||||
|   //Ne pas oublier de déduire la chute de tension de la resistance de precision pour la première thermistance
 | ||||
|   _resistanceMap[0] -= rPrecTension; | ||||
|   Serial.printf("Debug voltage delta : 0 -> ");Serial.println(_resistanceMap[0]); | ||||
|    | ||||
|   for(int i(0); i < _thermistorCount; i++) | ||||
|   { | ||||
|     //3) Nous en déduisons la résistance
 | ||||
|     //Serial.print("Resistance ");Serial.print(i);Serial.print(" ");Serial.println(_resistanceMap[i]);
 | ||||
|     _resistanceMap[i] /= courant; | ||||
|     //4) Nous en déduisons la temperature
 | ||||
|     _temperatures[i] = computeTemperature(_thermistorSetting.getBeta(), _resistanceMap[i], _thermistorSetting.getRat25()); | ||||
|     _temperatures[i] += _rOffsetMap[i] + _globalOffset; | ||||
|     #ifdef DEBUG_TEMP | ||||
|     Serial.print("Temperature ");Serial.print(i);Serial.print(" : ");Serial.println(_temperatures[i]); | ||||
|     #endif | ||||
|   } | ||||
|    | ||||
|   return _temperatures; | ||||
| } | ||||
| 
 | ||||
| double MeasureUnit::computeTemperature(double beta, double resistance, double rAt25) | ||||
| { | ||||
|   return (((25.0+273.15) * beta) / (beta + (25.0+273.15)*log(resistance / rAt25))) - 273.15; | ||||
| } | ||||
| 
 | ||||
| void MeasureUnit::setGlobalTempOffset(double offset) | ||||
| { | ||||
|   _globalOffset = offset; | ||||
| } | ||||
| 
 | ||||
| double MeasureUnit::getGlobalTempOffset() | ||||
| { | ||||
|   return _globalOffset; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Cette méthode permet de calibrer toutes les temperatures en faisans la moyenne et appliquant un offset individuel | ||||
|  */ | ||||
| void MeasureUnit::levelTemperaturesOff() | ||||
| { | ||||
|   double averageTemp(0); | ||||
|   //We reset the offset
 | ||||
|   for(int i(0); i < _thermistorCount; i++) | ||||
|   { | ||||
|     _rOffsetMap[i] = 0; | ||||
|   } | ||||
| 
 | ||||
|   getTemperatures(); | ||||
|    | ||||
|   for(int i(0); i < _thermistorCount; i++) | ||||
|   { | ||||
|     averageTemp += _temperatures[i]; | ||||
|   } | ||||
| 
 | ||||
|   averageTemp /= _thermistorCount; | ||||
| 
 | ||||
|   for(int i(0); i < _thermistorCount; i++) | ||||
|   { | ||||
|     _rOffsetMap[i] = averageTemp - _temperatures[i]; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| double *MeasureUnit::getROffsetMap() | ||||
| { | ||||
|   return _rOffsetMap; | ||||
| } | ||||
| 
 | ||||
| boolean MeasureUnit::startTemperatureMeasurement() | ||||
| { | ||||
| 
 | ||||
|   if(_state == IDLING) | ||||
|   { | ||||
|     _state = MEASURING; | ||||
|     _channel = 0; | ||||
|     return true; | ||||
|   } | ||||
| 
 | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| void MeasureUnit::levelAsyncTemperaturesOff() | ||||
| { | ||||
|   _triggerLevelOff = true; | ||||
| } | ||||
| 
 | ||||
| boolean MeasureUnit::isMeasurementReady() | ||||
| { | ||||
|   return _state == MEASUREMENT_READY; | ||||
| } | ||||
| 
 | ||||
| double *MeasureUnit::getAsyncTemperatures() | ||||
| { | ||||
|   double *p(NULL); | ||||
| 
 | ||||
|   if(_state == MEASUREMENT_READY) | ||||
|   { | ||||
|     p = _temperatures; | ||||
|     _state = IDLING; | ||||
|   } | ||||
|    | ||||
|   return p; | ||||
| } | ||||
| 
 | ||||
| void MeasureUnit::init() | ||||
| { | ||||
|   Serial.println(computeTemperature(3380, 18000, 10000)); | ||||
|   Serial.println(computeTemperature(3380, 11700, 10000)); | ||||
| } | ||||
							
								
								
									
										57
									
								
								lib/MeasureUnit_TTGO/MeasureUnit.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								lib/MeasureUnit_TTGO/MeasureUnit.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,57 @@ | ||||
| #ifndef MEASUREUNIT_H | ||||
| #define MEASUREUNIT_H | ||||
| #include "Ads1115.h" | ||||
| #include "ThermistorSetting.h" | ||||
| 
 | ||||
| //#define DEBUG_TEMP
 | ||||
| 
 | ||||
| class MeasureUnit | ||||
| { | ||||
|   public: | ||||
|     enum ERROR {OK = 0, MALLOC_ERR = 1}; | ||||
|     MeasureUnit(uint8_t *analogInput, uint16_t thermistorCount, uint64_t precResistor, ThermistorSetting thermistorSetting, Adc &adc); | ||||
|     ~MeasureUnit(); | ||||
|     void init(); | ||||
|     void run(); | ||||
|     void startOffsetComputing(); | ||||
|     void setOffsetIteration(uint8_t iteration); | ||||
|     void setGlobalTempOffset(double offset); | ||||
|     void levelTemperaturesOff(); | ||||
|     double getGlobalTempOffset(); | ||||
|     double *getTemperatures(); | ||||
|     double *getROffsetMap(); | ||||
| 
 | ||||
|     //Async methods
 | ||||
|     enum STATE {IDLING, MEASURING, COMPUTING, MEASUREMENT_READY}; | ||||
|     boolean startTemperatureMeasurement(); | ||||
|     boolean isMeasurementReady(); | ||||
|     double *getAsyncTemperatures(); | ||||
|     void levelAsyncTemperaturesOff(); | ||||
|     //End of assync methods
 | ||||
| 
 | ||||
|     ERROR getError(){return _error;} | ||||
|      | ||||
|   protected: | ||||
|   private: | ||||
|     double computeTemperature(double beta, double resistance, double rAt25); | ||||
|      | ||||
|     double _globalOffset; //Correspond à l'offset global nécessaire afin d'avoir une température qui corresponde à la réalité
 | ||||
|     double *_temperatures; //Tableau contenant toutes les températures
 | ||||
|     double *_rOffsetMap,*_rOffsetBuffer; //Tableau qui contient les offsets individuels pour chaque thermistance
 | ||||
|     double *_resistanceMap; //Tableau qui contient les resistances associées aux thermistances (pour debug seulement)
 | ||||
|     uint8_t *_analogInput; //Pointeur qui garde l'adresse du tableau contenant le nom des entrées analogiques
 | ||||
|     uint16_t _thermistorCount; | ||||
|     uint64_t _precResistor; | ||||
|     ERROR _error; | ||||
| 
 | ||||
|     Adc &_adc; | ||||
|     ThermistorSetting _thermistorSetting; | ||||
|      | ||||
|     //Async part
 | ||||
|     STATE _state; | ||||
|     uint8_t _channel, _offsetComputeIte,_offsetCounter; | ||||
|     double _courant, _tension; | ||||
|     boolean _triggerLevelOff; //Attribut permettant de savoir si un étalonnage a été demandé
 | ||||
| }; | ||||
| 
 | ||||
| #endif //MEASUREUNIT_H
 | ||||
| @ -20,47 +20,24 @@ | ||||
| 
 | ||||
| uint8_t analogInput[] = {0,1,2,3,4,5,6,7}; | ||||
| double *tempArray = NULL; | ||||
| char screenTxt[30] = "LES ALEAS DU DIRECT"; | ||||
| 
 | ||||
| /*
 | ||||
|  * Liste des offsets trouvés | ||||
|  * |  -0.49  |  0.36  |  -0.29  |  0.38  |  0.44  |  -0.35  |  -0.21  |  0.14  | | ||||
|  * |  -0.72  |  0.07  |  -0.52  |  -0.01  |  2.38  |  -0.65  |  -0.44  |  -0.11  | | ||||
|  * |  -0.99  |  -0.06  |  -0.74  |  2.24  |  0.73  |  -0.86  |  -0.68  |  0.35  | | ||||
|  * |  -0.53  |  -0.49  |  -0.27  |  1.17  |  0.07  |  0.14  |  -0.02  |  -0.08  | | ||||
|  * |  -0.62  |  -0.73  |  1.58  |  0.42  |  -0.27  |  0.09  |  -0.25  |  -0.21  | | ||||
| 
 | ||||
|  *  | ||||
|  */ | ||||
| 
 | ||||
| void downlinkHandler(u1_t length, u1_t dataBeg, u1_t *data) | ||||
| { | ||||
|   Serial.println("Downlink received : "); | ||||
|   for(uint8_t i(0); i < length; i++) | ||||
|   { | ||||
|     Serial.print(data[dataBeg + i],HEX); | ||||
|   } | ||||
|   Serial.println(); | ||||
| 
 | ||||
|   //Action en fonction de l'octet de commande
 | ||||
|   switch(data[0]) | ||||
|   { | ||||
|     case 0x01://Mise à jour de l'heure
 | ||||
|       //Octets suivants:
 | ||||
|       //2 jour 3 mois 4 année 5 heures 6 minutes
 | ||||
|       if(length == 6) | ||||
|       { | ||||
|         Serial.printf("dd: %u, m: %u, yyyy: %d, hh: %u, mm: %u\n", data[2], data[3], data[4]+2000, data[5], data[6]); | ||||
|       } | ||||
|       else | ||||
|         Serial.println("Action réglage RTC : paramètres insuffisants"); | ||||
|       break; | ||||
|     default: | ||||
|       Serial.println("Action inconnnue"); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| //Objet de calcule de la temperature
 | ||||
| //ThermistorSetting thermistorSetting(3380, 10000);
 | ||||
| ThermistorSetting thermistorSetting(3650, 470); | ||||
| ThermistorSetting thermistorSetting(3380, 10000); | ||||
| //ThermistorSetting thermistorSetting(3650, 470);
 | ||||
| //AdcSetting adcSetting(3300.0, 12, 310, 3);
 | ||||
| AdcSetting adcSetting(3320, 15, 6, 10); | ||||
| AdcSetting adcSetting(3310, 15, 6, 10); | ||||
| Ads1115 adc; | ||||
| MeasureUnit measureUnit(analogInput, 8, 990, thermistorSetting, adc); | ||||
| //MeasureUnit measureUnit(analogInput, 8, 99, thermistorSetting, adc);
 | ||||
| @ -91,6 +68,45 @@ u1_t dio[3] = {26,33,32}; | ||||
| PinMap pinMap(18, LMIC_UNUSED_PIN, 14, dio); | ||||
| LoRaRadio radio(pinMap); | ||||
| 
 | ||||
| void downlinkHandler(u1_t length, u1_t dataBeg, u1_t *data) | ||||
| { | ||||
|   Serial.println("Downlink received : "); | ||||
|   for(uint8_t i(0); i < length; i++) | ||||
|   { | ||||
|     Serial.printf("%u -> %d\n",i,data[dataBeg + i]); | ||||
|   } | ||||
|   Serial.println(); | ||||
| 
 | ||||
|   //Action en fonction de l'octet de commande
 | ||||
|   switch(data[dataBeg+0]) | ||||
|   { | ||||
|     case 0x01://Mise à jour de l'heure
 | ||||
|       //Octets suivants:
 | ||||
|       //2 jour 3 mois 4 année 5 heures 6 minutes
 | ||||
|       if(length == 6) | ||||
|       { | ||||
|         Serial.printf("dd: %u, m: %u, yyyy: %d, hh: %u, mm: %u\n", data[dataBeg+1], data[dataBeg+2], data[dataBeg+3]+2000, data[dataBeg+4], data[dataBeg+5]); | ||||
|       } | ||||
|       else | ||||
|         Serial.println("Action réglage RTC : paramètres insuffisants"); | ||||
|       break; | ||||
|     case 0x02: | ||||
|       memcpy(screenTxt,(data+dataBeg+1), length-1); | ||||
|       screenTxt[length-1] = '\0'; | ||||
|       display.stopscroll(); | ||||
|       display.clearDisplay(); | ||||
|       display.setTextColor(WHITE); | ||||
|       display.setCursor(0,15); | ||||
|       display.setTextSize(2); | ||||
|       display.print(screenTxt); | ||||
|       display.display(); | ||||
|       display.startscrollleft(0,16); | ||||
|       break; | ||||
|     default: | ||||
|       Serial.println("Action inconnue"); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void setup() { | ||||
|   Serial.begin(115200); | ||||
|   delay(1000); | ||||
| @ -107,7 +123,7 @@ void setup() { | ||||
|    * réception (Downlink). En effet ce slot doit durer 2 secondes et il peut durer moins en raison | ||||
|    * d'imprécisions d'horloge. | ||||
|    */ | ||||
|   radio.setMCUClockError(); | ||||
|   radio.setMCUClockError(50); | ||||
|   radio.setDownlinkHandler(&(downlinkHandler)); | ||||
|   #endif | ||||
|   //Adc init
 | ||||
| @ -125,7 +141,7 @@ void setup() { | ||||
|     display.setTextColor(WHITE); | ||||
|     display.setCursor(0,15); | ||||
|     display.setTextSize(2); | ||||
|     display.print("LES ALEAS DU DIRECT"); | ||||
|     display.print(screenTxt); | ||||
|     display.display(); | ||||
|   } | ||||
|   else Serial.println("SCREEN Fail!"); | ||||
							
								
								
									
										21
									
								
								lib/MeasureUnit_TTGO/ThermistorSetting.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								lib/MeasureUnit_TTGO/ThermistorSetting.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| #include "ThermistorSetting.h" | ||||
| 
 | ||||
| ThermistorSetting::ThermistorSetting(uint16_t beta, uint64_t rAt25) : _beta(beta), _rAt25(rAt25) | ||||
| { | ||||
|    | ||||
| } | ||||
| 
 | ||||
| ThermistorSetting::~ThermistorSetting() | ||||
| { | ||||
|    | ||||
| } | ||||
| 
 | ||||
| uint16_t ThermistorSetting::getBeta() | ||||
| { | ||||
|   return _beta; | ||||
| } | ||||
| 
 | ||||
| uint64_t ThermistorSetting::getRat25() | ||||
| { | ||||
|   return _rAt25; | ||||
| } | ||||
							
								
								
									
										18
									
								
								lib/MeasureUnit_TTGO/ThermistorSetting.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								lib/MeasureUnit_TTGO/ThermistorSetting.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| #ifndef THERMISTORSETTING_H | ||||
| #define THERMISTORSETTING_H | ||||
| #include <Arduino.h> //Necessaire afin d'avoir les types : uintxx_t | ||||
| 
 | ||||
| class ThermistorSetting | ||||
| { | ||||
|   public: | ||||
|     ThermistorSetting(uint16_t beta, uint64_t rAt25); | ||||
|     ~ThermistorSetting(); | ||||
|     uint16_t getBeta(); | ||||
|     uint64_t getRat25(); | ||||
|   protected: | ||||
|   private: | ||||
|     uint16_t _beta; | ||||
|     uint64_t _rAt25; | ||||
| }; | ||||
| 
 | ||||
| #endif //THERMISTORSETTING_H
 | ||||
| @ -1,3 +1,12 @@ | ||||
| /**
 | ||||
| * Anatole SCHRAMM-HENRY | ||||
| * Tim THUREL | ||||
| * Projet température de la ruche GROUPE 3 | ||||
| * Objet PayloadFormatter permettant de générer les trames contenants les températures, la date et les numéros de trames | ||||
| * | ||||
| * Tout droits réservés | ||||
| */ | ||||
| 
 | ||||
| #ifndef PAYLOADFORMATTER_H | ||||
| #define PAYLOADFORMATTER_H | ||||
| #include <math.h> | ||||
|  | ||||
							
								
								
									
										199
									
								
								src/app/app.ino
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								src/app/app.ino
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,199 @@ | ||||
| /**
 | ||||
| * Code source de l'application (qui a servi de démo pour la présentation finale) | ||||
| * Anatole SCHRAMM-HENRY et Tim THUREL | ||||
| *  | ||||
| * Récupère 16 mesures de température (une barrette) et les envoies en LoRa à interval de temps régulier | ||||
| **/ | ||||
| 
 | ||||
| #include <ESP8266WiFi.h> | ||||
| #include <RTClib.h> | ||||
| #include <PayloadFormatter.h> | ||||
| #include <LoRaRadio.h> | ||||
| #include <LTC2439.h> | ||||
| #include <MeasureUnit.h> | ||||
| #include <ThermistorSettings.h> | ||||
| #include <AdcSetting.h> | ||||
| #include <STS21.h> | ||||
| 
 | ||||
| #define RADIO_ENABLED | ||||
| #define ONE_CHANNEL_GW | ||||
| //INTERVAL_ENVOI en secondes (15 minutes)
 | ||||
| #define INTERVAL_ENVOI 15*60  | ||||
| 
 | ||||
| //16 CS, 12 MISO
 | ||||
| LTC2439 adc(16,12); | ||||
| 
 | ||||
| //Beta de 3380, Résistance à 25 °C de 10K Ohm
 | ||||
| ThermistorSettings thermistorSettings(3380, 10000); | ||||
| 
 | ||||
| //16 thermistances sur 1 rangée, résistance de précision de 1k Ohm
 | ||||
| MeasureUnit measureUnit(16, 1000, thermistorSettings, adc); | ||||
| 
 | ||||
| //Objet de création des trames LoRa
 | ||||
| PayloadFormatter payloadFormatter(2,8); | ||||
| 
 | ||||
| RTC_DS1307 rtc; | ||||
| DateTime payloadDate; | ||||
| STS21 sts21; | ||||
| 
 | ||||
| boolean data(false); | ||||
| uint8_t *payload(NULL), size(0), _channel(0); | ||||
| double *tempArray = NULL; | ||||
| 
 | ||||
| boolean sendTriggered(false); | ||||
| uint16_t counterSave(1); | ||||
| unsigned long ts(millis()); | ||||
| 
 | ||||
| /**
 | ||||
| * Partie d'initialisation de la radio | ||||
| * et définition des identifiants TTN | ||||
| **/ | ||||
| 
 | ||||
| void os_getArtEui (u1_t* buf) { } | ||||
| void os_getDevEui (u1_t* buf) { } | ||||
| void os_getDevKey (u1_t* buf) { } | ||||
| 
 | ||||
| static u1_t NWKSKEY[16] = { 0x1F, 0x9E, 0xE2, 0x7A, 0xC8, 0xBA, 0xE8, 0xEA, 0xF5, 0xC2, 0x5E, 0x47, 0x5D, 0xE0, 0x77, 0x55 }; | ||||
| static u1_t APPSKEY[16] = { 0x3B, 0x89, 0x86, 0x96, 0xBB, 0xAA, 0x38, 0x1E, 0x1F, 0xC4, 0xAD, 0x03, 0xEF, 0x3F, 0x56, 0x12 }; | ||||
| static u4_t DEVADDR = 0x260113D3; | ||||
| 
 | ||||
| u1_t dio[3] = {15,3,LMIC_UNUSED_PIN}; | ||||
| PinMap pinMap(2, LMIC_UNUSED_PIN, 0, dio); | ||||
| LoRaRadio radio(pinMap, DR_SF9); | ||||
| 
 | ||||
| void downlinkHandler(u1_t length, u1_t dataBeg, u1_t *data) | ||||
| { | ||||
|   Serial.println("Downlink received : "); | ||||
|   for(uint8_t i(0); i < length; i++) | ||||
|   { | ||||
|     Serial.printf("%u -> %d\n",i,data[dataBeg + i]); | ||||
|   } | ||||
|   Serial.println(); | ||||
| 
 | ||||
|   //Action en fonction de l'octet de commande
 | ||||
|   switch(data[dataBeg+0]) | ||||
|   { | ||||
|     case 0x01://Mise à jour de l'heure
 | ||||
|       //Octets suivants:
 | ||||
|       //2 jour 3 mois 4 année 5 heures 6 minutes
 | ||||
|       if(length == 6) | ||||
|       { | ||||
|         Serial.printf("dd: %u, m: %u, yyyy: %d, hh: %u, mm: %u\n", data[dataBeg+1], data[dataBeg+2], data[dataBeg+3]+2000, data[dataBeg+4], data[dataBeg+5]); | ||||
|       } | ||||
|       else | ||||
|         Serial.println("Action réglage RTC : paramètres insuffisants"); | ||||
|       break; | ||||
|     case 0x02: | ||||
|       break; | ||||
|     default: | ||||
|       Serial.println("Action inconnue"); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void sendCompleteHandler() | ||||
| { | ||||
|   Serial.printf("Send is done !\n"); | ||||
| } | ||||
| 
 | ||||
| void setup()  | ||||
| { | ||||
|   Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY); | ||||
|   //Met le pin 3 RX en GPIO
 | ||||
|   pinMode(3, FUNCTION_3); | ||||
|   delay(1000); | ||||
|   Serial.println("Start setup"); | ||||
|   WiFi.mode(WIFI_OFF); | ||||
| 
 | ||||
|   //Initialisation de la radio
 | ||||
|   #ifdef RADIO_ENABLED | ||||
|   radio.init(); | ||||
|   radio.setTTNSession(0x1, DEVADDR, NWKSKEY, APPSKEY); | ||||
|   radio.setRadioEUChannels(); | ||||
|   #ifdef ONE_CHANNEL_GW | ||||
|   radio.disableAllEUChannelsBut(0); | ||||
|   #endif | ||||
|   /**
 | ||||
|   * La directive setMCUClockError() permet de laisser une fenêtre plus grande pour le slot de | ||||
|   * réception (Downlink). En effet ce slot doit durer 2 secondes et il peut durer moins en raison | ||||
|   * d'imprécisions d'horloge. | ||||
|   **/ | ||||
|   radio.setMCUClockError(); | ||||
|   #endif | ||||
|   //Enregistrement des callbacks d'evenements
 | ||||
|   radio.setDownlinkHandler(&(downlinkHandler)); | ||||
|   radio.setSendCompleteHandler(&(sendCompleteHandler)); | ||||
| 
 | ||||
|   if(rtc.begin()) | ||||
|     Serial.println("RTC Ok!"); | ||||
|   else | ||||
|     Serial.println("RTC Fail!"); | ||||
| 
 | ||||
|   if(sts21.begin()) | ||||
|   { | ||||
|     Serial.println("Sensor present !"); | ||||
|     sts21.setResolution(STS21::RES_14); | ||||
|   } | ||||
|   else | ||||
|     Serial.println("Sensor missing !"); | ||||
|    | ||||
|   Serial.println("End setup"); | ||||
|   Serial.println("|   T1    |   T2    |   T3    |   T4    |   T5    |   T6    |   T7    |   T8    |   T9    |   T10   |   T11   |   T12   |   T13   |   T14   |   T15   |   T16   |"); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void loop() { | ||||
|   //Version asynchrone :
 | ||||
|   measureUnit.startTemperatureMeasurement(); | ||||
| 
 | ||||
|   //On peut tester si la conversion est terminée avec :
 | ||||
|   //if(measureUnit.isMeasurementReady())
 | ||||
|    | ||||
|   //measureUnit.getAsyncTemperatures() renvoie NULL si la recupération de la température n'est pas terminée
 | ||||
|   tempArray = measureUnit.getAsyncTemperatures(); | ||||
|    | ||||
|   double externalTemp = sts21.getTemperature(); | ||||
|    | ||||
|   if(tempArray != NULL) | ||||
|   { | ||||
|     Serial.print("|"); | ||||
|     for(int i(0); i < 16; i++) | ||||
|     { | ||||
|       Serial.print("  ");Serial.print(tempArray[i],2);Serial.print("  |"); | ||||
|     } | ||||
| 
 | ||||
|     //On affiche la trame associée:
 | ||||
|     payloadFormatter.startSession(1); | ||||
|     payloadDate = rtc.now(); | ||||
|     size = payloadFormatter.buildPayload(&payload, &payloadDate, externalTemp,tempArray); | ||||
|     if(size != 0) | ||||
|     { | ||||
|       //Serial.print("LoRa packet --> ");Serial.print("size : ");Serial.print(size);Serial.println(" bytes");
 | ||||
|       for(int i(0); i < size; i++) | ||||
|       { | ||||
|         payload[i] <= 0x0F ? Serial.print("0") : Serial.print(""); Serial.print(payload[i], HEX); Serial.print(" "); | ||||
|       } | ||||
|       Serial.printf("|%u-%u-%u %u:%u ext temp : %.2f \n", payloadDate.day(),payloadDate.month(),payloadDate.year(),payloadDate.hour(),payloadDate.minute(), externalTemp); | ||||
|     } | ||||
|     else | ||||
|       Serial.print("Failed to build LoRa packet"); | ||||
|      | ||||
|     payloadFormatter.endSession(); | ||||
|      | ||||
|     #ifdef RADIO_ENABLED | ||||
| 
 | ||||
|     //Envoie des trames à interval de temps régulier
 | ||||
|     if(millis() - ts > INTERVAL_ENVOI*1000 && size != 0) | ||||
|     { | ||||
|       Serial.println("Sending data"); | ||||
|       radio.send(1, payload, size); | ||||
| 
 | ||||
|       ts = millis(); | ||||
|     } | ||||
|     #endif | ||||
|   } | ||||
| 
 | ||||
|   #ifdef RADIO_ENABLED | ||||
|   radio.run(); | ||||
|   #endif | ||||
|   measureUnit.run(); | ||||
| } | ||||
							
								
								
									
										34
									
								
								test/TestLibAdc/TestLibAdc.ino
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								test/TestLibAdc/TestLibAdc.ino
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| #include "Ads1115V2.h" | ||||
| 
 | ||||
| AdcSetting adcSetting(3300.0, 15, 1, 10); | ||||
| Ads1115V2 adc; | ||||
| 
 | ||||
| uint8_t channel(0); | ||||
| 
 | ||||
| void setup() { | ||||
|   // put your setup code here, to run once:
 | ||||
|   Serial.begin(115200); | ||||
|   delay(1000); | ||||
|   Serial.println("Start setup"); | ||||
|   adc.begin(); | ||||
|   adc.setAdcSetting(adcSetting); | ||||
|   //measureUnit.setGlobalTempOffset(-17);
 | ||||
|   Serial.println("End setup"); | ||||
| } | ||||
| 
 | ||||
| void loop() { | ||||
|   // put your main code here, to run repeatedly:
 | ||||
|   adc.startSample(channel); | ||||
| 
 | ||||
|   if(adc.isSampleReady()) | ||||
|   { | ||||
|     Serial.print("Sample is ready : ");Serial.println(channel); | ||||
|     double raw = adc.getSampleValue(); | ||||
|     Serial.print("Value : ");Serial.println(raw,4); | ||||
|     Serial.print("Voltage : ");Serial.println(raw * adc.getQuantum()); | ||||
|     Serial.println(); | ||||
| 
 | ||||
|     channel++; | ||||
|     channel %= 8; | ||||
|   } | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user