#include #include #include #include /* * ------Geiger Tube board (Arduino Code) Example-------- * * Explanation: This example shows how to get the signal from the Geiger Tube * in Arduino, we use one of the Arduino interrupt pins (PIN2). * We count the time (ms) between two pulses of the Geiger tube. * * Copyright (C) 2011 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Version: 0.1 * Design: Marcos Yarza, David Gascon * Implementation: Marcos Yarza * * Explications en français : cet exemple montre comment acquérir le signal du tube Geiger * avec Arduino. On utilise une des entrées d'inerruption de l'Arduino (PIN2). * On compte le temps (en ms) entre deux impulsions du tube Geiger. * Cette version gère le dialogue avec l'application GeigerPC * (voir sur http://www.pascalchour.fr/ressources/geigerpc/geigerpc_fr.htm) * Elle utilise la fonction "sleep" pour tenter de limiter la consommation. * Le programme est réveillé sur les événements suivants : * - impulsion au niveau du tube Geiger * - réception de caractères * - toutes les secondes * * * Modifications P. Chour * Version 1.41 * Date 26/03/2012 */ // include the library code: //#include // initialisation de la bibliothèque avec les numéros des PINs de l'interface LiquidCrystal lcd(3,4,5,6,7,8); // directives de compilation #define USE_LED false // à mettre à true si on veut utiliser le barre de LEDs. False sinon. // valeurs de seuil pour la barre de LEDs #define TH1 50 #define TH2 150 #define TH3 300 #define TH4 600 #define TH5 900 #define version_pgm "1.41" // version du programme const int periode = 5; // periode en secondes const int periode_par_minute = 60/periode; // Nombre de périodes par minute. const int nb_minutes_par_24h = 1440; // nb de minutes en 24H const int max_recu = 25; // nb max d'octets pouvant être reçus const int maxeeprom = 1000; // taille max pour écriture en EEPROM const int DelaiGarde = 100; // delai de garde après écriture et avant sleep mode // facteur de conversion pour LDN 712 d'après GammaScout. Note: certains sites donnent d'autres valeurs. // Autres valeurs trouvées : 0.0081208 / 0,01 / etc. // De toute façon, la conversion en µSievert n'est qu'une grossière approximation. Pour la valeur proposée // ci-dessous, il s'agit du facteur de conversion utilisé sur mon propre GammaScout (le GammaScout renvoie // le nombre de CpM et la valeur calculée en µSv/h). const float conversion_factor = 0.007230658; // Variables int ledArray [] = { 10,11,12,13,9}; // {9,13,12,11,10} int geiger_input = 2; // entrée d'interruption int count = 0; int countMoyenneMin[periode_par_minute]; // nb de périodes par minutes int countMoyenneHeure[25]; // nb d'heures +1 par jours int nbMinutes24h = 0; // nb de minutes écoulées depuis le début du comptage limité à 24h00 int nbMinutes = 0; // nb de minutes pour le passage des heures int nbtipmn = 0; // index courant dans tableau comptage par minutes int nbtiph = 0; // index courant dans tableau comptage par jours int countParMinute = 0; long countParJour = 0; boolean depassement; // vrai si dépassement de capacité de comptage. unsigned long timePreviousMeasure = 0; // pour mesurer le temps pour le comptage float radiationValueMinute = 0.0; float radiationValueJour = 0.0; char recu[max_recu]; int irecu = 0; int iweeprom = 0; // index pour écriture en EEPROM. 0 au boot. boolean heeprom = false; // pas de comptage horaire en cours word countheeprom = 0; // pour comptage minutes pour EEPROM long valheeprom = 0; // pour comptages détection dans EEPROM // point d'entrée du programme. void setup(){ pinMode(geiger_input, INPUT); // initialisation entrée interruption digitalWrite(geiger_input,HIGH); for (int i=0;i<5;i++){ pinMode(ledArray[i],OUTPUT); // initialisation sorties pour les LEDs... digitalWrite(ledArray[i],LOW); // par défaut éteintes } Serial.begin(19200); // Vitesse port série (19200 bps) //Initialisation du nombre de colonnes et lignes de l'afficheur lcd.begin(16, 2); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Board - Arduino"); // texte accueil en colonne 0, ligne 0 lcd.setCursor(0,1); lcd.print("P. Chour "); lcd.print(version_pgm); // texte accueil en colonne 0, ligne 1 delay(2000); // petit temps d'attente pour pouvoir lire. lcd.clear(); // on efface tout lcd.setCursor(0, 0); // Curseur en colonne 0, ligne 0 lcd.print(" Initialisation"); // texte initialisation en colonne 0, ligne 0 // principe de comptage : un tableau comportant "periode_par_minute" positions // est utilisé pour calculer une moyenne glissante. Ex : si une période de comptage est // 5s, alors, il y a 12 périodes de comptage par minute. Ce tableau est initialisé // à 0 au démarrage. // Il faut attendre une minute pour que la moyenne de comptage soit // correcte. for (int i = 0; i < periode_par_minute;i++) { countMoyenneMin[i] = 0; } // on initialise les tableaux pour comptage par heure sur 24H for (int i = 0; i < 25; i++) { countMoyenneHeure[i] = 0; } #if USE_LED //---------------------------- section LED // on fait clignoter la barre de LEDs // A supprimer si on n'utilise pas les LEDs // et si on veut abaisser la consommation. for (int j = 0; j < 5; j++) { for (int i = 0;i < 5; i++) { ledVar(i); delay(100); } for (int i = 4; i>=0;i--) { ledVar(i); delay(100); } } // on éteint la barre de lED ledVar(0); #endif //--------------------------------- fin section LED Serial.print("VP="); // rapel version programme Serial.println(version_pgm); Serial.print("CF="); // rappel valeur du "conversion factor" à l'hôte. Serial.println(conversion_factor,5); set_sleep_mode(SLEEP_MODE_IDLE); // Type de "sleep mode" sleep_enable(); // active le bit "sleep" dans le registre MCUCR // La fonction "sleep" est maintenant activable MsTimer2::set(periode*1000, bidon); // Réveiller le processeur au moins toute les "periodes" // si pas d'événements MsTimer2::start(); count = 0; // initialisation nombre de comptage à 0. timePreviousMeasure = millis(); // Initialisation compteur de temps à valeur courante // fonction de comptage sur INT0 attachInterrupt(0,countPulse,FALLING); } // juste pour le timer 2. Ne fait rien ! Par contre, l'interruption fait sortir // le processeur du mode idle et la fonction loop redémarre. void bidon() { } // Boucle principale. Se répète indéfiniment. void loop(){ if (millis()-timePreviousMeasure >= periode*1000){ // on affiche une mesure toute les periodes. Attention // milli() fonctionne sur 50 jours environ. // en cas de débordement, on a une erreur de temps pouvant aller jusque'à Periode secondes timePreviousMeasure = timePreviousMeasure+periode*1000; // mise à jour du compteur countMoyenneMin[nbtipmn] = count; if (heeprom) { // si on doit écrire en EEPROM valheeprom = valheeprom + count; // alors, on incrémente } count = 0; // Nb de comptage par minutes. Il faut attende une minute pour que // le comptage soit valide. countParMinute = 0; for (int i = 0; i < periode_par_minute; i++) { countParMinute = countParMinute+countMoyenneMin[i]; } // La valeur en µSievert est égale à la moyenne du comptage par // minute multiplié par un facteur de conversion. radiationValueMinute = countParMinute*conversion_factor; // mise à jour de l'index du compteur par période de temps // si on est en dessous d'une minute, on incrémente le compteur nbtipmn = nbtipmn+1; if (nbtipmn >= periode_par_minute) { // sinon, on vient de passer une minute donc on revient au début du tableau (tableau circulaire) nbtipmn = 0; // On calcule combien de minutes se sont écoulées sur la période glissante courante de 24h. // Au début du comptage, le nb de minutes évolue de 0 à 24*60. Ce nb est à mémoriser // pour permettre le calcul de la moyenne alors que l'on n'a pas atteind 24H. Lorsque le // compteur à atteind 24H (24*60), une journée complète a été comptée. On peut donc calculer la moyenne // sur les dernières 24H. // Note : Dans le tableau de comptage par heure, la valeur -1 correspond à un débordement. // Tant qu'une valeur -1 est présente dans le tableau, la moyenne sur 24h00 n'est plus calculable. // On affiche alors *****. if (nbMinutes24h <= nb_minutes_par_24h) { nbMinutes24h = nbMinutes24h+1; } nbMinutes = nbMinutes+1; // On calcule ici le nombre d'impulsion sur 24H glissant if (countMoyenneHeure[nbtiph] != (-1)) { // si pas débordement countMoyenneHeure[nbtiph] += countParMinute; if (countMoyenneHeure[nbtiph] < 0) { countMoyenneHeure[nbtiph] = (-1); // débordement } } // on envoie la valeur du comptage par minute à l'hôte. Serial.print("CM="); Serial.println(countParMinute,DEC); delay(DelaiGarde); if (heeprom) { countheeprom = countheeprom+1; // une minute de plus } countParJour = 0; depassement = false; // pas d'overflow for (int i = 0; i < 25;i++) { if (countMoyenneHeure[i] == (-1)) { depassement =true; } countParJour = countMoyenneHeure[i]+countParJour; } if (!depassement) { if (nbMinutes24h <= nb_minutes_par_24h) { // si on n'a pas encore fait 24H countParJour = countParJour / nbMinutes24h; } else { // on a fait plus de 24h countParJour = countParJour - countMoyenneHeure[nbtiph]; // on vire l'heure en cours countParJour = countParJour / nb_minutes_par_24h; } radiationValueJour = countParJour*conversion_factor; } if (nbMinutes > 60) { nbMinutes = 0; nbtiph = nbtiph+1; if (nbtiph > 24) { nbtiph = 0; } countMoyenneHeure[nbtiph] = 0; } if ((heeprom) && (countheeprom >= 60)) { // traitement mémorisation EEPROM : si on a fait 60 mn... if (iweeprom < (maxeeprom-4)) { // si on ne dépasse pas la taille mémoire EEPROM.write(iweeprom+2,0); // on postionne la valeur d'arrêt EEPROM.write(iweeprom+3,0); if (valheeprom < 0x0000FFFF) { // si pas de dépassement... if (valheeprom == 0) { valheeprom = 1; } // valeur 0 interdite !!!!!! EEPROM.write(iweeprom,highByte(word(valheeprom))); EEPROM.write(iweeprom+1,lowByte(word(valheeprom))); } else { // si dépassement, on écrit -1 EEPROM.write(iweeprom,0xFF); EEPROM.write(iweeprom+1,0xFF); } iweeprom = iweeprom+2; valheeprom = 0; countheeprom = 0; delay(DelaiGarde); } } } // affichage valeur par minutes lcd.clear(); lcd.setCursor(0, 0); // affichage comptage par minute lcd.print("Cpt="); lcd.print(countParMinute); // Affichage µSv/h sur base comptage par minute lcd.setCursor(0, 1); lcd.print("uSv="); lcd.print(radiationValueMinute,3); lcd.setCursor(10, 0); // affichage indicateur mémorisation en cours if (heeprom) { lcd.print("*"); } else { lcd.print(" "); } if (countParJour != 0) { // on affiche le comptage sur base jour que si on a commencé à compter // affichage par jour lcd.setCursor(11, 0); // affichage moyenne comptage minute sur un jour lcd.print(countParJour); // Affichage µSv/h sur base comptage par jour lcd.setCursor(11, 1); if (depassement) { lcd.print("*****"); } else { lcd.print(radiationValueJour,3); } } // On peut supprimer l'affichage sur la barre de LEDs si // on ne l'utilise pas. Voir #define USE_LED #if USE_LED // pour le bargraph, on affiche la valeur instantanée countParMinute = count*periode_par_minute; //led var setting if(countParMinute <= TH1) ledVar(0); if((countParMinute <= TH2)&&(countParMinute>TH1)) ledVar(1); if((countParMinute <= TH3)&&(countParMinute>TH2)) ledVar(2); if((countParMinute <= TH4)&&(countParMinute>TH3)) ledVar(3); if((countParMinute <= TH5)&&(countParMinute>TH4)) ledVar(4); if(countParMinute > TH5) ledVar(5); #endif } trtIO(); MsTimer2::start(); // on veut être sûr d'être réveillé toute les x secondes sleep_mode(); // On met le programme en "sleep" // ... sleep_disable(); // Programme réveillé. On désactive le mode sleep // disable sleep... MsTimer2::stop(); // on arrête le timer } void trtIO() { int ireeprom; word donnee; if (Serial.available() > 0) { // lecture des octets reçus recu[irecu] = char(Serial.read()) & 0x7F; if (irecu < max_recu) { if (recu[irecu]==char(13)) { // traitement de la commande switch (recu[0]) { case 'B' : // boot soft asm volatile (" jmp 0"); break; case 'V' : // version programme Serial.print("VP="); Serial.println(version_pgm); delay(DelaiGarde); break; case 'F' : Serial.print("CF="); // rappel valeur du "conversion factor" à l'hôte. Serial.println(conversion_factor,5); delay(DelaiGarde); break; case 'I' : iweeprom = 0; // on ne fait pas de contrôle de cohérence for (int i=2;i<18;i++) { // rappel format commande : IAA/MM/JJHH:MN EEPROM.write(iweeprom,recu[i]); iweeprom = iweeprom+1; } EEPROM.write(16,0); // 0 = caractère d'arrêt EEPROM.write(17,0); countheeprom = 0; // nb de minutes valheeprom = 0; // nb de comptages heeprom = true; // désormais, on mémorise en EEPROM iweeprom = 16; Serial.println("INOK"); // acquittement de la demande delay(DelaiGarde); break; case 'D' : // download EEPROM ireeprom = EEPROM.read(0)|EEPROM.read(1)|EEPROM.read(2); if (ireeprom == 0xFF) { Serial.println("DL=NODATA"); // EEPROM PROBABLEMENT jamais écrite delay(DelaiGarde); } else { Serial.print("DL="); for (ireeprom=0; ireeprom<=15; ireeprom++) { // 16 premiers caractères = Date/Heure Serial.print(char(EEPROM.read(ireeprom))); } Serial.println(""); ireeprom = 16; while ((ireeprom <= maxeeprom) && ((EEPROM.read(ireeprom) | EEPROM.read(ireeprom+1)) != 0)) { Serial.print("DL="); donnee = EEPROM.read(ireeprom); donnee = ((unsigned int)donnee << 8) | EEPROM.read(ireeprom+1); Serial.println(donnee,DEC); ireeprom = ireeprom+2; } Serial.println("DL=END"); delay(DelaiGarde); } break; } // réinitialisation réception irecu = 0; } else { irecu = irecu+1; } } else { irecu = 0; // on oublie tout } } } // fin TrtIO // Compte les impulsions sur INT0 void countPulse(){ detachInterrupt(0); // on empêche les autres interruptions sur cette entrée count++; // on augmente le nombre d'impulsions comptées de 1 while(digitalRead(2)==0) { } // on attend que l'impulsion retombe attachInterrupt(0,countPulse,FALLING); // et on réactive l'interruption } #if USE_LED // allume / éteint la barre de LED // value = 0 : on éteint tout // = i : on allume les LED jusqu'à i et on éteint les autres // ce programme peut être supprimé si on n'utilise pas la barre de LEDs. Voir #define USE_LED void ledVar(int value){ if (value > 0){ for(int i = 0; i < value; i++){ digitalWrite(ledArray[i],HIGH); } for(int i = value; i <= 4; i++){ digitalWrite(ledArray[i],LOW); } } else { for(int i=4;i>=0;i--){ digitalWrite(ledArray[i],LOW); } } } #endif