/* Programme ESCLAVE pour tester le transmetteur Bluetooth HC-05 qui gère une télémesure.
   Ce programme est associé à P12_Maitre_F qui se contente d'interroger en boucle l'Esclave.
   Avant de démarrer le mesurage et de la transmission des données, il attend de reconnaitre la
   lettre 'S' de SYNCHRONISATION pour mesurer et commencer à transmettre les données.
   Ensuite, à chaque texte reçu qui n'est pas analysé, il transmet les valeurs mesurées.
   (La rampe de huit LEDs n'est plus branchée. Le BUZZER reste en place mais est ignoré.)
 
 BRANCHEMENTS à effectuer :
 --------------------------
  • Le +5V va sur VCC du HC-05.
  • GND va sur GND du HC-05.
  • GND va sur EN du HC-05.
  • D2 d'Arduino va sur TX du HC-05.
  • D3 d'Arduino va sur RX (1k,2k) du HC-05.
  • La sortie du module DHT11 est branchée sur D5.
  • Le +5Vcc de la carte Arduino va sur l'entrée analogique A0.

UTILISATION :  Téléverser le programme P11_Esclave.ino. Mettre en action par une alimentation USB de
=============  type bloc secteur. Puis "oublier" et utiliser l'entité Maître pour l'exploitation.

 Préalable à l'utilisation de ce démonstrateur :
 -----------------------------------------------
  • L'adresse de ce module a été initialisée dans le programme Maitre avec AT+BIND.
  • Les deux machines ont PSWD = 1905 comme Mot de passe.
  • Les deux machines ont UART = 9600,0,0 comme format de transfert série hertzien.
   
Compilateur v1.7.9.          PGM              RAM dynamique
                       5832 Octets (18%)    163 Octets (7%)  */

//------------------------ Constantes du programme --------------------------
#define Version "12/07/2025" // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#define Lgr_TEXTE 8 // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#define Temporisation 20 // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#define CR 13 // Code du Retour Chariot qui vaut 13 codé en ASCII sous forme décimale.
#define LF 10 // Code du passage à la ligne qui vaut 10 codé en ASCII sous forme décimale.

//------------- Définition des broches d'entrées analogiques ----------------
#define Entree_Vmetre 14       // A0 pour mesurer la tension de l'accumulateur.

//------------------- Définition des broches binaires -----------------------
// Les broches sont choisies dans l'ordre laissant libre D0 et D1 pour les téléversements.
#define RX 2 // Va sur TX du module Bluetooth.
#define TX 3 // Va sur RX du module Bluetooth avec pont de résistances.
// NOTE : Le BUZZER n'est pas déclaré donc ignoré. Mais il reste branché sur D4 pour des
//        expériences futuresd'ou l'implantation du DHT11 sur D5.


//---------------------- Déclarations pour le matériel ----------------------
// Cette section est placée après la déclaration des broches binaires qui doivent
// être définies lors de l'instruction SoftwareSerial Ligne_Bluetooth(RX,TX);
#include <SoftwareSerial.h>
SoftwareSerial Ligne_Bluetooth(RX,TX);
//------------ Déclarations pour le DHT11 ------------
#include <DHT11.h>
#define Broche_Com_DH11 5 // DATA branchée sur la broche binaire D5.
/* Code d'erreur de la fonction readDHT11() */
enum {
  DHT11_SUCCESS,          // Pas d'erreur.
  DHT11_TIMEOUT_ERROR,    // Temps d'attente dépassé.
  DHT11_CHECKSUM_ERROR};  // Données reçues erronées.

//------------------------- Variables du programme --------------------------
char CAR_sur_RX;
byte Erreur, Humidite, Index, Temperature;
int Tension_lue;
char TEXTE[Lgr_TEXTE];

//========================= Procédures de servitude ============================
/* >>> Lecture de la température et lu taux d'humidité mesurés par un capteur DHT11 <<<
  * Broche_DATA : Broche sur laquelle est câblée la sortie du capteur.
  * Temperature : Pointeur vers la variable stockant la température.
  * Humidite : Pointeur vers la variable stockant le taux d'humidité.
  * Retourne DHT11_SUCCESS si aucune erreur, DHT11_TIMEOUT_ERROR en cas de dépassement,
    ou DHT11_CHECKSUM_ERROR en cas d'erreur de checksum */

byte readDHT11(byte Broche_DATA, byte* Temperature, byte* Humidite) {
  byte Variable_DATA[5] = {0}, BIT_serie = 7, Index = 0;
  unsigned int timeout;
    // Variable_DATA[] : Tampon contenant les données du cpateur.
    // BIT_serie : Compteur permettant de savoir quel bit est reçu. (bitwise)
    // Index : Compteur permettant de savoir quel octet est reçu. (bitwise)
    // timeout : Compteur pour le délai en dépassement.
  //----------------------------------------------------------------------------------  
  // Conversion du numéro de broche Arduino en ports/masque binaire "bas niveau".
  // Utiliser les registres du microcontrôleur est bien plus rapide que digitalWrite().
  uint8_t bit = digitalPinToBitMask(Broche_DATA);
  uint8_t port = digitalPinToPort(Broche_DATA);
  volatile uint8_t *ddr = portModeRegister(port);   // Registre MODE (INPUT / OUTPUT)
  volatile uint8_t *out = portOutputRegister(port); // Registre OUT (Écriture)
  volatile uint8_t *in = portInputRegister(port);   // Registre IN (Lecture)
  // >>> Réveil du capteur <<<
  *ddr |= bit; // OUTPUT.
  *out &= ~bit; // LOW.
  delay(18); // Temps d'attente à LOW engendrant le réveil du capteur.
  *out |= bit; // HIGH
  delayMicroseconds(40); *ddr &= ~bit; // INPUT
  // >>> Attente de la réponse du capteur <<<
  timeout = 0; while(!(*in & bit)) // Attente d'un état LOW.
  if (++timeout == 10000) return DHT11_TIMEOUT_ERROR;
  timeout = 0; while(*in & bit) // Attente d'un état HIGH.
  if (++timeout == 10000) return DHT11_TIMEOUT_ERROR;
  // Lecture des 40 bits de données du capteur.
  for (byte I = 0; I < 40; ++I) {
    // Attente d'un état LOW.
    timeout = 0; while(!(*in & bit)) if (++timeout == 10000) return DHT11_TIMEOUT_ERROR;
    // Mise en mémoire du "temps courant".
    unsigned long t = micros(); // Attente d'un état HIGH ::
    timeout = 0; while(*in & bit)
    if (++timeout == 10000) return DHT11_TIMEOUT_ERROR;
    // Si le "delta Temps" est supérieur à 40µS c'est un "1", sinon c'est un "0".
    if ((micros() - t) > 40) Variable_DATA[Index] |= (1 << BIT_serie); // "1"
    // Le tableau Variable_DATA[] est initialisé à "0" par défaut si le compteur de bits atteint zéro.
    if (BIT_serie-- == 0) { BIT_serie = 7; ++Index;}} // On passe à l'octet suivant.
  /* Format des données :
   * [0] = Humidité en %
   * [1] = zéro
   * [2] = Température en degrés Celsius
   * [3] = zéro
   * [4] = checksum (humidité + température)   */
  *Humidite = Variable_DATA[0]; *Temperature = Variable_DATA[2];
  // >>> Vérifie la totalisation de contrôle. (Checksum) <<<
  if (Variable_DATA[4] != (Variable_DATA[0] + Variable_DATA[2])) return DHT11_CHECKSUM_ERROR;
  else return DHT11_SUCCESS;} // Pas d'erreur.

void Vider_le_tampon_HC05() {while (Ligne_Bluetooth.available()) Ligne_Bluetooth.read();}

void Saisie_texte_sur_Bluetooth() {
  Index = 0;
  while (!Ligne_Bluetooth.available()); // Attente du début de l'ACR.
  while(Ligne_Bluetooth.available()) {CAR_sur_RX = Ligne_Bluetooth.read();
        if ((Index < Lgr_TEXTE) && (CAR_sur_RX != CR) && (CAR_sur_RX != LF)) {
           TEXTE[Index] = CAR_sur_RX; Index++;} delay(5);}} // Délai impératif.

void Attente_de_la_synchronisation() {
  TEXTE[Index] = '@'; // caractère quelconque pour entrer dans la boucle.
  while (TEXTE[0] != 'S') {Ligne_Bluetooth.println('E'); Saisie_texte_sur_Bluetooth();}
  Ligne_Bluetooth.print('O'); Ligne_Bluetooth.println('K');}

void Mesures_sur_le_DHT11() {
  switch (readDHT11(Broche_Com_DH11, &Temperature, &Humidite)) {
     case DHT11_SUCCESS : {Erreur = 0; break;}      
     case DHT11_TIMEOUT_ERROR : {Erreur = 1 ; break;}
     case DHT11_CHECKSUM_ERROR : Erreur = 2;}}

//=========================== Corps du programme ===============================

void setup() {
  pinMode (RX,INPUT); pinMode (TX,OUTPUT);
  Ligne_Bluetooth.begin(9600); // Vitesse impérative pour dialoguer avec le module.
  Vider_le_tampon_HC05(); Attente_de_la_synchronisation();}

void loop() {
  Saisie_texte_sur_Bluetooth(); // Le texte reçu n'est plus analysé.
  //====================== Traiter un cycle de mesurage. =======================
  // Chaque cycle comportera trois échanges : Un pour la mesure de chaque paramètre.
  //--------------------------- Effectue les mesures ---------------------------
  Tension_lue = analogRead(Entree_Vmetre); // Mesure analogique [0 à 1023].
  Mesures_sur_le_DHT11();
  //----------------------- Traite l'accusé de réception -----------------------
  delay(Temporisation); Ligne_Bluetooth.println((Tension_lue / 205.0),1); Saisie_texte_sur_Bluetooth();
  if (Erreur == 0) {
      delay(Temporisation); Ligne_Bluetooth.println(Temperature); Saisie_texte_sur_Bluetooth();
      delay(Temporisation); Ligne_Bluetooth.println(Humidite);}
  else {delay(Temporisation); Ligne_Bluetooth.println("Erreur "); Saisie_texte_sur_Bluetooth();
        delay(Temporisation); Ligne_Bluetooth.println("Erreur ");}}



