Forum: Mikrocontroller und Digitale Elektronik PIC18F2550 und I²C


von Sven E. (azu-fl)


Lesenswert?

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

von Severino R. (severino)


Lesenswert?

Kannst Du den Sourcecode posten, am besten reduziert auf das 
Wesentliche?

von Sven E. (azu-fl)


Lesenswert?

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

von azu-fl (Gast)


Lesenswert?

Moin nochmal!

Weiß jetzt schon einer mehr. Wäre echt nett. ;)

von Andreas K. (a-k)


Lesenswert?

Für PIC Assembler ist das hier die falsche Ecke, sprut oder 
fernando-heitor sind da wohl besser geeignet.

von holger (Gast)


Lesenswert?

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
}

von Sven E. (azu-fl)


Lesenswert?

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?

von Severino R. (severino)


Lesenswert?

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.

von Sven E. (azu-fl)


Lesenswert?

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

von Sven E. (azu-fl)


Lesenswert?

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
}

von holger (Gast)


Lesenswert?

Pullups eingebaut ?

von Sven E. (azu-fl)


Lesenswert?

Ja die sind dran. 1,8k

von Severino R. (severino)


Lesenswert?

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

von Sven E. (azu-fl)


Lesenswert?

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.^^

von holger (Gast)


Lesenswert?

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
}

von Sven E. (azu-fl)


Lesenswert?

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.

von holger (Gast)


Lesenswert?

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.

von azu-fl (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.