Dans le cadre de mon projet de station météo, il s’agit ici de lire, depuis le raspberrry Pi, le port série sur lequel Arduino envoie les données de mes capteurs en utilisant la librarie wiringPi. Ensuite, nous enregistrerons les valeurs dans une Base de Données MySQL-MariaDB. Il est possible de faire tout cela facilement en utilisant Node-red , qui génére un code JS . Je ne sais pas bien si le code de Node-red sera durable dans le temps, alors je préfére me tourner vers du code en C-C++ qui de toute façon me donnera toute la flexibilité dont je pourrais avoir besoin.
J’ai longuement décrit l’installation et la gestion de la BDD MariaDB ici.
Il faudra aussi installer l’environement de dévelopement Arduino.
Installation du pilote du capteur
Du côté Arduino, il suffit d’installer le pilote du capteur HTU21D.
Ecriture des données sur le port série côté Arduino
Programmer le micrcontroleur à l’aide de la fonction suivante:
/***************************************************
This is an example for the HTU21D-F Humidity & Temp SensorDesigned specifically to work with the HTU21D-F sensor from Adafruit
—-> https://www.adafruit.com/products/1899These displays use I2C to communicate, 2 pins are required to
interface
****************************************************/#include <Wire.h>
#include « Adafruit_HTU21DF.h »// Connect Vin to 3-5VDC
// Connect GND to ground
// Connect SCL to I2C clock pin (A5 on UNO)
// Connect SDA to I2C data pin (A4 on UNO)Adafruit_HTU21DF htu = Adafruit_HTU21DF();
void setup() {
Serial.begin(9600);
Serial.println(« HTU21D-F test »);if (!htu.begin()) {
Serial.println(« Couldn’t find sensor! »);
while (1);
}
}void loop() {
float temp = htu.readTemperature();
float rel_hum = htu.readHumidity();
Serial.print(« \nT= »); Serial.print(temp);// Serial.print( » C »);
Serial.print(« ; »);
Serial.print(« H= »); Serial.print(rel_hum);// Serial.println( » \% »);
Serial.print(« ; »);
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(300); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOWdelay(2000);
}
Installation de la librairie wiringPi
Sur le site de Sir Drogon, ou trouvera :
sudo apt-get install git-core
git clone git://git.drogon.net/wiringPi
cd wiringPi
./build
La librarie (shared Object libwiringPi.so) est alors installée ici :
Ce répertoire est bien déclaré dans un fichier libc.conf du répertoire ci-dessous (accessible uniquement depuis le root et aussi l’usager):
ls -al /etc/ld.so.conf.d/
on remarque alors que le répertoireusr/local/lib est bien déclaré.
nano libc.conf
et on peut donc vérifier que la librairie est bien dans le cache:
ldconfig -p | grep *
Au passage, on remarquera que les fichiers .c et .h (qui définissent la libraire) sont présents dans le répertoire ci-dessous. Le fichier
On peut remarquer aussi la présence de la librarie elle-même libwiringPi.so, ce qui peut paraitre surprenant car elle figure deja dans usr/local/lib.
Je sousponne que lors de l’installation, le fichier .so est compilé dans le répertoire wiringPi ci-dessus puis copié dans usr/local/lib. Les 2 libraries .so ont la meme date , meme heure. Je pourrais vérifer que tout fonctionne en effacant la librairie ici dans ce dernier répertoire local (à tester).
J’ai du faire la même chose pour ma propre librarie.
Note:
La librairie est aussi ici présente dans le répertoire ci-dessous (aussi accessible depuis l’usager) mais je ne sais pas trop pourquoi…
ls -al //usr/lib
Enfin, on pourra voir les dépendances de la librairie :
ldd /home/cm70s/wiringPi/wiringPi/libwiringPi.so.2.46
Lecture de données sur le port série côté Raspberry Pi
Voici le code en C qui lit les caractères un par un sur le port série de mon raspberry Pi. La fcuntnio serialGetChar() lit un caractère à la fois et
#include <stdio.h>
#include <string.h>
#include <errno.h>#include <wiringSerial.h>
int main (){
int fd ;if ((fd = serialOpen (« /dev/ttyACM0 », 9600)) < 0){
fprintf (stderr, « Unable to open serial device: %s\n », strerror (errno)) ;return 1 ;
}// Loop, getting and printing characters
for (;;){
putchar (serialGetchar (fd)) ;
fflush (stdout) ;
}
return 0;
}
Compilation, exécution:
gcc -Wall -Wextra -o fromage moncode.c -lwiringPi
./fromage
Ce programme lit donc les données sur le port série en continue ou chaque ligne est envoyé toutes les 2 secondes environ.
Voici à peu près la meme chose en utlisant un code en C++:
#include <iostream>
#include <fstream>
#include <string>
#include <thread>
#include <wiringSerial.h>using namespace std;
int main () {
std::string ArduinoString(« »);
char CurrentChar = ‘\n’;int i=1,fd,data_integer;
if ((fd = serialOpen (« /dev/ttyACM0 », 9600)) < 0)
{
std::cout<<« ECHEC: Ouverture du Port. Verifier connection. « <<‘\n’;
return 0;
}
else
std::cout<<« Ouverture du Port reussie »<<‘\n’;for (;;){
data_integer = serialGetchar (fd);
fflush (stdout);
CurrentChar = static_cast<char>(data_integer);
ArduinoString += CurrentChar;
if (data_integer == 10) //carriage Return{
std::cout <<i++<<« Ligne recue –> »<<ArduinoString;
ArduinoString = » »;
}
}
return 0;
}
compilation
g++ -L/usr/local/lib/olivier -Wall maroille.cpp -o maroille -lwiringPi -std=c++11
Ecriture des données dans MariaDB
Et enfin, la totale ici :
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <thread>
#include <wiringSerial.h>
#include <mysql/mysql.h>
#include <sstream>using namespace std;
const string sDelim1(« = »);
const string sDelim2(« ; »);
MYSQL *conn, mysql;
MYSQL_RES *res;
MYSQL_ROW row;
int query_state;
string query;
string line;const char *server= »localhost »;
const char *user= »cm70s »;
const char *password= »kfMmIGHa »;
const char *database= »meteobdd3″;/************************************************************************************************/
int MeasureToDB(std::string sKeyword ,double Value)
{
if (!sKeyword.compare(0,1, »T »))
{
query = »INSERT INTO Mesure_Table (M_Nom,M_Famille,M_Valeur,M_Unite,M_Description,M_Date,M_Capteur,M_Fournisseur,M_Branchement) « ;
query += » VALUES (‘temperature’,’chaleur’, »;
query += to_string(Value);
query += « ,’C’,’Bureau de Singapour’,CURRENT_TIME(),’HTU21D’,’Adafruit’,’Pin 12-13 Arduino’ ); « ;
}
if (!sKeyword.compare(0,1, »H »))
{
query = »INSERT INTO Mesure_Table (M_Nom,M_Famille,M_Valeur,M_Unite,M_Description,M_Date,M_Capteur,M_Fournisseur,M_Branchement) « ;
query += » VALUES (‘humidite’,’chaleur’, »;
query += to_string(Value);
query += « ,’pc’,’Bureau de Singapour’,CURRENT_TIME(),’HTU21D’,’Adafruit’,’Pin 12-13 Arduino’ ); « ;
}query_state=mysql_query(conn, query.c_str());
if(query_state!=0){
cout<<mysql_error(conn)<<endl<<endl;
return 1;
}return 1;
}
/************************************************************************************************/
string::size_type GetSensor(std::string sLine,std::string SensorName,double & Value)
{std::string sValue(« »);
string::size_type posBeginIdx = 0,posEndIdx;
posEndIdx = sLine.find_first_of(SensorName);
if (posEndIdx < 0) //couldnt find a string
return posEndIdx;
posBeginIdx = posEndIdx + 1;
posEndIdx = sLine.find_first_of(SensorName);posBeginIdx = sLine.find(sDelim1,posEndIdx) + 1;
posEndIdx = sLine.find(sDelim2,posBeginIdx);
sValue = sLine.substr(posBeginIdx,posEndIdx-posBeginIdx);
Value = std::stod(sValue.c_str());return posBeginIdx;
}
/************************************************************************************************/
int main () {std::string ArduinoString(« »);
char CurrentChar = ‘\n’;
double SensorValue=0;
// ACCESS MYSQL DBmysql_init(&mysql);
conn=mysql_real_connect(&mysql, server, user, password, database, 0, 0, 0);
if(conn==NULL){
cout << mysql_error(&mysql) << endl << endl;
return 1;
}// OPEN SERIAL PORT
int i=0,fd,data_integer;
if ((fd = serialOpen (« /dev/ttyACM0 », 9600)) < 0)
{
std::cout<<« ECHEC: Ouverture du Port. Verifier connection. « <<‘\n’;
return 0;
}std::cout<<« Ouverture du Port reussie »<<‘\n’;
// READ LINE ON SERIAL PORT
for (;;)
{
data_integer = serialGetchar (fd);
fflush (stdout);
CurrentChar = static_cast<char>(data_integer);
ArduinoString += CurrentChar;
if ((data_integer == 10) && (ArduinoString.length()>2))//carriage Return
{
//cout<<« string: »<<ArduinoString <<endl;
GetSensor(ArduinoString, »T »,SensorValue);
MeasureToDB(« T »,SensorValue);
GetSensor(ArduinoString, »H »,SensorValue);
MeasureToDB(« H »,SensorValue);
ArduinoString= » »;
}
}
return 0;
}
Et voila, le résulat après 5 secondes:
Corrolaire 1: Lire une chaine de caractère en C++
Voici un petit bout de code en C++ qui permet de rechercher des delimiteurs dans une chaine de caractères.
#include <iostream>#include <fstream>#include <cstring>#include <cctype>int main(void){using namespace std;std::string ArduinoString(« Temperature=23.4;Humidite=45.6231;blablabla »);const string sDelim1(« = »);const string sDelim2(« ; »);string::size_type posBeginIdx = 0,posEndIdx;string sKeyword,sValue;std::cout <<endl<< » Example of Arduino String-> »<<ArduinoString<<endl;// Read First measure (temperature)posEndIdx = ArduinoString.find_first_of(sDelim1);sKeyword = ArduinoString.substr(posBeginIdx,posEndIdx-posBeginIdx);posBeginIdx = posEndIdx+1;posEndIdx=ArduinoString.find(sDelim2,posBeginIdx);sValue= ArduinoString.substr(posBeginIdx,posEndIdx-posBeginIdx);std::cout <<endl<<« T keyword-> » <<sKeyword <<endl<<« T value-> »<<sValue<<endl;// Read second measure (humidity)posBeginIdx = posEndIdx+1;posEndIdx=ArduinoString.find(sDelim1,posBeginIdx);sKeyword = ArduinoString.substr(posBeginIdx,posEndIdx-posBeginIdx);posBeginIdx = posEndIdx+1;posEndIdx=ArduinoString.find(sDelim2,posBeginIdx);sValue= ArduinoString.substr(posBeginIdx,posEndIdx-posBeginIdx);std::cout <<endl<<« H keyword-> » <<sKeyword <<endl<<« H value-> »<<sValue<<endl;return 1;}
compiler:
g++ -Wall monfichier.cpp -o monprogramme
Résultat:
Example of Arduino String->Temperature=23.4;Humidite=45.6231;blablabla
T keyword->Temperature T value->23.4 H keyword->Humidite H value->45.6231
Corrolaire 2: Compiler C et C++
solution 1
gcc -c -std=c99 -o file1.o file1.c
g++ -c -std=c++0x -o file2.o file2.cpp
g++ -o myapp file1.o file2.o
solution 2
gcc -std=c99 -c -o test.c.o test.c
g++ -std=c++0x -c -o test.cpp.o test.cpp
g++ -o executable test.cpp.o test.c.o
Liens:
Mixer C et C++
https://www.oracle.com/technetwork/articles/servers-storage-dev/mixingcandcpluspluscode-305840.html#c_from_cpp