Bienvenue aux nouveaux arrivants sur FantasPic !
- Pensez à lire les règles durant votre visite, il n'y en a pas beaucoup, mais encore faut-il les respecter .
- N’hésitez pas à faire des remarques et/ou suggestions sur le Forum, dans le but de l'améliorer et de rendre vos prochaines visites plus agréables.
- Vous pouvez regarder votre "panneau de l'utilisateur" afin de configurer vos préférences.
- Un passage par "l'utilisation du forum" est recommandé pour connaître les fonctionnalités du forum.
--- L’équipe FantasPic ---
- Pensez à lire les règles durant votre visite, il n'y en a pas beaucoup, mais encore faut-il les respecter .
- N’hésitez pas à faire des remarques et/ou suggestions sur le Forum, dans le but de l'améliorer et de rendre vos prochaines visites plus agréables.
- Vous pouvez regarder votre "panneau de l'utilisateur" afin de configurer vos préférences.
- Un passage par "l'utilisation du forum" est recommandé pour connaître les fonctionnalités du forum.
--- L’équipe FantasPic ---
Modérateur : Jérémy
Problème de communication I2C bloquante
-
Superphénix
Débutant- Messages : 54
- Enregistré en : mars 2020
Bonjour
C'est la première fois que je tente de créé une communication I2C. Je me suis inspiré des codes d'exemple que j'ai trouvé sur internet et que j'ai adaptés un peu à mon projet, et forcement ça ne marche pas du premier coup.
J'utilise un PIC18LF2620, et je veux le faire communiquer avec un capteur de type MS5837-02BA21
Voilà tout mon code :
Pour l'instant tout ce que j'ai testé c'est rajouter un LED = 1 ; à différents endroits du code pour voir si ça bloque quelque part, et effectivement ça bloque dans I2C_Ready au niveau de while(!PIR1bits.SSPIF) ; mais je ne vois pas pourquoi...
C'est la première fois que je tente de créé une communication I2C. Je me suis inspiré des codes d'exemple que j'ai trouvé sur internet et que j'ai adaptés un peu à mon projet, et forcement ça ne marche pas du premier coup.
J'utilise un PIC18LF2620, et je veux le faire communiquer avec un capteur de type MS5837-02BA21
Voilà tout mon code :
Code : Tout sélectionner
#include <XC.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#pragma config OSC = ECIO6
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config BOREN = OFF
#pragma config MCLRE = OFF
#pragma config PBADEN = OFF
#pragma config WDT = OFF
#pragma config LVP = OFF
#pragma config STVREN = OFF
#define _XTAL_FREQ 8000000
#define slave_write_address 0b11101100
#define slave_read_address 0b11101101
#define LED PORTCbits.RC5
unsigned short C1=0, C2=0, C3=0, C4=0, C5=0, C6=0 ; // 16 Bits
__uint24 D1=0, D2=0 ; // 24 Bits
signed int dT=0, TEMP=0 ; // 32 Bits , Utiliser var_inter64
signed long long OFF=0, SENS=0, var_inter64=0 ; // 64 Bits
unsigned int P=0 ; // 32 Bits , Utiliser var_inter64
signed int OFFi=0 ;
signed long long Ti=0, SENSi=0, OFF2=0, SENS2=0 ; // 64 Bits
signed short TEMP2=0 ; // 16 Bits , Utiliser var_inter64
__uint24 P2=0 ; // 24 Bits , Utiliser var_inter64
//### FONCTIONS déclarations :
void I2C_Start(char) ;
void I2C_Ready(void) ;
char I2C_Write(unsigned char) ;
void I2C_Stop(void) ;
char I2C_Read(char) ;
void write_MS5837(unsigned char) ;
__uint24 read_MS5837(unsigned char, unsigned char) ;
int main(int argc, char** argv)
{
TRISA = 0b10000000 ;
TRISB = 0b00111100 ;
TRISC = 0b00011000 ;
PORTA = 0b00000000 ;
PORTB = 0b00000000 ;
PORTC = 0b00000000 ;
ADCON1 = 0b00001111 ;
INTCON2bits.RBPU = 0 ;
//////// I2C :
SSPSTATbits.SMP = 1 ; // 1=Slew rate control disabled
SSPSTAT=0b10000000 ; // Slew rate disabled, other bits are cleared
SSPCON1=0b00101000 ; // Enable SSP port for I2C Master mode
SSPCON2 = 0b00000000 ;
SSPADD = 0b00010011 ; // 19 = 100kHz , CLK = FOSC/(4*(SSPADD+1
PIE1bits.SSPIE = 1 ; // Enable SSPIF interrupt
PIR1bits.SSPIF = 0 ;
//### INITIALISATIONS :
LED = 0 ;
write_MS5837(0x1E) ; // RESET
C1 = read_MS5837(0b10100010, 2) ; // C1
C2 = read_MS5837(0b10100100, 2) ; // C2
C3 = read_MS5837(0b10100110, 2) ; // C3
C4 = read_MS5837(0b10101000, 2) ; // C4
C5 = read_MS5837(0b10101010, 2) ; // C5
C6 = read_MS5837(0b10101100, 2) ; // C6
D1 = read_MS5837(0x4A, 3) ; // D1, OSR=8192
D2 = read_MS5837(0x5A, 3) ; // D2, OSR=8192
return (EXIT_SUCCESS);
}
//####################################
void I2C_Start(char wr)
{
SSPCON2bits.SEN = 1 ; // Send start pulse
while(SSPCON2bits.SEN) ; // Wait for completion of start pulse
PIR1bits.SSPIF = 0 ;
if(wr==0) I2C_Write(slave_write_address) ; // Write slave device address with write=0 to communicate
else I2C_Write(slave_read_address) ; // Read slave device address with read=1 to communicate
}
void I2C_Ready(void)
{
while(!PIR1bits.SSPIF) ; // Wait for operation complete
PIR1bits.SSPIF = 0 ; // Clear SSPIF interrupt flag
}
char I2C_Write(unsigned char data)
{
I2C_Ready() ;
SSPBUF = data ; // Write data to SSPBUF
I2C_Ready() ;
if(SSPCON2bits.ACKSTAT) return 1 ; // Check for acknowledge bit
else return 2 ;
}
void I2C_Stop(void)
{
I2C_Ready() ;
SSPCON2bits.PEN = 1 ; // Stop communication
while(SSPCON2bits.PEN) ; // Wait for end of stop pulse
PIR1bits.SSPIF = 0 ;
// if(!SSPSTATbits.P) return 0 ; // Check whether STOP is detected last. If not return 0 to indicate start failed
}
char I2C_Read(char flag)
{
char buffer = 0 ;
SSPCON2bits.RCEN = 1 ; // Enable receive
while(!SSPSTATbits.BF) ; // Wait for buffer full flag which when complete byte received
buffer = SSPBUF ; // Copy SSPBUF to buffer
if(flag==0)
{
SSPCON2bits.ACKDT = 0 ; // Acknowledge data 1:NACK,0:ACK // Send acknowledgment or negative acknowledgment after read to continue or stop reading
SSPCON2bits.ACKEN = 1 ; // Enable ACK to send
while(SSPCON2bits.ACKEN) ;
}
else
{
SSPCON2bits.ACKDT = 1 ; // Acknowledge data 1:NACK,0:ACK
SSPCON2bits.ACKEN = 1 ; // Enable ACK to send
while(SSPCON2bits.ACKEN) ;
}
I2C_Ready() ;
return(buffer) ;
}
//####################################
void write_MS5837(unsigned char dat)
{
I2C_Start(0) ;
I2C_Write(dat) ;
I2C_Stop() ;
}
__uint24 read_MS5837(unsigned char add, unsigned char seize)
{
__uint24 dat=0, dat24 = 0 ;
I2C_Start(0) ;
write_MS5837(add) ;
I2C_Start(1) ;
if(seize==2) // READ C1-6
{
dat = I2C_Read(0) ;
dat24 = dat<<8 ;
dat = I2C_Read(1) ;
dat24 = dat24 | dat ;
}
else if(seize==3) // READ Pression/Température
{
write_MS5837(0x00) ; // ADC READ
__delay_ms(20) ; // Conversion time
dat = I2C_Read(0) ;
dat24 = dat<<16 ;
dat = I2C_Read(0) ;
dat24 = dat24 | (dat<<8) ;
dat = I2C_Read(1) ;
dat24 = dat24 | dat ;
}
I2C_Stop() ;
return dat24 ;
}
Pour l'instant tout ce que j'ai testé c'est rajouter un LED = 1 ; à différents endroits du code pour voir si ça bloque quelque part, et effectivement ça bloque dans I2C_Ready au niveau de while(!PIR1bits.SSPIF) ; mais je ne vois pas pourquoi...
Problème de communication I2C bloquante
Bonjour Superphénix,
La fonction I2C_Ready() doit être employée lorsqu'on attend que SSPIF passe à 1, son nom serait plutôt I2C_Wait() ou I2C_WaitFinished(). Au démarrage SSPIF est à 0, normal, il passera à 1 pour signaler un évènement.
Si tu la mets en début de I2C_Write() sans avoir lancé une action, un envoi d'octet par exemple, tu vas attendre très, très longtemps :)
L'idéal est que la remise à 0 de SSPIF soit faite uniquement dans la fonction ready, d'autant plus qu'il est à 0 au reset. Dans ce cas il faut l'utiliser aussi pour détecter la fin du START, RESTART, STOP, voir le schéma d'une transaction I2C complète.
La fonction I2C_Ready() doit être employée lorsqu'on attend que SSPIF passe à 1, son nom serait plutôt I2C_Wait() ou I2C_WaitFinished(). Au démarrage SSPIF est à 0, normal, il passera à 1 pour signaler un évènement.
Si tu la mets en début de I2C_Write() sans avoir lancé une action, un envoi d'octet par exemple, tu vas attendre très, très longtemps :)
Code : Tout sélectionner
void I2C_Ready(void)
{
while(!PIR1bits.SSPIF) ; // Wait for operation complete
PIR1bits.SSPIF = 0 ; // Clear SSPIF interrupt flag
}
char I2C_Write(unsigned char data)
{
I2C_Ready() ;
SSPBUF = data ; // Write data to SSPBUF
I2C_Ready() ;
if(SSPCON2bits.ACKSTAT) return 1 ; // Check for acknowledge bit
else return 2 ;
}
void I2C_Start(char wr)
{
SSPCON2bits.SEN = 1 ; // Send start pulse
while(SSPCON2bits.SEN) ; // Wait for completion of start pulse
PIR1bits.SSPIF = 0 ;
if(wr==0) I2C_Write(slave_write_address) ; // Write slave device address with write=0 to communicate
else I2C_Write(slave_read_address) ; // Read slave device address with read=1 to communicate
}
L'idéal est que la remise à 0 de SSPIF soit faite uniquement dans la fonction ready, d'autant plus qu'il est à 0 au reset. Dans ce cas il faut l'utiliser aussi pour détecter la fin du START, RESTART, STOP, voir le schéma d'une transaction I2C complète.
Problème de communication I2C bloquante
Voilà ce que cela donne avec SSPIF utilisé à toutes les sauces.
Je n'ai testé que l'écriture sur un oled.
Dans ton programme, pourquoi fais-tu SSPIE = 1, ce n'est pas nécessaire, SSPIF est indépendant de SSPIE. Le mécanisme qui lève les flags IF est actif en permanence. SSPIE permet juste de démarrer une routine d'interruption si SSPIF passe à 1.
Je n'ai testé que l'écriture sur un oled.
Code : Tout sélectionner
// write data
SSPCON2bits.SEN = 1; I2C_WaitFinished(); // start
SSPBUF = 0x78; I2C_WaitFinished(); // envoi adresse + write
if (!SSPCON2bits.ACKSTAT) { // adresse acquittée
SSPBUF = 0x81; I2C_WaitFinished(); // envoi data
}
SSPCON2bits.PEN = 1; I2C_WaitFinished(); // stop
// read data
SSPCON2bits.SEN = 1; I2C_WaitFinished(); // start
SSPBUF = 0x79; I2C_WaitFinished(); // envoi adresse + read
if (!SSPCON2bits.ACKSTAT) { // adresse acquittée
SSPCON2bits.RCEN = 1; I2C_WaitFinished(); // recevoir data
buffer = SSPBUF;
SSPCON2bits.ACKDT = 0; // 0:ACK 1:NACK
SSPCON2bits.ACKEN = 1;I2C_WaitFinished(); // envoi ACK ou NACK
}
SSPCON2bits.PEN = 1; I2C_WaitFinished(); // stop
Dans ton programme, pourquoi fais-tu SSPIE = 1, ce n'est pas nécessaire, SSPIF est indépendant de SSPIE. Le mécanisme qui lève les flags IF est actif en permanence. SSPIE permet juste de démarrer une routine d'interruption si SSPIF passe à 1.
Problème de communication I2C bloquante
-
Superphénix
Débutant- Messages : 54
- Enregistré en : mars 2020
Ça a résolut mon problème.
J'ai également rectifié read_MS5837()...
Du j'obtiens aussi les valeurs attendus :)
Code : Tout sélectionner
#include <XC.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#pragma config OSC = ECIO6
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config BOREN = OFF
#pragma config MCLRE = OFF
#pragma config PBADEN = OFF
#pragma config WDT = OFF
#pragma config LVP = OFF
#pragma config STVREN = OFF
#define _XTAL_FREQ 8000000
#define slave_write_address 0b11101100
#define slave_read_address 0b11101101
#define LED PORTCbits.RC5
unsigned short C1=0, C2=0, C3=0, C4=0, C5=0, C6=0 ; // 16 Bits
__uint24 D1=0, D2=0 ; // 24 Bits
signed int dT=0, TEMP=0 ; // 32 Bits , Utiliser var_inter64
signed long long OFF=0, SENS=0, var_inter64=0 ; // 64 Bits
unsigned int P=0 ; // 32 Bits , Utiliser var_inter64
signed int OFFi=0 ;
signed long long Ti=0, SENSi=0, OFF2=0, SENS2=0 ; // 64 Bits
signed short TEMP2=0 ; // 16 Bits , Utiliser var_inter64
__uint24 P2=0 ; // 24 Bits , Utiliser var_inter64
//### FONCTIONS déclarations :
void I2C_Start(char) ;
void I2C_Ready(void) ;
char I2C_Write(unsigned char) ;
void I2C_Stop(void) ;
char I2C_Read(char) ;
void write_MS5837(unsigned char) ;
__uint24 read_MS5837(unsigned char, unsigned char) ;
int main(int argc, char** argv)
{
TRISA = 0b10000000 ;
TRISB = 0b00111100 ;
TRISC = 0b00011000 ;
PORTA = 0b00000000 ;
PORTB = 0b00000000 ;
PORTC = 0b00000000 ;
ADCON1 = 0b00001111 ;
INTCON2bits.RBPU = 0 ;
//////// I2C :
SSPSTATbits.SMP = 1 ; // 1=Slew rate control disabled
SSPSTAT=0b10000000 ; // Slew rate disabled, other bits are cleared
SSPCON1=0b00101000 ; // Enable SSP port for I2C Master mode
SSPCON2 = 0b00000000 ;
SSPADD = 0b00010011 ; // 19 = 100kHz , CLK = FOSC/(4*(SSPADD+1
PIR1bits.SSPIF = 0 ;
LED = 0 ;
write_MS5837(0x1E) ; // RESET
C1 = read_MS5837(0b10100010, 2) ; // C1
C2 = read_MS5837(0b10100100, 2) ; // C2
C3 = read_MS5837(0b10100110, 2) ; // C3
C4 = read_MS5837(0b10101000, 2) ; // C4
C5 = read_MS5837(0b10101010, 2) ; // C5
C6 = read_MS5837(0b10101100, 2) ; // C6
D1 = read_MS5837(0x4A, 3) ; // D1, OSR=8192
D2 = read_MS5837(0x5A, 3) ; // D2, OSR=8192
return (EXIT_SUCCESS);
}
//####################################
void I2C_Start(char wr)
{
SSPCON2bits.SEN = 1 ; // Send start pulse
while(SSPCON2bits.SEN) ; // Wait for completion of start pulse
PIR1bits.SSPIF = 0 ;
if(wr==0) I2C_Write(slave_write_address) ; // Write slave device address with write=0 to communicate
else I2C_Write(slave_read_address) ; // Read slave device address with read=1 to communicate
}
void I2C_Ready(void)
{
while(!PIR1bits.SSPIF) ; // Wait for operation complete
PIR1bits.SSPIF = 0 ; // Clear SSPIF interrupt flag
}
char I2C_Write(unsigned char data)
{
SSPBUF = data ; // Write data to SSPBUF
I2C_Ready() ;
if(SSPCON2bits.ACKSTAT) return 1 ; // Check for acknowledge bit
else return 2 ;
}
void I2C_Stop(void)
{
SSPCON2bits.PEN = 1 ; // Stop communication
while(SSPCON2bits.PEN) ; // Wait for end of stop pulse
PIR1bits.SSPIF = 0 ;
}
char I2C_Read(char flag)
{
char buffer = 0 ;
SSPCON2bits.RCEN = 1 ; // Enable receive
while(!SSPSTATbits.BF) ; // Wait for buffer full flag which when complete byte received
buffer = SSPBUF ; // Copy SSPBUF to buffer
if(flag==0)
{
SSPCON2bits.ACKDT = 0 ; // Acknowledge data 1:NACK,0:ACK // Send acknowledgment or negative acknowledgment after read to continue or stop reading
SSPCON2bits.ACKEN = 1 ; // Enable ACK to send
while(SSPCON2bits.ACKEN) ;
}
else
{
SSPCON2bits.ACKDT = 1 ; // Acknowledge data 1:NACK,0:ACK
SSPCON2bits.ACKEN = 1 ; // Enable ACK to send
while(SSPCON2bits.ACKEN) ;
}
I2C_Ready() ;
return(buffer) ;
}
//####################################
void write_MS5837(unsigned char dat)
{
I2C_Start(0) ;
I2C_Write(dat) ;
I2C_Stop() ;
}
__uint24 read_MS5837(unsigned char add, unsigned char seize)
{
__uint24 dat=0, dat24=0 ;
write_MS5837(add) ;
if(seize==2) // READ C1-6
{
I2C_Start(1) ;
dat = I2C_Read(0) ;
dat24 = dat<<8 ;
dat = I2C_Read(1) ;
dat24 = dat24 | dat ;
}
else if(seize==3) // READ Pression/Température
{
__delay_ms(20) ; // Conversion time
write_MS5837(0x00) ; // ADC READ
I2C_Start(1) ;
dat = I2C_Read(0) ;
dat24 = dat<<16 ;
dat = I2C_Read(0) ;
dat24 = dat24 | (dat<<8) ;
dat = I2C_Read(1) ;
dat24 = dat24 | dat ;
}
I2C_Stop() ;
return dat24 ;
}
Qui est en ligne
Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 6 invités