Moin! Ich versuche mich hier grade mit dem PIC18F2550 an einer I²C-Bus Schaltung. Ich habe mir bei sprut alles angelesen und auch versucht, sein Beispielprogramm für den PIC16F87x für meinen PIC abzuändern. Leider ohne Erfolg. Auf der SCL Leitung kommt nichts an und auf der SDA konnte ich mit dem Oszilloskop auch keine Signale erkennen. Vielleicht könnt ihr mir ja ein paar Tipps geben, wo mein Fehler liegt. Oder wenn ihr mehr Informationen braucht, fragt bitte. ;) Danke schonmal im Vorraus! Lg der Azu
Das ist es.
1 | #include <P18F2550.inc> |
2 | |
3 | |
4 | ; einstellen von RB0 & RB1 auf input |
5 | banksel TRISB ; Bank 1 |
6 | movlw B'00000011' ; RB0,1 inputs |
7 | movwf TRISB |
8 | banksel TRISC |
9 | movlw B'00000011' |
10 | iorwf TRISC, f ; + RC2=CCP1 output |
11 | |
12 | |
13 | ; einstellen des I2C-Taktes auf 100 kHz |
14 | banksel SSPADD ; Bank 1 |
15 | movlw d'9' ; clock = 4 MHz /(4*(9+1)) = 100kHz |
16 | movwf SSPADD ; für I2C |
17 | |
18 | |
19 | banksel SSPCON1 |
20 | movlw B'00001000' ; master mode, clock=Fosc/(4*(SSPADD+1)) |
21 | movwf SSPCON1 ; |
22 | |
23 | |
24 | bsf SSPCON1, SSPEN ; MSSP-Modul enable |
25 | |
26 | |
27 | |
28 | |
29 | ;**Schreibe Wert 5 auf Speicher-Adresse 3 in PCF8574AP**************************** |
30 | |
31 | call i2c_on ; Bus aktiv |
32 | movlw B'01110000' ; 0 111 '000' 0 |
33 | call i2c_tx ; PCF8574AP zum Schreiben adressieren |
34 | |
35 | movlw B'00000000' ; high Teil der Adresse (Page) |
36 | call i2c_tx |
37 | movlw B'01110000' ; low Teil der Adresse |
38 | call i2c_tx |
39 | |
40 | movlw B'10101010' ; Wert der auf Adresse 3 soll |
41 | call i2c_tx |
42 | |
43 | call i2c_off ; Bus freigeben |
44 | |
45 | |
46 | |
47 | ;***I2C UNTERPROGRAMME************************************************************ |
48 | ; |
49 | ; I2C-Bus im Master-Mode übernehmen |
50 | i2c_on |
51 | banksel PIR1 |
52 | bcf PIR1, SSPIF ; SSPIF Bit löschen |
53 | banksel SSPCON2 |
54 | bsf SSPCON2, SEN ; Bus Übernahme anweisen |
55 | goto i2c_warte |
56 | |
57 | ; ein Byte aus W senden |
58 | i2c_tx |
59 | banksel SSPBUF |
60 | movwf SSPBUF ; -> zum I2C-Slave übertragen |
61 | goto i2c_warte |
62 | |
63 | ;ein Byte vom Slave empfangen (nach SSPBUF) |
64 | i2c_rx |
65 | banksel SSPCON2 |
66 | bsf SSPCON2, RCEN ; Daten Empfang einschalten |
67 | goto i2c_warte |
68 | |
69 | ; I2C-Bus wieder freigeben |
70 | i2c_off |
71 | banksel SSPCON2 |
72 | bsf SSPCON2, PEN ; Bus Freigabe anweisen |
73 | |
74 | i2c_warte |
75 | banksel PIR1 |
76 | btfss PIR1, SSPIF ; fertig? |
77 | goto i2c_warte ; nein, noch nicht |
78 | bcf PIR1, SSPIF ; ja, alles fertig, nun noch SSPIF zurücksetzen |
79 | return |
80 | |
81 | ;***ENDE UNTERPROGRAMME********************************************************** |
82 | |
83 | end |
Für PIC Assembler ist das hier die falsche Ecke, sprut oder fernando-heitor sind da wohl besser geeignet.
Ist zwar kein Assembler, aber vieleicht reicht es als Tip ;) //############################################################ void I2C_STOP(void) { SSPCON2bits.PEN=1; //Sende Stopcondition while(SSPCON2bits.PEN); //warten bis Stopcondition beendet ist } //############################################################ void I2C_START(void) { SSPCON2bits.SEN=1; //Sende Startcondition while(SSPCON2bits.SEN); //warten bis Startcondition beendet ist }
1 | #include <p18f2550.h> |
2 | #include <i2c.h> |
3 | #include <p18cxxx.h> |
4 | |
5 | |
6 | #pragma config OSC = XT //CPU=4 MHz
|
7 | #pragma config PWRT = ON
|
8 | #pragma config BOR = OFF
|
9 | #pragma config WDT = OFF //Watchdog Timer
|
10 | #pragma config LVP = OFF //Low Voltage ICSP
|
11 | |
12 | |
13 | |
14 | INT8S steps1 = 0; |
15 | INT8S steps2 = 0; |
16 | INT16S steps = 0; |
17 | |
18 | |
19 | unsigned char I2CEmpfang(unsigned char Adresse); |
20 | |
21 | |
22 | |
23 | unsigned char I2CEmpfang(unsigned char Adresse) |
24 | {
|
25 | IdleI2C(); |
26 | StartI2C(); |
27 | IdleI2C(); |
28 | putcI2C(Adresse); |
29 | IdleI2C(); |
30 | if ( SSPCON2bits.ACKSTAT ) |
31 | {
|
32 | StopI2C(); |
33 | return 0; //Return 0 Not ACK |
34 | }
|
35 | steps1 = ReadI2C(); |
36 | IdleI2C(); |
37 | AckI2C(); |
38 | IdleI2C(); |
39 | steps2 = ReadI2C(); |
40 | IdleI2C(); |
41 | AckI2C(); |
42 | StopI2C(); |
43 | }
|
44 | |
45 | |
46 | |
47 | void main(void) |
48 | {
|
49 | |
50 | TRISC = 0xFF; |
51 | #define AdresseHandrad (0xA1)
|
52 | |
53 | //Konifiguration I2C Master
|
54 | SSPSTATbits.SMP = 1; //Slew Rate aus |
55 | SSPSTATbits.CKE = 0; // SMBus Inputs Disabled |
56 | SSPCON1 = 0b00101000; // MSSP ein in Mastermodus |
57 | SSPCON2 = 0b00001000; // Receive enable |
58 | SSPADD = 24; //Bus Takt 100Khz @ 10Mhz crystal |
59 | |
60 | Nop(); |
61 | |
62 | while(1) |
63 | {
|
64 | //Empfange 2 Datenbytes vom Handrad
|
65 | I2CEmpfang(AdresseHandrad); |
66 | // Adresse Handrad = A0 zum lesen verwende ich daher A1
|
67 | Nop(); |
68 | |
69 | |
70 | }
|
71 | }
|
Dieses Programm haben wir jetzt, aber wir können es nicht compilieren. Der Compiler meckert mit dem Error [1224] wegen dem "OSC" herum. Weiß einer Rat?
Versuchs mal mit #pragma config OSC = XT_XT //CPU=4 MHz Eventuell musst Du das Setting im Manual "PIC18 CONFIGURATION SETTINGS ADDENDUM" (Dokument 51537D) prüfen. Es gibt ein Dutzend Möglichkeiten, aber keine die nur XT heisst.
Ah tatsächlich. Danke! Im Addendum haben wir was gefunden. Es muss FOSC heißen. Jetzt sind zwar noch andere Fehler aufgetreten, aber wir versuchen es erstmal zu Fuß. Ich melde mich, wenn ich wieder Hilfe brauche. :P
So ... das Compilieren klappt nun, aber wenn wir den PIC in die fertige Schaltung einsetzen, haben wir nichtmal einen Takt auf dem CLK des I²C Bus.
1 | #include <p18f2550.h> |
2 | #include <i2c.h> |
3 | #include <p18cxxx.h> |
4 | |
5 | |
6 | #pragma config FOSC = XT_XT //CPU=4 MHz
|
7 | #pragma config PWRT = ON
|
8 | #pragma config BOR = OFF
|
9 | #pragma config WDT = OFF //Watchdog Timer
|
10 | #pragma config LVP = OFF //Low Voltage ICSP
|
11 | |
12 | |
13 | |
14 | int steps1 = 0; |
15 | int steps2 = 0; |
16 | int steps = 0; |
17 | |
18 | |
19 | unsigned char I2CEmpfang(unsigned char Adresse); |
20 | |
21 | |
22 | |
23 | unsigned char I2CEmpfang(unsigned char Adresse) |
24 | {
|
25 | IdleI2C(); |
26 | StartI2C(); |
27 | IdleI2C(); |
28 | putcI2C(Adresse); |
29 | IdleI2C(); |
30 | if ( SSPCON2bits.ACKSTAT ) |
31 | {
|
32 | StopI2C(); |
33 | return 0; //Return 0 Not ACK |
34 | }
|
35 | steps1 = ReadI2C(); |
36 | IdleI2C(); |
37 | AckI2C(); |
38 | IdleI2C(); |
39 | steps2 = ReadI2C(); |
40 | IdleI2C(); |
41 | AckI2C(); |
42 | StopI2C(); |
43 | }
|
44 | |
45 | |
46 | |
47 | void main(void) |
48 | {
|
49 | |
50 | TRISC = 0xFF; |
51 | #define AdresseHandrad (0xA1)
|
52 | |
53 | //Konifiguration I2C Master
|
54 | SSPSTATbits.SMP = 1; //Slew Rate aus |
55 | SSPSTATbits.CKE = 0; // SMBus Inputs Disabled |
56 | SSPCON1 = 0b00101000; // MSSP ein in Mastermodus |
57 | SSPCON2 = 0b00001000; // Receive enable |
58 | SSPADD = 24; //Bus Takt 100Khz @ 10Mhz crystal |
59 | |
60 | Nop(); |
61 | |
62 | while(1) |
63 | {
|
64 | //Empfange 2 Datenbytes vom Handrad
|
65 | I2CEmpfang(AdresseHandrad); |
66 | // Adresse Handrad = A0 zum lesen verwende ich daher A1
|
67 | Nop(); |
68 | |
69 | |
70 | }
|
71 | }
|
Achtung! Es hat zwar keinen Einfluss auf das Fehlen des Takts, aber #pragma config FOSC = XT_XT //CPU=4 MHz .. .. SSPADD = 24; //Bus Takt 100Khz @ 10Mhz crystal 4 != 10
Ja stimmt. Bei SSPADD muss eine 9 rein. Danke! Aber das löst wie du bereits sagtest das Problem mit dem fehlenden Takt noch nicht.^^
Kein Takt kann auch bedeuten das das Programm sich einfach aufhängt. Jetzt musst du mal feststellen wo ! Und nimm mal diese Routine. unsigned char I2CEmpfang(unsigned char Adresse) { IdleI2C(); StartI2C(); while ( SSPCON2bits.SEN ); // wait until start condition is over IdleI2C(); WriteI2C(Adresse | 0x01); // Wieso putcI2C(Adresse); ? IdleI2C(); if ( SSPCON2bits.ACKSTAT ) { StopI2C(); while ( SSPCON2bits.PEN ); // wait until stop condition is over return 0; //Return 0 Not ACK } steps1 = ReadI2C(); IdleI2C(); AckI2C(); IdleI2C(); steps2 = ReadI2C(); IdleI2C(); AckI2C(); StopI2C(); while ( SSPCON2bits.PEN ); // wait until stop condition is over }
Wenn ich das im Simulator teste, geht er immer zu den Abfragen und wartet auf das PIR1 bit im SSPCON Register. Das ist ja die Antwort vom Slave. Wenn ich dieses Bit manuell setze springt er weiter und wartet in der nächsten Routine auf das PIR1. So geht das immer weiter, bis der Simulator die Simulation mit Hardware Stack Underflow beendet.
Als erstes noch mal zu deinem ASM-Code >;**Schreibe Wert 5 auf Speicher-Adresse 3 in >PCF8574AP**************************** > > call i2c_on ; Bus aktiv > movlw B'01110000' ; 0 111 '000' 0 > call i2c_tx ; PCF8574AP zum Schreiben adressieren > > movlw B'00000000' ; high Teil der Adresse (Page) > call i2c_tx > movlw B'01110000' ; low Teil der Adresse > call i2c_tx > > movlw B'10101010' ; Wert der auf Adresse 3 soll > call i2c_tx > > call i2c_off ; Bus freigeben Das ist eine Sequenz für ein I2C EEPROM. Für PCF8574A nicht geeignet ! Warum nicht ? Der PCF8574 hat nur ein Register. Speicher Adressen kennt der nicht. Dann zum C-Code >#define AdresseHandrad (0xA1) Die Adresse des PCF8574A ist 0x70. Der C-Code lässt sich sicher nur mit einigen warnings compilieren. >#define AdresseHandrad (0xA1) #define mitten in der main.c unsigned char I2CEmpfang(unsigned char Adresse) gibt keinen return Wert zurück. >Wenn ich das im Simulator teste Der Simulator gibt dir sicher kein ACK. Das kann nur der Slave. Und der ist im Simulator nicht drin. >wartet auf das PIR1 bit im SSPCON Register PIR1 ist ein Register. SSPCON ist ein Register. PIR1 kann kein Bit in SSPCON sein. Beim PIC18F2550 gibt es auch nur SSPCON1 und SSPCON2. SSPCON kennt der nicht.
Danke für die ausführliche Antwort! Also ds Beste wäre für uns, wenn wir den ASM Code ans Laufen kriegen würden. Vielleicht hilft uns dein Tipp da ja schon. Mal schauen. Ja, dass der Simulator mir kein ACK geben kann, weiß ich. Daher meinte ich ja das mit dem SSPCON und dem PIR1. Hab mich da etwas vertan. Ich meinte das SSPIF Bit im PIR1 Register. Darauf wartet das Programm im Simulator ständig und wenn ich ihm das manuell gebe, springt er in die nächste Schleife und wartet wieder auf das SSPIF, bis er irgendwann mit Hardware Stack Underflow endet.
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.