Bonsoir,
Je suis actuellement en train de réaliser une communication I2C entre un PC et un PIC 16F819 (comportant l'I2C intégré, comme le 16F87x).
Je programme en C, sous Mplab, avec CC5X.
Côté PC, j'utilise une interface et un driver trouvés sur cette page.
L'initialisation du PIC (I2C en esclave sur une certaine adresse) se fait sans problème. En effet, lorsque depuis le PC je cherche tous les esclaves sur le port I2C, je retrouve bien mon PIC à l'adresse indiquée dans le PIC.
Mon but dans un premier temps : faire allumer une LED selon une commande envoyée par le PC (un octet valant une certaine valeur).
Voici le code à l'heure actuelle (le code est adapté de cette page dans laquelle il y avait selon moi plusieurs erreurs...) :
Lorsque j'envoie l'octet 5 (correspondant à "#define ETAT1 0x05") à l'adresse 32 (correspondant à "Code:#include "int16CXX.h" ////////////////////////////////////////////////////////////////// // Configuration Word (page 90) // ////////////////////////////////////////////////////////////////// #pragma config=0b11111100011000 // 3F18 // Oscillator INTRC-RA6 is Port I/O // Watchdog Timer Off // Power Up Timer Off // MCLR Select Bit RA5 is digital I/0, MCLR tied to VDD // Brown Out Detect Off // Low Voltage Program Disabled // Flash Program Write Write Protection Disabled // CCP1 Mux RB2 // Code Protect Disabled //#pragma interruptSaveCheck n // no warning or error #pragma bit STAT_DA @ SSPSTAT.5 #pragma bit STAT_RW @ SSPSTAT.2 #pragma bit STAT_BF @ SSPSTAT.0 #pragma bit STAT_S @ SSPSTAT.3 #define NODE_ADDR 0x20 //Adresse du PIC sur le bus #define ETAT1 0x05 #define IDENT1 0xFF #define IDENT2 0xFE #define IDLE 0x00 #define allume 0x11 // Déclaration des variables globales char rxindex,txindex; char commande ; char state ; bit inter @ PORTB.5; bit ledverte @ PORTA.0; bit ledorange @ PORTA.1; bit ledrouge @ PORTA.2; bit ledverte2 @ PORTA.3; bit RB0 @ PORTB.0; //-- Prototypes -- void ssp_handler(void) ; void setup_i2c_esclave(char adresse); void WriteI2C(char data); char ReadI2C(void); #pragma origin 4 //Prise en charge des interruptions interrupt serverX(void) { int_save_registers // W, STATUS (and PCLATH) char sv_FSR ; //char sv_FSR = FSR ; ssp_handler() ; //le gestionnaire d'I2C if (state==allume) { ledverte=1; } //FSR=sv_FSR ; int_restore_registers // W, STATUS (and PCLATH) } char ReadI2C(void) { return(SSPBUF) ; } void ssp_handler(void) { char data ; //------------------------------------------------------------------------------------------- // ETAT 1 : S'il s'agit d'une opération d'écriture et que le dernier octet etait une adresse //------------------------------------------------------------------------------------------- if( !STAT_DA && !STAT_RW && STAT_BF && STAT_S) { txindex=0 ; nop(); data=ReadI2C(); } //if(SSPOV) if(SSPIF) { //SSPOV = 0 ; SSPIF = 0 ; if (data==SSPADD) // On ignore si jamais c’est l’adresse ; { rxindex=1 ; return ; } if (rxindex==1) // Premier octet reçu = commande { commande=data ; rxindex++ ; if (commande==ETAT1) { ledrouge=1; state=allume; } return ; } return ; } else if (STAT_DA && !STAT_RW && STAT_BF) { data=ReadI2C() ; // Normalement , on y arrive jamais, mais on ne sait jamais... } //------------------------------------------------------------------------------------------- // ETAT 3 : Il s'agit d'une operation de Lecture (READ) et le dernier octet etait une adresse //-------------------------------------------------------------------------------------- // ETAT 5: Un NACK a été produit par le Maître afin d'indiquer la fin de la transmission //-------------------------------------------------------------------------------------- else if (STAT_DA && !STAT_RW && !STAT_BF) nop(); } void init_pic(void) { ADCON1=0b.0000.0110; // L’initialisation préalable du registre ADCON1 // est nécessaire pour l’utilisation du PORTA (page 82) OPTION=0b.1100.1000; // Réglage du timer 0 (page 53-54) + réglage pull-up PORTB (page 17) OSCTUNE=0b.0000.0000; // (page 36) OSCCON=0b.0110.0100; // Choix de la fréquence de l'oscillateur interne (page 38) TRISA=0; PORTA=0; TRISB=0; TRISB.0=1; // RB0 configured as input TRISB.5=1; // RB5 configured as input PIE1=0; TMR0=0; setup_i2c_esclave(NODE_ADDR); } void setup_i2c_esclave(char adresse) { TRISB.1=1; // SDA configured as input TRISB.4=1; // SCL configured as input PIE1.3=1; // Equivalent à SSPIE=1 => Enables the SSP interrupt SSPCON=0b.0011.0110; // Configuration du port série (page 73) SSPADD=adresse;//<<1 ; // On charge l’adresse du composant INTCON=0b.1101.1000; // Réglage des interruptions (page 18) //GIE = 1 ; // Interrupts allowed //PEIE = 1 ; // Contenu dans INTCON (page 18) SSPSTAT=0; SSPIF=0; // Contenu dans PIR1 (page 20) } void main(void) { init_pic(); state=0; while(1) { nop(); if (state==allume) { ledverte2=1; } } }
#define NODE_ADDR 0x20"), le PIC va bien dans l'interruption, il affectue la fonction "ssp_handler()" et affiche la "ledverte".
Rappel de la routine d'interruption :Le problème, c'est qu'apparemment le PIC ne sort pas de l'interruption et donc il ne revient pas dans la boucle principale. Donc le même test "if (state==allume)" dans la boucle principale ne fonctionne pas et ma ledverte2 ne s'affiche pas...Code:#pragma origin 4 //Prise en charge des interruptions interrupt serverX(void) { int_save_registers // W, STATUS (and PCLATH) char sv_FSR ; //char sv_FSR = FSR ; ssp_handler() ; //le gestionnaire d'I2C if (state==allume) { ledverte=1; } //FSR=sv_FSR ; int_restore_registers // W, STATUS (and PCLATH) }
J'espère avoir été clair dans la rédaction de mon problème...
Merci d'avance si quelqu'un peut m'aider
-----