Communication I2C Entre 2 PIC

9
Communication I2C entre 2 PIC Extrait du Association Québécoise de Robotique Amateur http://www.aqra.ca Communication I2C entre 2 PIC - Électronique - Date de mise en ligne : samedi 7 janvier 2006 Association Québécoise de Robotique Amateur Copyright © Association Québécoise de Robotique Amateur Page 1/9

Transcript of Communication I2C Entre 2 PIC

Page 1: Communication I2C Entre 2 PIC

Communication I2C entre 2 PIC

Extrait du Association Québécoise de Robotique Amateur

http://www.aqra.ca

Communication I2C entre 2

PIC - Électronique -

Date de mise en ligne : samedi 7 janvier 2006

Association Québécoise de Robotique Amateur

Copyright © Association Québécoise de Robotique Amateur Page 1/9

Page 2: Communication I2C Entre 2 PIC

Communication I2C entre 2 PIC

Avant tout pour la troisième version du robot aspirateur, ASAv3, et aussi pour mes futurs projets, j'ai besoin d'un buspour communiquer entre plusieurs microcontrôleurs. 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 nedétaillerai pas toutes les subtilitées de la communication I2C dans cette article car d'autre l'ont déjà fait. Je mets enlien 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 rechercheset sur l'aide reçue, en particulier celle de Thomas Cremel (T-Bot). Actuellement, le code ne sert qu'à démontrer lacommunication. La partie électronique est très simple. Pour mes tests, j'ai monté deux PIC 18F452 sur un petitbreadboard. 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 reliées ensemble, ainsi que les SCL. Chaque ligne a une résistance de pull-up de 4,7k (peut varier entre 1k et 100k, normalement).

Le code fonctionne tel que, coté Maître, si le module I2C reçoit un ACK de l'esclave, preuve que les données sontrendues, la led verte est allumée. En cas de Non-ACK, c'est la rouge qui s'allume. Pour l'esclave, c'est une led pourla lettre 'A' et une autre pour 'B', afin de démontrer que le PIC ne reçoit pas n'importe quoi, mais bien les caractèresvoulus. 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 Québécoise de Robotique Amateur Page 2/9

Page 3: Communication I2C Entre 2 PIC

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 ) // test received ack bit state

{

StopI2C();

return 0; // bus device responded with NOT ACK

}

putcI2C(data);

IdleI2C();

if ( SSPCON2bits.ACKSTAT ) // test received ack bit state

{

StopI2C();

return 0; // bus device responded with NOT ACK

}

StopI2C();

return 1;

}

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

// //

// Fonction Principale //

// //

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

void main (void)

{

//On désactive l'acquisition analogique

ADCON1=6;

Copyright © Association Québécoise de Robotique Amateur Page 3/9

Page 4: Communication I2C Entre 2 PIC

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 Québécoise de Robotique Amateur Page 4/9

Page 5: Communication I2C Entre 2 PIC

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 donnée reçue par le MSSP

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

// //

// Fonction Principale //

// //

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

void main (void)

{

//On désactive 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

SSPCON1bits.CKP = 1; //On relache l'horloge

Copyright © Association Québécoise de Robotique Amateur Page 5/9

Page 6: Communication I2C Entre 2 PIC

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 Québécoise de Robotique Amateur Page 6/9

Page 7: Communication I2C Entre 2 PIC

Communication I2C entre 2 PIC

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

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

// //

// [ASA v3] //

// I2C Slave //

// version 2.0 //

// //

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

// //

// PIC 18F452, 40 MHz //

// JFDuval //

// 06/01/2006 //

// //

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

///Gestion des ordre reçus par interruption plutôt 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 donnée reçue 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 // on déclare que lors d'une interruption

void atInterrupthigh(void)

{

_asm GOTO MyInterrupt _endasm // on doit éxecuter le code de la fonction MyHighInterrupt

}

#pragma code // retour à la zone de code

#pragma interrupt MyInterrupt

Copyright © Association Québécoise de Robotique Amateur Page 7/9

Page 8: Communication I2C Entre 2 PIC

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 réautoriser l'interruption

x = ReadI2C();

if(x == 'A')

{

ledACK = 1;

ledNAK = 0;

}

else

{

ledNAK = 1;

ledACK = 0;

}

}

PRODL = sauv1; // on restaure les registres de calcul

PRODH = sauv2;

}

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

// //

// Fonction Principale //

// //

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

void main (void)

{

//On désactive 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 Québécoise de Robotique Amateur Page 8/9

Page 9: Communication I2C Entre 2 PIC

Communication I2C entre 2 PIC

PIE1bits.SSPIE=1; // autorisation de l'interruption de l'i2c

PIR1bits.SSPIF=0; //on désactive le bit SSPIF pour

//permettre a l'interruption d'avoir lieu

OpenI2C(SLAVE_7, SLEW_OFF);

SSPADD = 0x40; //Adresse de l'esclave

SSPCON1bits.CKP = 1; //On relache l'horloge

while(1)

{

//rien a faire, tout est géré 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'espère que ces bouts de code vous aideront à développer vos propres applications en I2C. Personnellement, c'estle manque de code d'example, de référence, qui m'a le plus manqué. Je préçise qu'ils ne sont que des exemples,quoique parfaitement fonctionnels, d'une communication entre deux PIC. Maintenant que j'ai franchis ces étapes, jevais pouvoir faire évoluer mon code par une gestion de plusieurs données envoyées, l'ajout d'autres esclave, lalecture et non seulement l'écriture, la gestion par interruption plutôt que par polling (ok, codé dans la v2.0), etc. Boncodage !

Maitre

Esclave

Esclave v2.0

Copyright © Association Québécoise de Robotique Amateur Page 9/9