Outils pour utilisateurs

Outils du site


tdcom2

Ceci est une ancienne révision du document !


TD Bus de communication : Utilisation du bus Série synchrone I2C sur Arduino

Objectifs

  • Utilisation de la maquette Arduino
  • Utilisation haut niveau d'une communication série synchrone I2C
  • Compréhension des notions d'adressage, (sur le bus et dans le composant)
  • Réalisation de librairies pour accès à des périphériques externes (port E/S, horloge temps réel, ROM)

Carte d'extension pour le TD

Schéma de la carte principale:

Schéma de la carte amovible:

homepages.laas.fr_bvandepo_files_iut_td2_capt_modulertc.jpg

fichiers eagle: http://homepages.laas.fr/bvandepo/files/iut/td2_capt/carte-arduino-8574-12.sch et http://homepages.laas.fr/bvandepo/files/iut/td2_capt/carte-arduino-8574-12.brd

La carte d'extension utilisée pour ce TP permet de connecter plusieurs périphériques à l'Arduino. Elle dispose:

  1. de deux port E/S sur bus I2C dont un est piloté par des interrupteurs et l'autre pilote des leds. Le composant utilisé est un circuit PCF 8574A, dont la documentation est à l'adresse: http://www.farnell.com/datasheets/1846877.pdf. L'adresse de chacun de ces composants est en partie configurable via 3 cavaliers dont la fermeture revient à imposer un 0 logique sur le bit correspondant.
  2. d'une EEPROM SPI AT25040 (documentation: http://www.atmel.com/images/doc3348.pdf )
  3. d'une led infrarouge pour assurer la fonction de télécommande
  4. d'un module amovible assurant la fonction de RTC via le composant DS1307 (documentation: http://datasheets.maximintegrated.com/en/ds/DS1307.pdf ) et EEPROM I2C AT24C32N (documentation: http://www.atmel.com/images/doc0336.pdf ). Une sonde de températeur DS18B20 sur bus OneWire est également présente (documentation: http://datasheets.maximintegrated.com/en/ds/DS18B20.pdf )

Exercice 1 : Détermination des adresses des esclaves I2C

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Programmer l'arduino avec le sketch suivant et ouvrir la console arduino en 9600 8N1. (sketch récupéré sur http://playground.arduino.cc/Main/I2cScanner )

i2c_scanner.ino
    // --------------------------------------
    // i2c_scanner
    //
    // Version 1
    //    This program (or code that looks like it)
    //    can be found in many places.
    //    For example on the Arduino.cc forum.
    //    The original author is not know.
    // Version 2, Juni 2012, Using Arduino 1.0.1
    //     Adapted to be as simple as possible by Arduino.cc user Krodal
    // Version 3, Feb 26  2013
    //    V3 by louarnold
    // Version 4, March 3, 2013, Using Arduino 1.0.3
    //    by Arduino.cc user Krodal.
    //    Changes by louarnold removed.
    //    Scanning addresses changed from 0...127 to 1...119,
    //    according to the i2c scanner by Nick Gammon
    //    http://www.gammon.com.au/forum/?id=10896
    // Version 5, March 28, 2013
    //    As version 4, but address scans now to 127.
    //    A sensor seems to use address 120.
    //
    //
    // This sketch tests the standard 7-bit addresses
    // Devices with higher bit address might not be seen properly.
    //
 
    #include <Wire.h>
     void setup()
    {
      Wire.begin();
 
      Serial.begin(9600);
      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("I2C device found at address 0x");
          if (address<16)
            Serial.print("0");
          Serial.print(address,HEX);
          Serial.println("  !");
 
          nDevices++;
        }
        else if (error==4)
        {
          Serial.print("Unknow error at address 0x");
          if (address<16)
            Serial.print("0");
          Serial.println(address,HEX);
        }    
      }
      if (nDevices == 0)
        Serial.println("No I2C devices found\n");
      else
        Serial.println("done\n");
 
      delay(5000);           // wait 5 seconds for next scan
    }

Vous devriez obtenir un affichage ressemblant à:

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Débrancher et rebrancher le module amovible RTC et interpréter le résultat. Jouez sur les cavaliers permettant de configurer l'adresse matérielle des 8574. En déduire l'adresse de tous les composants que vous allez utiliser.

Exercice 2 : Utilisation du PCF8574

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Programmer l'arduino avec le sketch suivant et ouvrir la console arduino en 9600 8N1.

i2c_8574.ino
#include <Wire.h>
//adresses codées sur 7bits
#define SLAVE_ADDR_8574_A COMPLETER
#define SLAVE_ADDR_8574_B COMPLETER
 
//////////////////////////////////////////
char readPort8574(char addr, char * ptr_value)
/*addr, l'adresse du PCF8574
ptr_value, pointeur pour renvoyer la valeur lue sur le port
retourne -1 si échec 0 sinon*/
{
    Wire.requestFrom((byte)addr, (byte)1);// demande la lecture d'1 octet depuis l'adresse du pérpiphérique
    if (Wire.available()==1) //si l'octet est disponible
    {
        (* ptr_value) = Wire.read(); // lire l'octet
        return 0;
    }
    else
    {
        (* ptr_value) =0; //valeur par défaut si le composant n'a pas acquité
        return -1;
    }
}
//////////////////////////////////////////
char writePort8574(char addr, char value)
/*addr, l'adresse du PCF8574
value, la valeur à écrire sur le port
retourne -1 si échec 0 sinon */
{
    Wire.beginTransmission((byte)addr);//démarre la transmission avec l'adresse du pérpiphérique
    Wire.write((byte)value);     //envoie la donnée
    if (Wire.endTransmission()==0)      //stoppe la transmission
        return 0;
    else
        return -1;
}
//////////////////////////////////////////
void setup()
{
    Serial.begin(9600);  // start serial port at 9600 bps:
    Serial.print("Bonjour");
    Wire.begin();        // joindre le bus i2c en tant que maître
    writePort8574( SLAVE_ADDR_8574_B , 0xff); //configure le composant B en entrée
}
//////////////////////////////////////////
void loop()
{
}

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Compléter ce sketch pour écrire sur le port de sortie successivement les valeurs 0x55 et 0xAA. Inclure un délai suffisant pour pouvoir observer à l'oeil le clignotement des leds.

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Modifier le sketch pour effectuer la recopie du port d'entrée sur le port de sortie. Afficher des messages sur la console pour indiquer si les 8574 ont bien acquitté. Jouer sur la configuration des cavaliers pour vérifier que vous arrivez à détecter l'acquittement et le non acquittement.

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Observer les signaux SDA et SCL à l'oscilloscope. Déterminer la fréquence d'horloge utilisée pour le signal SCL. Repérer les phases d'adressage et d'échange des données et vérifier la valeur du bit d’acquittement lorsque l'adresse utilisée est correcte et lorsqu'elle est incorrecte.

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Appeler la fonction Wire.setClock() ( https://www.arduino.cc/en/Reference/WireSetClock ) dans setup() pour configurer l'horloge I2C à une fréquence de 400KHz et vérifier les signaux à l'oscilloscope. Comparer avec la fréquence d'horloge maximum autorisée pour le PCF8574 et conclure.

Exercice 3 : Utilisation de la RTC

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Compléter le sketch suivant pour activer la broche SQW/OUT successivement à 1 et à 0 en changeant toutes les secondes dans la fonction loop. Pour cela implémenter la fonctions writeRegI2C.

i2c_DS13072.ino
 #include <Wire.h>
//adresses codées sur 7bits
#define SLAVE_ADDR_DS13072 COMPLETER
//////////////////////////////////////////
char readRegI2C(char I2Caddr, byte Regaddr, byte * ptr_value)
/*I2Caddr, l'adresse du DS13072 sur le bus
Regaddr, l'adresse du registre du DS13072 à lire
ptr_value, pointeur pour renvoyer la valeur lue dans le registre
retourne -1 si échec 0 sinon
*/
{
    Wire.beginTransmission(I2Caddr);//démarre la transmission avec l'adresse du pérpiphérique
 
    //A COMPLETER
}
//////////////////////////////////////////
char writeRegI2C(char I2Caddr, byte Regaddr, byte value)
/*
I2Caddr, l'adresse du DS13072 sur le bus
Regaddr, l'adresse du registre du DS13072 à écrire
value,la valeur à écrire dans le registre
retourne -1 si échec 0 sinon
*/
{
    Wire.beginTransmission(I2Caddr);//démarre la transmission avec l'adresse du pérpiphérique
 
   //A COMPLETER
}
//////////////////////////////////////////
void displayTime()
{
    byte  val=0;
    if (0)   //A COMPLETER pour lire les heures
    {
        Serial.print(val, HEX);
        Serial.print(" : ");
    }
    if (0)   //A COMPLETER pour lire les minutes
    {
        Serial.print(val, HEX);
        Serial.print(" : ");
    }
    if (0)   //A COMPLETER pour lire les secondes
    {
        Serial.print(val, HEX);
        Serial.println(" sec");
    }
}
//////////////////////////////////////////
void dumpDS13072()
{
    byte  val,add;
   //A COMPLETER pour lire toutes les cases mémoire et afficher leurs adresses et contenus 
}
//////////////////////////////////////////
void setTime(byte hour,byte minute,byte sec)
{
    if (0)  //A COMPLETER pour régler les heures   
        Serial.println(" problème réglage heure");
    if (0)  //A COMPLETER pour régler les minutes   
        Serial.println(" problème réglage minute");
    if (0)   //A COMPLETER pour régler les secondes   
        Serial.println(" problème réglage sec");
}
//////////////////////////////////////////
void setup()
{
    Serial.begin(9600);  // start serial port at 9600 bps:
    Serial.print("Bonjour");
    Wire.begin();        // joindre le bus i2c en tant que maître
    //activation de l'oscillateur interne, remet également les secondes à 0
    if (writeRegI2C(SLAVE_ADDR_DS13072, 0, 0x00)==-1)
        Serial.println(" problème activation oscillateur");
    //activation sortie SQ à 1hz
    if (0) //A COMPLETER pour activation sortie SQ à 1hz
        Serial.println(" problème réglage SquareWave");
    //réglage de l'heure
    //A COMPLETER pour régler l'heure à 11h59 et 30 secondes   
}
//////////////////////////////////////////
void loop()
{
    //A COMPLETER selon les exercices
 
}
//////////////////////////////////////////
 

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Modifier le sketch pour demander le clignotement à 1hz de la sortie SQW/OUT dans la fonction setup et commenter le clignotement manuel dans loop.

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Modifier le sketch pour écrire la valeur 0xB3 dans la case d'adresse 0x12 puis pour relire cette même case et afficher son contenu chaque seconde dans la fonction loop.

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Compléter le sketch pour:

  1. Régler l'heure à 11h59 et 30 secondes dans l'initialisation. Pour cela, implémenter la fonction setTime(…) et l'appeler avec les bons paramètres depuis setup().
  2. Afficher l'heure deux fois par seconde dans la console.

Quand l'heure s'affiche correctement dans la console, débrancher le module RTC et vérifier que l'heure arrête de s'afficher. Lorsque vous rebranchez le module RTC, l'heure affichée doit avoir évoluée grâce à la batterie du module.

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Implémenter la fonction dumpDS13072() pour qu'elle permette de visualiser le contenu de chacune des 64 cases de la mémoire du DS13072 précédé de son adresse en héxadécimal.

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Consulter la documentation du composant DS1337 ( https://datasheets.maximintegrated.com/en/ds/DS1337-DS1337C.pdf ) pour comprendre la fonction supplémentaire qu'il propose par rapport au DS1307 et proposer un moyen d'exploiter cette fonctionnalité. Faire valider à l'enseignant votre proposition.

Exercice 4 : Utilisation de l' EEPROM I2C AT24C32

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Modifier le sketch précédent pour lire et écrire des cases dans la mémoire AT24C32. La documentation de ce composant est disponible ici: http://ww1.microchip.com/downloads/en/DeviceDoc/doc3348.pdf ou http://pdf.datasheetcatalog.com/datasheet/atmel/doc0336.pdf

ATTENTION, par rapport à l'exercice précédent:

  1. Le composant est lent pour écrire individuellement des octets. Après une écriture, il a besoin de temps avant de pouvoir gérer un ordre d'écriture suivant. Pour indiquer qu'il est occupé, le composant n'acquittera pas tant qu'il ne sera pas prêt.
  2. Le composant comportant plus de 256 cases de mémoire, l'adresse d'une case est stockée sur plus de 8 bits. Il faudra donc adapter les types utilisés pour coder les adresses ainsi que les fonctions gérant l'envoi de l'adresse de la case.

Exercice 5 : DAC Microchip 4725

Lire la documentation: https://www.sparkfun.com/datasheets/BreakoutBoards/MCP4725.pdf

homepages.laas.fr_bvandepo_files_iut_tp_tns_todo.jpg Déterminer l'adresse du composant sur le bus. Proposer un schéma pour le connecter à l'arduino. Indiquer le contenu de la fonction permettant d'écrire une valeur sur la sortie du DAC. Indiquer la valeur à utiliser pour obtenir 2V en sortie du DAC si il est alimenté en 5V. Proposer un programme pour générer une rampe sur la sortie du DAC.

documentation du module: https://cdn-learn.adafruit.com/downloads/pdf/mcp4725-12-bit-dac-tutorial.pdf

librairie disponible: https://github.com/adafruit/Adafruit_MCP4725

tdcom2.1549895715.txt.gz · Dernière modification : 2019/02/11 15:35 de bvandepo