Bonjour,
Je suis actuellement sur un projet ou j'ai besoin d'utiliser l'I2C entre deux PIC, le maitre est un 18F4553 et l'esclave un 18F4431 (enfin qu'importe finalement).
Dans un but entièrement didactique j'ai décidé de le faire entièrement sans bibliothèques de fonctions toutes faites.
J'utilise le compileur C18 dans l'IDE MPLAB.
Après de multiples vérifications, mon code me semble correct, mais lorsque je simule sous ISIS (je sais c'est mal, mais j'ai pas d'oscilloscope à mémoire), l'analyseur I2C me donne des résultats moches et ISIS m'insulte (enfin juste des warning mais...).
Je vous laisse admirer:
Et en pièces jointes le tas d'insultes ^.^Code:#include <p18F4553.h> #define ADRESSE_ESCLAVE 0b00000111 #define ECRITURE 0 #define LECTURE 1 #pragma config PLLDIV = 5 #pragma config FOSC = HS #pragma config DEBUG = ON /**********************************************/ /* Prototypes */ /**********************************************/ void analog_init(void); void I2C_init(void); void I2C_attendre_IDLE(void); void I2C_generer_start(void); void I2C_envoyer_adresse(char adresse, char mode); void I2C_attendre_ACK(void); void I2C_ecrire_octet(char octet); void I2C_generer_repeated_start(void); char I2C_lire_octet(void); void I2C_generer_noack(void); void I2C_generer_stop(void); void commande_potentiometres(char* duty_rouge, char* duty_vert, char* duty_bleu, char* duty_blanc); void envoi_valeurs(char* duty_rouge, char* duty_vert, char* duty_bleu, char* duty_blanc); /**********************************************/ /* Main */ /**********************************************/ void main(void) { char duty_rouge, duty_vert, duty_bleu, duty_blanc; I2C_init(); while(1) { commande_potentiometres(&duty_rouge, &duty_vert, &duty_bleu, &duty_blanc); envoi_valeurs(&duty_rouge, &duty_vert, &duty_bleu, &duty_blanc); } } void analog_init() { ADCON1 = 0b00001011; // Références VDD VSS, AD3 - AD0 analogiques, autres digital TRISA |= 0b00001111; // Pins analogiques en entrée ADCON2 = 0b00010101; // Tacq = 4 Tad / Conversion clock = Tosc/16 ADCON0bits.ADON = 1; // Démarrage de l'ADC } void commande_potentiometres(char* duty_rouge, char* duty_vert, char* duty_bleu, char* duty_blanc) { analog_init(); // Initialisation ADCON0 = 0b00000011; // Sélection AN0 + Lancement mesure while(ADCON0bits.GO==1); // Attente de la fin de la mesure *duty_rouge = ADRESH; ADCON0 = 0b00000111; // Sélection AN1 + Lancement mesure while(ADCON0bits.GO==1); // Attente de la fin de la mesure *duty_vert = ADRESH; ADCON0 = 0b00001011; // Sélection AN0 + Lancement mesure while(ADCON0bits.GO==1); // Attente de la fin de la mesure *duty_bleu = ADRESH; ADCON0 = 0b00001111; // Sélection AN0 + Lancement mesure while(ADCON0bits.GO==1); // Attente de la fin de la mesure *duty_blanc = ADRESH; ADCON0bits.ADON = 0; // Arrêt de l'ADC } void envoi_valeurs(char* duty_rouge, char* duty_vert, char* duty_bleu, char* duty_blanc) { I2C_generer_start(); I2C_envoyer_adresse(ADRESSE_ESCLAVE, ECRITURE); I2C_attendre_ACK(); I2C_ecrire_octet(*duty_rouge); I2C_attendre_ACK(); I2C_ecrire_octet(*duty_vert); I2C_attendre_ACK(); I2C_ecrire_octet(*duty_bleu); I2C_attendre_ACK(); I2C_ecrire_octet(*duty_blanc); I2C_attendre_ACK(); I2C_generer_stop(); } void I2C_init(void) { TRISBbits.TRISB0 = 1; // RB0 et RB1 (SCA et SCL) en entrée TRISBbits.TRISB1 = 1; SSPSTATbits.SMP = 0; // Slew-Rate control (pour 400kHz) SSPSTATbits.CKE = 0; // Mode I2C pas SMBus SSPADD = 12; // Configuration du Baudrate Generator SSPCON1bits.SSPEN = 1; // Activation du module I2C SSPCON1bits.SSPM3 = 1; // Mode Master sans interruption SSPCON1bits.SSPM2 = 0; // SSPCON1bits.SSPM1 = 0; // SSPCON1bits.SSPM0 = 0; // } void I2C_attendre_IDLE(void) { while(SSPSTATbits.R_W || SSPCON2bits.SEN || SSPCON2bits.RSEN || SSPCON2bits.PEN || SSPCON2bits.RCEN || SSPCON2bits.ACKEN); } void I2C_generer_start(void) { I2C_attendre_IDLE(); // Attendre que le bus soit disponible SSPCON2bits.SEN = 1; // Générer le start } void I2C_envoyer_adresse(char adresse, char mode) { I2C_attendre_IDLE(); // Attendre que le bus soit disponible if(mode == 0) { SSPBUF = (adresse*2); } else { SSPBUF = (adresse*2 + 1); } } void I2C_attendre_ACK(void) { //I2C_attendre_IDLE(); // Attendre que le bus soit disponible while(SSPCON2bits.ACKSTAT); // Tant qu'on n'a pas recu l'acknoledge on attend } void I2C_ecrire_octet(char octet) { I2C_attendre_IDLE(); // Attendre que le bus soit disponible SSPBUF = octet; // On lance le transfert while(SSPSTATbits.R_W); // On attend la fin du transfert } void I2C_generer_repeated_start(void) { I2C_attendre_IDLE(); // Attendre que le bus soit disponible SSPCON2bits.RSEN = 1; // Envoi du repeated start } char I2C_lire_octet(void) { I2C_attendre_IDLE(); // Attendre que le bus soit disponible SSPCON2bits.RCEN = 1; // On lance la réception while(SSPSTATbits.R_W); // On attend la fin du transfert return SSPBUF; } void I2C_generer_noack(void) { I2C_attendre_IDLE(); // Attendre que le bus soit disponible SSPCON2bits.ACKDT = 1; // Not Acknoledge = 1 SSPCON2bits.ACKEN = 1; // Lancer le Not Acknoledge } void I2C_generer_stop(void) { I2C_attendre_IDLE(); // Attendre que le bus soit disponible SSPCON2bits.PEN = 1; // Génération du stop }
Si des plus expérimentés que moi voient ce qui clochent, je les remercie déjà d'avance de leur aide!
-----