dimanche 10 avril 2011

Thermo

Mon programme de thermostat actuel traite plusieurs points que je vais aborder ici.

  • Lecture de la température via thermistor
  • Utilisation de constantes en mémoire Flash
  • Gestion des horaires de chauffage
  • Gestion de l'heure




Lecture de la température
La mesure de la température se fait avec un thermistor qui est une résistance dont la capacité change en fonction de la chaleur.



Cette variation n'est pas linéaire et afin d'avoir la température correspondant à une valeur à l'entrée de l'Arduino, on fait le lien avec un tableau de valeurs.

Voir les détails de l'utilisation du thermistor avec Arduino sur Playground.

Utilisation de constantes en mémoire Flash
Lors de mes tests avec une version simplifiée du programme précédent, j'obtenais des résultats bizarres et des plantages aléatoires du Arduino. Après quelques recherches, j'ai découvert que la mémoire SRAM était entièrement utilisée.


Flash Memory : 32 KB (0.5 KB pour le bootloader)
SRAM : 2 KB
EEPROM : 1 KB


Afin d'alléger l'utilisation de la RAM, une solution consiste à transférer la gestion de certaines variables à la mémoire Flash, utilisée pour stocker le programme, via la librairie PROGMEM.

Voir les détails de l'utilisation de PROGMEM sur le site mon-club-elec.


Dans le code
Tableau de valeurs optimisé :

const prog_uint16_t temperatures[] PROGMEM = { 0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 143, 144, 145, 146, 147, 148, 149, 150, 151, 151, 152, 153, 154, 155, 156, 157, 158, 159, 159, 160, 161, 162, 163, 164, 165, 166, 167, 167, 168, 169, 170, 171, 172, 173, 174, 175, 175, 176, 177, 178, 179, 180, 181, 182, 182, 183, 184, 185, 186, 187, 188, 189, 190, 190, 191, 192, 193, 194, 195, 196, 197, 197, 198, 199, 200, 201, 202, 203, 204, 205, 205, 206, 207, 208, 209, 210, 211, 212, 212, 213, 214, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 225, 226, 227, 228, 228, 229, 230, 231, 232, 233, 234, 235, 235, 236, 237, 238, 239, 240, 241, 242, 243, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 252, 253, 254, 255, 256, 257, 258, 259, 260, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 422, 423, 424, 425, 426, 427, 428, 429, 430, 432, 433, 434, 435, 436, 437, 438, 439, 441, 442, 443, 444, 445, 446, 448, 449, 450, 451, 452, 453, 455, 456, 457, 458, 459, 460, 462, 463, 464, 465, 466, 468, 469, 470, 471, 472, 474, 475, 476, 477, 479, 480, 481, 482, 484, 485, 486, 487, 489, 490, 491, 492, 494, 495, 496, 498, 499, 500, 501, 503, 504, 505, 507, 508, 509, 511, 512, 513, 515, 516, 517, 519, 520, 521, 523, 524, 525, 527, 528, 530, 531, 532, 534, 535, 537, 538, 539, 541, 542, 544, 545, 547, 548, 550, 551, 552, 554, 555, 557, 558, 560, 561, 563, 564, 566, 567, 569, 570, 572, 574, 575, 577, 578, 580, 581, 583, 585, 586, 588, 589, 591, 593, 594, 596, 598, 599, 601, 603, 604, 606, 608, 609, 611, 613, 614, 616, 618, 620, 621, 623, 625, 627, 628, 630, 632, 634, 636, 638, 639, 641, 643, 645, 647, 649, 651, 653, 654, 656, 658, 660, 662, 664, 666, 668, 670, 672, 674, 676, 678, 680, 683, 685, 687, 689, 691, 693, 695, 697, 700, 702, 704, 706, 708, 711, 713, 715, 718, 720, 722, 725, 727, 729, 732, 734, 737, 739, 741, 744, 746, 749, 752, 754, 757, 759, 762, 764, 767, 770, 773, 775, 778, 781, 784, 786, 789, 792, 795, 798, 801, 804, 807, 810, 813, 816, 819, 822, 825, 829, 832, 835, 838, 842, 845, 848, 852, 855, 859, 862, 866, 869, 873, 877, 881, 884, 888, 892, 896, 900, 904, 908, 912, 916, 920, 925, 929, 933, 938, 942, 947, 952, 956, 961, 966, 971, 976, 981, 986, 991, 997, 1002, 1007, 1013, 1019, 1024, 1030, 1036, 1042, 1049, 1055, 1061, 1068, 1075, 1082, 1088, 1096, 1103, 1110, 1118, 1126, 1134, 1142, 1150, 1159, 1168, 1177, 1186, 1196, 1206, 1216, 1226, 1237, 1248, 1260, 1272, 1284, 1297, 1310, 1324, 1338, 1353, 1369, 1385, 1402, 1420, 1439, 1459, 1480, 1502 };

Fonction de lecture de la température optimisée :
const int getTemperature() {
  int sensorValue = analogRead(A0);
  int index = constrain(sensorValue - 238, 0, 771);
  return pgm_read_word_near(temperatures + index);
}


Fonction donnant l'espace SRAM restante :

int availableMemory() {
  int size = 2048;
  byte *buf;
  while ((buf = (byte *) malloc(--size)) == NULL)
    ;
  free(buf);
  return size;
}

Gestion des horaires de chauffage
Le but de cette gestion est d'avoir une température minimum pour chaque moment de la semaine.
Pour ce faire j'ai initialisé les heures de début et de fin dans des tableaux, ainsi que les températures associées aux périodes. Ensuite afin de simplifier les traitements, je transforme les horaires en minutes écoulés depuis le début de semaine.

Initialisation des horaires :

const int nbHoraires = 19;
const prog_uint16_t horaireDebutJour[] PROGMEM = {     0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 6,    6,     6    };
const prog_uint16_t horaireFinJour[] PROGMEM = {       0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 6,    6,     6    };
const prog_uint16_t horaireDebutHeure[] PROGMEM = {    5, 11, 17, 5, 11, 17, 5, 11, 17, 5, 11, 17, 5, 11, 17, 8, 16,   16,    8    };
const prog_uint16_t horaireDebutMinute[] PROGMEM = {  45, 30, 45, 45, 30, 45, 45, 30, 45, 45, 30, 45, 45, 30, 45, 0, 41,   44,    0    };
const prog_uint16_t horaireFinHeure[] PROGMEM = {      8, 14, 23, 8, 14, 23, 8, 14, 23, 8, 14, 23, 8, 14, 23, 23, 16,   16,    23   };
const prog_uint16_t horaireFinMinute[] PROGMEM = {    20, 5, 0, 20, 5, 0, 20, 5, 0, 20, 5, 0, 20, 5, 0, 0, 42,   45,    0    };
const int horaireTemperature[] = {             220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 230,  240,   220  };

Fonction d'optimisation des horaires :

unsigned int horaireDebut[nbHoraires];
unsigned int horaireFin[nbHoraires];
unsigned int horaireEnCours;
void calculerOptimisationHoraires() {
  for(int i=0;i<nbHoraires;i++) {
    horaireDebut[i] = pgm_read_word_near(horaireDebutJour + i) * 1440 + pgm_read_word_near(horaireDebutHeure + i) * 60 + pgm_read_word_near(horaireDebutMinute + i);
    horaireFin[i] = pgm_read_word_near(horaireFinJour + i) * 1440 + pgm_read_word_near(horaireFinHeure + i) * 60 + pgm_read_word_near(horaireFinMinute + i);
  }
  horaireEnCours = jours * 1440 + heures * 60 + minutes;
}


Fonction donnant la température cible :

const int getTemperatureCible() {
  for(int i=0;i<nbHoraires;i++) {
    if ((horaireDebut[i] <= horaireEnCours) && (horaireFin[i] >= horaireEnCours)) {
      return horaireTemperature[i];
    }
  }
  return temperatureParDefaut;
}




Quelle heure est-il ?
Le but est d'afficher l'heure et de pouvoir débrancher l'Arduino tout en conservant l'heure, de manière simple et sans pile. L'idée est de conserver l'heure dans la mémoire EEPROM.


  • index 0 : initialisation de l'heure
  • index 1 : secondes
  • index 2 : minutes
  • index 3 : heures
  • index 4 : jours

Variables et constantes :
byte heures = 16;
byte minutes = 40;
byte secondes = 0;
byte jours = 6;
const byte reset = 1;
const unsigned int uneSeconde = 1000;
unsigned long previousMillis = 0;
const char* NOMS_JOURS[] = { "Lun","Mar","Mer","Jeu","Ven","Sam","Dim" };

Dans le setup :

  byte init = EEPROM.read(0);
  Serial.println(init,DEC);
  if ((init == 1) && (reset != 1)) {
    secondes = EEPROM.read(1);
    minutes = EEPROM.read(2);
    heures = EEPROM.read(3);
    jours = EEPROM.read(4);
  } else {
    EEPROM.write(1,secondes);
    EEPROM.write(2,minutes);
    EEPROM.write(3,heures);
    EEPROM.write(4,jours);
    EEPROM.write(0,1);
  }


Dans le loop :
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > uneSeconde) {
  previousMillis = millis();
  uneSecondeDePlus();
  Serial.print(getTime(heures,minutes,secondes,jours));
}

Fonction d'incrémentation de l'heure :
void uneSecondeDePlus() {
  secondes++;
  if(secondes >= 60) {
    secondes = 0;
    minutes++;
    horaireEnCours = jours * 1440 + heures * 60 + minutes;
  }
  if(minutes >= 60) {
    minutes = 0;
    heures++;
  }
  if(heures >= 24) {
    heures = 0;
    jours++;
    dureeChauffage = 0;
  }
  if(jours >= 7) {
    jours = 0;
  }
  EEPROM.write(1,secondes);
  EEPROM.write(2,minutes);
  EEPROM.write(3,heures);
  EEPROM.write(4,jours);
}


Fonction de formatage de l'heure :

char* getTime(byte hh,byte mm,byte ss,byte jj) {
  char myTime[18];
  sprintf(myTime,"%02d:%02d:%02d %s",hh,mm,ss,NOMS_JOURS[jj]);
  return myTime;
}


Aucun commentaire:

Enregistrer un commentaire