Compare commits
No commits in common. "8c7c12178aac55a6a92b56cdd4946474f69fd792" and "88a936198ed9637a7cbd1ea9fe5a71898b5fa289" have entirely different histories.
8c7c12178a
...
88a936198e
@ -1,98 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
/**
|
||||
* 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
|
@ -1,23 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
#######################################
|
||||
# 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,10 +1,7 @@
|
||||
#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)
|
||||
{
|
||||
@ -72,11 +69,6 @@ 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
|
||||
*/
|
||||
@ -86,9 +78,6 @@ 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,13 +1,3 @@
|
||||
/**
|
||||
* 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
|
||||
|
||||
@ -15,10 +5,9 @@
|
||||
#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
|
||||
@ -48,14 +37,12 @@ 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,7 +21,6 @@ run KEYWORD2
|
||||
setDownlinkHandler KEYWORD2
|
||||
disableEUChannel KEYWORD2
|
||||
disableAllEUChannelsBut KEYWORD2
|
||||
setSendCompleteHandler KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
|
@ -20,24 +20,47 @@
|
||||
|
||||
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(3310, 15, 6, 10);
|
||||
AdcSetting adcSetting(3320, 15, 6, 10);
|
||||
Ads1115 adc;
|
||||
MeasureUnit measureUnit(analogInput, 8, 990, thermistorSetting, adc);
|
||||
//MeasureUnit measureUnit(analogInput, 8, 99, thermistorSetting, adc);
|
||||
@ -68,45 +91,6 @@ 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);
|
||||
@ -123,7 +107,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(50);
|
||||
radio.setMCUClockError();
|
||||
radio.setDownlinkHandler(&(downlinkHandler));
|
||||
#endif
|
||||
//Adc init
|
||||
@ -141,7 +125,7 @@ void setup() {
|
||||
display.setTextColor(WHITE);
|
||||
display.setCursor(0,15);
|
||||
display.setTextSize(2);
|
||||
display.print(screenTxt);
|
||||
display.print("LES ALEAS DU DIRECT");
|
||||
display.display();
|
||||
}
|
||||
else Serial.println("SCREEN Fail!");
|
@ -1,201 +0,0 @@
|
||||
/**
|
||||
* 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
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
#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
|
@ -1,183 +0,0 @@
|
||||
#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()
|
||||
{
|
||||
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
#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
|
@ -1,198 +0,0 @@
|
||||
/**
|
||||
* 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();
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
#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
|
@ -1,34 +0,0 @@
|
||||
#######################################
|
||||
# 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
|
@ -1,43 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
#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
|
@ -1,19 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
#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
|
@ -1,127 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
#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
|
@ -1,134 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
#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
|
@ -1,375 +0,0 @@
|
||||
#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));
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
#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
|
@ -1,21 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
#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,12 +1,3 @@
|
||||
/**
|
||||
* 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
199
src/app/app.ino
@ -1,199 +0,0 @@
|
||||
/**
|
||||
* 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();
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
#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