'-- lm75-i2c.bas ------------------------------------------------- >>fst'02<< - ' - liest den 9-Bit Temperatursensor LM75 ueber den Parallelport aus ' - Spannungsversorgung des LM75 aus dem Parallelport ' - Mit i2c-BUS Befehlssatz in separaten SUBs / FUNCTIONs ' - Verbindungen: (Bauanleitung im Internet; s.u.) ' -- LM75 -- -- LPT ----------- -- Zweck ------------------------- ' Pin1 (SDA) --o-< Pin14 (AUTO FEED) = Datenleitung vom PC ' +-> Pin10 (ACKNOWLEDGE) = Datenleitung zum PC ' Pin2 (SCL) -< Pin 1 (STROBE) = Takleitung ' Pin3 (O.S.) nicht verbunden = Schaltausgang LM75 ' Pin4 (GND) - Pin18-25 (GND) = Masse ' Pin5 (A2) - Pin18-25 (GND) = Slave-Adress Einsteller 2 ' Pin6 (A1) - Pin18-25 (GND) = Slave-Adress Einsteller 1 ' Pin7 (A0) - Pin18-25 (GND) = Slave-Adress Einsteller 0 ' Pin8 (+Vs) - Pin 9 (DATA7) = Versorgungsspannung '-- V 20050411 ------------------------------- http://www.FrankSteinberg.de - DECLARE SUB i2cStart () DECLARE SUB i2cSCHREIBEN (ByteW%) DECLARE FUNCTION i2cLESEN% () DECLARE SUB i2cAckMaster () DECLARE SUB i2cNoAckMaster () DECLARE FUNCTION i2cAckSlave% () DECLARE SUB i2cStop () DECLARE SUB SDA (BitW%) DECLARE SUB SCL (BitW%) DECLARE SUB SVC (Flag%) DECLARE FUNCTION SDAin% () DECLARE SUB Ports () DECLARE FUNCTION Celsius! (Byte1%, Byte2%) DECLARE SUB Pause (Ticks%) DEFINT A-Z 'Standard fuer alle Variablen = Integer 'Registeradressen fr alle SUBs/FUNCTIONs zugaenglich machen: DIM SHARED BA0, BA1, BA2 'fuer QBasic, ... 'SHARED BA0, BA1, BA2 'fuer Power Basic 'Grosse Schrift: WIDTH 40 'Parameter der Schnittstelle ermitteln: CALL Ports PRINT PRINT " Temperaturmessung >>fst'02<<" PRINT PRINT " LM75 <-> i2c-BUS <-> Parallelport" 'Grundstellung Steuer-Register (alle Steuerausgaenge 0V, Bits4-7 auf 0) OUT BA2, 11 'Versorgungsspannung ueber die LPT-Datenausgaenge einschalten: CALL SVC(1) 'Stopsequenz ausgeben: CALL i2cStop DO 'Hauptschleife '90 Millisekunden Wartezeit fuer LM75: CALL Pause(419) 'Startsequenz ausgeben: CALL i2cStart 'Adressbyte des LM75 ausgeben: CALL i2cSCHREIBEN(145) '145 = 1 0 0 1 0 0 0 1 binaer ' ^ ^ ^ ^ : feste Adresse des LM75 ' ^ ^ ^ : variable Adresse des LM75, wie ' Pin5/Pin6/Pin7 = A2/A1/A0 verbunden ' ^ : 0=Master (PC) schreibt anschliessend ' 1=Master (PC) liest anschliessend 'Acknowledge vom LM75 lesen und Anzahl der Fehler speichern: IF i2cAckSlave THEN Fehler = Fehler + 1 'Datenbyte 1 lesen: Byte1 = i2cLESEN 'Acknowledge vom Master ausgeben: CALL i2cAckMaster 'Datenbyte 2 lesen: Byte2 = i2cLESEN 'No Acknowledge vom Master (nicht unbedingt erforderlich): CALL i2cNoAckMaster 'Stopsequenz ausgeben: CALL i2cStop 'Bytes in C umrechnen: GradC! = Celsius!(Byte1, Byte2) 'Messungen pro Sek. ermitteln: z = z + 1: IF T1$ <> TIME$ THEN ZS = z: z = 0: T1$ = TIME$ 'Anzeigen: LOCATE 9 COLOR 15, 0 PRINT USING " Temperatur = ###.#C "; GradC! COLOR 7, 0 PRINT : PRINT PRINT USING " Daten-Byte 1 = ###"; Byte1 PRINT PRINT USING " Daten-Byte 2 = ###"; Byte2 PRINT PRINT USING " Acknowledge vom LM75 =#### Fehler"; Fehler PRINT PRINT USING " Messungen/Sek = ###"; ZS LOOP WHILE INKEY$ = "" 'Hauptschleife wiederholen bis Tastendruck 'Versorgungsspannung ueber die LPT-Datenausgaenge ausschalten: CALL SVC(0) FUNCTION Celsius! (Byte1, Byte2) 'Daten vom LM75 nach C umrechnen IF (Byte1 AND 128) THEN 'Vorzeichen-Bit (Byte1,Bit7) auswerten x! = Byte1 - 256 'Temperatur unter Null ELSE x! = Byte1 'Temperatur Null oder darueber END IF IF (Byte2 AND 128) THEN x! = x! + .5 'Halbgrad-Bit (Byte2,Bit7) auswerten Celsius! = x! END FUNCTION SUB i2cAckMaster '"Acknowledge" auf den i2c-BUS geben CALL SDA(0) 'SDA low ausgeben CALL SCL(1) 'SCL high ausgeben CALL SCL(0) 'SCL low ausgeben END SUB FUNCTION i2cAckSlave '"Acknowledge" des Slave vom i2c-BUS lesen CALL SDA(0) 'SDA high ausgeben CALL SCL(1) 'SCL low ausgeben CALL SDA(1) 'lesen fuer PC nur moeglich, wenn SDA high i2cAckSlave = SDAin 'Acknowledge-Bit vom Slave lesen (FUNCTION SDAin) CALL SDA(0) 'SDA wieder in den Ausgangszustand CALL SCL(0) 'SCL low ausgeben END FUNCTION FUNCTION i2cLESEN 'ein Byte vom i2c-BUS lesen BitW = 128 'erstes Bit hat den Wert 128 (MSB) FOR i = 0 TO 7 '8 Bits schreiben: CALL SCL(1) 'SCL low ausgeben IF SDAin THEN ByteW = ByteW + BitW 'ein Bit von SDA lesen (FUNCTION SDAin) BitW = BitW \ 2 'Bit-Wert fuer naechste Abfrage aendern CALL SCL(0) 'SCL high ausgeben NEXT i2cLESEN = ByteW END FUNCTION SUB i2cNoAckMaster '"No Acknowledge" auf den i2c-BUS geben CALL SDA(1) 'SDA high ausgeben CALL SCL(1) 'SCL high ausgeben CALL SCL(0) 'SCL low ausgeben END SUB SUB i2cSCHREIBEN (ByteW) 'ein Byte auf den i2c-BUS schreiben BitW = 128 'erstes Bit hat den Wert 128 (MSB) FOR i = 0 TO 7 '8 Bits schreiben: IF (ByteW AND BitW) THEN 'wenn Bit=1 ... CALL SDA(1) 'dann SDA high ausgeben ELSE 'wenn Bit=0 ... CALL SDA(0) 'dann SDA low ausgeben END IF BitW = BitW \ 2 'Bit-Wert fuer naechste Abfrage aendern CALL SCL(1) 'SCL high ausgeben CALL SCL(0) 'SCL low ausgeben NEXT i END SUB SUB i2cStart 'Startsequenz auf den i2c-BUS schreiben CALL SDA(0) 'SDA low ausgeben CALL SCL(0) 'SCL low ausgeben END SUB SUB i2cStop 'Stopsequenz auf den i2c-BUS schreiben CALL SCL(1) 'SCL high ausgeben CALL SDA(1) 'SDA high ausgeben END SUB SUB Pause (Ticks) 'erzeugt eine Pause von ca. 0,00022 Sekunden (Ticks%=1) bis '70,3016 Sekunden (Ticks%=32767) Sekunden mit Hilfe des PIT 8253 Timers. 'Es wird die Anzahl der zu wartenden Timer-Ticks uebergeben. 'Ein Tick entspricht 0,21455 Millisekunden. 'Einer Sekunde entsprechen ca. 4661 Ticks. OUT (&H61), INP(&H61) OR 1 'Lautsprecherkanal einschalten OUT (&H43), 164 'PIT 8253 konfigurieren OUT (&H42), 255 'Zaehler mit Startwert laden OUT (&H42), 255 'wiederholen fuer schnelle PCs Hi = Ticks \ 256 'HighByte von Anzahl der Ticks bestimmen Lo = 255 - (Ticks MOD 256) 'LowByte von Anzahl der Ticks bestimmen '(Zaehler zeahlt abwaerts) DO x = INP(&H42) 'Zaehler auslesen IF x > y THEN z = z + 1 'Uebertrag bei Zaehlersprung y = x 'alten Wert speichern LOOP UNTIL (z > Hi) AND (x <= Lo) 'Ende, wenn Zielwerte erreicht END SUB SUB Ports 'Basisadresse (Daten-Register) aus BIOS-Datenbereich lesen: DEF SEG = 0 BA0 = PEEK(&H408) + PEEK(&H409) * 256 'LPT 1 BA02 = PEEK(&H40A) + PEEK(&H40B) * 256 'LPT 2 DEF SEG 'Abfrage, wenn LPT2 vorhanden: IF BA02 THEN LOCATE 10 PRINT " Parallelport waehlen:" PRINT PRINT " - Taste [2] fuer LPT 2," PRINT " - andere Taste fuer LPT 1." IF INPUT$(1) = "2" THEN BA0 = BA02 CLS END IF BA1 = BA0 + 1 'Status-Register an Offset 1 BA2 = BA0 + 2 'Steuer-Register an Offset 2 END SUB SUB SCL (BitW) 'gibt "high" oder "low " auf die Taktleitung (SCL) des i2c-BUS 'und loescht jedesmal explizit das Bidirektional-Bit (Bit5, Wert 32) IF BitW THEN 'wenn BitW 1 uebergeben ... OUT BA2, INP(BA2) AND 222 'STROBE -> SCL high, bidirekt. low ELSE 'wenn BitW 0 uebergeben ... OUT BA2, (INP(BA2) OR 1) AND 223 'STROBE -> SCL low, bidirekt. low END IF CALL Pause(2) '0,430 Millisekunden warten END SUB SUB SDA (BitW) 'gibt "high" oder "low " auf die Datenleitung (SDA) des i2c-BUS 'und loescht jedesmal explizit das Bidirektional-Bit (Bit5, Wert 32) IF BitW THEN 'wenn BitW 1 uebergeben ... OUT BA2, INP(BA2) AND 221 'AUTO FEED -> SDA high, bidirekt. low ELSE 'wenn BitW 0 uebergeben ... OUT BA2, (INP(BA2) OR 2) AND 223 'AUTO FEED -> SDA low, bidirekt. low END IF CALL Pause(2) '0,430 Millisekunden warten END SUB FUNCTION SDAin 'liest ein Bit vom i2c-BUS CALL SDA(1) 'AUTO FEED -> SDA muss high sein, damit 'ueber ACKNOWLEDGE gelesen werden kann! IF (INP(BA1) AND 64) THEN SDAin = 1 'high erkannt (SDA -> ACKNOWLEDGE) END FUNCTION SUB SVC (Flag) 'gibt "high" oder "low " auf eine Datenleitung des Parallelports 'zur Spannungsversorgung des angeschlossenen Bauteils (hier LM75) OUT BA2, INP(BA2) AND 223 'Bit5 loeschen (bidirektional) 'erforderlich fuer Omnibook IF Flag THEN OUT BA0, 128 'Spannung auf D7 -> +Vs geben ELSE OUT BA0, 0 'Spannung AUS fr D0-D7 END IF END SUB