| |
— | telecommande:ext1 [2019/08/13 10:16] (Version actuelle) – créée - modification externe 127.0.0.1 |
---|
| ====== Test avec un encoder/switch ====== |
| |
| La reconnaissance vocale n'étant pas fiable, j'ai cherché un autre moyen de piloter mon module.\\ |
| Je me suis tourné vers un encodeur/switch. |
| |
| [[http://www.aliexpress.com/snapshot/6536924073.html?orderId=66197489434089|Ma commande aliexpress]] |
| |
| Je vous invite à regarder une page google pour en savoir plus sur les encodeurs.\\ |
| [[https://www.google.fr/search?q=arduino+encoder&biw=1920&bih=894&tbm=isch&tbo=u&source=univ&sa=X&ei=9lx0VcTvHMzsUsjugdgL&sqi=2&ved=0CCwQsAQ|Recherche google]] |
| |
| En gros on récupère un signal de cette forme aux bornes de codeur.\\ |
| Suivant le décalage De A ou B on connais le sens et la vitesse.\\ |
| {{wiki:rotaryencoderwaveform.gif?300 |}} \\ |
| |
| |
| |
| Afin de voir dans un menu le résultat de la rotation du codeur, j'ai ajouter un écran LCD 2x16 en I2C.\\ |
| Et pour le fun, une led RGB !\\ |
| Je me suis créer une petit maquette avec le fruit de mes réflexions sur l'émission IR et le capteur de lumière. |
| |
| ====== Schémas ====== |
| Sous eagle comme d'hab. |
| |
| |
| ====== Programmation ====== |
| Comme je voulais laisser la place pour un émetteur/récepteur RF433MHz et un récepteur IF.\\ |
| J'ai été obligé de laisser les pattes : 2,3,10 et 11 disponibles.\\ |
| J'avais donc un problème pour le codeur et le switch afin de récupérer une action rapidement.\\ |
| J'ai découvert que quasi toutes les pattes de l'arduino pouvait générer une interruption, du coup plus de soucis.\\ |
| J'ai commencé avec la librairie attachinterrupt :\\ |
| [[http://www.arduino.cc/en/Reference/AttachInterrupt]] \\ |
| Puis utilisé EnableInterrupt qui est plus récent et mis à jour :\\ |
| [[https://github.com/GreyGnome/EnableInterrupt]] |
| |
| ====== Quelques mots sur le code ====== |
| Tout n'est pas de moi !\\ |
| J'ai pris des exemples à droite et gauche puis assemblé le tout.\\ |
| Les sources sont cités au début.\\ |
| Le menu n'a que 5 choix, mais on peu en ajouter plus et même créer des sous menus.\\ |
| Il n'y a pas la gestion RF et récepteur IF comprise. Pour l'instant je suis sur une maquette. |
| |
| <code c++> |
| /* Logiciel des fonctions de la platine |
| * exemple lcd de la lib liquidcrystal_i2c |
| * encodeur sur http://bildr.org/2012/08/rotary-encoder-arduino/ |
| * Encodeur utilise EnableInterrupt |
| * DHT11 http://total-informatique.com/utiliser-le-dht11-avec-un-ecran-lcd/ |
| * RGB http://www.mbeckler.org/microcontrollers/rgb_led/ |
| * Menu https://skyduino.wordpress.com/2014/07/06/arduino-lcd-faire-un-menu-sous-forme-de-liste/ |
| * |
| * Synoptique : |
| * On affiche un message de bienvenue |
| * Affiche température et humidité |
| * Si bouton tourne ou push |
| * Affiche menu |
| * Gestion menu |
| */ |
| |
| #include <avr/pgmspace.h> // library for keeping variables in Flash RAM |
| #include "Wire.h" |
| #include "LiquidCrystal_I2C.h" |
| #include "DHT.h" // Librairie pour le capteur DHT |
| #include <IRremote.h> |
| #include <EnableInterrupt.h> |
| |
| // ### Menu ### |
| prog_char const mainMenu1[] PROGMEM = "1.Television "; |
| prog_char const mainMenu2[] PROGMEM = "2.XBMC "; |
| prog_char const mainMenu3[] PROGMEM = "3.Lum centre "; |
| prog_char const mainMenu4[] PROGMEM = "4.Lum bandeau"; |
| prog_char const mainMenu5[] PROGMEM = "5.Luminosite"; |
| const char* const mainMenu[] PROGMEM = { |
| mainMenu1, mainMenu2, mainMenu3, mainMenu4, mainMenu5}; |
| |
| // Data télécommande |
| #define cmd_code 0xffffffff // remote code pour transmettre. |
| #define Tv_onoff 0x20df10ef // Codes des télécommandes |
| #define Tv_volP 0x20df40bf |
| #define Tv_volM 0x20dfc03f |
| #define Ampli_on 0x7e817e81 |
| #define Ampli_off 0x7e81fe01 |
| #define Ampli3 0x5eA1609e |
| #define Ampli2 0x5eA1c03e |
| #define Ampli_volP 0x5eA158a7 |
| #define Ampli_volM 0x5eA1d827 // Codes des télécommandes |
| |
| // ### Definition DHT ### |
| #define DHTPIN 6 //Pin auquel est connecté le capteur DHT |
| #define DHTTYPE DHT11 //Si vous utiliser le DHT 11 |
| //#define DHTTYPE DHT22 //Si vous utiliser le DHT 22 (AM2302) |
| //#define DHTTYPE DHT21 //Si vous utiliser le DHT 21 (AM2301) |
| |
| // ### Definition RGB ### |
| #define slen 7 // 7 characters, e.g. '#ff6666' |
| |
| /* Définition IR */ |
| #define REMOTE_BIT 3532 |
| #define tempsIR 100 // Temps entre 2 commandes IR |
| |
| // ### Definition senseur lumière ### |
| #define LUM_SENSOR_PIN A0 // lumière sensor connected to this analog pin |
| |
| // Var pour DHT |
| float fltHumidity; //Pourcentage d'humidité mesuré |
| float fltTemperature; //Température mesurée en Celsius |
| float hum; // ancienne val humidité |
| float temp; // ancienne val température |
| |
| // Var pour RGB |
| int redPin = 10; // Red LED, connected to digital pin 9 |
| int greenPin = 9; // Green LED, connected to digital pin 10 |
| int bluePin = 12; // Blue LED, connected to digital pin 11 |
| |
| // ### Definition Encoder ### |
| //these pins can not be changed 2/3 are special pins |
| #define encoderPin1 7 |
| #define encoderPin2 8 |
| #define encoderSwitchPin 4 //push button switch |
| |
| volatile int lastEncoded = 0; |
| volatile long encoderValue = 0; |
| |
| //long lastencoderValue = 0; |
| long ancienencoderValue = 0; |
| |
| // ==== Variables Générales ==== |
| const int intTimePause = 5000; //Par défaut on actualise les valeures toutes les 5 secondes |
| long position = -999; |
| char serInStr[slen]; // array to hold the incoming serial string bytes |
| |
| boolean TV = false; |
| boolean sortm = false; |
| unsigned long TimeOut; |
| char buffer[16]; // make sure this is large enough for the largest string it must hold |
| //char prompt = "Choisissez !"; |
| |
| //IR LED must be connected to Arduino PWM pin 3. |
| IRsend irsend; // innitialise l' IR object |
| |
| LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display |
| DHT dht(DHTPIN, DHTTYPE); //On initialise le capteur DHT |
| |
| boolean bp=false; |
| int r, v, b; |
| |
| void BPtest() { |
| bp=true; // Renvoie bp vrai si bouton pressé |
| } |
| |
| void updateEncoder() { |
| int MSB = digitalRead(encoderPin1); //MSB = most significant bit |
| int LSB = digitalRead(encoderPin2); //LSB = least significant bit |
| |
| int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number |
| int sum = (lastEncoded << 2) | encoded; //adding it to the previous encoded value |
| |
| if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++; |
| if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --; |
| |
| lastEncoded = encoded; //store this value for next time |
| // Renvoie la valeur encoderValue contenant la position. |
| } |
| |
| // Attach the interrupt in setup() |
| void setup() { |
| |
| Serial.begin(115200); |
| lcd.init(); // initialize the lcd |
| |
| pinMode(encoderPin1, INPUT_PULLUP); // Défini les pattes de l'encodeur |
| pinMode(encoderPin2, INPUT_PULLUP); |
| pinMode(encoderSwitchPin, INPUT_PULLUP); |
| |
| enableInterrupt(encoderPin1, updateEncoder, CHANGE); |
| enableInterrupt(encoderPin2, updateEncoder, CHANGE); |
| enableInterrupt(encoderSwitchPin, BPtest, CHANGE); |
| |
| pinMode(redPin, OUTPUT); // sets the pins LED RGB as output |
| pinMode(greenPin, OUTPUT); |
| pinMode(bluePin, OUTPUT); |
| |
| ancienencoderValue=encoderValue=0; |
| bp=false; |
| |
| // Message de bienvenue sur le LCD. |
| lcd.backlight(); |
| lcd.print("Salut le monde!"); |
| lcd.setCursor(0, 1); |
| lcd.print("Tourne le bouton"); |
| delay(1500); |
| lcd.clear(); |
| |
| } |
| |
| // Affiche une couleur de led |
| void led_rgb(int teinte) { |
| HSVtoRGB(&r, &v, &b, teinte, 255, 255); |
| analogWrite(redPin, r ); |
| analogWrite(greenPin, v ); |
| analogWrite(bluePin, b ); |
| } //Fin du void |
| |
| |
| void loop() { |
| |
| //Affiche la temp/humidité si pas menu |
| tmphum(); // Affiche temp et humidité |
| |
| //Test, gestion menu |
| if (ancienencoderValue != encoderValue) { // Si le bouton tourne |
| Serial.println("tourne"); |
| affmenu3(); |
| } |
| |
| // Affiche une led rouge prete |
| led_rgb(0); |
| |
| } //FIN DE LOOP |
| |
| |
| // *** Affiche le choix du menu suivant la position de l'encoder |
| // Change aussi la couleur de la led *** |
| void affmenu3() { |
| Serial.print("Entree dans le choix"); //Serial.println(bp); |
| /* Variable pour le menu */ |
| int nbItems = 5; // Défini le nb d'irem dans le menu |
| byte selectedMenuItem = 1; // Choix sélectionné |
| byte shouldExitMenu = false; // Devient true quand l'utilisateur veut quitter le menu |
| unsigned long TempMax; |
| boolean boucle = false; // Test de boucle pour aff |
| long color; // Stock la couleur |
| int ValC[ ]= {40, 80, 120, 160, 200}; |
| |
| // Affiche une premiere valeur |
| lcd.clear(); |
| lcd.print("Choisissez !"); |
| strcpy_P(buffer, (char*)pgm_read_word(&(mainMenu[selectedMenuItem-1]))); |
| lcd.setCursor(0, 1); |
| lcd.print(buffer); |
| TempMax=millis(); |
| |
| while ((!bp) && (millis() < TempMax+20000)) { // tant que bp off et tempsMAx < |
| /* change la led rgd */ |
| led_rgb(ValC[selectedMenuItem+1]); |
| |
| /* Gére le sens du codeur */ |
| long encoder = encoderValue - ancienencoderValue; |
| Serial.println(selectedMenuItem); |
| //Serial.print("Encoder :"); Serial.println(encoder); |
| if (encoder != 0) { |
| |
| if (encoder > 0) { // on inc |
| /* S'il existe un choix précédent */ |
| if(selectedMenuItem > 1) { |
| selectedMenuItem--; |
| } |
| } else { // on dec |
| /* S'il existe un choix suivant */ |
| if(selectedMenuItem < nbItems) { |
| |
| /* Passe au choix suivant */ |
| selectedMenuItem++; |
| } else { |
| selectedMenuItem=nbItems; |
| } |
| } |
| |
| // Affiche le nouveau menu |
| lcd.setCursor(0, 1); |
| lcd.print(" "); // Aff ligne vide |
| strcpy_P(buffer, (char*)pgm_read_word(&(mainMenu[selectedMenuItem-1]))); |
| lcd.setCursor(0, 1); |
| lcd.print(buffer); |
| |
| Serial.print("Menu :");Serial.println(selectedMenuItem); |
| } |
| |
| ancienencoderValue=encoderValue; |
| |
| } |
| /* Bouton appuyé */ |
| //Serial.print("bp appuyé :"); Serial.println(bp); |
| if(bp) { |
| displayChoice(selectedMenuItem); |
| } |
| |
| bp=false; |
| led_rgb(0); |
| |
| } // Fin du void |
| |
| |
| void tmphum() { // Lit le capteur et affiche les résultats. |
| |
| fltHumidity = dht.readHumidity(); //On lit le pourcentage d'humidité |
| fltTemperature = dht.readTemperature(); //On lit la température en degrés Celsuis |
| if (isnan(fltTemperature) || isnan(fltHumidity)) //Si les valeures retournées ne sont pas des nombres : |
| { |
| lcd.setCursor(0, 1); //Positionnement du curseur |
| lcd.print(DHTTYPE); //On affiche le type de capteur |
| lcd.setCursor(5, 1); |
| lcd.print(" illisible"); //On affiche l'erreur |
| } |
| else |
| { |
| if ((hum != fltHumidity) || (temp != fltTemperature)) lcd.clear(); |
| //Serial.print("Lecture temp/hum"); Serial.println(fltTemperature); |
| |
| //mise en forme et affichage des informations sur l'écran LCD |
| //lcd.setdelay(intTimePause); //On actualise les informations toutes les x millisecondes.Cursor(0, 0); //Positionnement du curseur |
| if (hum != fltHumidity) { |
| lcd.setCursor(0, 0); |
| lcd.print(" "); // Aff ligne videlcd.print( |
| } |
| lcd.setCursor(0, 0); |
| lcd.print("Degres : "); |
| lcd.setCursor(9, 0); |
| lcd.print(fltTemperature); //Affichage de la température |
| lcd.setCursor(13, 0); |
| lcd.print((char)223); //Affiche le caractère ° (degrés) |
| lcd.setCursor(14, 0); |
| lcd.print("C"); //En degrés Celsuis |
| if (temp != fltTemperature) { |
| lcd.setCursor(0, 1); |
| lcd.print(" "); // Aff ligne videlcd.print( |
| } |
| lcd.setCursor(0, 1); |
| lcd.print("Humidite : "); |
| lcd.setCursor(11, 1); |
| lcd.print(fltHumidity); //Affichage de l'humidité |
| lcd.setCursor(15, 1); |
| lcd.print("%"); |
| } |
| |
| //delay(intTimePause); //On actualise les informations toutes les x millisecondes. |
| |
| temp = fltTemperature; |
| hum = fltHumidity; |
| } |
| |
| |
| /** Affiche le choix de l'utilisateur */ |
| void displayChoice(byte selectedMenuItem) { |
| |
| bp=false; |
| /* Affiche le choix de l'utilisateur */ |
| lcd.clear(); |
| lcd.print(F("Z'avez choisi :")); |
| lcd.setCursor(0, 1); |
| strcpy_P(buffer, (char*)pgm_read_word(&(mainMenu[selectedMenuItem]))); |
| lcd.print(buffer); |
| delay(500); |
| |
| /* Selection de l'ordre */ |
| switch(selectedMenuItem) { |
| case 0 : //television |
| lcd.clear(); |
| lcd.print(F("Television")); |
| if (!TV) { // Tv pas allumé |
| Serial.write("ordre tv on");Serial.println(selectedMenuItem); |
| irsend.sendNEC(Ampli3, REMOTE_BIT); |
| // irsend.sendNEC(cmd_code, REMOTE_BIT); |
| // delay(tempsIR); |
| irsend.sendNEC(0x20df10ef, 3532); |
| // irsend.sendNEC(cmd_code, REMOTE_BIT); |
| // delay(tempsIR); |
| TV=true; |
| } |
| else { |
| Serial.write("ordre tv off"); |
| irsend.sendNEC(Ampli_off, REMOTE_BIT); |
| irsend.sendNEC(cmd_code, REMOTE_BIT); |
| delay(tempsIR); |
| irsend.sendNEC(Tv_onoff, REMOTE_BIT); |
| irsend.sendNEC(cmd_code, REMOTE_BIT); |
| delay(tempsIR); |
| TV=false; |
| } |
| break; |
| |
| case 1 : //XBMC |
| lcd.clear(); |
| lcd.print(F("XBMC")); |
| if (!TV) { // xbmc pas allumé |
| Serial.write("ordre xbmc on"); |
| irsend.sendNEC(Ampli2, REMOTE_BIT); |
| irsend.sendNEC(cmd_code, REMOTE_BIT); |
| delay(tempsIR); |
| irsend.sendNEC(Tv_onoff, REMOTE_BIT); |
| irsend.sendNEC(cmd_code, REMOTE_BIT); |
| delay(tempsIR); |
| TV=true; |
| } |
| else { |
| Serial.write("ordre xbmc off"); |
| irsend.sendNEC(Ampli_off, REMOTE_BIT); |
| irsend.sendNEC(cmd_code, REMOTE_BIT); |
| delay(tempsIR); |
| irsend.sendNEC(Tv_onoff, REMOTE_BIT); |
| irsend.sendNEC(cmd_code, REMOTE_BIT); |
| delay(tempsIR); |
| TV=false; |
| } |
| break; |
| case 2 : //Lumière table |
| lcd.clear(); |
| lcd.print(F("Lum Table")); |
| break; |
| case 3 : //Lumière bandeau |
| lcd.clear(); |
| lcd.print(F("Lum bandeau")); |
| break; |
| case 4 : //Luminosité |
| lumin(); |
| break; |
| delay(2000); |
| } |
| bp=false; |
| Serial.println("Fin d'ordre"); |
| |
| } //Fin displayChoice |
| |
| |
| void lumin() { //Affiche la luminosité meusurée |
| long tempsMax; |
| lcd.clear(); |
| lcd.print(F("Luminosite")); |
| //Serial.print("bp > :"); Serial.println(bp); |
| //delay(50); |
| while (!bp) { |
| tempsMax = millis(); |
| //Serial.print(digitalRead(encoderSwitchPin)); Serial.print(encoderValue); Serial.println(ancienencoderValue); |
| lcd.setCursor(0, 1); |
| lcd.print(" "); // Aff ligne videlcd.print( |
| lcd.setCursor(0, 1); //Positionnement du curseur |
| lcd.print(analogRead(LUM_SENSOR_PIN)); |
| //delay(200); |
| while (millis() < tempsMax+500) { |
| } |
| } |
| bp=false; |
| } //Fin lumin |
| |
| // *** Convertie une lumiére TSV (teinte, saturation, valeur) [HSVen anglais] en RGB (hackable N°6) |
| void HSVtoRGB(int *r, int *g, int *b, int h, int s, int v) { |
| int c; |
| long l, m, n; |
| |
| // saturation zéro, pas de couleur |
| if (s == 0) { |
| *r = *g = *b = v; |
| return; |
| } |
| |
| // chroma |
| c = ((h % 60) * 255) / 60; |
| h /= 60; |
| |
| // intermédiaire |
| l = (v * (256 - s)) / 256; |
| m = (v * (256 - (s * c) / 256)) / 256; |
| n = (v * (256 - (s * (256 - c)) / 256)) / 256; |
| |
| // choix dominante |
| switch (h) { |
| case 0: |
| *r = v; *g = n; *b = l; |
| break; |
| case 1: |
| *r = m; *g = v; *b = l; |
| break; |
| case 2: |
| *r = l; *g = v; *b = n; |
| break; |
| case 3: |
| *r = l; *g = m; *b = v; |
| break; |
| case 4: |
| *r = n; *g = l; *b = v; |
| break; |
| default: |
| *r = v; *g = l; *b = m; |
| break; |
| } |
| } // Fin HSVtoRGB |
| |
| |
| </code> |
| |
| |
| ======= Quelques mots sur la finalisation du projet ======= |
| |
| J'ai pensé mettre ce module dans un cylindre avec 1 bague tournante et l'afficheur en haut derrière un plexi fume.\\ |
| Les diodes IF seraient à la base tournées dans tout les sens.\\ |
| On peu prévoir un alim par induction sur un socle.\\ |
| Le codeur demandera un peu de mécanique pour que la bague l’entraîne mais avec le possibilité d'appuyer pour déclencher le switch.\\ |
| |
| |
| ======= BILAN ======= |
| Un encodeur c'est pas mal à condition d'utiliser les interruptions.\\ |
| Sinon on loupe des crans, mais malgré les int., on ne peu pas tourner trop vite.\\ |
| Sous mon code j'ai des pas de 4 à chaque cran, construction du codeur ? Erreur de prog ?\\ |
| Je ne sais pas, mais il faut y penser dans le code. |