Ich migriere diese Frage von StackOverflow in dieses Forum, weil ich glaube, dass sie angemessener ist.
Ich schreibe eine I2C-Slave-Routine für PIC18F25K80 und stecke bei einem seltsamen Problem fest.
Dies ist meine Routine: (BEARBEITET MIT DER NEUESTEN VERSION BASIERT AUF DEN KOMMENTAREN - NOCH DAS GLEICHE PROBLEM)
void interrupt interruption_handler() {
INTCON1bits.GIE = 0; // Disable Master Synchronous Serial Port Interrupt
if (PIR1bits.ADIF == 1) {
//This is a A/D interruption
PIR1bits.ADIF = 0;
INTCON1bits.GIE = 1; // Enable Master Synchronous Serial Port Interrupt
return;
} else
if (PIR1bits.SSPIF == 1) {
//This is a I2C interruption
PIR1bits.SSPIF = 0;
//Treat overflow
if ((SSPCON1bits.SSPOV) || (SSPCON1bits.WCOL)) {
dummy = SSPBUF; // Read the previous value to clear the buffer
SSPCON1bits.SSPOV = 0; // Clear the overflow flag
SSPCON1bits.WCOL = 0; // Clear the collision bit
SSPCON1bits.CKP = 1;
board_state = BOARD_STATE_ERROR;
} else {
if (!SSPSTATbits.D_NOT_A) {
//Slave address
debug(0, ON);
//Read address (A/D number)
address = SSPBUF; //Clear BF
while (BF); //Wait until completion
if (SSPSTATbits.R_NOT_W) {
SSPCON1bits.WCOL = 0;
unsigned char a = 0x01;
SSPBUF = a; //0x01; //a+1; //Deliver first byte
}
} else {
if (SSPSTATbits.BF) {
dummy = SSPBUF; // Clear BF (just in case)
while (BF);
}
if (SSPSTATbits.R_NOT_W) {
//Multi-byte read
debug(1, ON);
SSPCON1bits.WCOL = 0;
SSPBUF = 0x02; //Deliver second byte
} else {
//WRITE
debug(2, ON);
}
}
transmitted = TRUE;
SSPCON1bits.CKP = 1;
PIR1bits.SSPIF = 0; //Clear again just in case
INTCON1bits.GIE = 1; // Enable Master Synchronous Serial Port Interrupt
}
} else
PIR1 = 0x00; //Just in case
}
Es funktioniert wie ein Zauber, wenn ich konstante Werte für SSPBUF setze. Wenn Sie zum Beispiel Folgendes tun:
SSPBUF = 0x01;
(...)
SSPBUF = 0x02;
Ich bekomme die zwei Bytes auf dem Master. Ich kann sogar die Wellenformen der übertragenen Bytes auf dem Oszilloskop sehen. Ziemlich lustig!
Aber wenn ich versuche, SSPBUF mit einer Variablen wie der folgenden festzulegen:
unsigned char a = 0x01;
SSPBUF = a;
Beim Master bekomme ich null.
Es macht mich verrückt.
Einige Hypothesen, die ich verworfen habe:
Es ergibt keinen Sinn für mich. Wie gut ist es, wenn Sie keinen beliebigen Wert über eine Variable definieren können?
Bitte Gurus da draußen, klärt diesen armen Programmierer auf.
Vielen Dank im Voraus.
Schalten Sie den erweiterten Befehlssatz in Ihren Codes-Konfigurationsbiteinstellungen aus, dh:
#pragma config XINST = OFF // Extended Instruction Set (Disabled)
Es macht alle möglichen seltsamen Probleme, denken Sie nur daran, es von Anfang an auszuschalten.
I2C-Sachen geraten manchmal auch in Aufregung, wenn Sie keine kleine Verzögerung zwischen der Initialisierung von I2C, dem Aufrufen von Funktionen usw. einplanen.
Ich habe eine Problemumgehung gefunden. Es ist absolut umwerfend. Wenn ich mich wechsle:
SSPBUF = a;
Zu
SSPBUF = a+1;
Es klappt. Die Daten + 1 gehen an den I2C-Server. Ich denke, es hat etwas mit dem generierten Assembler-Code zu tun.
Lassen Sie uns die Optionen analysieren:
Der Code
SSPBUF = 0x23;
ergibt:
1548 ;naplaca.c: 320: SSPBUF = 0x2;
1549 00008A 0E02 movlw 2
1550 00008C D00F goto L3
(...)
1661 0000BA L3:
1662 0000BA 6EC9 movwf 4041,c ;volatile
Der Code:
unsigned char a = 0x2;
SSPBUF = a;//0x01; //Deliver first byte
ergibt:
1544 ;naplaca.c: 318: unsigned char a = 0x2;
1545 000086 0E02 movlw 2
1546 000088 6E11 movwf interruption_handler@a,c
1547
1548 ;naplaca.c: 319: SSPBUF = a;
1549 00008A C011 FFC9 movff interruption_handler@a,4041 ;volatile
Der Code:
unsigned char a = 0x2;
SSPBUF = a+1;//0x01; //Deliver first byte
ergibt:
1544 ;naplaca.c: 318: unsigned char a = 0x2;
1545 000086 0E02 movlw 2
1546 000088 6E11 movwf interruption_handler@a,c
1547
1548 ;naplaca.c: 319: SSPBUF = a+1;
1549 00008A 2811 incf interruption_handler@a,w,c
1550 00008C D00F goto L3
1551 00
(...)
1661 0000BA L3:
1662 0000BA 6EC9 movwf 4041,c ;volatile
Ich habe versucht, 0 zu summieren, aber der Compiler optimiert es und macht es gleich Option 2. Das gleiche passiert für a+1-1 und a+2-1-1.
Daher besteht die bisherige Problemumgehung darin, Daten + 1 zu senden.
Der Code:
volatile unsigned char a = 0x09;
SSPBUF = a;// byte1_0 + 1; //0x01; //Deliver first byte
ergibt:
1634 ;naplaca.c: 350: volatile unsigned char a = 0x09;
1635 000098 0E09 movlw 9
1636 00009A 6E11 movwf interruption_handler@a,c ;volatile
1637
1638 ;naplaca.c: 351: SSPBUF = a;
1639 00009C C011 FFC9 movff interruption_handler@a,4041 ;volatile
1640
Es scheint zu funktionieren, wenn der Compiler SSPBUF mit movwf einen Wert zuweist. Wenn es Move verwendet, funktioniert es nicht.
Ich poste dies als Antwort, aber ich werde es nicht als die richtige Antwort markieren. Ich hoffe jemand bringt etwas Licht in dieses Problem.
bitsmack
if (PIR1bits.SSPIF != 1)
) verursacht wurde, löschen Sie keine Interrupt-Flags. Wenn der Interrupt tatsächlich von einer anderen Interrupt-Quelle verursacht wurde, wird die ISR sofort wieder aufgerufen, für immer ...Schlagschmied
bitsmack
rdtsc
volatile unsigned char a = 0x01;
Schlagschmied
Gabor Móczik
Gabor Móczik
Schlagschmied