Cours:InfoS2 tdI2cSlave

De troyesGEII
Aller à la navigation Aller à la recherche

Fiche résumé

Retour à la liste des Tds/Tps

Éléments de correction

simuler avec simulIDE

Pensez à mettre sur la 1ère ligne de votre code :
// Compiler: Avrgcc device: nomDuMicrocontroleur


Fichiers pour simulide : SchemaI2cSlave.sim1
**************************************************
***  Attention, programme dans un fichier .ino ***
**************************************************


Vous disposez de 3 µcontrôleurs sur le schéma :

  • l'atmega2560 sera un esclave i2c et permettra d'allumer 1 seule led parmi les 32
  • l'atmega328p sur lequel sont connectés les boutons poussoirs sera également un esclave i2c
  • le dernier atmega328p sera le master i2c


Programmons les cibles i2c

Recevoir des données sur une cible

Dans ce cas, le master i2c enverra des données à l'esclave i2c.

Ici la valeur envoyée sera un nombre entre 0 et 31 qui indique le numéro de la led à allumer;

Le principe est le suivant :

#include <Wire.h>

const int8_t i2cAddress = 0x??;
volatile uint8_t i2cData=0;
volatile bool newValue=true;

//fonction d'interruption exécutée lors de la réception de données sur le bus i2c
void receiveEvent(int nbBytes)
{ 
	while (Wire.available())
	{
		i2cData = Wire.read();
		newValue=true;
	}
}

int main()
{
	// initialise la liaison i2c en mode slave
	Wire.begin(i2cAddress);
	//indique la fonction à exécuter lors de la réception de données
	Wire.onReceive(receiveEvent);
	sei();
	while(1)
	{
		if (newValue)
		{
			....
			newValue=false;
		}
	}
}


Ecrire les programmes :

  • du slave : modifie la led allumée en fonction de la valeur reçue
  • du master : envoie en boucle les valeurs de 0 à 31

Pensez à utiliser un programme pour lister les adresses des targets i2c, cf td précédent !

Envoyer des données depuis la cible

Dans ce cas, le master i2c recevra des données de l'esclave i2c.

Ici la valeur envoyée sera un nombre entre 0 et 31 que l'on augmente/diminue à l'aide des boutons (penser aux pull-up !)

Le principe est le suivant :

#include <Wire.h>

const int8_t i2cAddress = 0x??;
volatile uint8_t i2cData=0;
volatile bool newValue=true;

//fonction d'interruption exécutée lors de l'envoi de données sur le bus i2c
void requestEvent()
{
	// envoi de la donnée
	Wire.write(i2cData);
}

int main()
{
	// initialise la liaison i2c en mode slave
	Wire.begin(i2cAddress);
	//indique la fonction à exécuter lors de la réception de données
	Wire.onRequest(requestEvent);
	sei();
	while(1)
	{
	}
}


Ecrire les programmes :

  • du slave : incrémente/décrémente une valeur avec les boutons et "envoie" la valeur en i2c
  • du master : affiche régulièrement la valeur reçue sur la liaison série

envoi/réception sur le même esclave i2c

Bien sûr on pourra combiner les 2 fonctions sur la même cible, mais ce n'est pas l'objet de ce td !

Programmons le master i2c

Bien sûr, vous avez certainement déjà vérifié le fonctionnement de vos esclaves i2c au fur et à mesure :-)

ne reste plus qu'à assembler le tout pour modifier la led allumée en appuyant sur les bps


Pour aller plus loin

On pourra ajouter la notion de registres sur les esclaves :

Le slave envoie les valeurs de ses registres

// Include the required Wire library for I2C
#include <Wire.h>

const uint8_t i2cAddress = 9;
const uint8_t nbRegistres=6;
uint8_t registresValue[nbRegistres]={0,0,0,0,0,0};

void receiveEvent(int nbBytes)
{
  // la 1ère valeur reçue correspond au numéro de registre
  uint8_t numRegistre=Wire.read();

  // s'il y a plus de 2 valeurs à lire, on passe au registre suivant dans l'ordre
  while(Wire.available())
  {
    // les valeurs suivantes correspondent aux valeurs des registres
    uint8_t value=Wire.read();
    if (numRegistre<nbRegistres)
    {
      registresValue[numRegistre]=value;
    }
    // on passe automatiquement au registre suivant
    numRegistre++;
    if (numRegistre>=nbRegistres) numRegistre=0;
  }
}

int main()
{
  // Start the I2C Bus as Slave on address 
  Wire.begin(i2cAddress);
  // fonction à exécuter lors de la réception des données envoyées par le master
  Wire.onReceive(receiveEvent);
  sei();
  while(1)
  {
  }
}

Le slave reçoit de nouvelles valeurs pour ses registres

#include <Wire.h>

const uint8_t i2cAddress = 0x1A;
const uint8_t nbRegistres=4;
// variables utilisées dans des interruptions
volatile uint8_t numRegistre=0;
volatile uint16_t registresValue[nbRegistres];


void receiveEvent(int nbBytes)
{
  numRegistre=Wire.read();
  while(Wire.available())    // slave may send less than requested
  {
    Wire.read();    // receive a byte as character
  }
  // registre qui n'existe pas !
  if (numRegistre>=nbRegistres) numRegistre=0;
}

void requestEvent()
{
  Wire.write(registresValue[numRegistre]);
  // facultatif, permet de lire les registres dans l'ordre plus rapidement
  numRegistre++;
  if (numRegistre>=nbRegistres) numRegistre=0;
}

int main()
{
  // Start the I2C Bus as Slave on address 
  Wire.begin(i2cAddress);
  // la transmission commence par un envoi du numéro de registre par le master
  // on indique la fonction à exécuter pour obtenir le numéro de registre
  Wire.onReceive(receiveEvent);
  // fonction à exécuter pour envoyer des données au master
  Wire.onRequest(requestEvent);
  sei();
  while(1)
  {
  }
}