Forum: Mikrocontroller und Digitale Elektronik IIC-Kommunikation friert ein


von Peter (Gast)


Lesenswert?

Hallo liebe Gemeinde,

Ich habe eine kleine Hardware angefertigt, bestehend aus:
- einer Platine mit einem LM75-Temperatursensor
- einer µC-Platine mit einem PIC16F877A
- und einem LC-Display

Soweit funktionierte auch alles ganz gut, 1x kann ich die Temperatur 
korrekt einlesen, auch die Ausgabe am Display geht.

Wiederholt sich nun aber die Schleife zum ersten Mal (nach ca. 5 
Sekunden Pause) treten schier willkürlich folgende Ergebnisse auf:
- der Wert wird weitere ein- oder zweimal eingelesen, danach friert 
alles ein
- der Wert wird noch einmal eingelesen, die Logik friert jedoch schon 
beim freigeben des Bus ein

Mache ich einen Reset über den !MCLR ist kann er den Bus nicht einmal 
mehr übernehmen.

Auch wenn ich die Versorgungsspannung entferne und wieder anlege ergeben 
sich die zwei oben genannten Zustände.


Hat jemand vielleicht schon einmal ein solches oder ähnliches Problem 
gehabt?
(Ich vermute es hat etwas mit dem Freigeben des Bus zu tun, ich bin mir 
aber nicht sicher.)

Ich werde morgen noch meine Routine zum Freigeben posten.

Vielen Dank im Voraus,
Peter

von Bernd R. (Firma: Promaxx.net) (bigwumpus)


Lesenswert?

Viel mehr als (auf) die Routine zu (warten) sehen, würde uns alle das 
Schaltbild interessieren.

I2C ist nicht so ganz ohne. Machst Du es in Software oder in Hardware ? 
Der uC kann ja beides. Und bei der Hardware-Lösung gibt es einige 
Fehler, die man machen kann.

von holger (Gast)


Lesenswert?

>Mache ich einen Reset über den !MCLR ist kann er den Bus nicht einmal
>mehr übernehmen.

Dann hat der LM75 wohl schon aufgegeben.
Pullups an SDA und SCL sind vorhanden?

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

I2C braucht relativ starke Pullups, so um die 1k können nicht schaden. 
3,3 oder 5 Volt ?
Die empfohlene I2C Reset Routine ist m.W. ausgeben von mindestens 9 SCL 
Pulsen bei inaktivem ( high ) SDA, können aber evtl. noch mehr sein.

von Peter (Gast)


Lesenswert?

Ich steuere den Bus harwaremäßig mit den vom µC bereitgestellten 
Mitteln.

Pull-Up's sind vorhanden, allerdings sind es 4k7.

Der Sensor ist übrigens ein 5V-Typ.

Hier der ganze Code, vielleicht fällt jemandem der Fehler auf?
1
  errorlevel -203    ;These removes unwanted warnings
2
  errorlevel -205    ;from the compile information listing
3
  errorlevel -207 
4
  errorlevel -301 
5
  errorlevel -302 
6
7
   __config h'3f39'  
8
9
  list  p=16f877
10
  include <p16f877.inc>
11
  include <lcd.inc>
12
13
;-----------------------------------------------------------------------------------------
14
;  Deklarationen
15
;-----------------------------------------------------------------------------------------
16
  TMR1CONF1        equ    B'00001101'    ;Konfiguration für Timer 1
17
  TEMP          equ    0x20      ;Hilfsregister
18
  MSByte          equ    0x21
19
  LSByte          equ    0x22
20
  REPEAT          equ    0x29
21
  LM75ADDRESS        equ    B'10010001'    ;Adresse des LM75 + R/W-Bit
22
23
  h          equ    0x23
24
  z          equ    0x24
25
  e          equ    0x25
26
27
  TEMPByte        equ    0x26
28
  TEMPByte1        equ    0x27
29
  TEMPByte2        equ    0x28
30
31
  COUNT1          equ    0x30
32
  COUNT2          equ    0x31
33
34
  lcdnumberprefix      equ      b'00110000'
35
  gradzeichen        equ     b'11011111'
36
37
;-----------------------------------------------------------------------------------------
38
;  Adresszuteilungen
39
;-----------------------------------------------------------------------------------------
40
41
  org  0x00                    ;Startadresse
42
43
;-----------------------------------------------------------------------------------------
44
main            ;Hauptprogramm
45
;-----------------------------------------------------------------------------------------
46
47
  call  picinit
48
49
  call  lcdinit
50
51
  call  iicinit
52
53
  call  waitwhilestartup
54
55
  hauptschleife
56
57
    movlw  LCDDISPLAYCLEAR
58
59
    call  lcdsendinstruction
60
  
61
    call  iicrepeatbus
62
    
63
    call  iicsendaddress
64
  
65
    call  iicreadvalue
66
  
67
    call  lcdsendtemp
68
69
    call  iicreleasebus
70
71
    call  warte15sekunden
72
73
    goto  hauptschleife
74
75
76
;-----------------------------------------------------------------------------------------
77
iicinit            ;Initialisierung des IIC-Moduls
78
;-----------------------------------------------------------------------------------------
79
  bsf    STATUS, RP0                ;Bankumschaltung auf Bank 1
80
  movlw  d'9'
81
  movwf  SSPADD                  ;Teiler für 100kHz bei 4MHz-Takt laden
82
  bcf    STATUS, RP0                ;Bankumschaltung auf Bank 0
83
84
  movlw  B'00001000'
85
  movwf  SSPCON                  
86
  
87
  bsf    SSPCON, SSPEN              ;MSSP-Modul einschalten
88
  
89
  return
90
91
;-----------------------------------------------------------------------------------------
92
iicgetbus          ;Übernehmen des Busses
93
;-----------------------------------------------------------------------------------------
94
  bcf    PIR1, SSPIF                ;SSPIF-Bit löschen
95
96
  bsf    STATUS, RP0                ;Bankumschaltung auf Bank 1
97
  bsf    SSPCON2, SEN              ;Bus-Übernahme starten
98
  bcf    STATUS, RP0                ;Bankumschaltung auf Bank 0
99
100
  iicwait1
101
    btfss  PIR1, SSPIF              ;Prüfe ob Bus übernommen wurde
102
    goto  iicwait1              ;Nein, wiederhole
103
    bcf    PIR1, SSPIF              ;Ja, Bus übernommen
104
  
105
  return
106
107
;-----------------------------------------------------------------------------------------
108
iicrepeatbus          ;erneutes Übernehmen des Busses
109
;-----------------------------------------------------------------------------------------
110
  bcf    PIR1, SSPIF                ;SSPIF-Bit löschen
111
112
  bsf    STATUS, RP0                ;Bankumschaltung auf Bank 1
113
  bsf    SSPCON2, RSEN              ;Bus-Übernahme starten
114
  bcf    STATUS, RP0                ;Bankumschaltung auf Bank 0
115
116
  iicwait6
117
    btfss  PIR1, SSPIF              ;Prüfe ob Bus übernommen wurde
118
    goto  iicwait6              ;Nein, wiederhole
119
    bcf    PIR1, SSPIF              ;Ja, Bus übernommen
120
  
121
  return
122
123
;-----------------------------------------------------------------------------------------
124
iicsendaddress        ;Adresse senden
125
;-----------------------------------------------------------------------------------------
126
  bcf    PIR1, SSPIF  
127
128
  movlw  B'10010001'                ;Adresse des Sensors + Read-Bit
129
  movwf  SSPBUF                  ;Adresse in den Sende-Puffer schieben
130
  
131
  iicwait2
132
    btfss  PIR1, SSPIF              ;Prüfe ob Acknowledge empfangen wurde
133
    goto  iicwait2              ;Nein, wiederhole
134
    bcf    PIR1, SSPIF              ;Ja, Daten sind im Slave
135
136
  return
137
138
;-----------------------------------------------------------------------------------------
139
iicreadvalue        ;Temperaturwert auslesen
140
;-----------------------------------------------------------------------------------------
141
142
;MSB einlesen
143
144
  bcf    PIR1, SSPIF              
145
146
  bsf    STATUS, RP0                ;Bankumschaltung auf Bank 1
147
  bsf    SSPCON2, RCEN              ;Datenempfang einschalten
148
  bcf    STATUS, RP0                ;Bankumschaltung auf Bank 0
149
150
  iicwait3
151
    btfss  PIR1, SSPIF              ;Daten empfangen?
152
    goto  iicwait3              ;Nein, wiederhole
153
    bcf    PIR1, SSPIF              ;Ja, Daten empfangen
154
155
  movf  SSPBUF, 0
156
  movwf  MSByte
157
158
  bsf    STATUS, RP0                ;Bankumschaltung auf Bank 1
159
  bsf    SSPCON2, ACKEN              ;ein Acknowledge senden
160
  bcf    STATUS, RP0                ;Bankumschaltung auf Bank 0
161
162
;LSB einlesen 
163
164
  bcf    PIR1, SSPIF              
165
166
  bsf    STATUS, RP0                ;Bankumschaltung auf Bank 1
167
  bsf    SSPCON2, RCEN              ;Datenempfang einschalten
168
  bcf    STATUS, RP0                ;Bankumschaltung auf Bank 0
169
170
  iicwait4
171
    btfss  PIR1, SSPIF              ;Daten empfangen?
172
    goto  iicwait4              ;Nein, wiederhole
173
    bcf    PIR1, SSPIF              ;Ja, Daten empfangen
174
175
  movf  SSPBUF, 0
176
  movwf  LSByte
177
178
  bsf     STATUS, RP0                ;Bankumschaltung auf Bank 1
179
     bcf     SSPCON2, RCEN               ;Datenempfang ausschalten
180
    bcf     STATUS, RP0                ;Bankumschaltung auf Bank 0
181
182
  return
183
184
;-----------------------------------------------------------------------------------------
185
iicreleasebus        ;Den Bus wieder freigeben
186
;-----------------------------------------------------------------------------------------
187
  bcf    PIR1, SSPIF  
188
189
  bsf    STATUS, RP0
190
;  bsf    SSPCON2, ACKDT              ;Art des Acknowledges auf NOT umstellen          
191
;  bsf    SSPCON2, ACKEN              ;ein Acknowledge senden
192
  bsf    SSPCON2, PEN              ;Bus-Freigabe starten
193
  bcf    STATUS, RP0
194
195
  iicwait5
196
    btfss  PIR1, SSPIF
197
    goto  iicwait5
198
    bcf    PIR1, SSPIF
199
200
  return
201
202
;-----------------------------------------------------------------------------------------
203
picinit            ;Initialisierung des µControllers
204
;-----------------------------------------------------------------------------------------
205
  bsf    STATUS,RP0                ;Bankumschaltung auf Bank 1
206
  movlw  B'00000111'                
207
  movwf  ADCON1                  ;PORTA als digitale I/O's konfigur.
208
  movlw  B'11111110'                
209
  movwf  TRISA                  ;RA0 als Ausgang definieren (Power-On)
210
  movlw  B'00000000'                
211
  movwf  TRISB                  ;PORTB als Ausgang definieren
212
  movlw  B'00011000'                
213
  movwf  TRISC                  ;PORTC3,4 als Eingang definieren
214
  movlw  B'00000000'                
215
  movwf  TRISE                  ;PORTE als Ausgang definieren
216
  bcf    INTCON,GIE                ;Alle Interrupts sperren
217
  bcf    STATUS,RP0                ;Bankumschaltung auf Bank 0
218
  bsf    POWERONLED,0              ;Power-On Led einschalten
219
220
  return                      ;Ruecksprung zum Hauptprogramm
221
222
;-----------------------------------------------------------------------------------------
223
lcdinit            ;Initialisierung des Displays
224
;-----------------------------------------------------------------------------------------
225
  movlw  LCDFUNCTIONSET              ;Datenwort zur Initialisierung, siehe DB.
226
  call  lcdsendinstruction
227
  movlw  LCDFUNCTIONSET              ;Datenwort zur Initialisierung, siehe DB.
228
  call  lcdsendinstruction
229
  movlw  LCDFUNCTIONSET              ;Datenwort zur Initialisierung, siehe DB.
230
  call  lcdsendinstruction
231
  movlw  LCDDISPLAYFORMAT            ;5x8dot-Zeichen
232
  call  lcdsendinstruction
233
  movlw  LCDDISPLAYOFF              ;Display ausschalten
234
  call  lcdsendinstruction
235
  movlw  LCDDISPLAYCLEAR              ;Gesamten Display löschen
236
  call  lcdsendinstruction
237
  movlw  LCDENTRYMODESET              
238
  call  lcdsendinstruction
239
  movlw  LCDDISPLAYON              ;Display und blinkenden Cursor einschalten
240
  call  lcdsendinstruction
241
242
  return
243
244
;-----------------------------------------------------------------------------------------
245
lcdapplydata        ;Auf dem PORTB liegende Daten durch einen Impuls an der
246
              ;Enable-Leitung (RE0) an das Display übergeben.
247
;-----------------------------------------------------------------------------------------
248
  bsf    LCDCONTROLPORT,0            ;Enable-Leitung auf H setzen
249
  nop                        ;warten...
250
  nop                        ;warten...
251
  nop                        ;warten...
252
  bcf    LCDCONTROLPORT,0            ;Enable-Leitung auf L setzen
253
254
  return                      ;Ruecksprung zum Hauptprogramm
255
256
;-----------------------------------------------------------------------------------------
257
lcdsendinstruction      ;Einen Befehl an das Display senden
258
;-----------------------------------------------------------------------------------------
259
  bcf    LCDCONTROLPORT,1            ;RS auf L setzen
260
  bcf    LCDCONTROLPORT,2            ;R/W auf L setzen
261
  movwf  LCDDATAPORT                ;Daten auf den PORTB legen
262
  call  lcdapplydata              ;Daten an das Display übergeben
263
  call  waitwhilebusy              ;Busy-Flag überprüfen
264
265
  return                      ;Ruecksprung zum Hauptprogramm
266
267
;-----------------------------------------------------------------------------------------
268
lcdsenddata        ;Ein Zeichen an das Display senden
269
;-----------------------------------------------------------------------------------------
270
  bsf    LCDCONTROLPORT,1            ;RS auf L setzen
271
  bcf    LCDCONTROLPORT,2            ;R/W auf L setzen
272
  movwf  LCDDATAPORT                ;Daten auf den PORTB legen
273
  call  lcdapplydata              ;Daten an das Display übergeben
274
  call  waitwhilebusy              ;Busy-Flag überprüfen
275
276
  return                      ;Ruecksprung zum Hauptprogramm
277
278
;-----------------------------------------------------------------------------------------
279
waitwhilebusy      ;Warte ~5ms
280
;-----------------------------------------------------------------------------------------
281
  movlw  TMR1CONF1    ;Timer 1-Konfiguration
282
  movwf  T1CON      ;Konfiguration in Timer 1 laden
283
  movlw  0xEF      
284
  movwf  TMR1H      ;MSByte des Timer 1 mit 0x9F laden
285
  movlw  0xFF      
286
  movwf  TMR1L      ;LSByte des Timer 1 mit 0xFF laden
287
  movlw  D'1'      
288
  movwf  TEMP      ;w-Reg. ins TEMP-Reg.
289
    wait0
290
      btfss  PIR1,0    ;Teste ob Überlauf aufgetreten ist
291
      goto  wait0    ;Ansonsten bleibe in der Schleife
292
    bcf    PIR1,0      ;lösche das Timer 1-Interrupt Flag
293
    movlw  0x3F      ;0x0A(10) in das w-Reg.
294
  return            ;Ruecksprung zum Hauptprogramm
295
296
;-----------------------------------------------------------------------------------------
297
waitwhilestartup    ;Warte 100ms
298
;-----------------------------------------------------------------------------------------
299
  movlw  D'4'      
300
  movwf  TEMP      ;w-Reg. ins TEMP-Reg.
301
  movlw  TMR1CONF1    ;Timer 1-Konfiguration
302
  movwf  T1CON      ;Konfiguration in Timer 1 laden
303
  wait1
304
    movlw  0x00      
305
    movwf  TMR1H      ;MSByte des Timer 1 mit 0x9F laden
306
    movlw  0x00      
307
    movwf  TMR1L      ;LSByte des Timer 1 mit 0xFF laden
308
  
309
      wait2
310
        btfss  PIR1,0    ;Teste ob Überlauf aufgetreten ist
311
        goto  wait2    ;Ansonsten bleibe in der Schleife
312
        bcf    PIR1,0      ;lösche das Timer 1-Interrupt Flag
313
  
314
    decfsz  TEMP
315
    goto  wait1
316
        
317
  return            ;Ruecksprung zum Hauptprogramm
318
319
;-----------------------------------------------------------------------------------------
320
lcdsendtemp        ;Temperatur auswerten und an den LCD senden
321
;-----------------------------------------------------------------------------------------
322
  
323
  movlw  '+'
324
325
  btfsc  MSByte,7
326
    movlw  '-'
327
328
  call  lcdsenddata
329
330
  btfsc  MSByte,7
331
    call  negativeZahl
332
333
  clrf  h
334
  clrf  z
335
  clrf  e
336
337
  movlw  d'100'
338
339
  hunderter
340
    incf  h
341
    subwf  MSByte,1
342
    btfsc  STATUS,C  ;Überprüfe ob Subtraktion 0 ergab
343
    goto  hunderter
344
345
  bcf   STATUS,C
346
347
  addwf  MSByte,1
348
  decf  h
349
350
  movlw  lcdnumberprefix
351
  iorwf  h,0
352
353
  call  lcdsenddata
354
355
  movlw  d'10'
356
357
  zehner
358
    incf  z
359
    subwf  MSByte,1
360
    btfsc  STATUS,C  ;Überprüfe ob Subtraktion 0 ergab
361
    goto  zehner
362
363
  bcf   STATUS,C
364
365
  addwf  MSByte,1
366
  decf  z
367
368
  movlw  lcdnumberprefix
369
  iorwf  z,0
370
371
  call  lcdsenddata
372
373
  movlw  d'1'
374
375
  einer
376
    incf  e
377
    subwf  MSByte,1
378
    btfsc  STATUS,C  ;Überprüfe ob Subtraktion 0 ergab
379
    goto  einer
380
381
  bcf   STATUS,C
382
383
  addwf  MSByte,1
384
  decf  e
385
386
  movlw  lcdnumberprefix
387
  iorwf  e,0
388
389
  call  lcdsenddata
390
391
  movlw  '.'
392
  call  lcdsenddata
393
394
  movlw  '0'
395
396
  btfsc  LSByte,7
397
    movlw  '5'
398
399
  call  lcdsenddata
400
  
401
  movlw  gradzeichen
402
  call  lcdsenddata
403
  movlw  'C'
404
  call  lcdsenddata
405
406
  return
407
408
;-----------------------------------------------------------------------------------------
409
negativeZahl
410
;-----------------------------------------------------------------------------------------
411
  movlw  0xFF
412
  movwf  TEMPByte2  ;255 ins TEMPByte2
413
414
  movf  MSByte,0  ;Schreibe MSByte ins w-Reg.
415
416
  subwf  TEMPByte2,0  ;Subtrahiere MSByte von 255
417
418
  movwf  MSByte
419
420
  incf  MSByte,1
421
422
  return  
423
424
;-----------------------------------------------------------------------------------------
425
warte15sekunden
426
;-----------------------------------------------------------------------------------------
427
  movlw  d'255'
428
  movwf  COUNT1
429
  movlw  d'5'
430
  movwf  COUNT2
431
432
  schleife
433
    warte
434
    call  waitwhilebusy
435
    decfsz  COUNT1
436
    goto  warte
437
  decfsz  COUNT2
438
  goto  schleife
439
  
440
  return
441
442
    
443
444
445
  END              ;EOF

von gwq345gh (Gast)


Lesenswert?

Wie wär's denn mal mit einem Wechsel zu C?

von Peter (Gast)


Lesenswert?

Wie wär's mit einer Antwort die mir hilft?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter schrieb:
> Wie wär's mit einer Antwort die mir hilft?

Du hast das Problem nicht verstanden: in 500 Zeilen fremden
Assemblersourcecodes sucht niemand freiwillig einen Fehler.  In
100 Zeilen C-Code schon eher.

von Andreas (Gast)


Lesenswert?

Peter schrieb:
Hallo Peter

Ich gestehe, dass ich momentan auch zu faul bin, durch den Code zu 
scannen.
Und das hast Du ja sicher schon selbst gelesen: 
http://ww1.microchip.com/downloads/en/appnotes/00735a.pdf

Ein paar allgemeine Fragen hab ich aber noch (see below)
>
> Soweit funktionierte auch alles ganz gut, 1x kann ich die Temperatur
> korrekt einlesen, auch die Ausgabe am Display geht.
>
> Wiederholt sich nun aber die Schleife zum ersten Mal (nach ca. 5
> Sekunden Pause) treten schier willkürlich folgende Ergebnisse auf:
> - der Wert wird weitere ein- oder zweimal eingelesen, danach friert
> alles ein
Ok, es bilden sich Eisblumen an den Fenstern und ...
Was heisst einfrieren ? Läuft die PIC Clock noch ?
Hast Du ein Scope ? Dann check mal den I2C Bus ob der noch zuckt.

> - der Wert wird noch einmal eingelesen, die Logik friert jedoch schon
> beim freigeben des Bus ein
Same story again: Woher weisst Du das ? WANN friert der bus ein ?
Hat der PIC noch das Adressbyte (oder mehr) gesendet ? Hat der LM75 
geantwortet ? Mit der richtigen Länge ?
Ist Dein Processing für das LCD auch korrekt, wenn der LM75 totalen 
Schrott schickt (aka wird der gesamte, evtl. sinnlosse, Wertebereich 
korrekt gehandelt) ?

>
> Mache ich einen Reset über den !MCLR ist kann er den Bus nicht einmal
> mehr übernehmen.
Das !MCLR nur den PIC reseted, nicht den LM75, ist klar ?
Woher weisst Du, dass der PIC den I2C nicht "übernehmen" kann ?
Ein (mehr als) flüchtiger Blick in den Code sagt mir, dass Du zB ewig 
wartest, wenn der LM75 Dir kein ACK beim zweiten Zugriff schickt (darum 
die Fragen zum "Einfrieren").
Vielleicht hängt er ja auch da ?

>
> Auch wenn ich die Versorgungsspannung entferne und wieder anlege ergeben
> sich die zwei oben genannten Zustände.
>
Das heisst, es wird mindestens ein mal der richtige Wert angezeigt ?

>
> Hat jemand vielleicht schon einmal ein solches oder ähnliches Problem
> gehabt?
Einmal ? ;-)

Grüße
Andreas

von spess53 (Gast)


Lesenswert?

Hi

Irgendwie kommen mir deine ACKs komisch vor. Wo sagst du deinem PIC, das 
er nach dem ersten gelesenen Byte ein ACK und nach dem zweiten ein NACK 
senden soll?

MfG Spess

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.