Besucher seit 10/07/2004

kostenlose counter
   

Im WWW Suchen

Benutzerdefinierte Suche
   


 TSic(TM) 206/306 Thermometer

Portview oben

Ich habe den Tsic 206 schon bei meiner Tinyclock eingesetzt. Nun habe ich mir den Sensor nochmal vorgenommen um meine Kenntnisse zu erweitern. Während ich bei der Tinyclock noch keine Auswertung des Paritätsbit und Sensorerkennung programmiert habe, habe ich diese Funktionen beim TSic 206/306 Thermometer nachgeholt.
Das Thermometer zeigt Temperaturen von -50 °C bis 150 °C an. Der verwendete Sensor hat eine Auflösung von 0,1 °C und eine Genauigkeit von 0,3 °C (TSic306)  im Temperaturbereich von 10° bis 90°.  Das beste ist jedoch das Handliche TO92 Gehäuse und das der Tsic schon kalibriert ist. Wer schon einmal bei einem Selbstbauthermometer den Temperatursensor mit Eiswasser und Fieberthermometer abgeglichen hat, weiss wovon ich rede.
Da das Display nur 3 stellig ist, werden nur im Bereich von -9.9° bis +99.9°C Zehntel Grad angezeigt. Von -50° bis -10° und von +100° bis 150° werden nur Ganzzahlige Temperaturwerte angezeigt. Bei einem Übertragungsfehler wird im Display "P-E" für Parity-Error angezeigt. Ist kein Sensor angeschlossen oder der TSic antwortet aus anderen Gründen nicht, erscheint im Display "S-E" für Sensor-Error.
Mehr zum Sensor in diesem Datenblatt.
Als Hardware habe ich (wie schon öfter) mein Portview Modul benutzt. Diese kleine Platine hat im Wesentlichen einen AT Mega48 oder AT Mega8 auf der Unterseite und 3 Siebensegmentanzeigen auf der Oberseite.

Anschluss

TSic206

Der Tsic 206 oder 306 wird wie folgt am Portview Modul angeschlossen.

Pin1 V+ SV1 - 2 rot
Pin2 Signal SV1 - 1 orange
Pin3 GND SV1 - 9 blau

Zwischen Pin1 und 3 ist ein 100nF Kerko im SMD 0805 Gehäuse angelötet. Zusätzlich ist ein 220 Ohm Widerstand in die V+ Leitung einzulöten, den man am besten mit einem Stück Schrumpfschlauch einschließt. Der Sensor lässt sich sehr schön in ein Kugeschreiberdruckknopf einschliessen (siehe Tinyclock) wird dadurch aber etwas träger.

Da ich anfangs selbst auf der Suche nach Informationen über das Zacwire Protokoll war und diese im WWW recht spärlich ausfallen möchte ich hier meine Erfahrungen mit dem (wie ich finde) interessanten Sensor weitergeben, vielleicht hilft es ja jemanden.  Wer also nur das Thermometer nachbauen möchte, kann die Technischen Details unten überspringen und  einfach die kleine Portview Platine aufbauen den Sensor anschliessen und die Thermometer Firmware aufspielen. Die Fuse-Bits werden dabei so eingestellt, das der Mega8(48) mit den internen R-C Oszilator mit 8 MHz läuft.

Für den Dezimalpunkt ist ein weiterer 120 Ohm Widerstand von PC5 an das freie Lötpad der mittleren 7-Segmentanzeige zu  löten. Das geht am besten auf der Unterseite der Platine. Um Kurzschlüsse zu vermeiden ist es Ratsam den Widerstand in einem Stückchen Schrumpfschlauch einzuschliessen.

Das Zacwire(TM) Protokoll

Der TSic 206/306 sendet die Temperaturdaten über das sogenannte Zacwire Protokoll. Sobald man die Versorgungsspannung an den Sensor anlegt sendet dieser nach 65 bis 85 mS seine 2 Datenbytes über die Datenleitung. Anders als bei anderen digitalen Sensoren mit  z.B. I2C oder SPI Schnittstelle, sendet der TSic 206/306 seine Daten ungefragt. Bleibt die Spannung eingeschaltet  "feuert" der TSic ca. alle 100 mS eine weiteres Datenwort ab. Die Datenleitung des TSic ist also zu jeder Zeit Ausgang, während der Dateneingang am Mikrocontroller zu jeder Zeit Eingang ist. Die Datenleitung ist im Ruhezustand auf Highpegel.

Möchte man nur eine Portleitung für den Temperatursensor opfern, müsste V+ des TSic fest mit +5V verbunden werden und das Programm vor dem auslesen des Sensors testen ob dieser gerade sendet.

Das könnte man einfach realisieren, indem man sicherstellt, das vor dem Auslesen die Datenleitung für mindestens 160 µS auf Highpegel ist. In meiner Schaltung habe ich den V+ des TSic Sensors an einen Ausgangspin des AVR angeschlossen und kann so den Sensor über Software ein und ausschalten. Das Datenblatt sieht bei dieser Anschlussart einen 220Ohm Widerstand in der V+ Leitung vor, der zusammen mit dem 100nF Kondensator einen Tiefpass bildet.

Die beiden Datenbytes...

...enthalten einen 11 Bit Rohwert der Temperatur, der später mit einer Formel in °C (oder aber °F) umgerechnet wird und jeweils ein Start- und ein Paritybit. Zuerst wird das Highbyte übertragen das in den Bits 3..7 eine Null enthält und in Bit 0..2 die höherwertigen Bits des 11 Bit Rohwertes. Danach folgt (nach einem ominösen halben Stopbit)  das Lowbyte, welches als Beispiel im Bild unten zu sehen ist. Die Datenübertragung beginnt mit einer negativen Flanke auf der Datenleitung.
Die Übertragung der beiden Datenbytes ist in 2,7 mS abgeschlossen.

Auf dem Bild unten ist der Verlauf von einem Datenbyte dargestellt.

Zacwire Oszi

Die Übertragungsdauer für ein Bit ist ca. 125µS. Der Unterschied zwischen Logisch 0 und Logisch 1, wird über das Tastverhältniss (Duty-Cycle) gesteuert. Bei Logisch 0 beträgt dieses 25% bei Logisch 1 75%.
Das Startbit ist im Datenblatt mit T-Strobe benannt und hat ein Tastverhältnis von 50%. Danach folgen 8 Datenbits und zum Schluss das Paritybit. Der Ausgangswert von T-Strobe ist im Datenblatt mit 62,5 µS angegeben. Leider bleibt dieser Wert nicht mit der Temperatur konstant, deshalb ist es ratsam die T-Strobezeit vor jedem übertragenen Byte erneut zu messen. Im Bild oben habe ich für die zu messende T-Strobe Zeit eine gelbe Strecke eingezeichnet.
Die gemessene T-Strobe Zeit, wartet man bei den folgenden Bits ab (im Bild die eingezeichneten roten Strecken), bevor man die Datenleitung abfragt. Der Timer wird bei jedem Bit, ab der fallenden Flanke gestartet. Da die Übertragung jedes weiteren Bits auch mit einer negativen Flanke beginnt, wird die Übertragung mit jedem Bit neu synchronisiert. 

Assembler Beispiel:

            ;---------------------------------------------------------------------
            ;T-Strobe Zeit (etwa 62,5 µS) messen.
            ;Hier für den Mega48 mit dem 8-Bit Timer/Counter0 (Compare A Match)
            ;---------------------------------------------------------------------
            ;Da sich T-Strobe mit der Temperatur ändert, bei jedem Byte neu messen
            ;---------------------------------------------------------------------
TStrobe_time:
            out        TCNT0,null            ;8Bit Timer0, Zähler=0
            ldi        temp2,1<<CS01         ;Prescaler /8 vorbereiten
wdl:        sbic       PinC,tsic_dat         ;Auf TSIC, neg. Flanke warten
            rjmp       wdl
            out        TCCR0B,temp2          ;Timer Los
wpc:        sbis       PinC,tsic_dat         ;Warten, bis die Datenleitung wieder High
            rjmp       wpc
            out        TCCR0B,null           ;Timer Stop
            in         temp2,TCNT0           ;Zählerstand holen...
            out        OCR0A,temp2           ;und in das Timer Vergleichsreg. A schreiben
            ret
        ;-----------------------------------------------------------------
        ;Die oben gemessene Zeit abwarten
        ;-----------------------------------------------------------------
Wait_TStrobe:
            sbi        TIFR0,OCF0A           ;Vergleichsflag A löschen
            out        TCNT0,null            ;Zähler=0
            ldi        temp2,1<<CS01         ;Vorteiler /8 vorbereiten
wstr:       sbic       PinC,tsic_dat         ;Auf neg. Flanke warten
            rjmp       wstr
            out        TCCR0B,temp2          ;Timer Los
wt0:        sbis       TIFR0,OCF0A           ;Auf Match warten
            rjmp       wt0
            out        TCCR0B,null           ;Timer Stop
            ret

Im Beispiel oben sind die beiden Unterprogramme zum messen und abwarten der T-Strobe Zeit mit einem 8-Bit Timer dargestellt. Im kompletten Quellcode ist auch ein Beispiel in dem einfach Zyklen gezählt werden, für den Fall das der Timer für andere Zwecke gebraucht wird. Da mein Programm nur den Sensor ausliest und auf dem Display anzeigt, habe ich mich für das Auslesen über polling entschieden, vielleicht probier ich das irgendwann auch interruptgesteuert aus.

Das Parity Bit...

...dient der Erkennung von Übertragungsfehlern wie sie z.B. bei Verwendung von zu langen oder schlecht abgeschirmten Kabeln auftreten können. Bei den Tsic 206/306 Sensoren wird auf even (gerade) Parity geprüft. Dazu werden alle gesetzten Bits (die Einsen)  im Datenbyte gezählt und das  Paritybit  addiert. Das Ergebnis muss eine gerade Zahl sein, ansonsten ist  ein Übertragungsfehler aufgetreten. Im Bild oben wird die Binärzahl 0b11101010 übertragen. Die Quersumme ist 5 (dezimal), welche ja eine ungerade Zahl ist. Also ist in diesem Fall das Paritätsbit gesetzt.

Assembler Beispiel: Ein Byte lesen und Parity testen

;-----------------------------------------------------------------
;Datenbyte vom TSic lesen
;-----------------------------------------------------------------
TSIC_byte:
       clr     temp4              ;Parity
       ldi     temp3,1            ;Hier kommt das Datenbyte des TSIC rein   
       rcall   TStrobe_time       ;Wie lange ist PinC0 (Daten TSic) low ?
w_msb: lsl     temp3              ;Eine 0 ins DatenByte schieben
       rcall   Wait_TStrobe       ;TStrobe Zeit abwarten
       sbic    PinC,tsic_dat      ;Wenn Datenpin auf 0, die 0(lsl oben)stehen lassen      
       inc     temp3              ;Ansonsten Bit0 setzen
       sbrc    temp3,0            ;Wenn Bit0 auf 1...
       inc     temp4              ;...zum Paritybyte addieren
wh0:   sbis    pinc,tsic_dat      ;Auf High warten
       rjmp    wh0
       brcc    w_msb        ;Wenn die 1 (oben, ldi temp3,1)im Carry ist, sind wir fertig
       ;-----------------------------------------------------------------
       ;Paritätsbit holen und auf even prüfen
       ;Bei Even Parity, muss die Summe aller Bits + das Paritybit gerade sein
       ;-----------------------------------------------------------------   
       rcall   Wait_TStrobe       ;TStrobe Zeit abwarten
       sbic    pinc,tsic_dat
       inc     temp4              ;Wenn Paritybit=1, Temp4=Temp4+1
       sbrc    temp4,0            ;Zahl in Temp4 muss gerade (even Parity) sein
       sbr     flags,1<<par_err   ;sonst Übertragungsfehler
wh1:   sbis    pinc,tsic_dat      ;Auf High warten
       rjmp    wh1
       ret

Um den 11 Bit Temperaturwert zu erhalten muss TSIC_byte 2 mal hintereinander aufgerufen werden. Das im Datenblatt  erwähnte halbe Stopbit zwischen High- und Lowbyte, kann ignoriert werden, da dieses keine negative Flanke sendet sondern lediglich den Highpegel des Paritybit um etwa 62,5 µS verlängert.

Ein komplettes Datenpaket.

Zacwire

Im Beispiel oben wurde das Datenwort 0b01011011010 ($2DA) übertragen, welches nach Umrechnung 21,3°C ergibt.

Temperatur berechnen

Dafür steht als Formel im Datenblatt T= (Digital_signal/2047*(HT-LT)+LT) [°C].  Wobei HT 150 (das ist die Max. Temperatur) und LT -50 (Min.Temperatur) ist. Löst man die Klammer (HT-LT) auf, erhält man 200. Das +LT ersetzt man durch -50 und erhält T= (Digital_signal/2047*200-50) [°C]  wobei es in Assemler besser ist, zuerst zu multiplizieren und dann zu dividieren. Man kann auch schreiben T= (Digital_signal*200/2047-50) [°C].
Bei einer Division durch 2047 horcht der ASM-Programmierer auf.  Wen man statt 2047 als Divisor 2048 nehmen würde, hätte man eine  Potenz mit der Basis 2 und könnte die Division alleine durch Rechtsschieben lösen und dadurch eine Menge Code und Laufzeit sparen.  Der Fehler währe eigentlich zu Vernachlässigen (siehe Tabelle im Quelltext unten), trotzdem habe ich durch zufügen von 4 Befehlen  das Digital_signal so angepasst das es genau zu den Angaben (Tabelle) im  Datenblatt (Seite 3) passt.
Ein weiterer Vortei ist das man T= (Digital_signal*200/2048-50) /8 kürzen kann und erhält so T= (Digital_signal*25/256-50). Da mein Thermometer auch Zehntel Grad Anzeigen soll wird anstatt *25 mit 250 multipliziert und anstatt -50 wird 500 subtrahiert und erhält so die Temperatur*10. Der Dezimalpunkt wird dann einfach vor die letzte Stelle gesetzt und schon stimmt es wieder. Das ganze nennt sich Festkommaarithmetik. Infos hierzu z.B. bei Mikrocontroller.net oder Wikipedia

Meine Endgültige Formel für den TSic 206/306 lautet also T*10= (Digital_signal*250/256-500)

Assembler Beispiel:Temperaturwert berechnen 

Im Beispiel wurde TSic_Byte: 2 mal aufgerufen und der TSic-Rohwert  (Digital_signal) den Registern rawlow und rawhigh zugewiesen.

;***************************************************************************************
;    11Bit Rohwert des TSic in Temperatur umrechnen
;***************************************************************************************
calctemp:
;---------------------------------------------------------------------------------------
;Werte lt. Datenblatt
;$000=-50°, $199=-10°, $200=0°, $2ff=25°, $465=60°, $6fe=125°, $7ff=150°   
;---------------------------------------------------------------------------------------
;Wert   Formel-Datenbl.      Meine Formel ... nach Anpassung     Soll   
;---------------------------------------------------------------------------------------
;$199    |    -10,04        |    -10,06        |       -10,0    |     -10,0        
;$200    |      0,02        |      0,00        |         0,0    |       0,0       
;$2ff    |     24,94        |     24,90        |        25,0    |      25,0       
;$465    |     59,92        |     59,86        |        60,0    |      60,0       
;$6fe    |    124,89        |    124,80        |       125,0    |     125,0
;$7ff    |    150,00        |    149,90        |       150,1    |     150,0       
;---------------------------------------------------------------------------------------
;Zum testen der Werte, die Auskommentierung unten entfernen
;---------------------------------------------------------------------------------------
/*
        .equ    test = $2ff
        ldi    rawlow,low(test)
        ldi    rawhigh,high(test)
*/
;----------------------------------------------------------
;Tsic Rohwert dem Soll (Tab. oben) lt. Datenblatt anpassen
;---------------------------------------------------------
;Dazu die beiden höchsten Bits (Bit10 und 9) des TSIC auswerten
;Bei TSIC Wert $000..$1ff keine Änderung   
;Bei TSIC Wert $200..3ff TSIC Wert+1
;Bei TSIC Wert $400..5ff TSIC Wert+2
;Bei TSIC Wert $600..7ff TSIC Wert+3
;--------------------------------------------------------------
        sbrc    rawhigh,1
        adiw    rawlow:rawhigh,1        ;Wenn Bit9=1, Tsic+1
        sbrc    rawhigh,2
        adiw    rawlow:rawhigh,2        ;Wenn Bit10=1, Tsic+2
;---------------------------------------------------------------------------------------
;    11Bit Rohwert des TSic in Temperatur umrechnen
;    Originalformel aus dem Datenblatt T= (Digital_signal/2047*(HT-LT)+LT) [°C]
;    LT = -50,  HT = 150 als Standardwert für die Temperatur-Berechnung
;
;    Umgestellt für ASM
;    t=TSic_Wert*200 /2048-50   (die 2047 um 1 erhöht um besser rechnen zu können)
;    t=TSic_Wert*25/256-50  (gekürzt /8)
;    Da eine Stelle hinter dem Komma angezeigt wird, rechne ich die Temperatur*10 und 
;    setze vor die letzte Stelle den Dezimalpunkt (Festkomma).
;
;    Temperatur*10=(TSic_Wert*250)/256-500
;---------------------------------------------------------------------------------------
;temp3/2/1 enthält durch zufügen von Temp1 (0) den TSicwert * 256
        clr     temp1 
        mov     temp2,rawlow
        mov     temp3,rawhigh
        lsl     rawlow          ;*2
        rol     rawhigh
        add     rawlow,temp2    ;*3
        adc     rawhigh,temp3
        lsl     rawlow          ;*6
        rol     rawhigh
        sub     temp1,rawlow    ;*256 - *6 = *250
        sbc     temp2,rawhigh   ;TSic_Wert*250 steht jetzt in temp1/temp2/temp3
        sbci    temp3,0         ;Durch verwerfen des LSB (temp1) wird durch 256 geteilt   
        subi    temp2,low(500)  ;500 (50.0) abziehen
        sbci    temp3,high(500)
;Nun steht die Temperatur(*10) in temp2 (low) und temp3 (high)

Die Temperatur*10 steht nun als 16 Bitzahl zur Verfügung und muss nur noch in den 7-Segmentcode gewandelt werden. Ausserdem ist bei Temperaturen unter 0° das N-Flag durch die Subtraktion schon gesetzt.

Interruptprobleme

TstrobeDa die Siebensegmentanzeigen in einem Timerinterrupt gemultiplext werden, kann es vorkommen das die ISR genau dann aufgerufen wird wenn im Hauptprogramm  der Sensor ausgelesen wird und so das Timing durcheinander bringt. Den Interrupt während dem Auslesen des Sensors abzuschalten, hätte zur Folge das die Anzeige periodisch flackert. Das ist also keine Lösung.
 Am besten ist es die ISR so schnell zu durchlaufen, das die Laufzeit noch in das Zeitfenster des Zacwire-Protokoll passt. Da jedes Bit 125µS Dauert und das Tastverhältnis bei Logisch 0 bei 25% und bei Logisch 1 bei 75% liegt, lässt sich der optimale Auslesezeitpunkt der ja genau in der Mitte ( 50%) liegt nach rechts oder links verschieben (Im Bild die Strecke +/-31µS).

Theoretisch währe 31,2 µS die maximale Zeit, die man den TSic früher oder später ohne Fehler auslesen könnte.

ISR

Die Ziffern hinter dem Semikolon sind die Taktzyklen für den entsprechenden Befehl. Die Maximale ISR-Dauer ist knapp 2,4µS, da währe noch jede Menge Luft nach oben.

;****************************************************************************************
;Timerinterrrupt alle 1mS
;Da die ISR auch währed dem auslesen des TSIC auftritt, ist sie Geschwindigkeitsoptimiert.
;----------------------------------------------------------------------------------------
;Die Maximale ISR-Dauer sind knapp 2,4µS. Der mittlere T-Strobe Wert = 62,5 µS (s. Zackwire Datenblatt)
;T-Strobe würde bei einem Interrupt max. 65µS dauern, ist also noch im grünen Bereich.
;****************************************************************************************
;                                  ;4
ISR:in     s,sreg                  ;1
    dec    tick                    ;1     Jede mS runterzählen
;--------------------------------------------------------------------------------------
;Display Multiplexen. Bei3 Anzeigen *1mS sind das 3mS für einen Durchlauf.
;Die Muxfreq. ist 1/3mS = 333.3 Hz
;--------------------------------------------------------------------------------------
    sbic    PortD,PD5              ;1|2  War zuletzt die 3. Anzeige eingeschaltet,...                                         ;     ...1. Anzeige einschalten
    rjmp    _mux1                  ;2
    out     PortD,pnp1             ;1    PNP Stelle 1, Einschalten (PD7=0)
    out     PortB,seg0             ;1    Kathoden
    out     sreg,s                 ;1    Statusbits zurücklesen
    reti                           ;4    in der Main weitermachen
    ;15 = 1,875µS
_mux1:
    sbic    PortD,PD7              ;1|2  War Anz.1 an, Anz.2 einschalten
    rjmp    _mux2                  ;2
    out     PortD,pnp2             ;1    PNP  Einschalten (PD6=0)
    out     PortB,seg1             ;1    Kathoden
    out     sreg,s                 ;1    Statusbits zurücklesen
    reti                           ;4    in der Main weitermachen
    ;18 = 2,25µS
_mux2:
    out     PortD,pnp3             ;1    Kann nur noch Stelle 3 sein
    out     PortB,seg2             ;1
    out      sreg,s                ;1    Statusbits zurücklesen
    reti                           ;4    in der Main weitermachen
    ;19 = 2,375µS
;***************************************************************************************************************
;                                    --- ENDE ISR ---
;***************************************************************************************************************                                                       

Die Register pnp1..3 werden am Programmanfang initialisiert und enthalten die fertigen Bitmasken um den entsprechenden PNP-Transistor  in der ISR zu schalten. Diese Verschwendung ist Eigentlich nicht nötig, aber die Register werden bei diesem kleinen Programm eh nicht anderweitig benötigt. Die Register seg0..2 enthalten den Siebensegmentcode der Anzeige. Der Interrupt wird an 3 verschiedenen Stellen verlassen. Das spart den rjmp Befehl und somit etwas Zeit. 

Download

Der Hoffentlich gut genug kommentierte Assembler Quellcode für AVR-Studio 4.xx

und die brennfertige .hex für den AT Mega48.

Beim brennen des Megas, die Fuses auf internen 8 MHz Takt stellen.