Cours:InfoS2 tdI2cSlave : Différence entre versions
(→Registres) |
(→Programmons le master i2c) |
||
Ligne 116 : | Ligne 116 : | ||
{{Question|ne reste plus qu'à assembler le tout pour modifier la led allumée en appuyant sur les bps}} | {{Question|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== | ||
+ | |||
+ | <source lang=cpp> | ||
+ | // 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) | ||
+ | { | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | </source> | ||
+ | |||
+ | ==Le slave reçoit de nouvelles valeurs pour ses registres== | ||
+ | |||
+ | <source lang=cpp> | ||
+ | #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) | ||
+ | { | ||
+ | } | ||
+ | } | ||
+ | |||
+ | </source> |
Version du 26 mars 2024 à 17:07
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 {{Rouge|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 un programme qui modifie la led allumée en fonction de la valeur reçue
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 un programme qui modifie la led allumée en fonction de la valeur reçue
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 :-)
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)
{
}
}