Forum: Mikrocontroller und Digitale Elektronik seltsames Problem mit mikroC for PIC


von Michael S. (rbs_phoenix)


Lesenswert?

Hallo zusammen. Ich bin dabei eine Kommunikation von 2 PICs über I²C zu 
realisieren. Da ich erstmal mit I²C selber klarkommen will, will ich 
erstmal etwas in ein I²C-EEPROM schreiben und auslesen. Hierfür benutze 
ich einen PIC16F1937 bei 8MHz internen Takt und 4xPLL:
1
sbit button1 at RA0_bit;
2
3
void init(){
4
     OSCCON = 0b11110010; // 1-PLL Enable, 1110-8MHz internal Oscillator,
5
                          // 0-unimplemented, 10-Internal oscillator block
6
     ADCON0 = 0;
7
     ADCON1 = 0;
8
     ANSELA = 0;
9
     ANSELB = 0;
10
     ANSELD = 0;
11
     ANSELE = 0;
12
     DACCON0 = 0;
13
     CM1CON0 = 0;
14
     CM2CON0 = 0;
15
     LCDCON = 0;
16
     CCP1CON = 0;
17
     CCP2CON = 0;
18
     CCP3CON = 0;
19
     CCP4CON = 0;
20
     CCP5CON = 0;
21
     TRISA = 1;
22
     TRISB = 0b01110111;
23
     TRISC = 0;
24
     TRISD = 0;
25
     TRISE = 0;
26
     PORTA = 0;
27
     PORTB = 0;
28
     PORTC = 0;
29
     PORTD = 0;
30
     PORTE = 0;
31
     I2C1_Init(100000);
32
}
33
34
void main() {
35
     init();
36
37
     while(1){
38
          while(!button1);
39
          delay_ms(20);
40
          while(button1);
41
          
42
          I2C1_Start();
43
          I2C1_Wr(0b10100100);
44
          I2C1_Wr(0);
45
          I2C1_Wr(0);
46
          I2C1_Wr(0b00001010);
47
          I2C1_Stop();
48
49
          delay_ms(20);
50
51
          I2C1_Start();
52
          I2C1_Wr(0b10100100);
53
          I2C1_Wr(0);
54
          I2C1_Wr(0);
55
          I2C1_Repeated_Start();
56
          I2C1_Wr(0b10100101);
57
          PORTD = I2C1_Rd(0);
58
          I2C1_Stop();
59
     }
60
}

Das funktioniert so nicht bzw. die LEDs, die an PORTD hängen zeigen 
nichts an. Also hab ich zwischendurch eine "Debug"-Ausgabe gemacht:
1
          while(!button1);
2
          delay_ms(20);
3
          while(button1);
4
          
5
          I2C1_Start();
6
          I2C1_Wr(0b10100100);
7
          I2C1_Wr(0);
8
          I2C1_Wr(0);
9
          I2C1_Wr(0b00001010);
10
          I2C1_Stop();
11
          PORTD = 0x0F;
12
13
          while(!button1);
14
          delay_ms(20);
15
          while(button1);
16
          
17
          I2C1_Start();
18
          I2C1_Wr(0b10100100);
19
          I2C1_Wr(0);
20
          I2C1_Wr(0);
21
          I2C1_Repeated_Start();
22
          I2C1_Wr(0b10100101);
23
          PORTD = I2C1_Rd(0);
24
          I2C1_Stop();

und dort hab ich dann gesehen, dass die LEDs nichtmal die 0x0F 
ausgegeben haben. Also hab ich den Code solange reduziert, bis die LEDs 
angingen:
1
          while(!button1);
2
          delay_ms(20);
3
          while(button1);
4
          
5
          I2C1_Start();
6
          I2C1_Wr(0b10100100);
7
          //I2C1_Wr(0);
8
          //I2C1_Wr(0);
9
          //I2C1_Wr(0b00001010);
10
          I2C1_Stop();
11
          PORTD = 0x0F;
12
13
          while(!button1);
14
          delay_ms(20);
15
          while(button1);
16
          
17
          /*I2C1_Start();
18
          I2C1_Wr(0b10100100);
19
          I2C1_Wr(0);
20
          I2C1_Wr(0);
21
          I2C1_Repeated_Start();
22
          I2C1_Wr(0b10100101);
23
          PORTD = I2C1_Rd(0);
24
          I2C1_Stop();*/

Doch wenn ich dann das erste "I2C1_Wr(0);" wieder reinnehme, bzw die 
"//" davor lösche, dass es nicht mehr auskommentiert ist, gehen die LEDs 
nicht mehr an. Da frage ich mich, warum das so ist und mir ist beim 
besten Willen nichts eingefallen. Hängt sich der PIC auf, wenn er vom 
EEPROM nichts mitbekommt? Anderer Seits soll er ja auch nur schreiben 
und es ist ja auch nicht sehr klug, dass das Programm abstürzt, nur weil 
ein Slave nicht erreicht wird/werden sollte. Es hängt schon ein EEPROM 
dran und sollte eigentlich so auch funktionieren.

Kann mir da jemand helfen?

von AA-PROM (Gast)


Lesenswert?

Was für LEDs?
Du schreibst, Du wolltest ein EEPROM füttern...

von Michael S. (rbs_phoenix)


Lesenswert?

Ja will ich auch. Ich hab mir gedacht, damit ich Prüfen kann, was ich 
ins EEPROM schreibe ( "I2C1_Wr(0b00001010);" ), lese ich es aus und geb 
es an PORTD aus, wo die LEDs hinter hängen ( "PORTD = I2C1_Rd(0);" ).

edit:
> Das funktioniert so nicht bzw. die LEDs, die an PORTD hängen zeigen
> nichts an.

Ich habs am Anfang nicht gleich gesagt. Also am PORTD hängen LEDs dran, 
die bei High leuchten.

von Stefan (Gast)


Lesenswert?

Was für ein EEPROM ?

von Michael S. (rbs_phoenix)


Angehängte Dateien:

Lesenswert?

Das EEPROM ist ein 24FC1025, auch von Microchip.
Angehängt auch mal den auf die Schnelle gemachten Schaltplan. Jedoch 
funktioniert es ja soweit, dass wenn ich den Taster drücke und loslasse 
die 4 LEDs leuchten (solange das //I2C1_Wr(0); auskommentiert ist).
Das Problem ist halt, wenn 2 mal "I2C1_Wr();" hintereinander kommen hab 
ich das Gefühl.

Benutzen tu ich mikroC for PIC 4.60. Ich hab es auch einmal mit der 5.40 
Version compiliert, ist aber das gleiche. Sobald ich ein zweiter I2C1_Wr 
benutze, bleibt das Programm wohl hängen und die LEDs bleiben alle aus.

Ich hab auch schonmal mit "I2C1_Is_Idle" geprüft, ob durch irgendwas der 
Bus "in Benutzung" ist, das ist jedoch nicht der Fall.

von Stefan (Gast)


Lesenswert?

Biste sicher das die Device Adresse
stimmt ? Muß die nicht A2 sein ?

von Michael S. (rbs_phoenix)


Lesenswert?

Also laut Datenblatt nicht:
http://ww1.microchip.com/downloads/en/DeviceDoc/21941J.pdf

Seite 8:
Startbit, 1010, Block Select Bit, A1, A0, R/W, ACK.

Der A2 Pin muss auf Vcc liegen, da offen oder auf GND einen 
undefinierten Zustand hervor ruft.

Aber was ich mich frage, selbst wenn die Adresse falsch wäre, der EEPROM 
kaputt wäre oder auch wenn garkein EEPROM oder anderer Slave am Bus ist, 
wieso geht das Programm nicht weiter.

Wenn z.B. durch was auch immer die Leitung zum EEPROM gestört oder 
kaputt ist oder der EEPROM durch was auch immer defekt ist, dann kann 
doch nicht das Programm abschmieren!?

Mein Verdacht liegt daran, dass das evtl ein Fehler von der 
Compilerseite ist. Doch die Funktion I2C1_Wr geht ja ansich, wenn sie 
nur einmal da steht.

Naja, wie gesagt, ich bin ratlos.

von Stefan (Gast)


Lesenswert?

Die Device Adresse + W ergibt A2.
So sollte es aussehen_

I2C1_Init(100000);
         I2C1_Start();
         I2C1_Wr(0xA2);
         I2C1_Wr(0x00);
         I2C1_Wr(0x02);
         I2C1_Wr(0xAA);
         I2C1_Stop();

         Delay_100ms();

         I2C1_Start();
         I2C1_Wr(0xA2);
         I2C1_Wr(0x00);
         I2C1_Wr(0x02);
         I2C1_Repeated_Start();
         I2C1_Wr(0xA3);
         PORTB = I2C1_Rd(0u);
         I2C1_Stop();

von Michael S. (rbs_phoenix)


Lesenswert?

Aber so hab ich das doch. Ich hab A0 auf low und A1 auf high, deswegen 
ist bei mir das Commandbyte nicht 0xA2 sondern 0xA4. Und ich schreib in 
Adresse 0 und nicht in Adresse 2. Das init ist in der init-Funktion und 
was für Daten ich schreibe sollte ja egal sein. Doch, und korrigiert 
mich bitte, wenn ich falsch liege, darf doch das Programm nicht 
abstürzen, nur weil ein Slave am Bus nicht antwortet (da Leitung defekt 
oder falsch adressiert o.ä.)!?

von Chris B. (dekatz)


Lesenswert?

Laut deinem Schaltplan hast du A0 auf LOW, A1 UND A2 auf HIGH.
Also lauten die beiden Adressen:
b'10101100' = 0xAC
b'10101101' = 0xAD
         ^----R/W
        ^-----A0
       ^------A1
      ^-------A2

von Chris B. (dekatz)


Lesenswert?

Sehe gerade an denBeispielen im Datenblatt wird A2 immer als "0" 
behandelt.
Das ergäbe dann die Adressen:
b'10100100' = 0xA4
b'10100101' = 0xA5
         ^----R/W
        ^-----A0
       ^------A1
      ^-------A2

von Michael S. (rbs_phoenix)


Lesenswert?

nein. Im datenblatt steht, das A2 high sein muss und beim Adressieren 
1010 und dann der Block gewählt wird. Also als wären in dem 1024k 
Speicher 2 512k Speicher drin, einmal mit "A2" auf 0 und einmal auf 1.

Doch nochmals: Wieso kackt das Programm ab? Selbst wenn die Adresse 
falsch ist darf das doch nicht passieren. Ein Riss auf der Leiterbahn 
vom I2C und schon kann das ganze System nicht mehr funktionieren? Das 
kann doch nicht sein.

von TTL (Gast)


Lesenswert?

Dann Must du dir halt deine eigenen Funktionen programmieren bei denen 
das nich passiert.

von Der Rächer der Transistormorde (Gast)


Lesenswert?

Michael Skropski schrieb:
> Doch nochmals: Wieso kackt das Programm ab? Selbst wenn die Adresse
> falsch ist darf das doch nicht passieren. Ein Riss auf der Leiterbahn
> vom I2C und schon kann das ganze System nicht mehr funktionieren? Das
> kann doch nicht sein.


Das ist so, weil du es so programmierst. Die Routine hat keinen timeout. 
Woher soll Sie auch wissen ob du das willst und wie Sie den 
bewerkstelligen soll?

Das Programm wird auch noch laufen, es kann sein das es auf das Ende der 
letzten I2C Operation wartet.

Schau dir mal die I2C Register an ob die Daten wirklich gesendet 
wurden, vermutlich kommt kein ACK vom EEprom.

von Michael S. (rbs_phoenix)


Lesenswert?

Boa ich Trottel-.- Ich hab von der Datenleitung den Pullup-Widerstand 
nicht festgelötet...

Doch ich werd mir wohl eigene Funktionen bauen. Wenn sowas durch eine 
kalte Lötstelle oder so nochmal passiert, soll mein Programm trotzdem 
laufen und einen Error anzeigen oder sonstwas.

Dennoch danke an alle. Mein Programm hat soweit auch auf Anhieb 
Funktioniert.

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.