Forum: PC-Programmierung Anfänger: LM75 Temperatursensor am LPT Port mit c++ auslesen


von Rocco (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich versuche einen LM75 Temperatursensor über meine druckerschnittstelle 
auszulesen. Leider bin ich blutiger Anfänger was programmieren angeht. 
Ein Lauflicht in c++ über die Druckerschnittstelle ist mein bisherige 
Highlight.

Bitte nicht zu doll schimpfen aber hier ist mein bischen Quelltext. Ist 
übrigens ein Mix aus zusammengegoogelten Code

dabei interessiert mich vorallem ob ich die ganze Kommunikation nicht 
vereinfachen kann. Meine jetzige Version beinhaltet viel zu viele 
fehlermöglichkeiten. Ich hoffe das es irgen eine andere Methode gibt an 
den LM75 Einzen und Nullen zu senden - und zu empfangen.
1
#include <stdio.h>
2
#include <conio.h>
3
#include <windows.h>
4
#include <math.h>
5
//#include <iostream.h>
6
7
//using namesapce std;
8
9
#define lpt 0x378
10
11
//#define D_IN 64       //Byte for SDA -> ACKNOWLEDGE high
12
#define oo 0       //SDA -> low / SCL -> low
13
#define oi 1       //SDA -> low / SCL -> high
14
#define io 2       //SDA -> high / SCL -> low
15
#define ii 3       //SDA -> high / SCL -> high
16
17
18
//void funktion();
19
void func_stop()
20
{
21
  outp( lpt, ii );
22
  Sleep( 10 );
23
}
24
25
void func_start()
26
{
27
  outp( lpt, oi );
28
  Sleep( 10 );
29
  outp( lpt, oo );
30
  Sleep( 10 );
31
}
32
33
void func_send_adress_byte()
34
{
35
  int counter;
36
37
  outp( lpt, ii ); //1
38
  Sleep( 10 );
39
  outp( lpt, oo );
40
  Sleep( 10 );
41
  outp( lpt, oi ); //0
42
  Sleep( 10 );
43
  outp( lpt, oo );
44
  Sleep( 10 );
45
  outp( lpt, oi ); //0
46
  Sleep( 10 );
47
  outp( lpt, oi );
48
  Sleep( 10 );
49
  outp( lpt, ii ); //1
50
  Sleep( 10 );
51
  outp( lpt, oo );
52
  Sleep( 10 );
53
  outp( lpt, oi ); //0
54
  Sleep( 10 );
55
  outp( lpt, oo );
56
  Sleep( 10 );
57
  outp( lpt, oi ); //0
58
  Sleep( 10 );
59
  outp( lpt, oo );
60
  Sleep( 10 );
61
  outp( lpt, oi ); //0
62
  Sleep( 10 );
63
  outp( lpt, oo );
64
  Sleep( 10 );
65
  outp( lpt, ii ); //1
66
  Sleep( 10 );
67
68
 
69
70
void func_slave_acknowledge()
71
{
72
  outp( lpt, oi );
73
  Sleep( 10 );
74
  inp( lpt, 0x04 );   //SDA abhorchen: for SDA low - > weiter machen -> else stop und wieder von vorne und fehler melden
75
  Sleep( 10 );
76
}
77
int func_slave_send_data_ganzzahl()  //ganzzahligen Anteil der Temperatur abholden
78
{
79
    int nachkomma;
80
  outp( lpt, oo );
81
  Sleep( 10 );
82
//irgend wie die abgehorcheten Bits in Variablen a,b,c,d,e,f,g,h speichern?! - Bsp Ergebniss 10011010  = 128 + 16 + 8 + 2= -26°C
83
  outp( lpt, oi );
84
  Sleep( 10 );
85
  inp( lpt, 0x04 );   //SDA abhorchen: 1.bit  high->128 ->-°C    low->128 ->+°C
86
  Sleep( 10 );
87
  outp( lpt, oo );
88
  Sleep( 10 );
89
  outp( lpt, oi );
90
  Sleep( 10 );
91
  inp( lpt, 0x04 );   //SDA abhorchen: 2.bit    64
92
  Sleep( 10 );
93
  outp( lpt, oo );
94
  Sleep( 10 );
95
  outp( lpt, oi );
96
  Sleep( 10 );
97
  inp( lpt, 0x04 );   //SDA abhorchen: 3.bit    32
98
  Sleep( 10 );
99
  outp( lpt, oo );
100
  Sleep( 10 );
101
  outp( lpt, oi );
102
  Sleep( 10 );
103
  inp( lpt, 0x04 );   //SDA abhorchen: 4.bit    16
104
  Sleep( 10 );
105
  outp( lpt, oo );
106
  Sleep( 10 );
107
  outp( lpt, oi );
108
  Sleep( 10 );
109
  inp( lpt, 0x04 );   //SDA abhorchen: 5.bit    8
110
  Sleep( 10 );
111
  outp( lpt, oo );
112
  Sleep( 10 );
113
  outp( lpt, oi );
114
  Sleep( 10 );
115
  inp( lpt, 0x04 );   //SDA abhorchen: 6.bit    4
116
  Sleep( 10 );
117
  outp( lpt, oo );
118
  Sleep( 10 );
119
  outp( lpt, oi );
120
  Sleep( 10 );
121
  inp( lpt, 0x04 );   //SDA abhorchen: 7.bit    2
122
  Sleep( 10 );
123
  outp( lpt, oo );
124
  Sleep( 10 );
125
  outp( lpt, oi );
126
  Sleep( 10 );
127
  inp( lpt, 0x04 );   //SDA abhorchen: 8.bit    1
128
  Sleep( 10 );
129
130
  outp( lpt, oo );
131
  Sleep( 10 );
132
  }
133
  return ganzzahl;
134
}
135
136
void func_master_acknowledge()
137
{
138
  outp( lpt, oo );
139
  Sleep( 10 );
140
  outp( lpt, oi );
141
  Sleep( 10 );
142
  outp( lpt, oo );
143
  Sleep( 10 );
144
}
145
146
147
int func_slave_send_data_nachkomma()  // Nachkommastelle der Temperatur abholden
148
{
149
  int nachkomma;
150
151
  outp( lpt, oo );
152
  Sleep( 10 );
153
//irgend wie die abgehorcheten bits in variablen a,b,c,d,e,f,g,h speichern?! - Bsp Ergebniss 10011010  -> nur das erste bit ist interesannt!
154
  outp( lpt, oi );
155
  Sleep( 10 );
156
  inp( lpt, 0x04 );   //SDA abhorchen: 1.bit  high->128 ->x,5°C    low->128 ->x,0°C
157
  Sleep( 10 );
158
  outp( lpt, oo );
159
  Sleep( 10 );
160
  outp( lpt, oi );
161
  Sleep( 10 );
162
  inp( lpt, 0x04 );   //SDA abhorchen: 2.bit    64
163
  Sleep( 10 );
164
  outp( lpt, oo );
165
  Sleep( 10 );
166
  outp( lpt, oi );
167
  Sleep( 10 );
168
  inp( lpt, 0x04 );   //SDA abhorchen: 3.bit    32
169
  Sleep( 10 );
170
  outp( lpt, oo );
171
  Sleep( 10 );
172
  outp( lpt, oi );
173
  Sleep( 10 );
174
  inp( lpt, 0x04 );   //SDA abhorchen: 4.bit    16
175
  Sleep( 10 );
176
  outp( lpt, oo );
177
  Sleep( 10 );
178
  outp( lpt, oi );
179
  Sleep( 10 );
180
  inp( lpt, 0x04 );   //SDA abhorchen: 5.bit    8
181
  Sleep( 10 );
182
  outp( lpt, oo );
183
  Sleep( 10 );
184
  outp( lpt, oi );
185
  Sleep( 10 );
186
  inp( lpt, 0x04 );   //SDA abhorchen: 6.bit    4
187
  Sleep( 10 );
188
  outp( lpt, oo );
189
  Sleep( 10 );
190
  outp( lpt, oi );
191
  Sleep( 10 );
192
  inp( lpt, 0x04 );   //SDA abhorchen: 7.bit    2
193
  Sleep( 10 );
194
  outp( lpt, oo );
195
  Sleep( 10 );
196
  outp( lpt, oi );
197
  Sleep( 10 );
198
  inp( lpt, 0x04 );   //SDA abhorchen: 8.bit    1
199
  Sleep( 10 );
200
201
  outp( lpt, oo );
202
  Sleep( 10 );
203
  return nachkomma;
204
}
205
206
207
208
209
void func_master_no_acknowledge()
210
{
211
  outp( lpt, io );
212
  Sleep( 10 );
213
  outp( lpt, ii );
214
  Sleep( 10 );
215
  outp( lpt, io );
216
  Sleep( 10 );
217
}
218
219
int main ()
220
{
221
222
    //Temperatur auslesen:
223
    //1. PC sendet stop an LM75
224
    //2. PC sendet start an LM 75
225
    //3. PC sendet adress byte an LM75
226
    //4. LM75 sendet acknowledge an PC
227
    //5. LM75 sendet 8 bit (ganzzahliger Temperaturanteil) an PC
228
    //6. PC sendet acknowledge an LM75
229
    //7. LM75 sendet 8 bit (Nachkommastelle der Temperatur - nur erstes bit ist dafür interesant) an PC
230
    //8. PC sendet no acknowledge - d.h. quitierung der erhaltenen daten, wünscht jedoch keine weiteren daten
231
    //9. PC sendet stop an LM75
232
func_stop();
233
func_send_adress_byte();
234
func_slave_acknowledge();
235
data_from_slave_a = func_slave_send_data_ganzzahl();
236
func_master_acknowledge();
237
data_from_slave_b = func_slave_send_data_nachkomma();
238
func_master_no_acknowledge();
239
240
241
return 0;
242
243
}
244
245
246
fg Rocco

von Stephan M. (stephanm)


Lesenswert?

Rocco schrieb:
> dabei interessiert mich vorallem ob ich die ganze Kommunikation nicht
> vereinfachen kann. Meine jetzige Version beinhaltet viel zu viele
> fehlermöglichkeiten. Ich hoffe das es irgen eine andere Methode gibt an
> den LM75 Einzen und Nullen zu senden - und zu empfangen.

Na ja, bei der Kommunikation passiert doch immer wieder das selbe, 
nämlich beim Senden von Daten an den LM75 in Etwa sowas:

- Datenbit (0 oder 1) auf Datenleitung ausgeben
- Möglicherweise kurz warten
- Clockleitung 0->1
- Möglicherweise kurz warten
- Clock 1 -> 0, damit die CLK-Leitung nicht auf einem Pegel festsitzt

Aus diesem Schema kannst Du Dir zunächst eine Funktion zusammenbasteln, 
die ein einzelnes Bit an den LM75 sendet, in Pseudocode also etwa:

function send_bit(bit) {
  set_data_signal(bit);
  short_delay();
  set_clock_signal(1);
  short_delay();
  set_clock_signal(0);
  short_delay();
}

Um ein einzelnes Byte zu senden macht man dann sowas:

function send_byte(value) {
  for (i = 0; i < 8; i++) { /* One Byte = 8 bits */
    bit = Nth_bit(value, i);
    send_bit(bit);
  }
}

Soviel zum Prinzip. In der Praxis muss dann ja noch die Startbedingung 
auf dem Bus richtig ausgegeben werden und das einlesen der Daten muss ja 
auch noch irgendwie erfolgen, und und und...

Das was Du gemacht hast, ist ja nicht verkehrt, es ist halt nur sehr 
viel langweilige "Prosa" im Code. Versuche als erstes, die sich 
wiederholenden Strukturen im Code zu Funktionen zusammenzufassen. So wie 
oben angedeutet kann man das Problem ja leicht auf mehrere Ebenen 
zerlegen:

- Bit-Ebene = Unterste Ebene: Einzelne Bits senden oder einlesen

- Byte-Ebene = Mittlere Ebene: Ganze Bytes (oder beliebig lange Gruppen 
von Bits) senden oder einlesen, im einfachsten Fall z.B. Funktionen, die 
z.B. ein Byte = 8 Bits gleichzeitig einlesen oder schreiben

- Protokoll-Ebene = Oberste Ebene: Hier stehen Funktionen wie "lese 
Temperatur aus" oder "programmiere Chip so um, dass er statt der 
Temperatur die Luftfeuchtigkeit misst" (nur als abstraktes Beispiel)

- Funktionale Ebene = Allerhöchste Ebene: Nach Programmstart wird alle 
10 Sekunden ein Temperaturmesswert ermittelt und in eine Datei 
geschrieben

Viel Spaß und Erfolg beim Bitbanging,

Stephan

von Rocco (Gast)


Lesenswert?

Hallo,

cooler Tip - genau das habe ich erst mal gebraucht.

ich würde also vom PC an den SCL Eingang des LM75 in einer for Schleife 
ein dauerndes high low - wechselndes Signal schicken. und wärend dessn 
zum richtigen Zeitpunkt SDA beschreiben oder auslesen.

Oben im Bild sieht man doch die wie die Adresse des LM75 angesprochen 
wird. dazu sendet der PC volgendes Bitmuster 10010001 an den SDA Eingang 
des Chips.
Während dessen "Tickt" an Scl der Tackt.
also wird follgendes vom PC an den LM75 gesendet:

PC -> SCL 1010101010101010
PC -> SDA 1 0 0 1 0 0 0 1

das wäre dann so etwas wie:
1
 for (i = 0; i < 8; i++) { /* scl Takt erzeugen 8x an und aus */
2
    outp( lpt, 0x01 ); //nur Pin D0 am LPT Port ein
3
    Sleep( 10 );
4
    outp( lpt, 0x00 ); //alle Pins am LPT Port aus
5
    Sleep( 10 );
6
 }

Was ich dabei nicht kapiere - wie schreibe ich wärend dessen den Pin D1 
ansteuere, an dem SDA vom LM 75 hängt?!


fG Rocco

von Rocco (Gast)


Lesenswert?

PS kann man das nicht irgend wie so machen:

PC -> SDA outp (lpt,0b10010001)

wie müsste dabei SCL angesteuert werden?

von Stephan M. (stephanm)


Lesenswert?

Rocco schrieb:
> das wäre dann so etwas wie:
>
1
>  for (i = 0; i < 8; i++) { /* scl Takt erzeugen 8x an und aus */
2
>     outp( lpt, 0x01 ); //nur Pin D0 am LPT Port ein
3
>     Sleep( 10 );
4
>     outp( lpt, 0x00 ); //alle Pins am LPT Port aus
5
>     Sleep( 10 );
6
>  }
7
>
>
> Was ich dabei nicht kapiere - wie schreibe ich wärend dessen den Pin D1
> ansteuere, an dem SDA vom LM 75 hängt?!

SDA hängt doch an der D1-Leitung der Druckerschnittstelle, oder? Also 
wie wäre es z.B. hiermit:

Pseudocode:

function send_bit(bit) { /* bit must be either 0 or 1 */
    bit <<= 1; // Now bit is either 0 or 2
               // One could use 'bit *= 2;', too :-)

    // Emit bit value, CLK is left in LOW state
    outp(lpt, bit);
    Sleep(10);

    // Clk LOW -> HIGH
    outp(lpt, bit | 1);
    Sleep(10);

    // Clk HIGH -> LOW
    outp(lpt, bit);
    Sleep(10);
};

Stephan

von Rocco (Gast)


Lesenswert?

mal schauen ob ich das richtig kapiere - bin wie gesagt Anfänger - also 
etwas Mitleid ;-)
1
function send_bit(bit) { /* bit must be either 0 or 1 */
2
    bit <<= 1; // hier wird der Variablen "bit" eine 1 zugeordnet
3
               // One could use 'bit *= 2;', too :-)
4
5
    // Emit bit value, CLK is left in LOW state
6
    outp(lpt, bit);        //hier wird D0 auf high gesetzt
7
    Sleep(10);
8
9
    // Clk LOW -> HIGH
10
    outp(lpt, bit | 1);   //hier wird D0 auf low gesetzt
11
    Sleep(10);
12
13
    // Clk HIGH -> LOW
14
    outp(lpt, bit);      //hier wird D0 wieder auf high gesetzt
15
    Sleep(10);
16
};

Warscheinlich schnall ich es einfach nicht - aber wie meinst du kann ich 
wärend dessen über D1 follgendes ausgeben 10010001?

fg Rocco

von Stephan M. (stephanm)


Lesenswert?

Rocco schrieb:
> mal schauen ob ich das richtig kapiere - bin wie gesagt Anfänger - also
> etwas Mitleid ;-)

Neee, Mitleid is nicht ;-)

> [...]
> Warscheinlich schnall ich es einfach nicht - aber wie meinst du kann ich
> wärend dessen über D1 follgendes ausgeben 10010001?

Die Funktion wie ich sie geschrieben habe, sendet ja nur ein einzelnes 
Bit, und zwar wie folgt in drei Schritten:

outp(lpt, bit);       -> CLK=0, SDA=bit
outp(lpt, bit | 1);   -> CLK=1, SDA=bit
outp(lpt, bit);       -> CLK=0, SDA=bit

Um 90 Grad gedreht gibt das folgenden Ablauf:

Zeit       T   T+1   T+2
-------------------------
SCL        0    1     0
SDA        B    B     B

(B = Wert des Bits, 0 oder 1) -> Bei T+1 liegt das Datenbit an SDA und 
eine Steigende CLK-Flanke kommt. Das sollte doch zum Senden eines Bits 
reichen, oder?

Nun zum Senden von Bytes: Ein Byte 0x11000101 sendet man nun halt als 
Folge von 8 Bits. Achtung: Reihenfolge beachten - MSB oder LSB zuerst?! 
Ich mach das mal mit MSB zuerst:

send_bit(1);
send_bit(1);
send_bit(0);
send_bit(0);
send_bit(0);
send_bit(1);
send_bit(0);
send_bit(1);

Oder, um die viele Schreibarbeit zu vereinfachen, halt in einer Schleife 
und das ganze dann noch in einer Funktion:

void send_byte(int byte) {
  for (int i = 7; i > -1; i--) {
    int bit = ((byte >> i) & 1);
    send_bit(bit);
  };
};

Dann sehen die 8 Zeilen send_bit() von oben so aus:

send_byte(0xC5);

Stephan

von Rocco (Gast)


Lesenswert?

was bedeuted der |  ?
Das ist doch bestimmt so ein wilder Bitoperator - oder?

fg Rocco

von Rocco (Gast)


Lesenswert?

ok, ich komme soweit mit - aber das hier kapier ich nicht:
outp(lpt, bit);       -> CLK=0, SDA=bit
outp(lpt, bit | 1);   -> CLK=1, SDA=bit
outp(lpt, bit);       -> CLK=0, SDA=bit

vorallem kann ich" bit | 1 " nicht interpretieren

ich weis das wenn ich follgendes sende nur der D0 pin an ist:
outp( lpt, 0x01 );

sende ich das hier sind D0 und D1 an:
outp( lpt, 0x03 );

das ist doch bestimmt das selbe was auch Dein Quelltext macht - nur das 
Du das binär und ich es hexadezimal mache - oder?

fG Rocco

von Rocco (Gast)


Lesenswert?

follgendes sollte doch eigentlich gehen - oder?
1
outp( lpt, 0x03);    //1
2
Sleep(10);
3
outp( lpt, 0x00);    
4
Sleep(10);
5
outp( lpt, 0x01);    //0
6
Sleep(10);
7
outp( lpt, 0x00);    
8
Sleep(10);
9
outp( lpt, 0x01);    //0
10
Sleep(10);
11
outp( lpt, 0x00);    
12
Sleep(10);
13
outp( lpt, 0x03);    //1
14
Sleep(10);
15
outp( lpt, 0x00);    
16
Sleep(10);
17
outp( lpt, 0x01);    //0
18
Sleep(10);
19
outp( lpt, 0x00);    
20
Sleep(10);
21
outp( lpt, 0x01);    //0
22
Sleep(10);
23
outp( lpt, 0x00);    
24
Sleep(10);
25
outp( lpt, 0x01);    //0
26
Sleep(10);
27
outp( lpt, 0x00);    
28
Sleep(10);
29
outp( lpt, 0x03);    //1
30
Sleep(10);
31
outp( lpt, 0x00);    
32
Sleep(10);

das färe dann die funktion Adresse

von Stephan M. (stephanm)


Lesenswert?

Rocco schrieb:
> [...]
> vorallem kann ich" bit | 1 " nicht interpretieren
> [...]
> das ist doch bestimmt das selbe was auch Dein Quelltext macht - nur das
> Du das binär und ich es hexadezimal mache - oder?

Egal wie man eine Zahl im Quelltext hinschreibt - dezimal, binär, oktal, 
hexadezimal, ... - der Computer verwurstet alles zu Folgen von Nullen 
und Einsen.

"|" ist ein binäres Oder. Auf die Schnelle hab ich dazu folgendes 
gefunden:

http://www.cprogramming.com/tutorial/bitwise_operators.html

Ich bin ehrlich gesagt geneigt, Dir zu empfehlen, mal 2-3 Tage den Kopf 
von diesem speziellen Problem freizumachen und ein wenig 
C/C++-Grundlagen zu lernen. Wenn das einigermassen sitzt, dann versuche 
das Problem nochmal neu aufzurollen. Das soll jetzt keine Ablehnung von 
Hilfe sein, aber ich seh im Moment für mich keine andere Wahl, als Dir 
das Programm zu schreiben, womit Du Null Lerneffekt hast.

Liebe Grüße,

Stephan

von Rocco (Gast)


Lesenswert?

Nein, ich nehme dir das nicht übel. Im Gegenteil, ich bin Dir für deine 
Hilfe sehr dankbar.

Ich bastel z.Z. eigentlich an einem Thermocycler für unser Labor.
Es soll also ein Progie entstehen mit dem man - über ein Relais - eine 
Heizung für eine betimmte Zeit eingeschaltet werden soll. Der Plan ist 
das mann 10 Temperaturen wählen kann die dann jeweils für eine bestimmte 
Zeit gehalten werden sollen.

Also wenn du ein zwei gute Tutorials kennst die mir da weiter helfen....


fG Rocco

von Stephan M. (stephanm)


Lesenswert?

Ach, noch ein Nachtrag: Ich hab glaub ich die Rollen der Datenleitung 
und die der Clockleitung (d.h. die Rollen von D0 und D1) vertauscht. 
Möglicherweise liegt da auch ein Teil Deines "Verständnisproblems" für 
das was ich geschrieben habe. Sorry, ich wollte eigentlich nicht für 
Verwirrung sorgen.

Nicht desto trotz, wenn Du den Code verbessern möchtest, solltest Du die 
Sprache, in der er geschrieben ist, mindestens 'ein bisschen' 
beherrschen.

Ein erster Schritt wäre doch: Schreib doch mal zwei Funktionen, eine für 
das Senden einer Null und eine für das Senden einer Eins. Das Senden der 
ersten 4 Bit der Addresse wären dann nur noch 4 Funktionsaufrufe:

send_bit_1();
send_bit_0();
send_bit_0();
send_bit_1();

Wenn Du das machst, dann schau Dir die beiden Funktionen mal genau an 
(oder poste sie hier) und vergleiche die beiden Funktionen miteinander.

Stephan

von Rocco (Gast)


Lesenswert?

ok, ich versuch erst mal ein bischen weiter zu kommen.

vielen Dank

Rocco

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.