Hallo! Ich soll hier im Rahmen meiner Diplomarbeit einen PIC16F876A programmieren. Ich komme allerdings überhaupt nicht weiter. Ich will über die I^2C Schnittstelle des Controllerseinen EEPROM mit Daten beschreiben. Es scheitert jedoch schon an der Initialisierung der Schnittstelle. der PIC soll im MAster Mode arbeiten da ein Rückschreiben vom EEPROM zum PIC nicht erwünscht ist Hier ist mal der Code wie ich es probiert habe. #include "pic168x76a.h" #include "types_ksg1.h" #fuses HS,WDT,PUT,NOBROWNOUT,NOLVP,WRT_50% #use delay(clock=4000000) // 4 MHz void TransmitData(int); void main(void) { int Adresse = 00110110; int i; //Setup Ports TRISA = 0xff; //All Ports are Outputs TRISB = 0xC0; //All Ports are Outputs RB7/RB6 are Inputs TRISC = 0xff; // Setup Watchdog setup_wdt(WDT_288MS); // Bits setzen: //Slew rate control disabled for standard speed mode (100 kHz and 1 MHz) //Disable SMBus specific inputs SSPSTAT |=0x80; //Bit3 I2C Master mode, clock = FOSC/(4 * (SSPADD + 1)) //Bit5 Enables the serial port and configures the SDA and SCL pins as the serial port pins SSPCON1 |=0x28; // Bit rücksetzen //Register&=~BIT; // Bit toggeln //Register^=BIT; //for (i=0;i<6000000000;i++) //{ // PORTA = 0xff; // //PORTA = 0x00; //} TransmitData(Adresse); //Daten senden } void TransmitData(Zieladresse) { // Start Enable Bit setzen SEN = 1 SEN = 1; SSPBUF = Zieladresse; while (BF) { } } Ich weiß wirklich nicht mehr weiter. Ich bedanke mich schon einmal für die Hilfe. Gruss Basti...
Hast du Pullups an SDA und SCL? geh ans Oszi,und schau dir SCL an, vor dem Start sollte die Leitung High sein. Nach Start Low. Als nächstes kommt die Adresse. (9 Pulse auf der Leitung) Wenn die Adresse stimmt bekommst du ein ACK vom EEPROM und kannst Daten senden. das letzte Datenbyte wird mit NACK bestätigt. Wenn du ein Beispiel sehen willst für den Zugriff auf einen EEPROM bei Winavr in den examples findest du eins.
Pullups habe ich dran. Beide Leitungen (SDA , SCL) sind vor dem Start auf High. Nach dem Start geht der SCL tatsächlich auf LOW. Schon mal ein gutes Zeichen. Kann ich mit dem Oszi auch sehen wie die Adresse gesendet wird? Es ist doch richtig dass ich die zu sendende Adresse einfach in das SSPBUF Register schreibe mit dem Befehl SSPBUF = Zieladresse;
Das Example habe ich leider nicht gefunden. Das zweite Problem ist was ich habe, wenn ich starte gehen beide Leitungen auf LOW. Sowohl SCL als auch SDA. Gruss Basti...
Schau dir SDA auch mit an. Ich kenne es von AVR aber es sollte analog beim PIC sein. Im nächsten Schritt musst du noch angeben ob du lesen oder Schreiben willst. Wahrscheinlich muss das mit der Zieladresse verknüpft werden bevor es in das Datenregister geschrieben wird. siehe Datenblatt. Hast du die Modi und die Abfolge schon kapiert?
Laut Datenblatt muss ich das Start Enable Bit setzen mit SEN = 1; Dann warten bis die Startbedingung erfüllt ist (SCL auf High und in SDA ein Wechsel von High auf Low ) . Jetzt kann man die Daten in den SSPBUF schreiben. Wie ich die Wrtezeiten realisiere weiß ich auch nicht so richtig. Gruss Basti...
>Jetzt kann man die Daten in den SSPBUF schreiben und das erste Byte was rüber geht gibt an welche Adresse und ob du lesen oder schreiben willst. nennt sich SLA+W /SLA+R schau ins Datenblatt wie man das auf einem Pic erzeugt. Dann kommen die Datenbytes. Anbei das schon erwähnte Beispiel, ist zwar für den AVR sollte aber relativ gleich für den PIC sein.
Ja genau. Bei einem PIC ist es so, wenn das letzte Bit der Adresse eine 0 ist dann will man schreiben und bei einer 1 lesen. Ich habe jetzt dasd Problem das wenn ich das Programm starte das beide (SDA/SCL) auf null gehen was aber laut Datenblatt falsch ist. Sie sollten auf 1 bleiben bis das SEN Bit gesetzt wird.
Hallo, >//Setup Ports > >TRISA = 0xff; //All Ports are Outputs Stimmt der Kommentar zum Code? Wenn ja, dann stimmt der Code nicht... 0xff -> Input, 0x00 -> Output, >TRISC = 0xff; hier eventuell auch nochmal überprüfen ob I oder O gemeint ist.
Wenn du mir Bits an den Kopf schmeisst bringt uns das beiden nichts, da ich das vom AVR kenne. Wenn dann die I2C Zustände. Wichtig zwischen deine Versuchen jeweils einen Reset,da I2C eine Statemachine ist wo du nicht so ohne weiters von einem state in den anderen kommst. Gilt auch für den eeprom! Also nach der Startbedingung sagt der Mikrocontroller zu dir ok wenn er den Bus in Beschlag genommen hat. Dann kommt ein SLA+W wo du die Adresse des I2C Slaves angibst. als nächstes kommt das Kommando das an den Slave geht. Alles sollte jeweils mit ACK vom Slave bestätigt werden. Deshalb ist es wichtig das der Slave dranhängt.
ok. Einen Slave(EEPROM) habe ich noch nicht dranhängen. Daran könnt es ja dann liegen das sich an den Zuständen nichts mehr ändert. Ich glaube es ist aber auch schon falsch das beide Ausgänge auf Low gehen oder kann das an dem fehlenden Slave liegen???
Ach ja und der Kommentar zum Code ist falsch. Habe es berichtigt TRISA = 0xff; //All Ports are Inputs
ohne Slave kommst du über die Adresse nicht heraus da der Slave diese mit ACK bestätigen muss. Hast du das Datenblatt schon gelesen? Beim AVR sind das über 25 Seiten zum i2c Interface. Frage dich folgendes : Wie sieht eine Startbedingung auf dem i2c Bus aus? Solltest du dies nicht beantworten können, wäre es Zeit da nochmal nachzuschauen. Aber anscheinend hat sich ja noch ein PICcer eingefunden vielleicht bekommst du den Code von ihm. Allerdings würde ich es bei einer Diplomarbeit vorziehen es verstanden zu haben.
J habe ich gelesen. Sind auch bei dem PIC so um die 25 Seiten. Habe ich ja schon gemeinet die Startbedingung ist das der SDA von High auf Low geht während der SCL auf High bleibt. Das ist die Startbedingung. Nun kann die Adresse in den SSPBUF geschrieben werden. Diese wird dann von selbst gesendet. In dieser Zeit ist das BF Bit gersetzt welches im statusregister ist. Ich versuche jetzt mal den Slave anzuschließen und nochmal zu testen.
Mach mal weiter SCL kommt auch noch auf low... Ich mach Schluss für heute, viel Spass noch Beim Adresse senden nicht das letzte Bit vergessen
Also, PIC und I2C-Master... da gibt es eine Abfolge im Datenblatt des PICs... Ich habe es in PicBasic programmiert und es ist im Grunde so, daß jede Aktion (z.B. SEN) eingeleitet wird und von der Hardware mit einem SSPIF beantwortet wird. Der wird gelöscht und die nächste Aktion wird gesetzt und SSPIF abgewartet. Das Warten auf den SSPIF habe ich mit einem Timeout versehen... Es klappt prima ! Als Hilfe (Krücke): I2C_WR: I2C_ERR=1:SSPIF=0:SEN=1:Gosub Wait_SSPIF ;Start-Condition IF SSPIF Then SSPIF=0:SSPBUF=I2C_ADR:Gosub Wait_SSPIF ;Adresse setzen & Write-Modus If SSPIF Then SSPIF=0 If ACKSTAT=0 THEN SSPBUF=Dummy:Gosub Wait_SSPIF ;Byte schreiben If SSPIF Then SSPIF=0:IF ACKSTAT=0 Then I2C_ERR=0 Endif ENDIF Endif ENDIF PEN=1:Pause 1:Return ;Stop-Condition
Morgen!!! Also muss ich quasi in einer Schleife immer nachfragen ob SSPIF gesetzt ist und dann warten bis es wieder rückgesetzt wird bis ich die nächste Aktion durchführen kann. Ich habe es in C mal so realisiert void TransmitData(Zieladresse) { // Start Enable Bit setzen SEN = 1 SEN = 1; while(SSPIF) { //warten bis SSPIF rückgesetzt wird } SSPBUF = Zieladresse; // Puffer mit Adresse laden while (BF) { // BF ist während des sendens gesetzt // Warten bis BF null //dann nächste Aktion } //erneute Startbedingung SEN = 1; . . . . return; }
Falsch! SSPIF muß "von Hand" gelöscht werden, um dann von der Hardware wieder gesetzt zu werden, wenn die nächste Aktion abgeschlossen ist.
Also dann eher so void TransmitData(Zieladresse) { // Start Enable Bit setzen SEN = 1 SEN = 1; if(SSPIF) { SSPIF = 0; } SSPBUF = Zieladresse; //Zieladresse in Puffer laden while (BF) {} return; }
Hallo!!! Ich bin echt am Ende! Jetzt gehen beide Leitungen für ca. 20 us auf Low und dann gehen beide wieder hoch. Weiß einer was das für ein Phänomen ist??? Gruss Basti...
Kannst du mal deinen Programmcode gut Dokumentiert zeigen? Antwortet der EEPROM auf die Zieladresse mit ACK? Oszidiagramm der gesamten Kommunikation?
Nur so nebenbei, habe ich nach 10 sec. suchen auf der Microchip Seite gefunden. http://ww1.microchip.com/downloads/en/DeviceDoc/i2c.pdf
Hey!!! Ja klar hier ist er. Der EEPROM antwortet bis jetzt noch nicht. #include "pic168x76a.h" #include "types_ksg1.h" #fuses HS,WDT,PUT,NOBROWNOUT,NOLVP,CPD,PROTECT,WRT_50% #use delay(clock=4000000) // 4 MHz void TransmitData(int); void main(void) { int Adresse = 10100000; // Adresse des EEPROMS, letzte Null--> schreiben //Setup Ports TRISA = 0xff; //All Ports are Inputs TRISB = 0xC0; //All Ports are Outputs (RB7/RB6 are Inputs) TRISC = 0x18; //All Ports are Outputs (18 RC3/RC4 are Inputs) // Setup Watchdog // setup_wdt(WDT_288MS); // Bits setzen: //Slew rate control disabled for standard speed mode (100 kHz and 1 MHz) //Disable SMBus specific inputs SSPSTAT |=0x80; //Bit3 I2C Master mode, clock = FOSC/(4 * (SSPADD + 1)) //Bit5 Enables the serial port and configures the SDA and SCL pins as the serial port pins SSPCON1 |=0x28; TransmitData(Adresse); //Daten senden return; } void TransmitData(Zieladresse) { //Interrupt Flag löschen SSPIF =0; // Start Enable Bit setzen SEN = 1 STATUS_RP0 = 1; SEN = 1; STATUS_RP0 = 0; while(SSPIF = 0) {} SSPIF = 0; // Wenn Bus mein ist dann SSPIF rücksetzen SSPBUF = Zieladresse; //Zieladresse in Puffer laden while(BF) // abwarten bis fertig gesendet {} while(SSPIF = 0) // Warten bis senden abgeschlossen ist {} SSPIF = 0; // nach Erfolgreichem senden SSPIF wieder löschen //Datenbyte senden SSPBUF = 11110000; // Datenbyte in Puffer laden while(SSPIF = 0) // Warten bis senden abgeschlossen ist {} SSPIF = 0; // nach Erfolgreichem senden SSPIF wieder löschen // Bus wieder freigeben durch setzten des PEN Bits STATUS_RP0 = 1; PEN = 1; STATUS_RP0 = 0; while(SSPIF = 0) // Warten bis Bus wieder freigegeben ist {} SSPIF = 0; // Nach Freigabe Interrupt Flag wieder löschen PEN = 1; // STOP Bit setzen return; }
int Adresse = 10100000; Die Adresse des EEPROMS ist 10100000 dezimal? Das ist ja wohl nicht ganz ernst gemeint... Ich sehe im Moment nicht wo du du lesen oder schreiben als Richtung angibst. Das muss im Zusammenhang mit der Adresse erfolgen. TWI ist eine Stateengine da schaut man sich nach jedem Byte den Status an und reagiert entsprechend! Ich weiss nicht was du tun willst, also als erstes Start senden 2. Adresse des EEPROMs senden mit Richtung 3. Kommando an EEPROM <- Wo ist das? Schau dir nochmal das Beispiel an es ist doch eigentlich ganz klar gezeigt wie man mit einem EEPROM umgeht, auch wenn es ein anderer Prozessor ist.
Diese Präsentation habe ich schon mal gelesen,. Mein Programm ist auch stark daran orientiert. Trotzdem Danke!!!!
Die Richtung (in diesem Fall schreiben) ist in dem letzten Bit der Adressierung angegeben. Also 0 ist schreiben und 1 ist lesen.
int Adresse = 10100000; ist falsch ! dezimal 10100000 ist ...00100000 binär. Damit kann das EEPROM nicht angesprochen werden.
Morgen!!!! Bei dem EEPROM den ich benutze sind erst 5 Adressbits dann 2 Mode Bits und dann das R/W Bit. Also in der Form AAAAAMMR Dann ist ja bei mir die Adresse nur 10100. Das müsste doch gehen. Gruss Basti...
Du hast anscheinend wirklich ein Verständnisproblem.
Die Adresse die du nach der Startbedingung sendest ist die ADRESSE DES
EEPROMBAUSTEINS AM I2C BUS. Die Speicheradresse auf die du IM EEPROM
zugreifen willst teilst du ihm erst später in der Kommandosequenz mit.
Es gibt einen Unterschied zwischen Geräteadresse und und
Speicheradresse im eeprom.
>Dann ist ja bei mir die Adresse nur 10100. Das müsste doch gehen
nur zur Sicherheit, in C bedeutet die Anweisung
int Adresse=10100;
Erstelle eine Variable vom Typ Integer und weise ihr den Wert
zehntausendeinhundert dezimal zu.
Wenn du von der Form AAAAAMMR sprichst ist das binär gemeint.
Also laut dem Datenblatt kann ich gleich die Adresse des EEPROM's angerben wo ich hinschreiben will
auf Seite 9 ist die Adressierung beschrieben. Oder steh ich jetzt total auf dem schlauch???
Du hast es richtig verstanden Aber lies mal weiter bis Seite 12 Abschnitt 5.2.3 Behandlung nach Reset
Aha muss ich dann erst so tun als will ich ein Byte auslesen ohne ein ACK danach zu senden. Dann STOP senden und dann beginnen mit der Adresse???
>dann beginnen mit der Adresse???
erst noch Start
aber so würde ich es verstehen
ja so habe ich das ja gemeint. Ok ist ein Versuch wert. Geb dann Bescheid!
Wie sollte es auch anders sein. Es funktioniert immernoch nicht. Hier nochmal der abgeänderte Quellcode. #include "pic168x76a.h" #include "types_ksg1.h" #fuses HS,WDT,PUT,NOBROWNOUT,NOLVP,CPD,PROTECT,WRT_50% #use delay(clock=4000000) // 4 MHz void TransmitData(int); void main(void) { int Adresse = 00011011; // Aufweckbedingung für den EEPROM //Setup Ports TRISA = 0xff; //All Ports are Inputs TRISB = 0x00; //All Ports are Outputs TRISC = 0x18; //All Ports are Outputs (18 RC3/RC4 are Inputs) // Setup Watchdog setup_wdt(WDT_288MS); // Bits setzen: SSPADD = 0x09; //Slew rate control disabled for standard speed mode (100 kHz and 1 MHz) //Disable SMBus specific inputs SSPSTAT |=0x80; //Bit3 I2C Master mode, clock = FOSC/(4 * (SSPADD + 1)) //Bit5 Enables the serial port and configures the SDA and SCL pins as the serial port pins SSPCON1 |=0x28; // enable all interrupts GIE = 1; // Bit rücksetzen //Register&=~BIT; // Bit toggeln //Register^=BIT; //TransmitData(Adresse); //Daten senden return; } void TransmitData(AufweckAdresse) { int Zieladresse = 10100010; // Start Enable Bit setzen SEN = 1 //STATUS_RP0 = 1; SEN = 1; //STATUS_RP0 = 0; while(SSPIF=0) {} SSPIF = 0; // Wenn Bus mein ist dann SSPIF rücksetzen //STATUS_RP0 = 0; SSPBUF = AufweckAdresse; //Aufwecken des EEPROM's while(SSPIF = 0) // Warten bis senden abgeschlossen ist {} SSPIF = 0; // nach Erfolgreichem senden SSPIF wieder löschen PEN =1; // STOP Bit while(SSPIF = 0) // Warten bis STOP Bedingung beendet {} SSPIF = 0; // nach Erfolgreichem senden SSPIF wieder löschen // Start Enable Bit setzen SEN = 1 //STATUS_RP0 = 1; SEN = 1; //STATUS_RP0 = 0; // Zieladresse senden SSPBUF = Zieladresse; // Datenbyte in Puffer laden while(SSPIF = 0) // Warten bis senden abgeschlossen ist {} SSPIF = 0; // nach Erfolgreichem senden SSPIF wieder löschen //// Bus wieder freigeben durch setzten des PEN Bits ////STATUS_RP0 = 1; PEN = 1; ////STATUS_RP0 = 0; // //while(SSPIF = 0) // Warten bis Bus wieder freigegeben ist //{} ////SSPIF = 0; // Nach Freigabe Interrupt Flag wieder löschen //PEN = 1; return; }
Die // Kommentar Zeichen vor dem Funktionsaufruf gehören natürlich weg! Sorry...
Hi, Es wurde zwar oben schonmal erwähnt, aber würdest du bitte mal angeben was das heissen soll, int Zieladresse = 10100010; Wie kommst du auf diese Codierung , und welche Zahl ist das dezimal? Oder mal zum Nachdenken, welche Bitbreite hat SSPBUF? Was ist die größte Zahl die man dieser Bitbreite zuweisen kann (?) und welche Zahl versuchst du in SSPBUF reinzuschreiben?
Die Adresse für das EEPROM soll sein 10100. Die nächsten 2 Bit sind für den Modus. das heisst 01 bedeutet erst das low bit dann das high bit. Das letzte Bit, also 0 bedeutet das man etwas auf den EEPROM schreiben will.
In das SSPBUF Register passen acht Bit. Das sind doch nur acht Bit und müsste doch somit unproblematisch sein. Oder?
Oder! int Zieladresse = 10100010; welche Zahl ist das deiner Meinung nach dezimal???
Endlich mal ein richtig schöner langer Thread über die falsche Schreibweise von Zahlen gepaart mit einer gehörigen Portion Ignoranz.
Och, jetzt hast du die Selbsterkenntnis verhindert...
Schuldigung... Lösungswort wäre wohl eher "Zahlenformate in C" gewesen?!
Ok, lösen wir auf, so du das richtig codiert hast( habe ich jetzt nicht kontrolliert)entspricht die Bitfolge 10100010 binär dem Wert 162 dezimal oder 0xA2 hexadezimal. Mit int Zieladresse = 10100010; weist du die Zahl 10100010 dezimal zu die mit Sicherheit nicht in das erste Datenbyte(8bit) passt. Mit unsigned char Zieladresse = 0xA2; wird da schon eher ein 1.Datenbyte draus.
Ah ok! Is natürlich eigentlich logisch. Da hab ich garnicht drangedacht das darauf raus willst. Hab im Datenblatt nach der Lösung geschaut und nicht in meinem C Buch. Aber der Fehler ist somit mal entfernt.
Ok! Die Schnittstelle reagiert schon mal. Gutes Zeichen. Allerdings kann ioch in meinem Code die Zieladresse änddern wie ich will aber es kommt immer die gleiche Zeichenfiolge raus. Warum das???
>Ok! Die Schnittstelle reagiert schon mal Woran merkst du das? Bekommst du ein Ack? >Allerdings kann ioch in meinem Code die Zieladresse änddern wie ich >will aber es kommt immer die gleiche Zeichenfiolge raus. Warum das??? Keine Ahnung, du hast bis jetzt keinen Code gepostet in dem du einen Lesezugriff machst. Was mich interessieren würde: Was hast du eigentlich schon mit Mikrocontrollern gemacht?
Jup ich bekomme ein ACK zurück. Ich meine das ich auf dem Oszi immer die gleiche Zeichenfolge in Richtung EEPROM habe egal welche Adresse ich rausschicke. Es ist das erste mal das ich selber was mit uC mache. In der FH hatte ich irgendwann eine Vorlesung über uC. Da ging es aber eher um den Aufbau und Speicherverwaltung und weniger um die Programmierung. Wenn wir programmiert haben dann in asm und jetzt muss ich in C
>Ich meine das ich auf dem Oszi immer die gleiche Zeichenfolge in >Richtung EEPROM habe egal welche Adresse ich rausschicke. auf SDA? Oszibild? >Es ist das erste mal das ich selber was mit uC mache Das merkt man etwas, ist halt schlecht dass du damit erst zur Diplomarbeit anfängst. >Wenn wir programmiert haben dann in asm und jetzt muss ich in C Das sollte eigentlich bequemer sein, da du dich in C nicht mehr um die Registeraufteilung kümmern musst. Das Ansprechen der Peripherie ist ja das gleiche. Wenn du den Rest noch nicht programmiert hast, mach das erstmal. Das sollte Dir noch etwas Sicherheit in C und Mikrocontrollerprogrammierung geben. Wenn z.B. noch eine Kommunikation zum PC sein soll dann mach erst die serielle Schnittstelle. Die ist einfacher als ein I2C Protokoll.
Ja SDA ist auf dem Oszi immer gleich. Das Problem ist das meine Dipl Arbeit nicht bei null anfängt, sondern in ein bestehendes System integriert wird. Alle anderen Schnittstellen sind schon definiert. Der Rest läuft über die UART des Controllers. Ich wusste vor der Dipl Arbeit garnicht das es auf uC Programmierung rausläuft. Mein Betreuer auch nicht. Es sollte eigentlich eine NanoNet Funkstrecke werden. Naja ich hoffe ich kriege es hin. es wird ja langsam aber sicher. Ich finde ehrlich gesagt auch die Entwicklungsumgebung nicht so optimal. Ich arbeite hier mit dem MPLAB ICD2 von Microchip. Dieses Teil stürzt die ganze Zeit ab und man muss immer voll umständlich zwischen dem Programmierer und dem Debugger umschalten.
Jtzt funktioniert sie fast. Wenn ich step by step durchgehe kommen alle Signale wie erwartet. Allerdings ist wohl noch ein Timing Problem drin. Wenn ich es ganz normal durchlaufen lasse dann funktioniert es nicht. Hier der Code #include "pic168x76a.h" #include "types_ksg1.h" #fuses HS,WDT,PUT,NOBROWNOUT,CPD,PROTECT,NOLVP,WRT_50% #use delay(clock=4000000) // 4 MHz void TransmitData(unsigned char); void main(void) { unsigned char Adresse = 0x13; // Aufweckbedingung für den EEPROM //Setup Ports TRISA = 0xff; //All Ports are Inputs TRISB = 0x00; //All Ports are Outputs TRISC = 0x18; //All Ports are Outputs (18 RC3/RC4 are Inputs) // Setup Watchdog setup_wdt(WDT_288MS); // Bits setzen: SSPADD = 0x09; //Slew rate control disabled for standard speed mode (100 kHz and 1 MHz) //Disable SMBus specific inputs SSPSTAT |=0x80; //Bit3 I2C Master mode, clock = FOSC/(4 * (SSPADD + 1)) //Bit5 Enables the serial port and configures the SDA and SCL pins as the serial port pins SSPCON1 |=0x28; // Bit rücksetzen //Register&=~BIT; // Bit toggeln //Register^=BIT; TransmitData(Adresse); //Daten senden return; } void TransmitData(AufweckAdresse) { unsigned char Zieladresse = 0xA2; // Start Enable Bit setzen SEN = 1 STATUS_RP0 = 1; SEN = 1; STATUS_RP0 = 0; while(SSPIF = 0) // Warten bis Aktion abgeschlossen und bestätigt wird {} SSPIF = 0; // nach Erfolgreichem Abschluss SSPIF wieder löschen SSPBUF = AufweckAdresse; //Aufwecken des EEPROM's while(SSPIF = 0)// Warten bis Aktion abgeschlossen und bestätigt wird {} SSPIF = 0; // nach Erfolgreichem Abschluss SSPIF wieder löschen STATUS_RP0 = 1; PEN =1; STATUS_RP0 = 0; while(SSPIF = 0)// Warten bis Aktion abgeschlossen und bestätigt wird {} SSPIF = 0; // nach Erfolgreichem Abschluss SSPIF wieder löschen // Start Enable Bit setzen SEN = 1 STATUS_RP0 = 1; SEN = 1; STATUS_RP0 = 0; // Zieladresse senden SSPBUF = Zieladresse; // Datenbyte in Puffer laden while(SSPIF = 0)// Warten bis Aktion abgeschlossen und bestätigt wird {} SSPIF = 0; // nach Erfolgreichem Abschluss SSPIF wieder löschen // Datenbyte senden SSPBUF = 0x56; while(SSPIF = 0)// Warten bis Aktion abgeschlossen und bestätigt wird {} SSPIF = 0; // nach Erfolgreichem Abschluss SSPIF wieder löschen // Bus wieder freigeben durch setzten des PEN Bits STATUS_RP0 = 1; PEN = 1; STATUS_RP0 = 0; while(SSPIF = 0)// Warten bis Aktion abgeschlossen und bestätigt wird {} SSPIF = 0; // nach Erfolgreichem Abschluss SSPIF wieder löschen return; }
Warum setzt Du die STATUS_RP0-Bits ? C sollte doch das Bankumschalten beim Adressieren von Bits beherrschen ! ;-)
Ich wollte es so ausführlich wie möglich machen. HAst schon Recht, es funkt auch ohne. Hast du für das Timing Problem eine Idee???
>while(SSPIF = 0)// Warten bis Aktion abgeschlossen und bestätigt wird >{} >SSPIF = 0; // nach Erfolgreichem Abschluss SSPIF wieder löschen >STATUS_RP0 = 1; >PEN =1; >STATUS_RP0 = 0; bei sowas kommt keiner der den PIC nicht genau kennt mit das sind keine Kommentare sondern Beschreibungen der C Anweisung while(SSPIF = 0){} //Warten bis Zeichen übertragen wurde? wäre ein Kommentar Bei den folgenden Zeilen was macht dein Bitsetzen? z.B. Sende Startbedingung Das sind Kommentare bei denen jeder mitkommt und dies auch überprüfen kann ob du richtig die Bits codiert hast, im anderen Fall muss man erstmal erraten WAS du machen willst und du hast da schon einige Fehler drin gehabt... wenn du ihn nach dem Reset das erste mal ansprichst Also Startbedingung+Datenbyte Sendest du danach eine Stopbedingung? Was ich vermisse , wo überprüfst du auf ACK es könnte ja auch ein NACK kommen. Also auch wenn ich nicht nachvollziehen kann was du genau tust, in einem Fall wirst du mit Sicherheit hängenbleiben.
>while(SSPIF = 0)
müsste da nicht while(SSPIF == 0) stehen?
mit Sicherheit, naja dann ist ja klar warum das step by step geht und am Stück nicht...
So siehts jetzt aus. Aber es kommt kein ACK vom Slave zurück. #include "pic168x76a.h" #fuses HS,WDT,PUT,NOBROWNOUT,CPD,PROTECT,NOLVP,WRT_50% #use delay(clock=4000000) // 4 MHz void TransmitData(unsigned char); void main(void) { unsigned char Adresse = 0x13; // Aufweckbedingung für den EEPROM // Setup Watchdog setup_wdt(WDT_288MS); //Setup Ports TRISA = 0xff; //All Ports are Inputs TRISB = 0x00; //All Ports are Outputs TRISC = 0x18; //All Ports are Outputs (18 RC3/RC4 are Inputs) // Bits setzen: SSPADD = 0x09; //Slew rate control disabled for standard speed mode (100 kHz and 1 MHz) //Disable SMBus specific inputs SSPSTAT |=0x80; //Bit3 I2C Master mode, clock = FOSC/(4 * (SSPADD + 1)) //Bit5 Enables the serial port and configures the SDA and SCL pins as the serial port pins SSPCON1 |=0x28; TransmitData(Adresse); //Daten senden } void TransmitData(AufweckAdresse) { unsigned char Zieladresse = 0xA2; // Start Enable Bit setzen SEN = 1 SEN = 1; while(SSPIF == 0) // Warten bis Start Bedingung abgeschlossen {} SSPIF = 0; // nach Erfolgreichem Abschluss SSPIF wieder löschen SSPBUF = AufweckAdresse; //Aufwecken des EEPROM's while(SSPIF == 0) // Warten bis alle 8 Bit gesendet {} SSPIF = 0; // nach Erfolgreichem Abschluss SSPIF wieder löschen PEN =1; // stop bedingung setzen while(SSPIF == 0) // warten bis pause bedingung abgeschlossen {} SSPIF = 0; // nach erfolgreichem abschluss sspif wieder löschen //start enable bit setzen sen = 1 SEN = 1; // Zieladresse senden SSPBUF = Zieladresse; // Datenbyte in Puffer laden while(ACKSTAT == 1) // Auf ACK vom Slave warten {} while(SSPIF == 0)// Warten bis Aktion abgeschlossen und bestätigt wird {} SSPIF = 0; // nach Erfolgreichem Abschluss SSPIF wieder löschen // Datenbyte senden SSPBUF = 0x56; while(SSPIF == 0)// Warten bis Aktion abgeschlossen und bestätigt wird {} SSPIF = 0; // nach Erfolgreichem Abschluss SSPIF wieder löschen // Bus wieder freigeben durch setzten des PEN Bits PEN = 1; while(SSPIF == 0)// Warten bis Aktion abgeschlossen und bestätigt wird {} SSPIF = 0; // nach Erfolgreichem Abschluss SSPIF wieder löschen }
Danke, das liest sich schon wesentlich besser, Codierungen wie: SSPADD = 0x09; Solltest du angeben mit SSPADD = (1<<3)|(1<<1); besser lesbar wird es wenn die Bitnamen von den C Headerfiles definiert sind,dann steht da SSPADD = (1<<Bitname1)|(1<<Bitname2); das verhindert Fehler und ist besser lesbar. sind ACKSTAT,SSPIF,SEN Register der Seriellen Schnittstelle oder Bits im Register? Ich vermute sehr es sind Bitnamen, wenn ja greifst du falsch zu. um obiges Schema zu verwenden: Registername=(1<<0); oder Registername=(1<<PEN) Registername ist der Name des Registers in dem PEN steht. analog die anderen...
Ja ACKSTAT, SSPIF, SEN und PEN sind Bits in den Registern. Ich versuch es mal wie du es beschrieben hast. Danke!!!
Eine kleine Frage noch zu der Syntax z.B. SSPCON1 = (1<<SSPEN)|(1<<SSPM3) steht die 1<< für setzen tu ich dann mit 0<< ein Bit rücksetzen???
kontrollier noch in der Headerdatei ob die Bitpositionen stimmen als in #include <pic...> ist im include verzeichnis deines compilers zu deiner Frage ,der Blick in ein C-Buch wäre anzuraten 1<<x bedeutet verschiebe 1 um x nach links wenn du das mit dem Register oderst dann wird das jeweilige Bit gesetzt SSPCON1&=~(1<<SSPEN); ~ invertiert also du hast eine 1 an der Position von sspen der rest sind Nullen invertiert rest einsen an stelle SSPEN 0 dies wird mit dem Register geandet (UND) damit bleiben die restlichen Bits unangetastet egal ob 0 oder 1 und das Bit wird gelöscht.
>>steht die 1<< für setzen >>tu ich dann mit 0<< ein Bit rücksetzen??? mit 1<< Bitstelle schiebst du eigentlich nur eine 1 nach links um die Nummer "Bitstelle". Wenn du 0<< Bitstelle schreibst, wird halt eine 0 an diese stelle geschoben--> somit "löschst" du ein Bit. Ob das die ideale Schreibform für diesen Compiler ist, bin ich mir aber nicht so ganz sicher. Wieso hast du eigentlich den Watchdog aktiviert? dieser wird, wenn ich mich nicht irre, nie zurückgesetzt und sollte somit immer einen Reset verursachen oder etwa nicht?!
Den Watchdog Timer benötige ich noch für spätere Funktionen. Also in der Software wo mein Teil implementiert wird ist der Watchdog in Gebrauch. Für diese Funktion brauche ich ihn eigentlich nicht. Beim Debuggen muss man ihn aber eh ausschalten
Die Bitpositionen stimmen mit den Registern im Datenblatt überein.
Aber so wie ich die Bits vorher gesetzt hatte konnte ich im Prgrammablauf zusehen wie sie gesetzt bzw. rückgesetzt wurden. Dann kann das doch nicht sooo falsch sein wenns klappt, oder???
Wenn dem wirklich so ist dann müssen in der .h Datei noch irgendwelche Makros stehen. Schau dir mal den erzeugten Assemblercode an, denn Assembler kannst du ja. Wenn SSPIF ein Bit in einem Register ist würde ich erwarten das in der .h Datei irgendwas ala #define SSPIF Bitposition steht. also ein (1<<SSPIF) würde dann zu (1<<Bitpositon) deine Zuweisung SSPIF=0; wird zu Bitposition=0; was Syntaktisch korrekt ist, da allerdings keine Zuweisung auf eine Variable erfolgt wird der Optimierer dies rauswerfen.
Morgen!!! so siet es in der .h Datei aus #BYTE SSPCON2 = 0x91 #BIT GCEN = 0x91.7 #BIT ACKSTAT= 0x91.6 #BIT ACKDT = 0x91.5 #BIT ACKEN = 0x91.4 #BIT RCEN = 0x91.3 #BIT PEN = 0x91.2 #BIT RSEN = 0x91.1 #BIT SEN = 0x91.0 #BYTE PIR1 = 0x0C #define POS_RCIF 5 #define POS_TXIF 4 #define POS_FERR 2 #define POS_TMR1IF 0 #define POS_RX9D 0 #BIT PSPIF = 0x0C.7 #BIT ADIF = 0x0C.6 #BIT RCIF = 0x0C.5 #BIT TXIF = 0x0C.4 #BIT SSPIF = 0x0C.3 #BIT CCP1IF = 0x0C.2 #BIT TMR2IF = 0x0C.1 #BIT TMR1IF = 0x0C.0 Sind alle definiert. Aslo kann ich sie doch ala SEN = 1; ansprechen.
Ich würde mich jetzt nicht so an den Bitschiebereien aufhängen. Die Schreibweise mit den Pfeilen finde ich äußerst unübersichtlich. Ich arbeite mit PicBasic und auch da ist die Schreibweise mit dem Punkt gebräuchlich und besser lesbar. Aber jeder hat da so eine Vorlieben. Ich sehe eher noch Probleme im Programm! Mein I2C-Code arbeitet schon seit über 12 Monaten in Tausenden von Steuerungen und wurde der Empfehlung von Microchip nachempfunden. Jeder Schritt, den der Master machen muß, wird durch ein gesetztes SSPIF-Bit abgeschlossen, das man dann wieder löscht und sich die Status-Bits ansieht, ob alles OK war. Es gibt doch tonnenweise C-Code, der die I2C-Schnittstelle bedient.
Das mache ich ja. Immer warten bis eine Aktion erledigt ist indem man das SSPIF Bit beobachtet. Sobald es gesetzt wird kann man es wieder löschen und weiter machen mit der nächsten Anweisung. Ich habe irgendwie keinen brauchbaren code gefunden für den PIC16F876A
Ja schon, das ist egal aber ich habe trotzdem keine Programme gefunden und wenn dann in Assembler
so siehts jetzt aus. Wenn ich es schritt für schritt durchgehe dann klappts. Wenn ich es aber laufen lasse funkts nicht??? #include "pic168x76a.h" #include "types_ksg1.h" #fuses HS,WDT,PUT,NOBROWNOUT,CPD,PROTECT,NOLVP,WRT_50% #use delay(clock=4000000) // 4 MHz void TransmitData(unsigned char); void main(void) { unsigned char Adresse; // Aufweckbedingung für den EEPROM Adresse = 0x13; // Setup Watchdog setup_wdt(WDT_288MS); //Setup Ports TRISA = 0xff; //All Ports are Inputs TRISB = 0x00; //All Ports are Outputs TRISC = 0x18; //All Ports are Outputs (18 RC3/RC4 are Inputs) // Bits setzen: SSPADD = 0x09; //Slew rate control disabled for standard speed mode (100 kHz and 1 MHz) //Disable SMBus specific inputs SSPSTAT |=0x80; //Bit3 I2C Master mode, clock = FOSC/(4 * (SSPADD + 1)) //Bit5 Enables the serial port and configures the SDA and SCL pins as the serial port pins SSPCON1 |=0x28; TransmitData(Adresse); //Daten senden } void TransmitData(AufweckAdresse) { unsigned char Zieladresse = 0xA2; // Start Enable Bit setzen SEN = 1 SEN = 1; while(SSPIF == 0)// Warten bis Start Bedingung abgeschlossen {} SSPIF = 0;// nach Erfolgreichem Abschluss SSPIF wieder löschen SSPBUF = AufweckAdresse;//Aufwecken des EEPROM's while(SSPIF == 0) // Warten bis alle 8 Bit gesendet {} SSPIF = 0;// nach Erfolgreichem Abschluss SSPIF wieder löschen PEN =1; // stop bedingung setzen while(SSPIF == 0)// warten bis pause bedingung abgeschlossen {} SSPIF = 0;// nach erfolgreichem abschluss sspif wieder löschen //start enable bit setzen sen = 1 SEN = 1; // Zieladresse senden SSPBUF = Zieladresse; // Datenbyte in Puffer laden // while(ACKSTAT == 1) // Auf ACK vom Slave warten // {} while(SSPIF == 0)// Warten bis Aktion abgeschlossen und bestätigt wird {} SSPIF = 0;// nach Erfolgreichem Abschluss SSPIF wieder löschen // Datenbyte senden SSPBUF = 0x56; while(SSPIF == 0)// Warten bis Aktion abgeschlossen und bestätigt wird {} SSPIF = 0;// nach Erfolgreichem Abschluss SSPIF wieder löschen // Bus wieder freigeben durch setzten des PEN Bits PEN = 1; while(SSPIF == 0)// Warten bis Aktion abgeschlossen und bestätigt wird {} SSPIF = 0;// nach Erfolgreichem Abschluss SSPIF wieder löschen }
Hä ? Wie oft wird denn jetzt die Adresse gesendet ? Und gleich danach wieder Stop... und wieder Adresse und dann etwas Daten... Als Slave würde ich mich da auch vera***** vorkommen. ;-)
Na das erste sit um den PIC wieder zu aktivieren. So steht das im Datenblatt das man einen Lesewunsch senden soll ohne ein ACK zu senden. Dann geht es weiter mi der riochtigen Zieladresse. worauf auch gleich die Daten folgen.
Für alle die jetzt der Code interessiert die können ihn mal im Anhang bewundern. Aus Pin RB5 kann man Man´chester codierte Bits senden und die I2C funkt auch! Die meisten Fehler waren in den Voreinstellungen des Compilers und nicht im Code. Danke für die rege Beteiligung und Hilfe Gruss Basti...
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.