mikrocontroller.net

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


Autor: Rocco (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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.
#include <stdio.h>
#include <conio.h>
#include <windows.h>
#include <math.h>
//#include <iostream.h>

//using namesapce std;

#define lpt 0x378

//#define D_IN 64       //Byte for SDA -> ACKNOWLEDGE high
#define oo 0       //SDA -> low / SCL -> low
#define oi 1       //SDA -> low / SCL -> high
#define io 2       //SDA -> high / SCL -> low
#define ii 3       //SDA -> high / SCL -> high


//void funktion();
void func_stop()
{
  outp( lpt, ii );
  Sleep( 10 );
}

void func_start()
{
  outp( lpt, oi );
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
}

void func_send_adress_byte()
{
  int counter;

  outp( lpt, ii ); //1
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
  outp( lpt, oi ); //0
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
  outp( lpt, oi ); //0
  Sleep( 10 );
  outp( lpt, oi );
  Sleep( 10 );
  outp( lpt, ii ); //1
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
  outp( lpt, oi ); //0
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
  outp( lpt, oi ); //0
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
  outp( lpt, oi ); //0
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
  outp( lpt, ii ); //1
  Sleep( 10 );

 

void func_slave_acknowledge()
{
  outp( lpt, oi );
  Sleep( 10 );
  inp( lpt, 0x04 );   //SDA abhorchen: for SDA low - > weiter machen -> else stop und wieder von vorne und fehler melden
  Sleep( 10 );
}
int func_slave_send_data_ganzzahl()  //ganzzahligen Anteil der Temperatur abholden
{
    int nachkomma;
  outp( lpt, oo );
  Sleep( 10 );
//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
  outp( lpt, oi );
  Sleep( 10 );
  inp( lpt, 0x04 );   //SDA abhorchen: 1.bit  high->128 ->-°C    low->128 ->+°C
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
  outp( lpt, oi );
  Sleep( 10 );
  inp( lpt, 0x04 );   //SDA abhorchen: 2.bit    64
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
  outp( lpt, oi );
  Sleep( 10 );
  inp( lpt, 0x04 );   //SDA abhorchen: 3.bit    32
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
  outp( lpt, oi );
  Sleep( 10 );
  inp( lpt, 0x04 );   //SDA abhorchen: 4.bit    16
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
  outp( lpt, oi );
  Sleep( 10 );
  inp( lpt, 0x04 );   //SDA abhorchen: 5.bit    8
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
  outp( lpt, oi );
  Sleep( 10 );
  inp( lpt, 0x04 );   //SDA abhorchen: 6.bit    4
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
  outp( lpt, oi );
  Sleep( 10 );
  inp( lpt, 0x04 );   //SDA abhorchen: 7.bit    2
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
  outp( lpt, oi );
  Sleep( 10 );
  inp( lpt, 0x04 );   //SDA abhorchen: 8.bit    1
  Sleep( 10 );

  outp( lpt, oo );
  Sleep( 10 );
  }
  return ganzzahl;
}

void func_master_acknowledge()
{
  outp( lpt, oo );
  Sleep( 10 );
  outp( lpt, oi );
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
}


int func_slave_send_data_nachkomma()  // Nachkommastelle der Temperatur abholden
{
  int nachkomma;

  outp( lpt, oo );
  Sleep( 10 );
//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!
  outp( lpt, oi );
  Sleep( 10 );
  inp( lpt, 0x04 );   //SDA abhorchen: 1.bit  high->128 ->x,5°C    low->128 ->x,0°C
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
  outp( lpt, oi );
  Sleep( 10 );
  inp( lpt, 0x04 );   //SDA abhorchen: 2.bit    64
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
  outp( lpt, oi );
  Sleep( 10 );
  inp( lpt, 0x04 );   //SDA abhorchen: 3.bit    32
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
  outp( lpt, oi );
  Sleep( 10 );
  inp( lpt, 0x04 );   //SDA abhorchen: 4.bit    16
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
  outp( lpt, oi );
  Sleep( 10 );
  inp( lpt, 0x04 );   //SDA abhorchen: 5.bit    8
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
  outp( lpt, oi );
  Sleep( 10 );
  inp( lpt, 0x04 );   //SDA abhorchen: 6.bit    4
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
  outp( lpt, oi );
  Sleep( 10 );
  inp( lpt, 0x04 );   //SDA abhorchen: 7.bit    2
  Sleep( 10 );
  outp( lpt, oo );
  Sleep( 10 );
  outp( lpt, oi );
  Sleep( 10 );
  inp( lpt, 0x04 );   //SDA abhorchen: 8.bit    1
  Sleep( 10 );

  outp( lpt, oo );
  Sleep( 10 );
  return nachkomma;
}




void func_master_no_acknowledge()
{
  outp( lpt, io );
  Sleep( 10 );
  outp( lpt, ii );
  Sleep( 10 );
  outp( lpt, io );
  Sleep( 10 );
}

int main ()
{

    //Temperatur auslesen:
    //1. PC sendet stop an LM75
    //2. PC sendet start an LM 75
    //3. PC sendet adress byte an LM75
    //4. LM75 sendet acknowledge an PC
    //5. LM75 sendet 8 bit (ganzzahliger Temperaturanteil) an PC
    //6. PC sendet acknowledge an LM75
    //7. LM75 sendet 8 bit (Nachkommastelle der Temperatur - nur erstes bit ist dafür interesant) an PC
    //8. PC sendet no acknowledge - d.h. quitierung der erhaltenen daten, wünscht jedoch keine weiteren daten
    //9. PC sendet stop an LM75
func_stop();
func_send_adress_byte();
func_slave_acknowledge();
data_from_slave_a = func_slave_send_data_ganzzahl();
func_master_acknowledge();
data_from_slave_b = func_slave_send_data_nachkomma();
func_master_no_acknowledge();


return 0;

}


fg Rocco


Autor: Stephan M. (stephanm)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Rocco (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
 for (i = 0; i < 8; i++) { /* scl Takt erzeugen 8x an und aus */
    outp( lpt, 0x01 ); //nur Pin D0 am LPT Port ein
    Sleep( 10 );
    outp( lpt, 0x00 ); //alle Pins am LPT Port aus
    Sleep( 10 );
 }

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

Autor: Rocco (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PS kann man das nicht irgend wie so machen:

PC -> SDA outp (lpt,0b10010001)

wie müsste dabei SCL angesteuert werden?

Autor: Stephan M. (stephanm)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rocco schrieb:
> das wäre dann so etwas wie:
>
>  for (i = 0; i < 8; i++) { /* scl Takt erzeugen 8x an und aus */
>     outp( lpt, 0x01 ); //nur Pin D0 am LPT Port ein
>     Sleep( 10 );
>     outp( lpt, 0x00 ); //alle Pins am LPT Port aus
>     Sleep( 10 );
>  }
> 
>
> 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

Autor: Rocco (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mal schauen ob ich das richtig kapiere - bin wie gesagt Anfänger - also 
etwas Mitleid ;-)
function send_bit(bit) { /* bit must be either 0 or 1 */
    bit <<= 1; // hier wird der Variablen "bit" eine 1 zugeordnet
               // One could use 'bit *= 2;', too :-)

    // Emit bit value, CLK is left in LOW state
    outp(lpt, bit);        //hier wird D0 auf high gesetzt
    Sleep(10);

    // Clk LOW -> HIGH
    outp(lpt, bit | 1);   //hier wird D0 auf low gesetzt
    Sleep(10);

    // Clk HIGH -> LOW
    outp(lpt, bit);      //hier wird D0 wieder auf high gesetzt
    Sleep(10);
};


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

fg Rocco

Autor: Stephan M. (stephanm)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Rocco (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
was bedeuted der |  ?
Das ist doch bestimmt so ein wilder Bitoperator - oder?

fg Rocco

Autor: Rocco (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Rocco (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
follgendes sollte doch eigentlich gehen - oder?
outp( lpt, 0x03);    //1
Sleep(10);
outp( lpt, 0x00);    
Sleep(10);
outp( lpt, 0x01);    //0
Sleep(10);
outp( lpt, 0x00);    
Sleep(10);
outp( lpt, 0x01);    //0
Sleep(10);
outp( lpt, 0x00);    
Sleep(10);
outp( lpt, 0x03);    //1
Sleep(10);
outp( lpt, 0x00);    
Sleep(10);
outp( lpt, 0x01);    //0
Sleep(10);
outp( lpt, 0x00);    
Sleep(10);
outp( lpt, 0x01);    //0
Sleep(10);
outp( lpt, 0x00);    
Sleep(10);
outp( lpt, 0x01);    //0
Sleep(10);
outp( lpt, 0x00);    
Sleep(10);
outp( lpt, 0x03);    //1
Sleep(10);
outp( lpt, 0x00);    
Sleep(10);

das färe dann die funktion Adresse

Autor: Stephan M. (stephanm)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Rocco (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stephan M. (stephanm)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Rocco (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok, ich versuch erst mal ein bischen weiter zu kommen.

vielen Dank

Rocco

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.