Wie von meinen Stacker-Kollegen in meinem vorherigen Beitrag empfohlen, habe ich die „Write_to_slave“-Funktion in Proteus ebenfalls in Echtzeit getestet, indem ich Bytes an die RTC gesendet habe und der Slave entsprechend mit einem Bestätigungsbit für jedes empfangene Byte antwortet, daher die Der Schreibvorgang funktioniert einwandfrei. Jetzt habe ich jedoch Probleme mit meiner Funktion "Read_from_slave". Das Problem ist, dass es während der Lesesequenz bis zum Senden der "Slave-Adresse + Lesen" dh 0xD1 funktioniert und auch eine Bestätigung vom Slave erhält, aber das Problem tritt nach der Ausführung der I2C_restart-Funktion auf. Die vom SSPBUF gelesenen oder vom Slave empfangenen Daten sind FF, während es die Sekunden sein sollten, die von 0 bis 60 zählen (und 63 auf dem LCD anzeigen), gefolgt von einem NACK. Und nach dem Senden des NACK, I2C_stop() sollte die Transaktion beenden, während dies nicht geschieht, wie Sie in Proteus Snapshot sehen können. Unten ist der Code, ich habe nur einen Lesevorgang durchgeführt, um das Sekundenregister zu lesen, um zu überprüfen, ob meine Methode funktioniert, aber leider nicht:
void Wait_MSSP()
{
while(SSPIF==0);
SSPIF = 0;
}
void check_ACK_Master_Transmit()
{
if(SSPCON2bits.ACKDT == 0) //If ACKDT is 0, ACK has been recieved
arraydisp("ACK success");
else if (SSPCON2bits.ACKDT == 1) //If ACKDT is 1, ACK has not been recieved
arraydisp("ACK fail");
}
unsigned char Read_from_slave(unsigned char addr)
{
unsigned char x;
I2C_start();
SSPBUF = RTC_ADDRW;
Wait_MSSP(); //Slave address+Write
SSPBUF = addr;
Wait_MSSP(); ////RTC register to be read
I2C_restart();
SSPBUF = RTC_ADDRR;
Wait_MSSP();
SSPCON2bits.RCEN = 1; //Enable Master to receive data from slave
x = SSPBUF; //Read the SSPBUF
SSPCON2bits.ACKDT = 1; //send NACK after receiving the data
SSPCON2bits.ACKEN = 1; //Enable Acknowledge sequence on SDA and SCL
I2C_stop(); //Wait until stop operation is completed
return(x);
}
void Write_to_slave(unsigned char addr, unsigned char data)
{
I2C_start();
SSPBUF = RTC_ADDRW; //Slave address + Write
Wait_MSSP();
check_ACK_Master_Transmit(); //Checks the
SSPBUF = addr; // RTC Registor location address to be written
Wait_MSSP();
check_ACK_Master_Transmit();
SSPBUF = data; //data to be writen to the address location
Wait_MSSP();
check_ACK_Master_Transmit();
I2C_stop();
Wait_MSSP();
}
void I2C_write(unsigned char addr)
{
PIR1bits.SSPIF = 0;
SSPBUF = addr;
while(PIR1bits.SSPIF == 0);
return;
}
void Reset_time()
{
I2C_start();
I2C_write(RTC_ADDRW);
I2C_write(0x00);
I2C_write(0x00);
I2C_write(0x00);
I2C_write(0x01);
I2C_write(0x01);
I2C_write(0x01);
I2C_write(0x01);
I2C_write(0x00);
I2C_stop();
return;
}
void Set_time()
{
Write_to_slave(0x00,0x00); //Write data 0x00 to address 00H (Seconds) of RTC (CH = 0)
Write_to_slave(0x01,0x30); //Write data 0x00 to address 01H(Minutes) of the RTC
Write_to_slave(0x02,0x10); //Write data 0x00 to address 02H(HOUR) of the RTC
Write_to_slave(0x03,0x06); //Write data 0x01 to address 03H (DAY) of the RTC
Write_to_slave(0x04,0x01); //Write data 0x01 to address 04H (Date) of the RTC
Write_to_slave(0x05,0x01); //Write data 0x01 to address 05H (Month) of the RTC
Write_to_slave(0x06,0x16); //Write data 0x00 to address 06H (Year) of the RTC
}
void main()
{
TRISCbits.TRISC0 = 0;
TRISCbits.TRISC1 = 0;
TRISCbits.TRISC2 = 0;
TRISD = 0;
char16x2LCDInit();
I2C_Init();
Reset_time();
Set_time();
while(1)
{
sec = Read_from_slave(0x00);
__delay_ms(10);
Write_Command(0xC0);
LCDWriteInt(BCD2Lowerch(sec),1);
LCDWriteInt(BCD2Upperch(sec),1);
}
}
Nur für ein klares Bild der Transaktionen, die auf dem I2C-Bus stattfinden, habe ich eine Momentaufnahme des I2C-Debugger-Fensters beigefügt, das die I2C-Operationen während der Simulation in Proteus anzeigt. Die erste Sequenz ist wie folgt: S = Start, D0 = Slave-Adresse + Schreiben, A = Bestätigung vom Slave, 05 = Registeradresse in der RTC, A = Bestätigung vom Slave, 01 = Daten auf 05H geschrieben, A = Bestätigung vom Slave, P = Stopp. Ähnlich für andere Schreibzyklen und auch Lesen, während beim Lesen „Sr“, dh I2C_restart, gefolgt von „N“ NACK ist, und wie wir sehen können, gibt es kein „P“, dh Stopp nach NACK. Ich habe auch das Bild der Hardware beigefügt. Ich habe den Slave als Sendermodus im DS1307-Datenblatt erneut gelesen, aber ich finde nichts Falsches an der Sequenz "Read_from _slave".
Entschuldigen Sie die langwierige Nachricht, da weitere Ratschläge oder Anweisungen zu meinem Ansatz zur Durchführung des Lesevorgangs oder zur Identifizierung von Problemen mit den Methoden eine große Hilfe wären. Danke noch einmal!
Gruß ~VD
Ein sehr häufiger Grund, warum Sie ein 0xFF erhalten, ist, dass die SCL-Leitung des I2C nicht lange genug gehalten wird, damit der Slave Daten übertragen kann. Ich schlage also vor, eine Verzögerung von beispielsweise 10 Mikrosekunden hinzuzufügen, um die Uhr nach der i2c-Lesefunktion zu dehnen und zu prüfen, ob Sie Daten empfangen. Es ist im Grunde eine Trial-and-Error-Methode. Erhöhen Sie einfach die Verzögerung, bis Sie relevante Daten erhalten. Ich hatte das gleiche Problem schon einmal mit einem Atmega und es wurde tatsächlich auf SE gelöscht: P.
sec = Read_from_slave(0x00); //Read address 00H(Seconds) from the RTC and display on LCD
_delay_ms(10); //add a small delay to stretch the clock.
Write_Command(0xC0);
Hoffe, es funktioniert! Und wenn es funktioniert, versuchen Sie, die Verzögerung zu verringern, damit Sie Ihre Werte in möglichst kurzer Zeit erhalten.
Ich bin mir nicht sicher, aber:
SSPBUF = addr; //RTC register to be read
check_ACK_Master_Transmit();
Wait_MSSP();
Anscheinend haben Sie zuerst nach dem ACK gesucht, bevor Sie auf die Bestätigung der erfolgreichen Übertragung gewartet haben. Dies ist auch in Ihrer vorhanden write_to_slave()
. Vielleicht könnten Sie versuchen, die Reihenfolge zu ändern, nur für den Fall.
Unten ist der Fluss, den ich regelmäßig verwende, um Daten von DS1307 zu lesen.
1. Senden Sie START.
2. Schreiben Sie SLAVE_ADDR + W. 3. Holen Sie sich eine Bestätigung
vom Slave von Slave 6. Senden Sie REPEATED_START 7. Schreiben Sie SLAVE_ADDR + R 8. Erhalten Sie ACK von Slave 9. Warten Sie auf DATA 10. Senden Sie ACK, um die nächsten DATA von ds1307 zu erhalten, und gehen Sie dann zu Schritt 9 11. Senden Sie NACK, um die Übertragung zu stoppen 12. Senden Sie STOP
In Ihrer Funktion Read_from_slave() sind step-6 und step-7 vertauscht, dh Sie senden RTC_ADDRR, bevor Sie I2C_restart() ausgeben.
Außerdem müssen Sie warten, bis die Übertragung abgeschlossen ist, und dann prüfen, ob Sie ACK oder NACK erhalten haben, wie von anderen Mitgliedern vorgeschlagen.
PsychedGuy
brhans
PsychedGuy