Différents montages Arduino

L'Arduino est un composant très sympathique qui se programme en C++ compilé
Le compilateur est gratuit. Il possède une grande quantité d'entrées et sorties, numérique,
analogique et permet même de piloter en PWM.

J'ai choisi un composant compatible le SODIAL NANO V3.0 à moins de 2€ avec le cable. Même en cas de mauvaise manipulation, y'a pas de mal!

Caractéristiques:

Voir le câblage Arduino Nano/ broches ICSP
Le capteur à fourche

Montage du capteur à fourche ITR9606.

Le programme suivant permet de savoir si il y a quelque chose entre les fourches.


const int encoderIn = 8; // Entrée D8  sur l'arduino 
const int statusLED = 13; // Sortie sur la led L de la carte
int detectState=0; // Variable pour lire le statu
void setup()
    {
       pinMode(encoderIn, INPUT); //Set pin 8 as input
       pinMode(statusLED, OUTPUT); //Set pin 13 as output
       Serial.begin(9600);
    }
void loop() {
	detectState=digitalRead(encoderIn);
	if (detectState == HIGH) { //If encoder output is high
		digitalWrite(statusLED, HIGH); //Turn on the status LED
		Serial.println("Objet présent");
       }
	else {
		digitalWrite(statusLED, LOW); //Turn off the status LED
	   Serial.println("Objet Absent");
       }
    }
		

Et si nous voulions l'utiliser en capteur de vitesse de rotation :

ITR9606_rpm.ino

	// Définition des broches utilisé et du timeout
#define PULSE_PIN 2
#define PULSE_TIMEOUT 1000000
 
// Variable contenant la vitesse du moteur en rotations par minute
unsigned long rpm; 
  
// setup()
void setup () {  
  // Initialisation du port série
  Serial.begin(9600);
   
  // Place la broche de la sonde en entrée 
  pinMode(PULSE_PIN, INPUT);
   
  // Sonde à collecteur ouvert -> pull-up obligatoire
  digitalWrite(PULSE_PIN, HIGH);
} 
 
// loop()
void loop () { 
   
  // Mesure de la durée du temps bas en us
  rpm = pulseIn(PULSE_PIN, LOW, PULSE_TIMEOUT); 
   
  // Calcul de la vitesse en RPM à partir du temps bas en us
  rpm = 60 / (rpm / 1000000.0);
   
  // Affichage sur le port série
  Serial.print("N= "),Serial.print(rpm),Serial.println(" RPM");
   
  // Délai no-flood
  delay(500);
} 
	

Et si nous voulions l'utiliser en capteur de position :


	A faire
	
Le capteur photorésistant

Câblage

int photocellPin = 0; // the cell and 10K pulldown are connected to a0
int photocellReading; // the analog reading from the analog resistor divider

void setup(void) {
  // We'll send debugging information via the Serial monitor
  Serial.begin(9600);
}

void loop(void) {
  photocellReading = analogRead(photocellPin);
  Serial.println("Résultat analogique = ");
  Serial.println(photocellReading); // the raw analog reading
  // We'll have a few threshholds, qualitatively determined
  if (photocellReading > 10) {
    Serial.println(" - Noir");
  } else if (photocellReading > 200) {
    Serial.println(" - Sombre");
  } else if (photocellReading > 500) {
    Serial.println(" - Lumiere");
  } else if (photocellReading > 800) {
    Serial.println(" - Lumineux");
  } else {
    Serial.println(" - Tres lumineux");
  }
  delay(5000); /*5 secondes */
}
HC-SR04 Capteur de distance
// [HC-SR04 Capteur de distance]
int trigPin=13; // On définis chaque Pin
int echoPin=12; // Arduino va communiquer via echo et trig 

void setup() 
{
 Serial.begin (9600); // On établis la liaison a 9600 Bauds
 // On définis les entrées et sorties
 pinMode(trigPin, OUTPUT);
 pinMode(echoPin, INPUT); 
}

void loop() {  
  long duration, distance;  
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
 /* On envoi une "salve" pendant une durée déterminé qui sera par la suite calculée */

 distance = (duration/2) / 29.1; // On calcule
 if (distance > 25) {
 /* ici « 25 » définis le fait qu'on ne signalera
 pas l'objet avant qu'il soit à 15cm du capteur */
  }

  if (distance <= 200 || distance >= 0){
 /* là on dit que si la distance de l'objet
 dépasse 200cm on affichera "Hors de portée" sur le port série */
Serial.println("Hors de portee");
  }
else 
{   
 Serial.print(distance);  
 Serial.println(" cm");
  }  delay(100);
}
PIR Capteur de présence IR

//Le temps laissé au capteur pour le calibrer (10 à 60 secondes selon la fiche technique)
//the time we give the sensor to calibrate (10-60 secs according to the datasheet)
int calibrationTime = 30;
int ledPin = 5;                // choisir la broche pour la LED
int inputPin = 7;               // choisir la broche d'entrée ( pour le capteur PIR )
int pirState = LOW;             // nous commençons , en supposant qu'aucun mouvement détecté
int val = 0;                    // variable pour la lecture de l'état de la broche

void setup() {
  pinMode(ledPin, OUTPUT);      // déclarer comme sortie LED
  pinMode(inputPin, INPUT);     // déclarer capteur en tant qu'entrée
  Serial.begin(9600);

  Serial.print("Etalonnage capteur PIR ");
  for (int i = 0; i < calibrationTime; i++) {
    Serial.print(".");
    digitalWrite(ledPin, HIGH);
    delay(500);
    digitalWrite(ledPin, LOW);
    delay(500);
  }
}

void loop() {
  val = digitalRead(inputPin);  //lire la valeur d'entrée
  
  //Serial.println(val);
  
  if (val == HIGH) { // vérifier si l'entrée est HIGH
    digitalWrite(ledPin, HIGH);  // passer LED ON
    delay(150);

    if (pirState == LOW) {
      // nous venons allumé      
      // Nous voulons seulement sortir sur le changement de sortie ,
      // pas le changement d'état
      pirState = HIGH;
      Serial.println("Un mouvement detecte!");
    }
  } else {
    digitalWrite(ledPin, LOW); // turn LED OFF
    delay(300);
    if (pirState == HIGH) {
      // We only want to print on the output change, not state
      pirState = LOW;
      // we have just turned off
      Serial.println("Pas ou plus de mouvement!");
    }
  }
}
Capteur effet Hall Magnétique Y3144

Capteur effet Hall 4. 5-24V, Détecteur magnétique
Dans un premier temps, capteur de présence magnétique.



/*
Capteur effet Hall Y3144 (C) Sammy76 - V1.0
Présence d'un champ magnétique
*/
int hallPin = 2;
int ledPin = 3;
int hallState;

void setup(){
  Serial.begin(9600);
  pinMode(hallPin, INPUT);
  pinMode(ledPin, OUTPUT);
}
void loop(){
  hallState = digitalRead(hallPin);
  if (hallState == HIGH){
    Serial.print("Pas de signal, Etat: ");
    digitalWrite(ledPin, LOW);
  }
  if (hallState == LOW){
    Serial.print("Source magnetique proche, Etat: ");
    digitalWrite(ledPin, HIGH);
  }
  Serial.println(hallState);
  delay(100);
}
		

Réalisation d'un tachymètre :
J'en profite pour vous mettre la distance parcouru si vous avez un rayon de rotation
Le principe est de mesurer le nombre d'impulsions pendant une durée.
Dans le programme ci-dessous, la durée étant de 3s, le si j'ai une impulsion durant ces 3s cela fait :
$N=\dfrac{1 \times 60}{3}=20~RPM$, c'est donc la précision minimum.

/* Capteur effet Hall Y3144 
 *  Tachymetre avec gestion des interruptions
(C) Sammy76 - V1.0 */
 
//Rayon en mm pour la vitesse de translation
#define RAYON 300
long duree_test = 3000; // test sur 3 secondes

const float Pi = 3.1415927;
// Variable contenant la vitesse du moteur en rotations par minute
unsigned long rpm=0; 
float ms;  

long chrono = 0; // valeur courante du chrono 
long chrono_depart = 0; // valeur de départ du chrono
volatile long nb_chgt = 0; // nb de changement etat Pin
  
// Gestion de l'interruption 0
void gere_int0() { 
    nb_chgt = nb_chgt + 1 ;  
}
  
void setup () {
   // Initialisation du port série
  Serial.begin(9600);  
  chrono_depart = millis();
// l'interruption zero correspond à la pin 2 
// on enregistre tous lorsque la broche passe de 
//l'état HAUT vers l'état BAS (front descendant)
  attachInterrupt(0,gere_int0,FALLING); 
}

void loop() {
  chrono = millis();
  //durée de test terminée?
  if (chrono - chrono_depart > duree_test) { 
   // Mesure sur 3 secondes :
   // il faut multiplier le nb de chgt par 20
   // pour avoir le nb de changement par minute
   
   rpm=nb_chgt*(60000/duree_test); //Nombre de changement
   ms=Pi*rpm*RAYON/30000; //v=omegaxR=(pi.N/30)x(R/1000)
  // Affichage sur le port série
  Serial.print("N="),Serial.print(rpm),Serial.print(" RPM, ");
  Serial.print("V="),Serial.print(ms),Serial.println(" m/s");        
     
   chrono_depart = millis(); 
   nb_chgt=0;
  }     
}

Autre technique de mesure, je mesure le temps entre deux impulsions.
Cette technique est plus précise.


/* Capteur effet Hall Y3144 
 *  Tachymetre avec gestion des interruptions
 *  principe de mesure de temps entre deux impulsions
(C) Sammy76 - V1.0 */
 
//Rayon en mm pour la vitesse de translation
#define RAYON 300
boolean front;
const float Pi = 3.1415927;
// Variable contenant la vitesse du moteur en rotations par minute
unsigned long rpm=0; 
float ms;  
long chrono_depart = 0; // valeur de départ du chrono

// Gestion de l'interruption 0
void gere_int0() { 
    front=true; 
}
  
void setup () {
   // Initialisation du port série
  Serial.begin(9600);
  chrono_depart = millis();
// l'interruption zero correspond à la pin 2 
// on enregistre tous lorsque la broche passe de 
//l'état HAUT vers l'état BAS (front descendant)
  attachInterrupt(0,gere_int0,FALLING); 
}

void loop() {
  //changement de front
  if (front){
    rpm=millis() - chrono_depart;
    front=false;
    //(rpm/1000) durée entre deux impulsions en seconde
    rpm = 60000 / rpm ;
    ms=Pi*rpm*RAYON/30000; //v=omegaxR=(pi.N/30)x(R/1000)
  // Affichage sur le port série
    Serial.print("N="),Serial.print(rpm),Serial.print(" RPM, ");
    Serial.print("V="),Serial.print(ms),Serial.println(" m/s");
    chrono_depart=millis();
    }
  }     

		
Le protocole i2C

I²C : Inter-Integrated Circuit chez certain constructeur ce bus s'appelle TWI (Two Wire Interface)
source Wikipedia, très bien faite!
Le programme suivant permet de connaitre les périphériques i²C connectés :


/* --------------------------------------
   i2c_scanner
 * Pin Connections:
 *      SCL = A5
 *      SDA = A4
 *      VCC = 5V
 *      GND = GND
 -------------------------------------- */

#include "Wire.h" //Pour les périphériques I2C


void setup()
{
  Wire.begin();

  Serial.begin(9600);
  while (!Serial);             // Attent le moniteur série
  Serial.println("\nI2C Scanner");
}


void loop()
{
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for (address = 1; address < 127; address++ )
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.print("Périphérique I²C touvé à l'addresse 0x");
      if (address < 16)
        Serial.print("0");
      Serial.print(address, HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error == 4)
    {
      Serial.print("Erreur inconnu à l'addresse 0x");
      if (address < 16)
        Serial.print("0");
      Serial.println(address, HEX);
    }
  }
  if (nDevices == 0)
    Serial.println("Pas de périphérique I2C trouvé\n");
  else
    Serial.println("fin\n");

  delay(5000);           // wait 5 seconds for next scan
}

LCD 1602 i2C
/*LCD1602 sur I2C
* Pin Connections:
 *      SCL = A5
 *      SDA = A4
 *      VCC = 5V
 *      GND = GND
*/
#include "Wire.h"  // Comes with Arduino IDE
/* Inclut la librairie pour le lcd */
#include "LiquidCrystal_I2C.h"

LiquidCrystal_I2C lcd(0x3f, 16, 2); //Adresse LCD1602 0x3F

/* Caractères personnalisés */
byte r0[8] = {
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000
}; // 0 / 5
byte r1[8] = {
  B10000,
  B10000,
  B10000,
  B10000,
  B10000,
  B10000,
  B10000,
  B10000
}; // 1 / 5
byte r2[8] = {
  B11000,
  B11000,
  B11000,
  B11000,
  B11000,
  B11000,
  B11000,
  B11000
}; // 2 / 5
byte r3[8] = {
  B11100,
  B11100,
  B11100,
  B11100,
  B11100,
  B11100,
  B11100,
  B11100
}; // 3 / 5
byte r4[8] = {
  B11110,
  B11110,
  B11110,
  B11110,
  B11110,
  B11110,
  B11110,
  B11110
}; // 4 / 5
byte r5[8] = {
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111
}; // 5 / 5

// Fonction dessinant le bargraph
void draw_bargraph(byte percent) {
  byte i, cp, cl;
  // Affiche la nouvelle valeur
  lcd.setCursor(0, 0);
  lcd.print(percent);
  lcd.print(" %   ");
  // Ligne suivante
  lcd.setCursor(0, 1);

  /* Map percent de (0 ~ 100) vers (0 ~ 80) ( 1 char = 5 colonnes, 16 * 5 = 80) */
  percent = map(percent, 0, 100, 0, 80);

  /* Calcul le nombre de cases pleines et le nombre de colonnes dans la dernière case */
  cp = percent / 5; //diviser par 5
  cl = percent % 5; //Reste de la division

  /* Dessine les cases pleines */
  for (i = 0; i < cp; ++i)
    lcd.write(5);

  /* Dessine la dernière case */
  lcd.write(cl);

  /* Dessine les cases vides restantes */
  for (i = 0; i < 16 - (cp + (cl ? 1 : 0)); ++i)
    lcd.write((uint8_t)0);
}

/* setup() */
void setup() {
  lcd.begin();
  /* Enregistre les caractères personnalisés dans le lcd */
  lcd.createChar(0, r0);
  lcd.createChar(1, r1);
  lcd.createChar(2, r2);
  lcd.createChar(3, r3);
  lcd.createChar(4, r4);
  lcd.createChar(5, r5);

  /* Initialise le lcd */

  lcd.clear();

  /* Départ à 0% */
  draw_bargraph(0);
}

/* loop() */
void loop() {

  /* Valeur en % du bargraph */
  static byte percent = 0;

  /* Indique si la valeur a été modifiée */

  /* Lit les boutons et agis en conséquence */

  /* Dessine le nouveau bargraph*/
  for (percent = 0; percent <= 100; percent = percent + 1) {
    draw_bargraph(percent);
  }


  /* Refresh 2Hz */
  delay(1000);

}
MAX6675 + thermocouple type K +LCD 1602 i2C

/********************************************************
MAX6675 avec thermocouple type K
GND --> Gnd
Vcc --> Vcc 5V
SO Data Output --> D4
CS Chip Select --> D5
CLK clock --> D6

LCD1602 sur i2C
1 VCC alimentation du module --> Vcc 3.3v à 5V
2 GND masse--> Gnd
3 SCL Serial Clock --> A5
4 SDA Serial Data --> A4
5 DRDY --> n/a, Data ReaDY non utilisé.
*/
#include "max6675.h"  //La librairie du MAX6675
#include "Wire.h"   //Librairie Wire pour la communication I2C
#include "LiquidCrystal_I2C.h"
LiquidCrystal_I2C lcd(0x3f, 16, 2); //Adresse LCD1602 0x3F
#define consigne 240 //240°C

byte copyright[8] = {
  B01110, B10101, B11011, B11001, B11001, B11011, B10101, B01110
};
uint8_t deg[8] = {
  B00110,
  B01001,
  B01001,
  B00110,
  B00000,
  B00000,
  B00000,
  B00000
};
uint8_t e_acc[8] = {
  B00010,
  B00100,
  B01110,
  B10001,
  B11111,
  B10000,
  B01110,
  B00000
};
byte up[8] =
{
  B00100,
  B01110,
  B11111,
  B10101,
  B00100,
  B00100,
  B00100,
  B00100
};
byte down[8] =
{
  B00100,
  B00100,
  B00100,
  B00100,
  B10101,
  B11111,
  B01110,
  B00100
};
int thermoDO = 4;  // Data Out Port SPI sur 4-5-6
int thermoCS = 5;  //Chip Select
int thermoCLK = 6;  //Clock

// Déclarer les pins utilisées
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);

void setup() {
  Serial.begin(9600);  //Pour afficher à l'écran du PC
  lcd.begin();
  lcd.createChar(0, up);
  lcd.createChar(1, down);
  lcd.createChar(6, copyright);
  lcd.createChar(7, deg);
  lcd.createChar(5, e_acc);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("LCD1602+MAX6675");
  lcd.setCursor(4, 1);
  lcd.write(6);
  lcd.print("Sammy76");
  delay(2000); //Attendre l'initialisation du module MAX mini 500
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Temp");
  lcd.write(5);
  lcd.print("rature:");
  lcd.print(consigne);
}

void loop() {
  // Boucle de mesure de la température
  lcd.setCursor(0, 1);
  lcd.print("                "); //Efface la ligne
  lcd.setCursor(0, 1);
  lcd.print(thermocouple.readCelsius());
  lcd.write(7);
  lcd.print("C");
  lcd.setCursor(9, 1);
  lcd.print(thermocouple.readFahrenheit());
  lcd.print("F");
  lcd.setCursor(15, 0);
  if (thermocouple.readCelsius() > consigne) {
    lcd.write(1); //down
  }
  if (thermocouple.readCelsius() < consigne) {
    lcd.write(0); //up
  }
  if (thermocouple.readCelsius() == consigne) {
    lcd.print("=");
  }
  delay(2000); //2 secondes

}

Juste un exemple d'utilisation avec une température de consigne. Une flèche s'affiche pour monter ou descendre la température, en fonction de la consigne.
Pensez à installer la librairie MAX6675.
Tutoriel réalisation d'un thermomètre à thermocouple avec Arduino.

Principe de fonctionnement


Un thermocouple est simplement formé de 2 fils métalliques différents soudés ensemble.
Le type K comporte une jonction entre chromel (alliage nickel + chrome) et alumel (alliage nickel + aluminium + silicium).
Une faible différence de potentiel électrique apparaît à la jonction sous l'effet de la température.
Le signal est faible, typiquement 50 microV par degré, la réponse est non linéaire, et il faut une compensation de soudure froide (on mesure un écart de température entre deux jonctions, pas une température absolue).

Malgré ces inconvénients, le thermocouple est très intéressant car il est simple d'emploi, robuste à la chaleur, il couvre une très grande plage de mesure de température avec une forte précision.
On amplifie puis on convertit la mesure analogique en signal numérique, une liaison SPI permet de transmettre facilement à un micro contrôleur (Arduino) le résultat. Le module d'interface de conversion utilisé ici est un MAX6675, il assure l'amplification et la conversion sur 12 bits.

Caractéristiques du kit thermocouple + MAX6675:


  • Mesure de température jusqu' à 1024 °C.
  • Résolution 0.25 °C.
  • Compensation de jonction de température froide .
  • Alimentation 3.0 - 5V DC.
  • Note : le thermocouple K se distingue facilement des autres types, il est attiré par un fort aimant.

Boussole HMC5803L i2c+LCD 1602 i2C

    //*************************************************************
    //  Boussole
   //*************************************************************
   /*LCD1602 sur i2C et HMC5803L sur i2C
    * 1 VCC alimentation du module --> Vcc 3.3v à 5V
    2 GND masse--> Gnd
    3 SCL Serial Clock --> A5
    4 SDA Serial Data --> A4
    5 DRDY --> n/a, Data ReaDY non utilisé.
*/
    #include "Wire.h"   //Librairie Wire pour la communication I2C
    #include "LiquidCrystal_I2C.h"
    LiquidCrystal_I2C lcd(0x3f, 16, 2); //Adresse LCD1602 0x3F
    byte copyright[8] = {
 B01110, B10101, B11011, B11001, B11001, B11011, B10101, B01110
};
byte up[8] =
{
 B00100,
 B01110,
 B11111,
 B10101,
 B00100,
 B00100,
 B00100,
 B00100
};
    #define HMC5803L_Address 0x1E  //Adresse I2C du module

    #define X 3  //Adresses de registres pour les données X Y et Z
    #define Y 7
    #define Z 5
    double Xmagnetic;
    double Ymagnetic;
    double Zmagnetic;
    double Module_magnetic;
    double angle;

    void setup()
    {
      Serial.begin(9600);
      lcd.begin();
      lcd.createChar(0,up);
      lcd.createChar(6,copyright);
      lcd.clear();
        lcd.setCursor(0, 0);
  lcd.print("LCD1602+HMC5803L");
  lcd.setCursor(0, 1);
  lcd.print("    ");
  lcd.write(6);
  lcd.print("Sammy76");
  delay(5000);
  lcd.clear();
  lcd.setCursor(0, 0);
      lcd.print("x");
      lcd.setCursor(8, 0);
      lcd.print("y");
      lcd.setCursor(0, 1);
      lcd.print("z");
      lcd.setCursor(8, 1);
      lcd.print("a");
      Wire.begin();         //Initialisation de la livrairie Wire
      Init_HMC5803L();    //Initialiser le module boussole
    }

    // Boucle de mesures de champ magnétique
    void loop()
    {
      Xmagnetic = HMC5803L_Read(X);  //lecture sur 3 axes et sortie sur le port sériel
      Ymagnetic = HMC5803L_Read(Y);
      Zmagnetic = HMC5803L_Read(Z);
      /* 
      Serial.print("X");
      Serial.print (Xmagnetic);
      Serial.print("Y");
      Serial.print (Ymagnetic);
      Serial.print("Z");
      Serial.print (Zmagnetic);
      */
      lcd.setCursor(1, 0);
      lcd.print("       ");
      lcd.setCursor(1, 0);
      lcd.print(Xmagnetic);
      lcd.setCursor(9, 0);
      lcd.print("       ");
      lcd.setCursor(9, 0);
      lcd.print(Ymagnetic);
      lcd.setCursor(1, 1);
      lcd.print("       ");
      lcd.setCursor(1, 1);
      lcd.print(Zmagnetic);
      
       //Module du champ
      Module_magnetic = Xmagnetic * Xmagnetic + Ymagnetic * Ymagnetic + Zmagnetic * Zmagnetic;
      Module_magnetic = sqrt(Module_magnetic);
      /*Serial.print(" M= ");
      Serial.print(Module_magnetic);
     */
      //Calculer l'angle de la boussole à partir de X et Y (à plat)
      angle= atan2(Ymagnetic,Xmagnetic) * (180 / 3.14159265); // angle en degres
      if (angle<0) {angle=angle+360;}
      /*Serial.print("  "); 
      Serial.print("Angle  ");  //en degres
      Serial.println(angle);*/
      lcd.setCursor(9, 1);
      lcd.print("       ");
      lcd.setCursor(9, 1);
      lcd.print(angle);
      lcd.setCursor(15, 1);
      if (round(angle)==0) {
      lcd.write(0);
      }
      else {
        lcd.print(" ");
      }
     delay(500);
    }


     
    // === Fonction qui initialise le module boussole (à lancer une seule fois)
    void Init_HMC5803L(void)
    {
      /* Set the module to 8x averaging and 15Hz measurement rate */
      Wire.beginTransmission(HMC5803L_Address);
      Wire.write(0x00);
      Wire.write(0x70);
             
      Wire.write(0x01);
      Wire.write(0xA0);   //Règle un gain de 5
      Wire.endTransmission();
    }

    // === Fonction qui lit le module boussole (registre d'un des 3 axes, retourne 16 bits)
    int HMC5803L_Read(byte Axis)
    {
      int Result;
       /* Initiate a single measurement */
      Wire.beginTransmission(HMC5803L_Address);
      Wire.write(0x02);
      Wire.write(0x01);
      Wire.endTransmission();
      delay(6);
     
      /* Move modules the resiger pointer to one of the axis data registers */
      Wire.beginTransmission(HMC5803L_Address);
      Wire.write(Axis);
      Wire.endTransmission();
       
      /* Read the data from registers (there are two 8 bit registers for each axis) */ 
      Wire.requestFrom(HMC5803L_Address, 2);
      Result = Wire.read() << 8;
      Result |= Wire.read();

      return Result;
    }


Exemple d'utilisation de la boussole.
Affiche les vecteurs X,Y et Z et enfin l'angle par rapport au nord. Ce module inclut un capteur électromagnétique magnéto-résistif de dernière génération HMC118X à haute sensibilité, un amplificateur, une annulation de décalage d'offset.
Le technologie AMR (Anisotropic Magnetoresistive) offre une réponse linéaire, et 3 capteurs croisés permettent de mesurer le champ magnétique sur 3 axes X, Y, Z, du milli Gauss jusqu'à 8 Gauss, avec très peu de biais de mesure inter-axes.
L'adresse 7-bits I2C du module est 0x1E
Ne pas oublier de calibrer le capteur qui est en permanence influencé par son entourage électromagnétique.
Je mettrai prochainement une procédure.
Multi-capteurs température DS18B20+LCD 1602 i2C

Modèle étanche

Boitier TO-92

/*
Lecteur de température à partir d'un ou plusieurs DS18B20
Matériel :
-  LCD1602 sur I2C
 *  Pin Connections:
 *      SCL = A5
 *      SDA = A4
 *      VCC = 5V
 *      GND = GND
- Carte LCD/I2C
- Capteur(s) DS18B20 :
 *  Pin Connections:
 *      Data = D2
 *      VCC = 5V
 *      GND = GND
*/
#include "Wire.h"
#include "OneWire.h"
#include "LiquidCrystal_I2C.h"
OneWire capteur(2);// crée un objet One Wire sur la broche voulue

LiquidCrystal_I2C lcd(0x3F, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display
uint8_t deg[8] = {
  B00110,
  B01001,
  B01001,
  B00110,
  B00000,
  B00000,
  B00000,
  B00000
};
uint8_t e_acc[8] = {
  B00010,
  B00100,
  B01110,
  B10001,
  B11111,
  B10000,
  B01110,
  B00000
};
int DS18S20_Pin = 2; //DS18S20 Signal pin on digital 2

//Temperature chip i/o
OneWire ds(DS18S20_Pin);  // on digital pin 2
byte adresse[8];

void setup(void) {
  int comp = 1;
  String kk;
  Serial.begin(9600);

  lcd.begin();                      // initialize the lcd
  //lcd.cursor();
  lcd.createChar(7, deg);
  lcd.createChar(8, e_acc);
  // Print a message to the LCD.
  lcd.backlight();
  lcd.noAutoscroll();
  lcd.setCursor(0, 0);
  lcd.print("Nano+I2C+DS18B20");
  //Liste des capteurs
  while (capteur.search(adresse) == true) // tant qu'un nouveau capteur est détecté
  { kk = "";
    for (int i = 0; i < 8; i++) {
      kk = kk + String(adresse[i], HEX);
    }

    Serial.println("Capteur " + String(comp) + ":" + kk + "\n");
    lcd.setCursor(0, 1);
    lcd.print(kk);
    lcd.setCursor(0, 0);
    delay(2000);
    comp = comp + 1;
  }
}

void loop(void) {
  int comp = 1;
  while (capteur.search(adresse) == true) {
    //Une page par capteur
    float temperature = getTemp(adresse);
    float Fahrenheit = (9 / 5. * temperature) + 32;
    //lcd.clear();
    //Serial.println(temperature);
    lcd.setCursor(0, 0);
    lcd.print("Temp");
    lcd.write(8);
    lcd.print("rature " + String(comp) + " :   ");
    lcd.noAutoscroll();
    lcd.setCursor(0, 1);
    lcd.print(temperature);
    lcd.write(7);
    lcd.print("C--");
    lcd.print(Fahrenheit);
    lcd.print("F");
    delay(2000); //2 secondes
    comp = comp + 1;
  }
  //Page suivante
  lcd.setCursor(0, 0);
  lcd.print("Ca fonctionne!!!");

  lcd.setCursor(0, 1);
  lcd.print("Youpi!!!!       ");
  delay(2000); //2 secondes
}

float getTemp(byte addr[8]) {
  //returns the temperature from one DS18S20 in DEG Celsius
  byte data[12];
  //  if ( !ds.search(addr)) {
  //      //no more sensors on chain, reset search
  //      ds.reset_search();
  //      return -1000;
  //  }
  if ( OneWire::crc8( addr, 7) != addr[7]) {
    Serial.println("CRC non valide!\n");
    return -1000;
  }
  if ( addr[0] != 0x28) {
    Serial.println("Pas de la famille DS18B20.\n");
    return -1000;
  }
  if ( addr[0] != 0x10 && addr[0] != 0x28) {
    Serial.println("Composant non reconnu\n");
    return -1000;
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44, 1); // start conversion, with parasite power on at the end
  byte present = ds.reset();
  ds.select(addr);
  ds.write(0xBE); // Read Scratchpad
  for (int i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds.read();
  }
  ds.reset_search();
  byte MSB = data[1];
  byte LSB = data[0];

  float tempRead = ((MSB << 8) | LSB); //using two's compliment
  float TemperatureSum = tempRead / 16;

  return TemperatureSum;

}

Plusieurs capteurs de température. L'avantage du DS18B20 est un composant 1-Wire (1 fil!) en fait 3 fils.
L'alimentation, la masse et bien sur un fil pour les données.
Ce type de composant fonctionne sur des distances de fils inférieures à 200m (C'est déjà bien non!).
Comme chaque composant à une adresse spécifique sur 64bits.
Le DS18B20 a une gamme de mesure qui s’étend de -55 °C à +125 °C.
Il transmet sa mesure directement en degrés Celsius, codée sur 16 bits. Sa précision est de ±0,5 °C entre -10 °C et +85 °C.

Voir les composants 1-Wire
Capteur de pression BMP180+LCD 1602 i2C
Spécifications :
  • Échelle de pression mesurée : de 300 à 1100 hPa
    (de 9000m à -500m par rapport au niveau de la mer)
  • Résolution : jusqu'à 0,03hPa / 0,25m
  • Température : -40 / +85°C, précision de +-2°C
  • Fonctionne sous 3,3V
  • Adaptateur de niveau sur I²C et résistances de pull up incluses


/*
 * Base:
   Etude du BMP180 (on n'utilise aucune bibliothèque dédiée)
   Copyright 2015 - Eric Sérandour
   http://labo.serandour.com

Modif sammy76.free.fr

Matériel :
-  LCD1602 sur I2C
 *  Pin Connections:
 *      SCL = A5
 *      SDA = A4
 *      VCC = 5V
 *      GND = GND
- Carte LCD/I2C
- Capteur(s) Baromètre BMP180 :
 *  Pin Connections:
 *      SCL = A5
 *      SDA = A4
 *      VCC = 3.3V Attention ! 
 *      GND = GND
 *      
*/

#include "LiquidCrystal_I2C.h"
// Initialisation de la bibliothèque avec les numéros de broches utilisées
LiquidCrystal_I2C lcd(0x3F, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display

byte degre[8] = {   // Déclaration d’un tableau de 8 octets pour le caractère °.
  B00111,           // Définition de chaque octet au format binaire :
  B00101,           // 1 pour un pixel affiché – 0 pour un pixel éteint.
  B00111,           // Les 3 bits de poids forts sont ici inutiles.
  B00000,
  B00000,
  B00000,
  B00000,
  B00000
};
byte caractereDegre = 0;
// *** BMP180
#include "Wire.h"            // On importe la bibliothèque Wire pour l'I2C
#define ADRESSE_BMP180 0x77 
float pressionAbsolue = 0;
float pressionRelative = 0;
float altitude = 0;
float temperature = 0;       // Température à l'intérieur de la centrale
float altitudeReference = 0; // Altitude connue rentrée au clavier
float pressionReference = 0; // Pression à l'altitude de référence

//////////////////////////////////////////////////////////////////////////////////////////

void setup()
{
  lcd.begin();
  lcd.clear();
  Wire.begin();
  initBarometre(ADRESSE_BMP180);
}

//////////////////////////////////////////////////////////////////////////////////////////

void loop()
{
  afficherBarometre(ADRESSE_BMP180);
}

//////////////////////////////////////////////////////////////////////////////////////////
/*
    ALTI-BAROMETRE BMP180
*/
//////////////////////////////////////////////////////////////////////////////////////////

void afficherBarometre(int adresseI2C)
{
  // Réglage de l'alti-baromètre
  reglageAltimetre(adresseI2C);

  // Affichage des mesures
  lcd.createChar(caractereDegre, degre); // Création du caractère personnalisé degré
  boolean quitter = false;
  do {
    lcd.clear();
    byte codeErreur = barometreRead(adresseI2C);
    if (codeErreur != 0) {
      lcd.setCursor(0, 0);
      lcd.print("BARO-ALTIMETRE");
      lcd.setCursor(0, 1);
      lcd.print("ERREUR (CODE ");
      lcd.print(codeErreur);
      lcd.print(")");
      delay(1000);
      quitter = true;
    }
    else {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("BAROMETRE   ");
      lcd.print(temperature);
      lcd.write(caractereDegre);
      lcd.print("C");
      lcd.setCursor(0, 1);
      lcd.print("Pa : ");
      lcd.print(pressionAbsolue);
      lcd.print(" hPa");
      delay(1000);
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Pr : ");
      lcd.print(pressionRelative);
      lcd.print(" hPa");
      lcd.setCursor(0, 1);
      lcd.print("H  : ");
      lcd.print(altitude);
      lcd.print(" m");
      delay(1000);
    }
  } while (quitter == false);
}

//////////////////////////////////////////////////////////////////////////////////////////

void reglageAltimetre(int adresseI2C)
{
  altitudeReference = 140; //m
  barometreRead(adresseI2C);
  pressionReference = pressionAbsolue;
}

//////////////////////////////////////////////////////////////////////////////////////////

int16_t  ac1, ac2, ac3, b1, b2, mb, mc, md; // Calibration coefficients
uint16_t ac4, ac5, ac6;                     // Calibration coefficients
// Ultra low power       : oss = 0, osd =  5 ms
// Standard              : oss = 1, osd =  8 ms
// High resolution       : oss = 2, osd = 14 ms
// Ultra high resolution : oss = 3, osd = 26 ms
const uint8_t OSS = 3;     // Set oversampling setting
const uint8_t OSD = 26;    // with corresponding oversampling delay

//////////////////////////////////////////////////////////////////////////////////////////

void initBarometre(int adresseI2C) // Voir le Data sheet du BMP180, à la page 15.
{
  // Read calibration data from the EEPROM of the BMP180
  ac1 = readRegister16(adresseI2C, 0xAA);
  ac2 = readRegister16(adresseI2C, 0xAC);
  ac3 = readRegister16(adresseI2C, 0xAE);
  ac4 = readRegister16(adresseI2C, 0xB0);
  ac5 = readRegister16(adresseI2C, 0xB2);
  ac6 = readRegister16(adresseI2C, 0xB4);
  b1  = readRegister16(adresseI2C, 0xB6);
  b2  = readRegister16(adresseI2C, 0xB8);
  mb  = readRegister16(adresseI2C, 0xBA);
  mc  = readRegister16(adresseI2C, 0xBC);
  md  = readRegister16(adresseI2C, 0xBE);
}

//////////////////////////////////////////////////////////////////////////////////////////

uint16_t readRegister16(int adresseI2C, uint8_t code)
{
  uint16_t value = 0;
  Wire.beginTransmission(adresseI2C);         // Start transmission to device
  Wire.write(code);                           // Sends register address to read from
  byte error = Wire.endTransmission();        // End transmission
  if (error == 0) {
    Wire.requestFrom(adresseI2C, 2);          // Request 2 bytes from device
    while (Wire.available() < 2);             // Wait until bytes are ready
    value = (Wire.read() << 8) + Wire.read();
  }
  return value;
}

//////////////////////////////////////////////////////////////////////////////////////////

byte barometreRead(int adresseI2C) 
// Suivant datasheet BOSH BMP180, à la page 15.
{
  int32_t x1, x2, x3, b3, b5, b6, ut, up, t, p;
  uint32_t b4, b7;
  int16_t msb, lsb, xlsb;
  byte error = 0;

  // Read uncompensated temperature value (ut)
  Wire.beginTransmission(adresseI2C);          // Start transmission to device
  Wire.write(0xf4);                            // Sends register address
  Wire.write(0x2e);                            // Write data
  error = Wire.endTransmission();              // End transmission
  if (error == 0) { // On continue
    delay(5);                                  // Data sheet suggests 4.5 ms

    Wire.beginTransmission(adresseI2C);        // Start transmission to device
    Wire.write(0xf6);                          // Sends register address to read from
    error = Wire.endTransmission();            // End transmission
    if (error == 0) { // On continue
      Wire.requestFrom(adresseI2C, 2);         // Request 2 bytes (0xf6, 0xf7)
      while (Wire.available() < 2);            // Wait until bytes are ready
      msb = Wire.read();
      lsb = Wire.read();

      ut = ((int32_t)msb << 8) + (int32_t)lsb;

      // Read uncompensated pressure value (up)
      Wire.beginTransmission(adresseI2C);      // Start transmission to device
      Wire.write(0xf4);                        // Sends register address
      Wire.write(0x34 + (OSS << 6));           // Write data
      error = Wire.endTransmission();          // End transmission
      if (error == 0) { // On continue
        delay(OSD);                            // Oversampling setting delay

        Wire.beginTransmission(adresseI2C);    // Start transmission to device
        Wire.write(0xf6);                      // Sends register address to read from
        error = Wire.endTransmission();        // End transmission
        if (error == 0) { // On continue
          Wire.requestFrom(adresseI2C, 3);     // Request 3 bytes (0xf6, 0xf7, 0xf8)
          while (Wire.available() < 3);        // Wait until bytes are ready
          msb = Wire.read();
          lsb = Wire.read();
          xlsb = Wire.read();

          up = (((int32_t)msb << 16) + ((int32_t)lsb << 8) + ((int32_t)xlsb)) >> (8 - OSS);

          // Calcul de la température vraie
          x1 = (ut - (int32_t)ac6) * (int32_t)ac5 >> 15;
          x2 = ((int32_t)mc << 11) / (x1 + (int32_t)md);
          b5 = x1 + x2;
          t = (b5 + 8) >> 4;
          temperature = t / 10.0f;  // temperature in celsius

          // Calcul de la pression vraie
          // On étend la taille de certaines variables pour éviter des dépassements.
          // Par exemple, dans la 2ème ligne, x1 est int32_t, b2 est int16_t
          // et b6 est int_32t d'où le (int32_t)b2.
          // Pour gagner en vitesse de calcul, on utilise << ou >> :
          // << : un décalage de 1 bit vers la gauche revient à multiplier par 2
          // >> : un décalage de 1 bit vers la droite revient à diviser par 2
          b6 = b5 - 4000;
          x1 = ((int32_t)b2 * (b6 * b6 >> 12)) >> 11;
          x2 = (int32_t)ac2 * b6 >> 11;
          x3 = x1 + x2;
          b3 = ((((int32_t)ac1 * 4 + x3) << OSS) + 2) >> 2;
          x1 = (int32_t)ac3 * b6 >> 13;
          x2 = ((int32_t)b1 * (b6 * b6 >> 12)) >> 16;
          x3 = ((x1 + x2) + 2) >> 2;
          b4 = ((uint32_t)ac4 * (uint32_t)(x3 + 32768)) >> 15;
          b7 = ((uint32_t)up - (uint32_t)b3) * (uint32_t)(50000 >> OSS);
          if (b7 < 0x80000000) {
            p = (b7 << 1) / b4;
          }
          else {
            p = (b7 / b4) << 1;
          }
          x1 = (p >> 8) * (p >> 8);
          x1 = (x1 * 3038) >> 16;
          x2 = (-7357 * p) >> 16;
          p = p + ((x1 + x2 + 3791) >> 4);
          pressionAbsolue = p / 100.0f;  // pression en hPa

          // Calculate pressure at sea level
          pressionRelative = pressionAbsolue / pow((1.0f - (altitudeReference / 44330.0f)), 5.255f);

          // Calculate absolute altitude
          float pression0 = pressionReference / pow((1.0f - (altitudeReference / 44330.0f)), 5.255f);
          altitude = 44330.0f * (1 - pow(pressionAbsolue / pression0, (1 / 5.255f)));
        }
      }
    }
  }
  return error;
}

Milli-ampèremètre

Pour la précision, nous utiliserons la tension de référence interne soit pour le ATMEGA328 1,1V ±0.1 V.
C'est un mesure peut précise, le test avec un Arduino Nano donne :
1.089 V à une température ambiante de 21°C. soit 1089/1024=1,06mA de précision.
1.084 V à une température ambiante de -18 °C soit 1089/1024=1,05mA de précision.
L'écart entre les deux ne fait varier la résolution de l'ADC que de 10µA, ce qui est acceptable.

Câblage

/* (c) Sammy76.free.fr 2015
   Milli-ampèremètre

   Arduino NANO V3.0
   Interval ref=1,089V

   Avec Max451     1V/A
   Précision : 1089/1024=1,063mA
   
   Voir pour ACS712-5A  185mV/A
   Précision : 1089/1024/0.185=5,75mA

   Entrée A0 :
*/
const int CurrentIn = A0;

//Avec MAX451
int RawValue = 0;
float Current = 0;

void setup() {
  Serial.begin(9600);
  analogReference(INTERNAL); //DEFAULT 5V, INTERNAL 1,1V, ou EXTERNAL.
  pinMode(CurrentIn, INPUT);
}

void loop() {
  RawValue = analogRead(CurrentIn);
  Current = (RawValue * 1089.0 / 1024.0); // //Conversion sur 10 bits
  Serial.print("Courant = ");
  Serial.print(Current, 1); //1 digit après point decimale
  Serial.println(" mA");

  // Délai entre deux affichages
  delay(100);
}
Module Bluetooth HC-06+LCD 1602 i2C

// Test de commandes AT avec module HC-06 Bluetooth
// Connection du HC-06 avec le monitor serie
//
// The HC-06 defaults to AT mode when first powered on.
// The default baud rate is 9600
// The Hc-06 requires all AT commands to be in uppercase.
//NL+CR should not be added to the command string

#include "SoftwareSerial.h"
SoftwareSerial HC06(11, 10); // RX | TX
// Connect the HC-06 TX to the Arduino RX on pin 11.
// Connect the HC-06 RX to the Arduino TX on pin 10.

void setup()
{
  Serial.begin(9600);
  Serial.println("Enter AT commands:");
  // HC-06 default serial speed is 9600
  HC06.begin(9600);
}

void loop()
{
  // Keep reading from HC-06 and send to Arduino Serial Monitor
  if (HC06.available())
  {
    Serial.write(HC06.read());
  }

  // Keep reading from Arduino Serial Monitor and send to HC-06
  if (Serial.available())
  {
    HC06.write(Serial.read());
  }
}

Exemple de commande AT à envoyer :
Attention, les commandes sont enregistrées dans l'EEPROM du HC-06.
1. Test communication
Send: AT (please send it every second)
Back: OK
2. Reset the Bluetooth serial baud rate
Send: AT+BAUD1
Back: OK1200
Send: AT+BAUD2
Back: OK2400
……
1---------1200
2---------2400
3---------4800
4---------9600 (Default)
5---------19200
6---------38400
7---------57600
8---------115200
9---------230400
A---------460800
B---------921600
C---------1382400

3. Reset the Bluetooth name
Send: AT+NAMEname la taille maxi est 20 caractères
Back: OKname
Exemple :AT+NAMEHC-06
Le nouveau nom visible sera HC-06

4. change the Bluetooth pair password
Send: AT+PINxxxx
Back:OKsetpin
Exemple :AT+PIN8888
Le nouveau code pour accès est le 8888. Le code par default est "1234"

5. No parity check ( The version, higher than V1.5, can use this command )
Send: AT+PN (This is the default value)
Back: OK NONE
6. Set odd parity check ( The version, higher than V1.5, can use this command )
Send: AT+PO
Back: OK ODD
7. Set even parity check( The version, higher than V1.5, can use this command )
Send: AT+PE
Back: OK EVEN

8. Get the AT version
Send: AT+VERSION
Back: LinvorV1.n

Autre Exemple


Permet en envoyant la commande "LED:1" d'allumer une led (pin9) et "LED:0" pour l'éteindre.
Si par contre vous envoyer un message texte, il ecrit ce message sur la première ligne LCD

#include "SoftwareSerial.h"
#include "Wire.h"
#include "LiquidCrystal_I2C.h"
#define lcd_adr 0x3F
LiquidCrystal_I2C lcd(lcd_adr, 16, 2);
uint8_t a224[8] = {8, 4, 14, 1, 15, 17, 15, 0}; // à
uint8_t a231[8] = {0, 14, 16, 16, 17, 14, 4, 12}; // ç
uint8_t a232[8] = {8, 4, 14, 17, 31, 16, 14, 0}; //è
uint8_t a233[8] = {2, 4, 14, 17, 31, 16, 14, 0}; // é
uint8_t a234[8] = {4, 10, 14, 17, 31, 16, 14, 0}; // ê
uint8_t a235[8] = {10, 0, 14, 17, 31, 16, 15, 0}; // ë
uint8_t a249[8] = {4, 10, 0, 17, 17, 19, 13, 0}; // û
uint8_t a252[8] = {10, 0, 17, 17, 17, 19, 13, 0}; // ü

SoftwareSerial HC06(11, 10);
const char DOUT_LED = 9;
String messageRecu;

char change(char k) {
  if (k == 0xFFFFFFC3) {
    delay(3);
    k = HC06.read();
    switch (k) {
      case 0xFFFFFFA0: k = 0x0; break; //à
      case 0xFFFFFFA7: k = 0x1; break; // ç
      case 0xFFFFFFA8: k = 0x2; break; //è
      case 0xFFFFFFA9: k = 0x3; break; //é
      case 0xFFFFFFAA: k = 0x4; break; //ê
      case 0xFFFFFFAB: k = 0x5; break; //ë
      case 0xFFFFFFBC: k = 0x6; break; // û
      case 0xFFFFFFBB: k = 0x7; break; // ü
    }
  }
  return k;
}
void sendmessage(void) {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(messageRecu);
  }

void setup() {
  HC06.begin(9600);
  pinMode(DOUT_LED, OUTPUT);
  digitalWrite(DOUT_LED, LOW);
  lcd.begin();
  lcd.createChar(0, a224);//à
  lcd.createChar(1, a231);//ç
  lcd.createChar(2, a232);//è
  lcd.createChar(3, a233);//é
  lcd.createChar(4, a234);//ê
  lcd.createChar(5, a235);//ë
  lcd.createChar(6, a249);//ù
  lcd.createChar(7, a252);//ü
  
}

void loop()
{ 
  while (HC06.available())
  {
    delay(3);
    char c = HC06.read();
    messageRecu += change(c);
  }
  if (messageRecu.length() > 0)
  {
    if (messageRecu == "LED:1")
    {
      digitalWrite(DOUT_LED, HIGH);
    }
    if (messageRecu == "LED:0")
    {
      digitalWrite(DOUT_LED, LOW);
    }
    if (messageRecu != "LED:0" && messageRecu != "LED:1")
    {
      sendmessage();
    }
    messageRecu = "";
  }
}
Module RF FS1000A/XY-MK-5V
Emission du signal RF FS1000A
// library
#include "VirtualWire.h"
  int i=0;
void setup() 
{
  //Serial.begin(9600); 
  pinMode(13, OUTPUT);
  // virtual wire
  vw_set_tx_pin(12); // pin
  vw_setup(4000); // bps
}

void loop()
{

  sendString("Arduino "+String(i), true); 
  delay(1000); 
  digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(200);              // wait for a second
  digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
  i++;
}

void sendString(String message, bool wait)
{
  byte messageLength = message.length() + 1; 

  // convert string to char array
  char charBuffer[messageLength]; 
  message.toCharArray(charBuffer, messageLength);

  vw_send((uint8_t *)charBuffer, messageLength); 

  if (wait) vw_wait_tx(); 

  //Serial.println("sent: " + message); 
}
Réception du signal RF XY-MK-5V
// library
#include "VirtualWire.h"

byte message[VW_MAX_MESSAGE_LEN]; // a buffer to store the incoming messages
byte messageLength = VW_MAX_MESSAGE_LEN; // the size of the message

void setup()
{
  Serial.begin(9600);
  Serial.println("device is ready...");

  vw_set_rx_pin(12);
  vw_setup(4000); // bps
  vw_rx_start();
}

void loop()
{
  if (vw_get_message(message, &messageLength)) // non-blocking
  {
    Serial.print("received: ");
    for (int i = 0; i < messageLength; i++)
    {
      Serial.write(message[i]);
    }
    Serial.println();
  }
}
Module RFID6300
Multi poussoirs sur une entrée analogique
Connexion de un poussoir à une entrée analogique
Avec un seul poussoir, nous avons vu que l’entrée analogique de l’Arduino était tirée à la masse via une résistance de 10kΩ.
L’appui sur le poussoir amenait cette entrée à 5V.
Pour la suite, on va inverser la connexion.
Connexion d’un poussoir à l’entrée analogique de l’Arduino, état de repos à +5V
L’entrée analogique est tirée à +5V et l’appui sur le poussoir amène cette entrée à la masse.
En effet, avec plusieurs poussoirs, cette façon de faire est plus commode car, sur le réseau, la masse est distribuée partout alors que ce n’est pas le cas pour le +5V.
Connexion de deux poussoirs à une entrée analogique
Lorsque B0 est pressé, nous avons le même comportement, l’entrée analogique est à 0V.
Lorsque B1 est pressé, les deux résistances sont en série entre 5V et 0V et l’entrée analogique est à la tension qui existe entre les deux résistances.
On voit qu’il s’agit d’un diviseur de tension, et donc l’entrée analogique est à 2,5V.
Évidemment, on ne peut pas presser 2 poussoirs en même temps, l’Arduino ne verra que le poussoir de rang le plus bas.
On peut continuer à ajouter des poussoirs en parallèle avec la résistance adéquate pour que le diviseur de tension donne une tension précise pour chaque poussoir.
Pour nos 8 boutons-poussoir, nous allons procéder de cette manière.
Avec 8 poussoirs, il faut diviser les 1024 valeurs possibles en 8 intervalles de 1024 ÷ 8 = 128 valeurs.
Plus on ajoute des poussoirs et plus cet intervalle devient petit.
Plus cet intervalle devient petit et plus il est nécessaire d’avoir des résistances précises.
Or, les résistances standards ont des valeurs déterminées et sont précises à 5%.
Si les intervalles sont trop petits, il devient impossible de distinguer deux valeurs voisines de façon fiable.
Cela limite le nombre de poussoirs que l’on peut connecter mais 8 poussoirs ne devraient pas poser de problème.
Valeur pour chacun des boutons
AppuisTensionValeurSur la figure ci-contre, la plage de valeurs analogiques a été découpée en 8 intervalles.
Il faut donc déterminer les résistances R1 à R7 de manière à obtenir plus ou moins la tension voulue.
On va voir que ça se fait assez bien.
Rien5V1023
BT74.375V895
BT63.75V767
BT53.125V639
BT42.5V511
BT31.875V383
BT21.25V255
BT10.625V127
BT00V0
Détermination des Valeurs de R1 à R7
Avant tout nous allons choisir un courant maximum d'environ 15mA en entrée, soit une résistance, afin d'absorber les bruits :
Valeur de R1 pour U1=0,625V
Suivant la règle du pont diviseur $R_1=\dfrac{330\cdot V_s}{V_{cc}-V_s}=\dfrac{330\times 0,625}{5-0,625}=47,142857\Omega$ ce qui donne un valeur standard de $47\Omega$
$R2=\dfrac{330\times 1,25}{5-1,25}-R_1=62,857143\Omega$ Soit $62\Omega$
$R3=\dfrac{330\times 1,875}{5-1,875}-R_1-R_2=88\Omega$ Soit $82\Omega$
$...$
Tableau de tableau de valeur des résistances en fonction du nombre de boutons
Détermination des Valeurs de R1 à R9 pour 10 boutons
R ΩTensionValeurPar CalculR E24
R10.5V10236Ω36Ω
R21V20446Ω47Ω
R31.5V30658Ω56Ω
R42V40981Ω82Ω
R52.5V511109Ω110Ω
R63V613164Ω160Ω
R73.5V716279Ω270Ω
R84V818559Ω560Ω
R94.5V9201649Ω1600Ω
Détermination des Valeurs de R1 à R8 pour 9 boutons
R ΩTensionValeurPar CalculR E24
R10.56V11341Ω43Ω
R21.11V22751Ω51Ω
R31.67V34171Ω68Ω
R42.22V454102Ω100Ω
R52.78V568150Ω150Ω
R63.33V682248Ω240Ω
R73.89V795502Ω510Ω
R84.44V9091478Ω1500Ω
Détermination des Valeurs de R1 à R7 pour 8 boutons
R ΩTensionValeurPar CalculR E24
R10.63V12747Ω47Ω
R21.25V25563Ω62Ω
R31.88V38389Ω91Ω
R42.5V511130Ω130Ω
R53.13V639220Ω220Ω
R63.75V767440Ω430Ω
R74.38V8951330Ω1300Ω
Détermination des Valeurs de R1 à R6 pour 7 boutons
R ΩTensionValeurPar CalculR E24
R10.71V14655Ω56Ω
R21.43V29276Ω75Ω
R32.14V438116Ω120Ω
R42.86V584189Ω180Ω
R53.57V730394Ω390Ω
R64.29V8761158Ω1200Ω
Détermination des Valeurs de R1 à R5 pour 6 boutons
R ΩTensionValeurPar CalculR E24
R10.83V17066Ω68Ω
R21.67V34197Ω100Ω
R32.5V511162Ω160Ω
R43.33V682332Ω330Ω
R54.17V852992Ω1000Ω
Détermination des Valeurs de R1 à R4 pour 5 boutons
R ΩTensionValeurPar CalculR E24
R11V20482Ω82Ω
R22V409138Ω130Ω
R33V613283Ω270Ω
R44V818838Ω820Ω
Détermination des Valeurs de R1 à R3 pour 4 boutons
R ΩTensionValeurPar CalculR E24
R11.25V255110Ω110Ω
R22.5V511220Ω220Ω
R33.75V767660Ω680Ω
Détermination des Valeurs de R1 à R2 pour 3 boutons
R ΩTensionValeurPar CalculR E24
R11.67V341165Ω160Ω
R23.33V682500Ω510Ω

Il faut également éviter les rebonds, ce qui donne en c arduino pour 8 boutons:

    const byte NON_PRESSE = 0;
    const byte ENFONCE = 1;
    const byte PRESSE = 2;
     
    byte etatAutomate = NON_PRESSE;
    int etatPoussoir = -1;
     
    const byte AUCUN_EVENEMENT = 0;
    const byte EVENEMENT_PRESSE = 1;
    const byte EVENEMENT_RELACHE = 2;
     
    const int pinPoussoirs = 0; //A0
     
    int lirePoussoirs()
    {
        int resultat;
        int numPoussoir = (analogRead(pinPoussoirs) + 64) / 128;
     
        int nouvelEtatPoussoir = etatPoussoir; /* à priori rien ne change */
     
        switch (etatAutomate) {
            case NON_PRESSE:
                if (numPoussoir < 8)
                    etatAutomate = ENFONCE;
                break;
            case ENFONCE:
                if (numPoussoir < 8) {
                    etatAutomate = PRESSE;
                    nouvelEtatPoussoir = numPoussoir;
                }
                else {
                    etatAutomate = NON_PRESSE;
                }
                break;
            case PRESSE:
                if (numPoussoir == 8) {
                    etatAutomate = NON_PRESSE;
                    nouvelEtatPoussoir = -1;
                }
                break;
        }
     
        return nouvelEtatPoussoir;
    }
     
    /*
     * construction d'un événement en comparant
     * le nouvel état des poussoirs avec l'état précédent.
     */
    byte lireEvenement(int *numPoussoir)
    {
        byte evenement;
        int nouvelEtatPoussoir = lirePoussoirs();
     
        if (nouvelEtatPoussoir == etatPoussoir)
            evenement = AUCUN_EVENEMENT;
        if (nouvelEtatPoussoir >= 0 && etatPoussoir == -1) 
            evenement = EVENEMENT_PRESSE;
        if (nouvelEtatPoussoir == -1 && etatPoussoir >= 0) 
            evenement = EVENEMENT_RELACHE;
     
        etatPoussoir = nouvelEtatPoussoir;
        *numPoussoir = etatPoussoir;
     
        return evenement;
    }
     
    void setup()
    {
        Serial.begin(9600);
    }
     
    void loop()
    {
        int numPoussoir;
        byte evenement = lireEvenement(&numPoussoir);
     
        switch (evenement) {
            case EVENEMENT_PRESSE:
                Serial.print("Presse : ");
                Serial.println(numPoussoir);
                break;
            case EVENEMENT_RELACHE:
                Serial.print("Relache : ");
                Serial.println(numPoussoir);
                break;
        }
     
        delay(3);
    }
Attention à la précision des résistances (E24 c'est mieux), une autre solution serai d'utiliser des diodes.

Utilisation de diodes

En effet la chute de tension approximative de 0.6V par les diodes traditionnelle permet une bonne précision.
La diode D1 permet de ne pas saturer l'entrée et d'éviter de valeurs erronée.
Ici, j'utilise des diodes 1N4148 (Très standard et j'en ai 500 en stock pour 5€ chez Amaz...)

La première valeur lue sera donc juste un peu inférieur à 1024, la valeur diminuera de 100 à 150 par bouton.
L'avantage est de pouvoir ajouter des boutons simplement.
Attention si vous voulez plus que 8 boutons $\left(8\times 0,6=4,8~V\right)$, voir Sur le site de Louis ICI
Afin de conserver une référence à 0 losqu'il n'y à aucun bouton appuyé, une résistance R1 de 100K.
Une autre solution consiste à écrire digitalWrite(clavier, HIGH); Cela met en service une résistance interne.
R1 deviens donc inutile.
Schéma et montage à diodes

Information complète pour un système à 3 boutons

Ce système vas me permettre de pouvoir selectionner les fichiers sur une carte SD, les menus...
Fair un typon sera plus simple alors je propose de tout réaliser.

Le schéma:

Le programme :


#define BPPin  A7 // The buttons and the 100K pulldown are connected to A7
//================================================================================= BEGIN loadbp
uint8_t loadbp(){ //Load BP with diode
  uint8_t result_bp=0;
  uint16_t bpReading;
  while (result_bp==0){
  bpReading = analogRead(BPPin); // Analog playback from the buttons.
  result_bp=(bpReading+ 64) / 128; // (0.6V per diode) (5V/0.6~ 8 diodes) (1024/8=128) middle (256/2=64)
  delay(100); //Avoids the bounce
  }
  delay(100); //Avoids the bounce
  return result_bp-5; //The value 5 depends on the power supply of the circuit.
}
//================================================================================= END loadbp

void setup(void) {
  Serial.begin(115200);
}

void loop(void) {  
  switch(loadbp()){
    case 1:Serial.println(F("UP"));
        break;
    case 2:Serial.println(F("DOWN"));
        break;
    case 3:Serial.println(F("SELECT"));
        break;
        
  }
}

Le typhon et implantation


A suivre...
Optimisation Consommation Arduino

Avec une veille dans le temps durant 8s en consommation minimum.
Le programme propose une répétition de 8s plusieurs fois, ceci permet une consommation très réduite de l'Arduino et permet de faire une alimentation par batterie ou piles.


#include <avr/sleep.h>
#include <avr/wdt.h>

const byte LED = 13;
volatile int rept = 5; //Nombre de répétition 225x8S pour 30min prévoir 30min*60s/8s=225cycles

//*********************************** WATCHDOG TIMER ***************************************
// Interruption watchdog
ISR (WDT_vect) {
  wdt_disable();  // desactive watchdog
}  // end of WDT_vect

// paramètre : 0=16ms, 1=32ms, 2=64ms, 3=128ms, 4=250ms, 5=500ms, 6=1 sec,7=2 sec, 8=4 sec, 9=8 sec
void setup_watchdog(int ii) {
  byte bb;
  int ww;
  if (ii > 9 ) ii = 9;
  bb = ii & 7;
  if (ii > 7) bb |= (1 << 5);
  bb |= (1 << WDCE);
  ww = bb;
  // Clear the reset flag
  MCUSR &= ~(1 << WDRF);
  // start timed sequence
  WDTCSR |= (1 << WDCE) | (1 << WDE);
  // set new watchdog timeout value
  WDTCSR = bb;
  WDTCSR |= _BV(WDIE);
}

void sleep_watchdog() { //Veille temporisée
  setup_watchdog(9); //Programme le watchdog à 8s
  wdt_reset();  // pat the dog
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  noInterrupts ();           // timed sequence follows
  sleep_enable();
  // turn off brown-out enable in software
  MCUCR = bit (BODS) | bit (BODSE);
  MCUCR = bit (BODS);
  interrupts ();             // guarantees next instruction executed
  sleep_cpu ();
  // cancel sleep as a precaution
  sleep_disable();
} // fin de la veille
//*********************************** FIN WATCHDOG TIMER ***************************************
void flash (int nbr)
{
  for (byte i = 0; i < nbr; i++)
  {
    digitalWrite (LED, HIGH);
    delay (50);
    digitalWrite (LED, LOW);
    delay (50);
  }
}

void setup () {
  // paramètre : 0=16ms, 1=32ms, 2=64ms, 3=128ms, 4=250ms, 5=500ms, 6=1 sec,7=2 sec, 8=4 sec, 9=8 sec
  pinMode (LED, OUTPUT);
  Serial.begin(9600);
}
void loop (){
  Serial.print("Rept=");
  int temps=5*4-rept*4;
  Serial.print(temps);
  Serial.println(" s");  
  if (rept > 1) {
    flash (1); //1 flash toute les tempo
    rept--;
  }
  else {
    rept = 5;
    flash (1); //Ou programme de mesure
  }
  sleep_watchdog();

}

	

Watchdog par interruption

L'interruption sur la broche D2, en Pull-up permet de sortir du mode veille.
Les différents type de changement d'état:


#include <avr/sleep.h>
#include <avr/power.h>

void setup()
{
  pinMode(13, OUTPUT);
}
void wakeCallback() //Ne pas supprimer
{
  //Au moment du réveil, si il y un truc spécial hors loop

}

void sleepPwrDown() {
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  attachInterrupt(0, wakeCallback, CHANGE); //Changement d'état
  power_all_disable();
  sleep_mode();
  //Attente de l'interruption 0
  //sleep_disable();
  power_all_enable(); //Réactivation de toutes les fonctions
}

void loop()
{
  for ( int i = 0 ; i < 5 ; i++ ) {
    digitalWrite(13, LOW);
    delay(500);
    digitalWrite(13, HIGH);
    delay(500);
  }
  digitalWrite(13, LOW);
  sleepPwrDown();
  digitalWrite(13, HIGH);
}
A ne pas oublier:
avrdude -C ..\etc\avrdude.conf -p m328p -c arduino -P COM5 -b 57600 -U flash:w:"c:\temp\find_i2c.ino.hex":i

C'est tout pour aujourd'hui...