Vous êtes sur la page 1sur 9

Communication I2C entre 2 PIC Extrait du Association Qubcoise de Robotique Amateur http://www.aqra.

ca

Communication I2C entre 2 PIC


- lectronique -

Date de mise en ligne : samedi 7 janvier 2006

Association Qubcoise de Robotique Amateur

Copyright Association Qubcoise de Robotique Amateur

Page 1/9

Communication I2C entre 2 PIC

Avant tout pour la troisime version du robot aspirateur, ASAv3, et aussi pour mes futurs projets, j'ai besoin d'un bus pour communiquer entre plusieurs microcontrleurs. Mon choix s'est port sur le bus I2C pour sa grande flexibilit, sa relative facilit de mise en oeuvre et la possibilit de pouvoir ajouter des cartes sans influencer les autres. Je ne dtaillerai pas toutes les subtilites de la communication I2C dans cette article car d'autre l'ont dj fait. Je mets en lien quelques sites qui m'ont permis de bien comprendre, ainsi que certaines documentations de Microchip.

Site de Christian Tavernier

Page sur l'I2C de Thomas Cremel

AN989 de Microchip

Document sur les librairies C18 (explique la lib i2c.h)

Donc, ce que vous trouverai dans cette article, c'est le code de base que j'ai cris, en me basant sur mes recherches et sur l'aide reue, en particulier celle de Thomas Cremel (T-Bot). Actuellement, le code ne sert qu' dmontrer la communication. La partie lectronique est trs simple. Pour mes tests, j'ai mont deux PIC 18F452 sur un petit breadboard. Chacun a un crystal de 10MHz avec ses condensateurs, un circuit de reset simplissime et deux leds : une rouge sur RA1 et une verte sur RA0. Les pins SDA de chaque PIC sont relies ensemble, ainsi que les SCL. Chaque ligne a une rsistance de pull-up de 4,7k (peut varier entre 1k et 100k, normalement).

Le code fonctionne tel que, cot Matre, si le module I2C reoit un ACK de l'esclave, preuve que les donnes sont rendues, la led verte est allume. En cas de Non-ACK, c'est la rouge qui s'allume. Pour l'esclave, c'est une led pour la lettre 'A' et une autre pour 'B', afin de dmontrer que le PIC ne reoit pas n'importe quoi, mais bien les caractres voulus. Avec le code ci-dessous, la led verte et la led rouge alternent. Maintenant, voici le code :

///////////////////////////////////////////////////////////////////////////// // // // // // [ASA v3] I2C Master version 1.0 // // // // //

///////////////////////////////////////////////////////////////////////////// // // // // // PIC 18F452, 40 MHz JFDuval 06/01/2006 // // // // //

/////////////////////////////////////////////////////////////////////////////

#include <p18f452.h> //for ports declarations #include <delays.h> //for delay routines #include <i2c.h> //gestion de la communication I2C

#define TRIS_RC3 TRISCbits.TRISC3

Copyright Association Qubcoise de Robotique Amateur

Page 2/9

Communication I2C entre 2 PIC


#define TRIS_RC4 TRISCbits.TRISC4

#define ledACK PORTAbits.RA0 #define TRIS_ledACK TRISAbits.TRISA0 #define ledNAK PORTAbits.RA1 #define TRIS_ledNAK TRISAbits.TRISA1

char letter1 = 'A'; char letter2 = 'B';

///////////////////////////////////////////////////////////////////////////// // // // Fonctions // // //

/////////////////////////////////////////////////////////////////////////////

//from T. Cremel unsigned char envoyer_i2c(unsigned char addr, unsigned char data) { IdleI2C(); StartI2C(); IdleI2C(); putcI2C(addr&0xFE); IdleI2C(); if ( SSPCON2bits.ACKSTAT ) { StopI2C(); return 0; } putcI2C(data); IdleI2C(); if ( SSPCON2bits.ACKSTAT ) { StopI2C(); return 0; } StopI2C(); return 1; } // bus device responded with NOT ACK // test received ack bit state // bus device responded with NOT ACK // test received ack bit state

///////////////////////////////////////////////////////////////////////////// // // // Fonction Principale // // //

/////////////////////////////////////////////////////////////////////////////

void main (void) { //On dsactive l'acquisition analogique ADCON1=6;

Copyright Association Qubcoise de Robotique Amateur

Page 3/9

Communication I2C entre 2 PIC


TRIS_RC3 = 1; TRIS_RC4 = 1; TRIS_ledACK = 0; TRIS_ledNAK = 0;

ledACK = 0; ledNAK = 0;

OpenI2C(MASTER, SLEW_OFF); SSPADD = 99; //100KHz sous 40MHz

while(1) { if(envoyer_i2c(0x40, letter1)) //Si l'esclave envoie un ack, on allume la led ACK ledACK = 1; else ledNAK = 1;

Delay10KTCYx(0); Delay10KTCYx(0);

ledACK = 0; ledNAK = 0;

if(envoyer_i2c(0x40, letter2)) //Si l'esclave envoie un ack, on allume la led ACK ledACK = 1; else ledNAK = 1;

Delay10KTCYx(0); Delay10KTCYx(0);

ledACK = 0; ledNAK = 0; } }

//config du PIC #pragma config OSC = HSPLL #pragma config PWRT = ON #pragma config WDT = OFF #pragma config BOR = ON #pragma config BORV = 42 #pragma config LVP = OFF

Copyright Association Qubcoise de Robotique Amateur

Page 4/9

Communication I2C entre 2 PIC


///////////////////////////////////////////////////////////////////////////// // // // // // [ASA v3] I2C Slave version 1.0 // // // // //

///////////////////////////////////////////////////////////////////////////// // // // // // PIC 18F452, 40 MHz JFDuval 06/01/2006 // // // // //

/////////////////////////////////////////////////////////////////////////////

#include <p18f452.h> //for ports declarations #include <delays.h> //for delay routines #include <i2c.h> //gestion de la communication I2C

#define TRIS_RC3 TRISCbits.TRISC3 #define TRIS_RC4 TRISCbits.TRISC4

#define ledACK PORTAbits.RA0 #define TRIS_ledACK TRISAbits.TRISA0 #define ledNAK PORTAbits.RA1 #define TRIS_ledNAK TRISAbits.TRISA1

char x;

//contient la donne reue par le MSSP

///////////////////////////////////////////////////////////////////////////// // // // Fonction Principale // // //

/////////////////////////////////////////////////////////////////////////////

void main (void) { //On dsactive l'acquisition analogique ADCON1=6;

TRIS_RC3 = 1; TRIS_RC4 = 1; TRIS_ledACK = 0; TRIS_ledNAK = 0;

ledACK = 0; ledNAK = 0;

OpenI2C(SLAVE_7, SLEW_OFF); SSPADD = 0x40; //Adresse de l'esclave //On relache l'horloge

SSPCON1bits.CKP = 1;

Copyright Association Qubcoise de Robotique Amateur

Page 5/9

Communication I2C entre 2 PIC


while(1) {

if(DataRdyI2C()) { x = ReadI2C();

if(x == 'A') { ledACK = 1; ledNAK = 0; } else { ledNAK = 1; ledACK = 0; } } } }

//config du PIC #pragma config OSC = HSPLL #pragma config PWRT = ON #pragma config WDT = OFF #pragma config BOR = ON #pragma config BORV = 42 #pragma config LVP = OFF

Copyright Association Qubcoise de Robotique Amateur

Page 6/9

Communication I2C entre 2 PIC


Update : Voici ci dessous la v2.0 du code esclave, avec pour grand changement la gestion des communications par interruption.

///////////////////////////////////////////////////////////////////////////// // // // // // [ASA v3] I2C Slave version 2.0 // // // // //

///////////////////////////////////////////////////////////////////////////// // // // // // PIC 18F452, 40 MHz JFDuval 06/01/2006 // // // // //

///////////////////////////////////////////////////////////////////////////// ///Gestion des ordre reus par interruption plutt que par polling

#include <p18f452.h> //for ports declarations #include <delays.h> //for delay routines #include <i2c.h> //gestion de la communication I2C

#define TRIS_RC3 TRISCbits.TRISC3 #define TRIS_RC4 TRISCbits.TRISC4

#define ledACK PORTAbits.RA0 #define TRIS_ledACK TRISAbits.TRISA0 #define ledNAK PORTAbits.RA1 #define TRIS_ledNAK TRISAbits.TRISA1

volatile char x;

//contient la donne reue par le MSSP

//volatile permet l'utilisation dans l'ISR

///////////////////////////////////////////////////////////////////////////// // // // Interruptions // // //

/////////////////////////////////////////////////////////////////////////////

void MyInterrupt(void);

// fonction contenant le code de l'interruption

#pragma code highVector=0x008 void atInterrupthigh(void) { _asm GOTO MyInterrupt _endasm } #pragma code // retour la zone de code

// on dclare que lors d'une interruption

// on doit xecuter le code de la fonction MyHighInterrupt

#pragma interrupt MyInterrupt

Copyright Association Qubcoise de Robotique Amateur

Page 7/9

Communication I2C entre 2 PIC


void MyInterrupt(void) { unsigned char sauv1; unsigned char sauv2;

sauv1 = PRODL; // on sauvegarde le contenu des registres de calcul sauv2 = PRODH;

if (PIR1bits.SSPIF) // c'est le MSSP qui a lev l'interruption { PIR1bits.SSPIF = 0; // on va rautoriser l'interruption x = ReadI2C();

if(x == 'A') { ledACK = 1; ledNAK = 0; } else { ledNAK = 1; ledACK = 0; } }

PRODL = sauv1; PRODH = sauv2; }

// on restaure les registres de calcul

///////////////////////////////////////////////////////////////////////////// // // // Fonction Principale // // //

/////////////////////////////////////////////////////////////////////////////

void main (void) { //On dsactive l'acquisition analogique ADCON1=6;

TRIS_RC3 = 1; TRIS_RC4 = 1; TRIS_ledACK = 0; TRIS_ledNAK = 0;

ledACK = 0; ledNAK = 0;

// On autorise toutes les interruptions INTCONbits.GIE = 1; INTCONbits.PEIE = 1;

Copyright Association Qubcoise de Robotique Amateur

Page 8/9

Communication I2C entre 2 PIC


PIE1bits.SSPIE=1; PIR1bits.SSPIF=0; // autorisation de l'interruption de l'i2c //on dsactive le bit SSPIF pour

//permettre a l'interruption d'avoir lieu

OpenI2C(SLAVE_7, SLEW_OFF); SSPADD = 0x40; //Adresse de l'esclave //On relache l'horloge

SSPCON1bits.CKP = 1;

while(1) { //rien a faire, tout est gr dans la routine d'interruption } }

//config du PIC #pragma config OSC = HSPLL #pragma config PWRT = ON #pragma config WDT = OFF #pragma config BOR = ON #pragma config BORV = 42 #pragma config LVP = OFF

J'espre que ces bouts de code vous aideront dvelopper vos propres applications en I2C. Personnellement, c'est le manque de code d'example, de rfrence, qui m'a le plus manqu. Je prise qu'ils ne sont que des exemples, quoique parfaitement fonctionnels, d'une communication entre deux PIC. Maintenant que j'ai franchis ces tapes, je vais pouvoir faire voluer mon code par une gestion de plusieurs donnes envoyes, l'ajout d'autres esclave, la lecture et non seulement l'criture, la gestion par interruption plutt que par polling (ok, cod dans la v2.0), etc. Bon codage !

Maitre

Esclave

Esclave v2.0

Copyright Association Qubcoise de Robotique Amateur

Page 9/9