Cours:InfoS2 tdI2cSlave

De troyesGEII
Révision datée du 3 avril 2024 à 10:55 par Bjacquot (discussion | contributions) (Recevoir des données sur une cible)
Aller à : navigation, rechercher

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;
		}
	}
}


Question.jpg 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

Todo.jpg 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)
	{
	}
}


Question.jpg Ecrire un programme qui modifie la led allumée en fonction de la valeur reçue

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


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 :-)

Question.jpg 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)
  {
  }
}