Introduction
Parfois on souhaite utilisé un système de communication sans avoir forcément le module qui fonctionne bien. Il a 2 solution soit prendre un composant qui possède ce module , ou le réalisé nous même!
Pour ce petit cour, on se limiteras a l'I2C maitre , mais ce procédé est utilisable pour tout (Bus série , CAN , Diseqc ... ). Je ne proposerai pas des fonctions fonctionnelle car le but est d'expliquer comment sa fonctionne , et le code réalisé pour un PIC ne fonctionne pas avec le C167 , le 68HC11 , et bien sur les AVR et les autres micro contrôleurs.
1- Recherche d'une doc exploitable
Pour décomposer le problème il faut chercher une doc technique qui donne les règles ( niveaux des tensions, les temps ...)
J'ai trouvé une doc qu'on pourrais utiliser : Doc sur le bus I2C
Je n'ai pas trouvé les temps , mais on trouve a la dernière page : Standard à 100 Kbit/s donc on peux dire max 2 changement toutes les 10 us ( donc tout les delay seront de 10 us )
2- Décomposer le problème
On peux toujours décomposer un problème d'électronique en 2 partie le Hard et le soft ( le matériel et le logiciel ). Pour le bus I2C , s'est assez simple on a des entrées / sortie a collecteur ouvert.
Donc il ne faut jamais imposer un 1 logique!
Ce n'est pas très compliqué mais se n'est pas toujours le cas, par exemple pour le bus RS232 il faut changer les niveaux , donc se n'est pas aussi facile.
3- Décomposition des temps
On peux décomposer l'I2C en 4 parties , I2C_start , I2C_STOP , I2C_WRITE , I2C_READ
3.1- I2C start
Pour démarrer une trame en I2C , il faut faire un START , s'est très simple , il suffit de passer SDA a 0 , ensuite SCL.
void I2C_START(){
pin_SDA=sortie;
SDA=0;
delayus(10);
pin_SCL=sortie;
SCL=0;
delayus(10);}
Ceci devrai donner :

3.2- I2C_Write
L'i2c est une trame série , donc il faut faire un registre a décalage :
int I2C_WRITE(int mot){
int masque=0b10000000;
int i;
int ack=0;
for(i=0;i<8;i++){
if(mot&(masque>>i))//si on a 1 en i éme position
{
SDA = Z ;//( haute impédance )
horloge_SCL();
}
else
{
SDA = 0 ;//( haute impédance )
horloge_SCL();
}
}
//L'ack
SCL=Z;//haute impédance = 1
delayus(10);
if(SDA==1)
ack=1;
SCL=0;
delayus(10)
return ack;
}
On devrai avoir :

3.3- I2C_READ
Cette partie est la même que I2C write hormis que s'est l'esclave qui gère la communication.
int I2C_READ(){
int mot=0;
int masque=0b10000000;
int i;
for(i=0;i<8;i++){
scl=0;
delayus(10);
scl=Z;//1
if(SDA==1))
{
mot=mot+masque>>i;
}
else
{
//on ne fait rien
}
delayus(10);
}
//L'ack
SCL=Z;//haute impédance = 1
delayus(10);
SCL=0;
delayus(10)
return mot;
}
On devrai avoir :

3.4- I2C stop
Pour arréter une trame en I2C , il faut faire un STOP, s'est très simple , il suffit de passer SDA et SCL a 0 , ensuite relâcher SCL puis SDA.
void I2C_STOP(){
pin_SDA=sortie;
pin_SCL=sortie;
SCL=0;
SDA=0;
delayus(10);
pin_SCL=entree;
delayus(10);
pin_SDA=entree;}
Ceci devrai donner :

Limites dans le programme
J'ai souhaité faire des programmes simple , donc je n'ai pas utiliser les timers , dans la pratique si vous voulez faire plus qu'une seule chose il faudra utiliser ces timers.
Parfois il peux être intéressant de créé un petit module a coté en logique séquentiel ou combinatoire, il éviteras de contrôler tout le temps vos ports, donc vous faire gagner des cycles machine.
Si vous avez réalisé des programmes n'hésitez pas a nous contacter pour le proposer a tous.
L'équipe Robot-amateur .
|