Forum: Mikrocontroller und Digitale Elektronik I2C Temperaturwert ausgeben


von TimeOut (Gast)


Lesenswert?

Hallo Forum,

ich habe ein Programm bekommen, das per Polling zyklisch einen 
Temperaturwert aufs LCD Display ausgeben soll.
Das ganze passiert über einen IR-Sensor und den I2C Bus.

Das ganze funktioniert soweit, die Temperatur wird auf dem Display 
ausgegeben doch nur ein einziges Mal. Danach muss ich das Programm neu 
starten und er liest wieder einen neuen Wert.

Sprich: Das zyklische Auslesen der Temperatur funktioniert nicht.

Ich denke es hat etwas mit der Übertragung zu tun, (evtl setzt er ein 
Bit nicht richtig zurück?) hänge den Quellcode mal mit an

Danke

Gruß
TimeOut
1
double Transmission(void)
2
{
3
4
  double grad=0.0;
5
  vu8 d1=0;
6
  vu8 d2=0;
7
  double d1_double,d2_double;
8
  vu16 daten=0;
9
  
10
    
11
  /* Enable I2C1 ----------------------------------------------------*/
12
  I2C_Cmd(I2C1, ENABLE);
13
14
15
16
  /* I2C1 configuration: SMBus Host ------------------------------------------*/
17
  I2C_InitStructure.I2C_Mode = I2C_Mode_SMBusHost;
18
  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
19
  I2C_InitStructure.I2C_OwnAddress1 = I2C1_SLAVE_ADDRESS7;
20
  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
21
  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
22
  I2C_InitStructure.I2C_ClockSpeed = ClockSpeed;
23
  I2C_Init(I2C1, &I2C_InitStructure);
24
        
25
26
  /* Enable I2C2 ARP */
27
  I2C_ARPCmd(I2C2, ENABLE);
28
29
  /* Enable I2C1 and I2C2 PEC Transmission */
30
  I2C_CalculatePEC(I2C1, ENABLE);
31
  I2C_CalculatePEC(I2C2, ENABLE);
32
  
33
  /*----- Transmission Phase -----*/
34
  /* Send I2C1 START condition */
35
  I2C_GenerateSTART(I2C1, ENABLE);     
36
  /* Test on I2C1 EV5 and clear it */
37
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); 
38
  /* Send Slave address */
39
  I2C_Send7bitAddress(I2C1, SMBusDefaultHeader, I2C_Direction_Transmitter);
40
  /* Test on I2C1 EV6 and clear it */
41
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); 
42
43
  /* Get I2C2 SMBDEFAULT flag status */
44
  Status = I2C_GetFlagStatus(I2C2, I2C_FLAG_SMBDEFAULT);  //wird evtl. nicht benötigt
45
   /* Send Command */
46
  I2C_SendData(I2C1, Command);  
47
  /* Clear ADDR flag */
48
  I2C_ClearFlag(I2C2, I2C_FLAG_ADDR);
49
 
50
   /* Send I2C1 START condition */
51
  I2C_GenerateSTART(I2C1, ENABLE); 
52
  /* Test on I2C1 EV5 and clear it */
53
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); 
54
  /* Send Slave address */ 
55
  I2C_Send7bitAddress(I2C1, SMBusDefaultHeader, I2C_Direction_Receiver); 
56
  /* Test on I2C1 EV6 and clear it */
57
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); 
58
  /* Wait for I2C1 received data */
59
  while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE)); 
60
  /* Store received data on I2C1 */
61
  ReceivedCommand = I2C_ReceiveData(I2C1);     //LSB Byte 
62
  d1= ReceivedCommand;     //Zwischenspreicherung in vu8
63
  d1_double=(double)d1;     //Konvertierung in double ; Konvertierung in int funktioniert nicht
64
  
65
  /* Wait for I2C1 received data */
66
  while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE));   
67
  /* Store received data on I2C1 */
68
  ReceivedCommand = I2C_ReceiveData(I2C1);       //MSB Byte
69
  d2=ReceivedCommand;
70
  d2_double=(double)d2;
71
  
72
  //16Bit unsigned char
73
  daten =d1;
74
  daten|=(d2<<8);
75
  
76
  //Umrechnung in Grad Celsius
77
  grad=d2_double*256+d1_double;
78
  grad/=50.0;
79
  grad-=273.15;
80
  
81
  /* Enable Transfer PEC next for I2C1 */
82
  I2C_TransmitPEC(I2C1, ENABLE);
83
  /* Wait for I2C1 received data */
84
  while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE));  
85
  /* Store received PEC on I2C1 */
86
  PECValue = I2C_ReceiveData(I2C1);
87
  /* Test on I2C1 EV8 and clear it */
88
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
89
  
90
  /* Send I2C1 STOP Condition */
91
  I2C_GenerateSTOP(I2C1, ENABLE);
92
  /* Test on I2C1 EV4 and clear it */
93
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED )); 
94
  /* Clear I2C1 STOPF flag */
95
  I2C_ClearFlag(I2C1, I2C_FLAG_STOPF);
96
97
  return grad;
98
}

von Jörg S. (joerg-s)


Lesenswert?

> Das ganze passiert über einen IR-Sensor und den I2C Bus.
Geht es etwas genauer? Der Sensor ist I2C, ich nehme mal an LM75?
Um welchen Controller Typ geht es eigentlich?

> Das ganze funktioniert soweit, die Temperatur wird auf dem Display
> ausgegeben doch nur ein einziges Mal. Danach muss ich das Programm neu
> starten und er liest wieder einen neuen Wert.
Bleibt das Programm hängen oder läuft es weiter, zeigt aber nichts an?
Und wenn es hängen bleibt, wo?

von TimeOut (Gast)


Lesenswert?

Also der Sensor ist ein: MLX90614ESF-BAA
Controller: Cortex M3 (STM32F103ZE)


Soweit ich das sehe bleibt er immer bei:

 /* Test on I2C1 EV5 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

und

 /* Test on I2C1 EV6 and clear it */
  while(!I2C_CheckEvent(I2C1, 
I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

länger hängen, wenn ich es step-by step durchlaufe.

Allerdings wird der nachfolgende Code trotzdem später abgearbeitet, wenn 
ich ein Breakpoint danach setzte.

von Karl H. (kbuchegg)


Lesenswert?

Erst mal feststellen wer der Übeltäter ist:
Der Temperatur-Sensor oder das LCD.

Es ist nie schlau, zuviel Funktionalität in eine Funktion zu packen.
Mach dir 2 Funktionen
die eine, die einen Wert vom LM75 holt
und die andere, die einen Wert an das LCD ausgibt.


Und dann testest du erst mal, ob die Ausgabefunktion ein Problem hat. Zb 
in dem du in einer Schleife (oder was halt dann ausserhalb von 
Transmission steht) immer wieder die Ausgabefunktion mit einem 
Zahlenwert aufrufst, der zb hochgezählt wird. Wenn das klappt, dann 
weißt du, dass es wahrscheinlich nicht das LCD ist. WEnn es nicht 
klappt, dann weißt du, dass du ein Problem mit dem LCD hast.

Funktioniert das LCD, dann nimmst du den Sensor dazu.
In der Schleife wird die FUnktion aufgerufen, die den Sensor ausliest 
und der WErt, den die Funktion liefert wird der AUsgabefunktion 
übergeben (von der du schon weißt, das sie funktioniet - deswegen hast 
du die ja vorher getestet).


Keine 2-Fronten-Kriege anfangen! Daran sind schon ganz andere 
gescheitert. Je feiner und kleiner du eine AUfgabe unterteilen und auch 
testen kannst, umso besser.

von Karl H. (kbuchegg)


Lesenswert?

Und wieso musst du eigentlich jedesmal das I2C Subsystem neu 
initialisieren?


Also 3 Funktionen
* I2C Initialisieren
* Wert vom LM75 holen
* Wert am LCD ausgeben

von TimeOut (Gast)


Lesenswert?

Hallo Karl Heinz,

vielen Dank für deine Tipps.

Also das LCD Display wird richtig angesteuert, das funktioniert soweit.

Probleme gibt es, wenn ich in der Schleife die Funktion (Transmission) 
aufrufe, die ja den Sensor ausliest

klappt das wieder genau 1x. Beim nächsten Schleifen durchlauf bleibt er 
dann an dieser Funktion stehen und hängt...

von TimeOut (Gast)


Lesenswert?

Wenn ich das LCD teste und einen Wert ausgebe, den ich in einer Schleife 
hochzähle, geht das Display immer an und wieder aus und zeigt dann den 
neuen Wert an.

von Jörg S. (joerg-s)


Lesenswert?

TimeOut schrieb:
> Allerdings wird der nachfolgende Code trotzdem später abgearbeitet, wenn
> ich ein Breakpoint danach setzte.

>Beim nächsten Schleifen durchlauf bleibt er dann an dieser Funktion
>stehen und hängt
?


Hast du ein (Speicher)Oszi zur Hand um zu schauen was auf dem Bus los 
ist?

von TimeOut (Gast)


Lesenswert?

Also auf dem Bus kommt einmal das SDA Signal rein, danach ist Stille.

Mit hängenbleiben meine ich die Stelle:

/* Test on I2C1 EV5 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

Habe mich mal im Internet schlau gemacht und das Problem sei wohl die 
fehlerhafte Slaveadressierung in der Library. Dort wird davon 
gesprochen, dass man die Slaveadresse um 1 Bit nach links verschieben 
muss.

Allerdings führt dies nicht zum erhofften Erfolg bei mir.

Also er muss ja einmal durch die komplette "Transmission"-Routine laufen 
sont würde ich keinen Wert auf meinem Display ausgegeben bekommen, beim 
zweiten Mal bleibt er dann in der oben genannten Schleife hängen...

PS:In der main rufe ich die "Transmission()" in einer Endlosschleife auf

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.