Sie sind auf Seite 1von 37

;+----------------------------------------------------------------------------+ ;| ########################################################################## | ;| ## +------------------------------------------------------------------+ ## | ;| ## | H E A T C O U N T E R | ## | ;| ## +------------------------------------------------------------------+ ## | ;| ########################################################################## | ;|----------------------------------------------------------------------------| ;| Dieses Programm mit die Vorlauf- u.

R cklauftemperatur | ;| und den Volumenstrom eines Heizungssystems und berechnet daraus | ;| die W rmemenge, W rmeleistung, Volumen | ;|----------------------------------------------------------------------------| $TITLE (Diplomarbeit: ELEKTRONISCHER WAERMEMENGENMESSER) $SUBTITLE (Autor: Markus Stark WS94/95 FHC) ; ; ; ************************************************************* * CONSTANTS * ************************************************************* EQU 31H ;wenn W rmez hler seine Nummer ber ser. Schni ;er seine Daten zur ck (1200 baud, 8, 1, n o Parity) MAX_FLOW $EJECT ; ; ; EQU 255 ;max. 255l/min=15300l/h Durchflu

WAERME_ZAEHLER_NUMMER ttstelle erkennt, sendet

************************************************************* * DATA * ************************************************************* ;Bitsegment enth lt Flags zum Programmablauf

BSEG AT 0 (int. RAM ab 20H)

FLAG_MEASURE_AND_CALCULATE: DBIT 1 ;H -> Temperatur messen FLAG_CONVERGENCE DBIT 1 ;H -> bei Berechnungen f llt immer Nachkommat eil weg -> ;bei jeder 2. Ber. muss 1 in LSB-Stelle add iert werden, damit ;Berechnungsfehler statistisch gesehen gege n Null konvergiert FLAG_DISPLAY_WAERME: DBIT 1 ;H -> Waermemenge anzeigen FLAG_DISPLAY_VORLAUF_TEMP: DBIT 1 ;H -> Vorlauftemperatur anzeigen FLAG_DISPLAY_RUECKLAUF_TEMP: DBIT 1 ;usw. FLAG_DISPLAY_TEMP_DIFFERENZ: DBIT 1 ; FLAG_DISPLAY_VOLUMEN: DBIT 1 ; FLAG_DISPLAY_WAERMELEISTUNG: DBIT 1 ; FLAG_DISPLAY_OFF: DBIT 1 ;H -> nach 1 Minute Display abschalten (Ene rgiespar-Mode) FLAG_VOL_ERROR: DBIT 1 ;H -> berlauf des Volumenz hlers (unwahrschein lich) FLAG_TEMP_ERROR: DBIT 1 ;H -> Temperatursensoren defekt (z.B. Kabel bruch) oder manipuliert FLAG_DATA_ERROR: DBIT 1 ;H -> Daten sind inkonsistent FLAG_SAVE_DATA: DBIT 1 ;H -> berechnete Werte im EEPROM ablegen $EJECT

DSEG AT 23H SEC_COUNTER t MIN_COUNTER COUNTER wendet DS DS DS 1 1 1 ;!! Datensegment 20H .. 22H sind f r FLAGS reservier ;Datensegment von 26H bis einschl. 2AH ;wird zur Tastenentprellung und Display_ON/OFF ver

DSEG AT 2CH VOL_COUNTER EEH EEL ADR_EE DS DS DS DS 1 1 1 1 ;enth lt Volumen/min ;EEH und EEL sind bergabe- bzw. R ckgaberegister ;der Subroutinen zur Ansteuerung eines I2C-EEPROMs ;ADR_EE ist I2C-EEPROM-ADRESSE

DSEG AT 30H WAERME: VOLUMEN: VORLAUF_TEMP: RUECKLAUF_TEMP: TEMP_DIFFERENZ: WAERMELEISTUNG: $EJECT ; ; ; DS DS DS DS DS DS 6 6 4 4 4 4 ;6 Byte ;(LSBCD ;(LSBCD ;(LSBCD ;(LSBCD ;(LSBCD entspricht 12 BCD-Stellen (LSBCD = 1kJ) = 1 Liter) = 0.01 C) = 0.01 C) = 0.01 Kelvin) = 1 W)

************************************************************* * CODE * ************************************************************* INT_0 TIMER_0 INT_1 TIMER_1 SER_INT CODE CODE CODE CODE CODE 03H 0BH 13H 1BH 23H ;Interrupteinsprungadressen

CSEG AT RESET LJMP PROGRAM_START CSEG AT INT_0 LJMP INT0_VECTOR CSEG AT TIMER_0 LJMP TIMER0_VECTOR CSEG AT INT_1 LJMP INT1_VECTOR CSEG AT TIMER_1 LJMP TIMER1_VECTOR CSEG AT SER_INT LJMP SER_INT_VECTOR $EJECT ;**************************************************************************** ;* R E S E T * ;* * ;* wird nach Netzausfall (Vcc aus) und bei Systemstart (Vcc ein) ausgel st *

;* -> das Programm muss so aufgebaut sein, das ein Netzausfall zu einem * ;* beliebigen Zeitpunkt, die Funktion des Programmes nicht beeintr chtigt. * ;* ->nach der Initialisierungsphase der Hardware (INIT_HARDWARE) und des * ;* LCD-Moduls (INIT_DISPLAY) m ssen die gesicherten Me- u. Statusdaten aus* ;* dem EEPROM ins interne RAM des Mikrocontollers transferiert werden und * ;* auf Datenkonsistenz (z.B. mit Checksum) berpr ft werden. Da die Daten * ;* alle Stunde ins EEPROM gesichert werden, entsteht nur ein vernach* ;* l ssigbarer Mefehler (s. KAP 4.1.6). * ;* Nachdem die Daten f r OK befunden wurden ,wird der Prozessor in den * ;* IDLE-Mode (Energiespar-Mode) versetzt, den er nur durch einen Interrupt * ;* verlassen kann. Nach Beendigung eines Interrupts wird Prozessor wieder * ;* IDLE-Mode versetzt (Endlosschleife) * ;*--------------------------------------------------------------------------* ;* Parameter: -* ;* Flags: -* ;* Max.-Stack: -* ;**************************************************************************** PROGRAM_START: CALL INIT_HARDWARE CALL INIT_DISPLAY MOV CALL MOV MOV MOV DJNZ DJNZ DJNZ MOV CALL CALL DPTR,#START_2_TEXT DISPLAY_TEXT R1,#05H R2,#0FFH ;bei 1.843MHz ca. 5sec Verz gerung R3,#0FFH R3,$ R2,R_1 R1,R_2 DPTR,#START_1_TEXT DISPLAY_TEXT READ_DATA

R_2: R_1:

MAINLOOP: NOP NOP NOP SETB SCL sparen SETB SDA setzt) CLR CHARGE_C ORL PCON,#00000001B ;IDLE-Mode aktivieren (Emergie-Spar-Modu s) wird durch freigegebene Interrupts beendet ORL PCON,#00100000B ; SJMP MAINLOOP ;hier k nnen sonstige timerunabh ngige Tasks eingef gt werden, die nicht in den Interrupts erledigt werden $EJECT ;**************************************************************************** ;* E x t e r n e r I n t e r r u p t 0 * ;* * ;* Ext. Interrupt 0 wird durch neg. Flanke vom Durchflussz hler ausgel st * ;* Durchflussz hler gibt z.B. pro Liter Volumen einen Impuls aus (s. Daten-* ;* blatt Durchflussz hler) * ;* VOL_COUNTER-Register wird um eins erh ht. Dieses Register wird alle * ;* Minute ausgelesen und enth lt somit zu diesem Zeitpunkt den Volumen* ;P1.5 (Display_off wird im Timer0-Int ge ;Port-Bits werden gesetzt, um Energie zu

;* strom in Liter/Minute. * ;*--------------------------------------------------------------------------* ;* Parameter: >/VOL_COUNTER/>. * ;* Max.-Stack: 1 * ;**************************************************************************** INT0_VECTOR: PUSH ACC MOV A,#MAX_FLOW mes=255 Liter/Minute CJNE A,VOL_COUNTER,INT0_INC e gemessen werden, wird SJMP INT0_END INT0_INC: INC VOL_COUNTER INT0_END: POP ACC zt, d.h. enth lt Volumen/min RETI igkeit (z.B. 5 l/Imp.) t werden -> ;MOV A, #IMPULSWERTIGKEIT_VOLUMENZ HLER ;ADD A, VOL_COUNTER ;MOV VOL_COUNTER, A $EJECT ;**************************************************************************** ;* T i m e r 0 I n t e r r u p t * ;* * ;* Int. Zeitreferenz (wird alle 0.4 Sekunden bei einer Quarzfrequenz von * ;* 1.843 MHz aufgerufen) und steuert zeitabh ngige TASKS (z.B.: * ;* DISPLAY_OFF, ruft pro Minute Mess-u.Berechnungroutinen auf ; pro Stunde * ;* werden Daten einmal ins EEPROM abgelegt ...) * ;*--------------------------------------------------------------------------* ;* Parameter: >/SEC_COUNTER/, /MIN_COUNTER/, /VOL_COUNTER/>, /COUNTER/> * ;* Flags: >/MEASURE_AND_CALCULATE/, /SAVE_DATA/, /DISPLAY_OFF/> * ;* Max.-Stack: -* ;**************************************************************************** TIMER0_VECTOR: PUSH ACC CLR TR0 MOV TH0,#HIGH(-61428) ;Reload-Wert (muss ebenfal ls im Timer0-Interrupt ins TH0/TL0-Register geschrieben werden MOV TL0,#LOW(-61428) ;bei fosz=11.059MHz/6 soll alle 0.4 Sekunden ein Interrupt ausgel st und die Zeitregister gesettz werden SETB TR0 ;->Reload-Wert=2^16-Interr uptintervall/Periodendauer (es muss aber noch die Zeit abgezogen werden, (schon erledigt ung. 9 Maschinenzyklen) ;um im Interruptprogramm d en Timer zu stoppen/reloaden/starten !!!! ;ab hier Zeitregister und Flags zur Programmsteuerung setzen INC SEC_COUNTER ;wird alle 0.4 Sekunden be i fosz=1.84MHz erh ht MOV A,#150D ;Z hlerstand von 150 entspri cht 1 Minute CJNE A,SEC_COUNTER,T0_ utenz hler inkrementieren ;falls 1 Minute vorbei Min

;absolute maximum rating des Volumenstro ;falls mehr als 255 Volumenimpulse/Minut ;nicht mehr inkrementiert ;wird alle Minute ausgelesen und r ckgeset ;bei Volumenz hlern mit anderer Impulswert ;m te das Volumen_Counter_register um 5 erh h

MOV SEC_COUNTER,#00H INC MIN_COUNTER SETB FLAG_MEASURE_AND_CALCULATE MOV A,#60D sen und Berechnung starten CJNE A,MIN_COUNTER,T0_ ndenz hler inkrementieren SETB FLAG_SAVE_DATA OM sichern MOV MIN_COUNTER,#00H ;pro Minute Temperatur mes ;falls 1 Stunde vorbei Stu ;pro Stunde Daten ins EEPR

T0_: JNB FLAG_MEASURE_AND_CALCULATE,T0_INT_0 ;FLAG_MEASURE_AND_CALCULAT E wird gesetzt, falls 1 Minute vorbei ist CALL MEASURE_AND_CALCULATE ;damit Routine Measure... nicht sofoert wieder beim n chsten T0_Interrupt aufgerufen wird CLR FLAG_MEASURE_AND_CALCULATE ;Flag muss nachdem es gese tzt wurde, sofort wieder r ckgesetzt werden, T0_INT_0: JNB FLAG_SAVE_DATA,T0_INT_1 _AND_CALCULATE CALL SAVE_DATA CLR FLAG_SAVE_DATA T0_INT_1: JNB FLAG_DISPLAY_OFF,T0_INT_2 INC COUNTER MOV A,#1D CJNE A,COUNTER,T0_INT_4 CLR IE1 SETB EX1 T0_INT_4: MOV A,#150D CJNE A,COUNTER,T0_END orbei ->springen CALL DISPLAY_OFF SETB FLAG_DISPLAY_WAERME ltet wurde, wird beim erneuten Einschalten MOV COUNTER,#00H T0_INT_2: JNB MOV SETB CALL T0_INT_3: JNB MOV SETB CALL T0_END: FLAG_TEMP_ERROR,T0_INT_3 DPTR,#TEMP_SENSOR_FEHLERTEXT TI SEND_STRING FLAG_VOL_ERROR,T0_END DPTR,#VOL_ZAEHLER_FEHLERTEXT TI SEND_STRING ;wie oben bei FLAG_MEASURE

;150*0.4 Sek = 1 Minute ;Tastenentprellung ;falls noch keine Minute v ;nachdem Display ausgescha ;immer W rmemenge angezeigt

; bertragung starten

; bertragung starten

POP ACC RETI

$EJECT ;**************************************************************************** ;* E x t e r n e r I n t e r r u p t 1 * ;* * ;* wird durch Tastenbet tigung ausgel st * ;* Beim ersten Tastendruck wird W rmemenge angezeigt, beim n chsten Vor- * ;* lauftemperatur usw. Beim siebten Tastendruck wird wieder W rmemenge an- * ;* gezeigt. *

;* COUNTER-Register wird r ckgesetzt (wird im Timer1-Interrupt alle 0.4 s * ;* inkrementiert und abgefragt ob eine minute vorbei ist, dann wird das * ;* Display automatisch ausgeschaltet). * ;*--------------------------------------------------------------------------* ;* Parameter: >/COUNTER/> * ;* Flags: >/DISPLAY_OFF/, /DISPLAY_WAERME/, ...> * ;* Max.-Stack: -* ;**************************************************************************** INT1_VECTOR: CLR rellung) CALL INT1_9: PUSH PUSH PUSH JBC JBC JBC JBC JBC JBC INT1_0: gt EX1 DISPLAY_ON 01H 06H 07H FLAG_DISPLAY_WAERME, INT1_0 FLAG_DISPLAY_VORLAUF_TEMP, INT1_1 FLAG_DISPLAY_RUECKLAUF_TEMP,INT1_2 FLAG_DISPLAY_TEMP_DIFFERENZ,INT1_3 FLAG_DISPLAY_VOLUMEN, INT1_4 FLAG_DISPLAY_WAERMELEISTUNG,INT1_5 ;wird beim n chsten Tastendruck angezei ;ext. Interrupt 1 sperren (Tastenentp

SETB FLAG_DISPLAY_VORLAUF_TEMP MOV CALL MOV MOV MOV CALL JMP DPTR,#WAERME_TEXT DISPLAY_TEXT R1,#WAERME R6,#6 R7,#6 DISPLAY_NUMBER INT1_END FLAG_DISPLAY_RUECKLAUF_TEMP DPTR,#VORLAUF_TEMP_TEXT DISPLAY_TEXT R1,#VORLAUF_TEMP R6,#4 R7,#3 DISPLAY_NUMBER INT1_END FLAG_DISPLAY_TEMP_DIFFERENZ DPTR,#RUECKLAUF_TEMP_TEXT DISPLAY_TEXT R1,#RUECKLAUF_TEMP R6,#4 R7,#3 DISPLAY_NUMBER INT1_END FLAG_DISPLAY_VOLUMEN DPTR,#TEMP_DIFFERENZ_TEXT DISPLAY_TEXT R1,#TEMP_DIFFERENZ R6,#4 R7,#3 DISPLAY_NUMBER INT1_END

;Zeiger auf W rmewert richten ;Kommastelle von MSBCD aus gez hlt ;6 Byte (=12 BCD-Stellen)

INT1_1:

SETB MOV CALL MOV MOV MOV CALL JMP SETB MOV CALL MOV MOV MOV CALL JMP SETB MOV CALL MOV MOV MOV CALL JMP

INT1_2:

INT1_3:

INT1_4:

SETB MOV CALL MOV MOV MOV CALL JMP SETB MOV CALL MOV MOV MOV CALL JMP

FLAG_DISPLAY_WAERMELEISTUNG DPTR,#VOLUMEN_TEXT DISPLAY_TEXT R1,#VOLUMEN R6,#9 R7,#6 DISPLAY_NUMBER INT1_END FLAG_DISPLAY_WAERME DPTR,#WAERMELEISTUNG_TEXT DISPLAY_TEXT R1,#WAERMELEISTUNG R6,#5 R7,#4 DISPLAY_NUMBER INT1_END ;immer wenn eine Taste bet tigt wird, wird d ;(wen es nicht schon eingeschaltet war) un

INT1_5:

INT1_END: MOV COUNTER,#00H as Display eingeschaltet d es wird daf r gesorgt, da

;Display maximal eine Minute eingeschaltet bleibt -> Counter clearen SETB FLAG_DISPLAY_OFF geschaltet POP 07H POP 06H POP 01H CLR IE1 l schen RETI $EJECT ;**************************************************************************** ;* T i m e r 1 I n t e r r u p t * ;* * ;* wird durch Fehler bei Zeitkonstantenmessung ( berlauf von Timer 1) * ;* ausgel st, z.B. Kabelbruch oder Manipulation an den Temperatursensoren) * ;*--------------------------------------------------------------------------* ;* Parameter: -* ;* Flags: >/TEMP_ERROR/> * ;* Max.-Stack: -* ;**************************************************************************** TIMER1_VECTOR: PUSH 07H SETB FLAG_TEMP_ERROR ;wird in SAVE abgefragt und ins EPROM ge speichert mit Datum MOV DPTR,#TEMP_SENSOR_FEHLERTEXT CALL DISPLAY_TEXT SETB DISCHARGE_COMP ;Kondensator wird zwangsentladen, damit Endlosschleife in POP 07H RETI ;Routine MEASURE_AND_CALCULATE verlassen werden kann ;nach 1 Min wird Display in Stromsparmode

;Taste prellt -> Interrupt-Anforderungsbit

$EJECT ;**************************************************************************** ;* S e r i e l l e r I n t e r r u p t * ;* * ;* wird durch Fernabfrage der Daten ausgel st * ;*--------------------------------------------------------------------------* ;* Parameter: -* ;* Flags: -* ;* Max.-Stack: -* ;**************************************************************************** SER_INT_VECTOR: JB RI,SER_R_1 SJMP SER_R_2 SER_R_1: JMP SER_RECEIVE SER_R_2: JB TI,SER_AUS_1 SER_AUS_1:JMP SER_AUS SER_TRANSMIT: CALL DISPLAY_ON geben MOV COUNTER,#00H MOV DPTR,#FERNABFRAGE_TEXT CALL DISPLAY_TEXT SETB TI MOV DPTR,#WAERME_SENDETEXT CALL SEND_STRING MOV MOV MOV CALL R1,#WAERME R6,#6 R7,#6 SEND_NUMBER ; Sprung, falls Empf nger Interrupt

;Meldung 'Fernabfrage der Medaten' aus

; bertragung starten ;Text 'W rmemenge' ausgeben ; ; ; ; Zeiger auf W rmewert richten Kommastelle von MSBCD aus gez hlt 6 Byte (=12 BCD-Stellen) W rmemenge ausgeben

MOV DPTR,#WAERME_EINHEIT CALL SEND_STRING MOV DPTR,#VOLUMEN_SENDETEXT CALL SEND_STRING MOV MOV MOV CALL R1,#VOLUMEN R6,#9 R7,#6 SEND_NUMBER

;Text 'GJ' ausgeben ;Text 'Volumen' ausgeben ; ; ; ; Zeiger auf Volumenwert richten Kommastelle von MSBCD aus gez hlt 6 Byte (=12 BCD-Stellen) Volumen ausgeben ;Text 'm' ausgeben

MOV DPTR,#VOLUMEN_EINHEIT CALL SEND_STRING MOV DPTR,#VORLAUF_TEMP_SENDETEXT CALL SEND_STRING MOV MOV MOV CALL R1,#VORLAUF_TEMP R6,#4 R7,#3 SEND_NUMBER

MOV DPTR,#TEMPERATUR_EINHEIT CALL SEND_STRING

MOV DPTR,#RUECKLAUF_TEMP_SENDETEXT CALL SEND_STRING MOV MOV MOV CALL R1,#RUECKLAUF_TEMP R6,#4 R7,#3 SEND_NUMBER

MOV DPTR,#TEMPERATUR_EINHEIT CALL SEND_STRING MOV DPTR,#WAERMELEISTUNG_SENDETEXT CALL SEND_STRING MOV MOV MOV CALL R1,#WAERMELEISTUNG R6,#5 R7,#4 SEND_NUMBER

MOV DPTR,#WAERMELEISTUNG_EINHEIT CALL SEND_STRING JMP SER_AUS SER_RECEIVE: MOV A,SBUF ; Empfangenes Zeichen in Akku laden CLR RI ; Empf nger-Flag l schen CJNE A,#WAERME_ZAEHLER_NUMMER,SER_AUS ; Nummer des W rmemengenmessers JMP SER_TRANSMIT CLR TI SER_AUS: RETI

$EJECT ;**************************************************************************** ;* I N I T _ H A R D W A R E * ;* * ;* setzt Ein- u. Ausg nge, Timer, SCL, SDA * ;*--------------------------------------------------------------------------* ;* Parameter: -* ;* Flags: -* ;* Max.-Stack: 0 * ;**************************************************************************** INIT_HARDWARE: ;int. RAM l schen von 20H .. 7FH MOV R1,#20H I_H_1: MOV @R1,#00H ;int. RAM l schen ,damit nicht mit falschen Werten INC R1 ;weitergerechnet wird CJNE R1,#80H,I_H_1 ;Hardware initialisieren CLR DISCHARGE_COMP CLR DISCHARGE_TEMP_1 CLR DISCHARGE_TEMP_2 CLR KEY_DRIVELINE es kann ein Interrupt durch CLR CHARGE_C ssung kann Taste keinen Int. ausl sen ;Fets ausschalten ; " ; " ;Taste aktivieren (Driveline L setzen -> ;Taste ausgel st werden) nur w hrend Temp.me

SETB COMPARATOR ort-FlipFlop CLR P1.5 ;EEPROM initialisieren SETB SCL SETB SDA CLR SDA NOP NOP NOP NOP SETB SDA MOV ADR_EE,#0

;wird als Eingang verwendet -> 'H' ins P

;Stopbit erzeugen ;NOPs sind nur bei 12MHz-Takt n tig

;EEPROM AB ADR. 00H BELEGEN

;Zeitregister init. MOV SEC_COUNTER,#00H ;Sekundenz hler l schen MOV MIN_COUNTER,#00H ;Minutenz hler l schen MOV COUNTER,#00H ;universelles Zeitregister (wird benutzt um z.B. Display max. 1 Minute aktiv sein zu lassen) ;Timer0 als interne Zeitreferenz initialisieren ANL TMOD,#0F0H ;alle Timer0-Modebits l schen ORL TMOD,#01H ;Timer0: 16-Bit Timer MOV TH0,#HIGH(-61438) ;Reload-Wert (muss ebenfalls im Timer0-I nterrupt ins TH0/TL0-Register geschrieben werden MOV TL0,#LOW(-61438) ;bei fosz=11.059MHz/6 soll alle 0.4 Seku nden ein Interrupt ausgel st und die Zeitregister gesetzt werden CLR TF0 SETB TR0 ;->Reload-Wert=2^16-Interruptintervall/P eriodendauer (es muss aber noch die Zeit abgezogen werden, ;um im Interruptprogramm den Timer zu st oppen/reloaden/starten !!!! ;Timer1 f r ser. Int initialisieren (wird w hrend Temperaturmessung zur Pe riodendauermessung mibraucht) ANL TMOD,#0FH ;alle Timer1-Modebits l schen ORL TMOD,#20H ;Timer1: Auto-Reload Mode MOV TH1,#-4 ;Baudrate=fosz/(32*12*(256-TH1)) -> CLR TF1 ;fosz=11.059MHz/6 und Baudrate=1200 -> T H1=252=-4 SETB TR1 ;Start Timer 1 MOV SCON,#01010000B ;UART Mode 1, Empf nger freigeben ;Externen Interrupt 0 initialisieren SETB IT0 ;Triggerung des ext. Interrupts 0 durch 1->0 Flanke ;Externen Interrupt 1 initialisieren SETB IT1 ;Triggerung des ext. Interrupts 1 durch 1->0 Flanke ;Interrupts freigeben und Priorit t festlegen SETB EX0 ;alle Interrupts bis auf Timer1-Interrup t freigeben SETB EX1 ;(wird nur w hrend Temperaturmessung ben tig t) SETB ET0 SETB ES SETB EA

;SETB PT1 ;Timer1 hat h here Priorit t (damit T0-Int von T1-Int im Subroutine Mess.. unterbrochen werden kann) CLR PT1 RET $EJECT ;**************************************************************************** ;* S A V E _ D A T A * ;* * ;* legt Datenblock im internen RAM des Mikrocontrollers ab DATA_BLOCK_START* ;* mit DATA_BLOCK_LENGTH im I2C-EEPROM ab ADR_EE (Adresse des Bytes im * ;* EEPROM; Wertebereich 0..255) * ;* Aus den Daten wird eine Pr fsumme gebildet und ebenfalls im EEPROM ge- * ;* sichert um bertragungsfehler feststellen zu k nnen * ;*--------------------------------------------------------------------------* ;* Parameter: >/DATA_BLOCK_START/, /DATA_BLOCK_LENGTH/, /WRITE/, /READ/ * ;* /ADR_EE/> * ;* Flags: -* ;* Max.-Stack: 8 * ;**************************************************************************** DATA_BLOCK_START EQU WAERME DATA_BLOCK_LENGTH EQU 12 Volumen) WRITE EQU 0A0H re: A2..A0 = L) READ EQU 0A1H CSEG SDA SCL SAVE_DATA: PUSH PUSH PUSH MOV MOV (30H) S_D_1: MOV INC MOV INC CALL ACC 01H 03H ADR_EE,#0D ;Zieladresse 0 im EEPROM R1,#DATA_BLOCK_START ;Zeiger auf Datenblockanfang im internen RAM EEH,@R1 R1 EEL,@R1 R1 E_WRITE BIT P1.6 BIT P1.7 ; ;Datenblock ist 12 Byte lang (je 6 Byte f r W rme und ;Slave Address zum Beschreiben des EEPROMs (Hardwa ;Slave Address zum Lesen des EEPROMs

;abspeichern

INC ADR_EE INC ADR_EE MOV R4,#70D ;bei 1.843MHz ca. 25msec Verz gerung um n chstes Datum abspeichern zu S_D_3: MOV R5,#32D ;k nnen (Delaytime liegt zw. 5..25 ms) DJNZ R5,$ DJNZ R4,S_D_3 CJNE R1,#(DATA_BLOCK_START+DATA_BLOCK_LENGTH),S_D_1 ;Checksum berechnen und am Ende des Datenblocks schreiben CLR A

S_D_2:

MOV MOV ADD INC CJNE CPL

R1,#DATA_BLOCK_START 03H,@R1 A,R3 R1 R1,#(DATA_BLOCK_START+DATA_BLOCK_LENGTH),S_D_2 A EEH,A EEL,A E_WRITE 03H 01H ACC ;complementierte Checksum am Datenblockende doppel ;Checksum wurde komplementiert, damit z.B. bei lee ;Datenblock nicht als o.K. erkannt wird

MOV t abspeichern MOV ren EEPROM CALL POP POP POP RET

$EJECT ;**************************************************************************** ;* R E A D _ D A T A * ;* * ;* liest Datenblock aus EEPROM ab ADR_EE (Adresse des Bytes im EEPROM; * ;* Wertebereich: 0..255) im internen RAM des Mikrocontrollers ab * ;* DATA_BLOCK_START mit DATA_BLOCK_LENGTH ein. Von den eingelesen Daten * ;* wird eine Pr fsumme gebildet und mit der gesicherten Pr fsumme ver* ;* glichen. Falls verschieden, wird FLAG_DATA_ERROR gesetzt. * ;*--------------------------------------------------------------------------* ;* Parameter: >/DATA_BLOCK_START/, /DATA_BLOCK_LENGTH/, /WRITE/, /READ/ * ;* /ADR_EE/> * ;* Flags: >/DATA_ERROR/> * ;* Max.-Stack: 8 * ;**************************************************************************** READ_DATA:PUSH ACC PUSH 01H PUSH 03H MOV ADR_EE,#0D MOV R1,#DATA_BLOCK_START ;Anfang des Datenblockes im int. RAM, wo als o gelesene Daten abgelegt werden sollen R_D_1: CALL E_READ MOV @R1,EEH INC R1 MOV @R1,EEL INC R1 INC ADR_EE INC ADR_EE CJNE R1,#(DATA_BLOCK_START+DATA_BLOCK_LENGTH),R_D_1 ;Ende des Datenbl ockes erreicht CALL E_READ ;in EEH/EEL sollte jetzt compl. Checksum aus EEPRO M stehen CLR um vergleichen MOV R_D_2: MOV ADD INC CJNE A ;Checksum nochmals berechnen und mit EEPROM-Checks

R1,#DATA_BLOCK_START 03H,@R1 A,R3 R1 R1,#(DATA_BLOCK_START+DATA_BLOCK_LENGTH),R_D_2

CPL A CJNE SJMP CJNE CLR SJMP SETB MOV MOV INC CJNE A,EEH,R_D_3 ;pr fen, ob Checksummen gleich R_D_4 A,EEL,R_D_5 ;Flag, mu sp ter abgefragt werden FLAG_DATA_ERROR R_D_7 FLAG_DATA_ERROR R1,#DATA_BLOCK_START ;Daten ung ltig oder Neustart -> @R1,#00H ;int. RAM l schen ,damit nicht mit falschen Werten R1 ;weitergerechnet wird R1,#(DATA_BLOCK_START+DATA_BLOCK_LENGTH+2),R_D_6

R_D_3: R_D_4: R_D_5: R_D_6:

R_D_7:

POP 03H POP 01H POP ACC RET

$EJECT ;**************************************************************************** ;* SUBROUTINEN ZUR I2C-EEPROM-ANSTEUERUNG (f r 12 MHz Taktfrequenz * ;* ausgelegt (daher die vielen NOPs) * ;* Bei einer Taktfrequenz von 1.8432 Mhz k nnen die NOPs weggelassen werden* ;**************************************************************************** S_OUT: S_OU1: PUSH MOV RLC MOV SETB NOP CLR DJNZ NOP NOP SETB SETB NOP CLR POP RET PUSH MOV SETB SETB MOV RLC CLR DJNZ POP RET 02 R2, #8 A SDA,C SCL SCL R2,S_OU1 SDA SCL SCL 02 02 R2,#8 SDA SCL C, SDA A SCL R2, S_I1 02 ; ACK holen

S_IN: S_I1:

;Unterprogramm: E_READ (EEPROM LESEN) ;Eingabe: ADR_EE ;Ausgabe: EEH,EEL ;veraenderte Register: AKKU,EEH,EEL

E_READ:

CLR NOP NOP CLR MOV CALL MOV CALL SETB NOP NOP SETB NOP NOP CLR NOP NOP CLR MOV CALL CALL CLR NOP NOP SETB NOP CLR MOV CALL MOV SETB NOP NOP SETB NOP CLR

SDA SCL A, #WRITE S_OUT A, ADR_EE S_OUT SDA SCL SDA SCL A, #READ S_OUT S_IN SDA SCL SCL EEH, A S_IN EEL, A SDA SCL SCL ; Stopbit ausgeben ; Startbit erzeugen ; ; Lesebefehl schreiben ; erstes Byte einlesen

;Schreiben Adresse vorbereiten ;Adresse schreiben

; ACK ausgeben

; zweites Byte einlesen

; kein ACK ausgeben

CLR SDA SETB SCL NOP NOP SETB SDA RET

;Unterprogramm: E_WRITE (EEPROM BESCHREIBEN) ;Eingabe: ADR_EE, EEH, EEL ;Ausgabe: AKKU ;veraenderte Register: AKKU E_WRITE: CLR CLR MOV CALL MOV CALL MOV CALL MOV CALL CLR SDA SCL A, #WRITE S_OUT A,ADR_EE S_OUT A, EEH S_OUT A,EEL S_OUT SDA ; Startbedingung ; Schreibbefehl ausgeben ; WORD ADDRESS ; High-Byte schreiben ; Low-Byte schreiben

NOP NOP SETB SCL NOP NOP SETB SDA RET

; Stop-Bedingung erzeugen

$EJECT ;**************************************************************************** ;* S E N D _ N U M B E R * ;* * ;* gibt Datenblock ber serielle Schnittstelle aus * ;* R1 muss Zeiger auf Datenblockanfang enthalten (z.B.: 30H f r WAERME) * ;* R7 enth lt die Byteanzahl die gesendet werden soll; R6 legt bei num. * ;* Ausgabe die Kommastelle der Zahl fest. * ;*--------------------------------------------------------------------------* ;* Parameter: >/R1/, /R6/, /R7> * ;* Flags: >/NO_LEADING_ZERO/> * ;* Max.-Stack: 5 * ;**************************************************************************** SEND_NUMBER: CLR MOV ADD MOV SD_1: BCD) ANL A,#11110000B SWAP A CJNE A,#00H,SD_4 esetzt, JB FLAG_NO_LEADING_ZERO,SD_4 MOV A,#20H ;dann diese Null nicht angezeigen, da sie vor der SJMP SD_5 ;ersten g ltigen Ziffer steht SD_4: SETB FLAG_NO_LEADING_ZERO ;dieses Bit wird gesetzt, sobald erstes von Null versch. Zeichen ;erkannt wird und sorgt daf , das kommende Nullen al s Ziffer ausgegeben werden ADD A,#30H ;BCD-Code in ASCII-Code wandeln SD_5: CALL SER_OUT ;Zahl ausgeben DJNZ R6,SD_2 MOV A,#2EH CALL SER_OUT SD_2: SD_8: ;Kommastelle erreicht ->J, dann Komma ausgeben ;ASCII-Code des Kommas (bzw. Punktes) ;h herwertiges BCD ausmaskieren ;falls gleich und Flag 'keine f hrende Null' nicht g FLAG_NO_LEADING_ZERO A,R7 ;Zeiger auf MSBCD+1 richten A,R1 R1,A ;R1 enth lt Adresse der zwei BCD-Zahlen (1 Byte = 2

DEC R1 MOV A,@R1

CJNE R6,#01,SD_8 ;erstes Zeichen vor dem Komma erreicht SETB FLAG_NO_LEADING_ZERO MOV A,@R1 ANL A,#00001111B CJNE A,#00H,SD_6 ;niederwertiges BCD ausmaskieren ;falls gleich und Flag 'keine f hrende Null' nicht g

esetzt,

JB FLAG_NO_LEADING_ZERO,SD_6 MOV A,#20H ;dann diese Null nicht angezeigen, da sie vor der SJMP SD_7 ;ersten g ltigen Ziffer steht SD_6: SETB FLAG_NO_LEADING_ZERO ;dieses Bit wird gesetzt, sobald erstes von Null versch. Zeichen ;erkannt wird und sorgt daf , das kommende Nullen al s Ziffer ausgegeben werden ADD A,#30H ;BCD-Code in ASCII-Code wandeln SD_7: CALL SER_OUT DJNZ R6,SD_3 MOV A,#2EH CALL SER_OUT SD_3: SD_9: ;Kommastelle erreicht ->J, dann Komma ausgeben ;ASCII-Code des Kommas (bzw. Punktes)

CJNE R6,#01,SD_9 ;erstes Zeichen vor dem Komma erreicht SETB FLAG_NO_LEADING_ZERO DJNZ R7,SD_1 RET

;**************************************************************************** ;* S E N D _ S T R I N G * ;* * ;* gibt Textstring ,dessen Ende mit 00H markiert sein mu ber serielle * ;* Schnittstelle aus. Anfangsadresse ddes Strings mu zuvor in DPTR ge* ;* schrieben werden * ;*--------------------------------------------------------------------------* ;* Parameter: >/DPTR/ * ;* Flags: -* ;* Max.-Stack: 2 * ;**************************************************************************** SEND_STRING: CLR MOVC JZ CALL INC SJMP STRING_END: RET SER_OUT: JNB TI,$ MOV SBUF,A CLR TI RET $EJECT ; ; ; ; ; BINLSB BINMSB A A,@A+DPTR STRING_END SER_OUT DPTR SEND_STRING

************************************************************* * Routine: Binary to BCD - Conversion * * Description: konvertiert 16 Bit-Dualzahl (max 270FH) * * in 3 Byte-BCD (4 Stellen) * ************************************************************* EQU 2BH EQU 2AH ;BIN Wort LSB ;BIN Wort MSB

ZWSLSB BCDLSB BCDMSB ZBIT ZBYBCD ZBYBIN

EQU EQU EQU EQU EQU EQU

29H 27H 26H 10H 2D 2D R2,#ZBYBCD R1,#BCDMSB A @R1,A R1 R2,LOE_3 R0,#BINLSB R1,#ZWSLSB TRA2 R0,#ZWSLSB R1,#BINLSB R2,#ZBYBIN A,@R0 @R1,A R0 R1 R2,TRA3 R3,#ZBIT R0,#BINLSB C R2,#ZBYBIN A,@R0 A @R0,A R0 R2,CB_2 R1,#BCDLSB R2,#ZBYBCD A,@R1 A,@R1 A @R1,A R1 R2,CB_3 R3,CB_1 R0,#ZWSLSB R1,#BINLSB R2,#ZBYBIN A,@R0 @R1,A R0 R1 R2,TRA6

;Zwischenspeicher SLB ;BCD Wort LSB ;BCD Wort MSB ;Bitz hlwort ;BCD Wortz hler ;BIN Wortz hler

BIN_TO_BCD: LOE_1: MOV MOV LOE_2: CLR LOE_3: MOV INC DJNZ TRA0: TRA1: TRA2: TRA3: MOV MOV JMP MOV MOV MOV MOV MOV DEC DEC DJNZ MOV MOV CLR MOV MOV RLC MOV DEC DJNZ MOV MOV MOV ADDC DA MOV DEC DJNZ DJNZ MOV MOV MOV MOV MOV DEC DEC DJNZ RET

CB_1: CB_2:

CB_3:

TRA4: TRA5: TRA6:

$EJECT ;************************************************************************

;* BCD - ADDITIONSPROGRAMM A D D _ B C D * ;* Im Unterprogramm ADD_BCD werden 2 mehrstellige BCD-Zahlen (R2 * ;* enthaelt die Anzahl der Bytes) mit gleicher Stellenanzahl ad* ;* diert. Die BCD-Zahlen werden mit R0 und R1 adressiert und das * ;* Ergebnis wird bei der mit R0 adressierten BCD-Zahl abgespei* ;* chert. Die Wertigkeit der BCD-Zahlen nimmt mit steigender * ;* Adresse (R0, R1) zu. Bei Ueberlauf ist Carry gesetzt. * ;************************************************************************ ; ADD_BCD: CLR C ;CY loeschen AD0: MOV A,@R0 ;1.Summand laden ADDC A,@R1 ;2.Summand addieren DA A ;Dezimalkorrektur **1 MOV @R0,A ;Ergebnis abspeichern INC R0 ;Naechstes Byte 1.Summand INC R1 ; " " 2.Summand DJNZ R2,AD0 ;Addition beendet ? RET ; ; ;************************************************************************ ;* BCD - SUBTRAKTIONSPROGRAMM S U B B _ B C D * ;* Im Unterprogramm SUBB_BCD wird eine mehrstellige BCD-Zahl (R2 * ;* enthaelt die Anzahl der Bytes) von einer zweiten BCD-Zahl mit * ;* gleicher Stellenanzahl subtrahiert. Bei negativer Ergebnis * ;* (CY=1) ist diese als Zehner-Komplement dargestellt. Flag F0 * ;* ist ein Steuerbit fuer das Divisionsprogramm DIV_BCD mit fol* ;* gender Bedeutung : * ;* F0 = 0 : R0 --> Adresse Minuend und Differenz * ;* R1 --> " Subtrahend * ;* F0 = 1 : R0 --> " Subtrahend und Differenz * ;* R1 --> " Minuend * ;* Die Wertigkeit der BCD-Zahl nimmt mit steigender Adresse (R0, * ;* R1) zu. * ;************************************************************************ ; SUBB_BCD: CLR C ;CY loeschen SB0: JNB F0,SB1 ;Sprung, falls F0 nicht gesetzt MOV A,@R1 ;Minuend laden SUBB A,@R0 ;Subtrahend subtrahieren SJMP SB2 ; SB1: MOV A,@R0 ;Minuend laden SUBB A,@R1 ;Subtrahend subtrahieren SB2: JBC CY,SB3 ;Sprung, falls Ergebnis negativ **2 JNB AC,SB5 ;Falls CY=0 und AC=0 Sprung **3 SUBB A,#06H ;Dezimalkorrektur niederes Halbbyte **4 SJMP SB5 ;CY=0 **5 SB3: JNB AC,SB4 ;Sprung, falls AC=0 **6 SUBB A,#06H ;Dezimalkorrektur niederes Halbbyte **7 SB4: SUBB A,#60H ; " oberes Halbbyte **8 SETB C ;CY=1 : negatives Ergebnis **9 SB5: MOV @R0,A ;Ergebnis abspeichern INC R0 ;Naechstes Byte subtrahieren INC R1 ; " " Minuend DJNZ R2,SB0 ;Subtraktion beendet ? RET ; $EJECT

;************************************************************************ ;* Unterprogramm Z E H N E R _ C P L * ;* Das Unterprogramm ZEHNER_CPL wird von einer mehrstelligen * ;* BCD-Zahl (R2 enthaelt die Anzahl der Bytes), welche mit R0 * ;* adressiert wird, das Zehner-Komplement gebildet. Die Wertig* ;* keit der BCD-Zahl nimmt mit steigender Adresse (R0) zu. * ;************************************************************************ ; ZEHNER_CPL: CLR C ;CY loeschen ZE0: CLR A ;Minuend=0 SUBB A,@R0 ;Subtraktion JBC CY,ZE1 ;Sprung, falls Ergebnis negativ **10 SJMP ZE3 ;Ergebnis=0 **11 ZE1: JNB AC,ZE2 ;Sprung, falls AC=0 **12 SUBB A,#06H ;Dezimalkorrektur niederes Halbbyte **13 ZE2: SUBB A,#60H ; " oberes Halbbyte **14 SETB C ;CY=1 fuer naechste Subtraktion **15 ZE3: MOV @R0,A ;Ergebnis abspeichern INC R0 ;Naechstes Byte DJNZ R2,ZE0 ;Letztes Byte ? RET ; $EJECT ;************************************************************************ ;* BCD - MULTIPLIKATIONSPROGRAMM M U L _ B C D * ;* Mit dem Programm M U L _ B C D wird eine Multiplikation von * ;* BCD-Zahlen ausgefuehrt : N-Byte * M-Byte * ;* Multiplikand und Multiplikator koennen aus einer unterschied* ;* lichen Anzahl von Bytes bestehen, welche mit <MULTIPLIKATOR> * ;* und <MULTIPLIKAND> definiert sind. Die Anzahl der Bytes des * ;* Produkts berechnet sich aus <MULTIPLIKAND>+<MULTIPLIKATOR>. * ;* Die Wertigkeit der Bytes steigt mit hoeherer Adresse. Die be* ;* noetigte Anzahl Bytes an Datenspeicher berechnet sich aus : * ;* 1 Registerbank + 2 * ( <MULTIPLIKAND>+<MULTIPLIKATOR> ) * ;* Ausserdem werden 2 Bits des bitadressierbaren Datenspeichers * ;* benoetigt. Zur Ausfuehrung der Multiplikation wird der Multi* ;* plikand (LSB bei <AREG>) und der Multiplikator (LSB bei <BREG>) * ;* geladen . Das Ergebnis (LSB) befindet sich in <CREG>. * ;************************************************************************ ; MULTIPLIKAND EQU 3 ;Byteanzahl MULTIPLIKATOR EQU 3 ; " PRODUKT EQU MULTIPLIKAND+MULTIPLIKATOR ;Byteanzahl MANZ EQU MULTIPLIKAND*2 ;Halbbyte-Anzahl BSEG ABIT: BBIT: DSEG AREG: BREG: CREG: ; AREG_PNTR CREG_PNTR DS DS DS EQU EQU MULTIPLIKAND MULTIPLIKATOR PRODUKT R0 R1 ;Register (LSB) fuer Multiplikand ; " " " Multiplikator ; " " " Produkt ;Pointer fuer AREG ; " " CREG DBIT 1 DBIT 1 ;Stelle fuer Multiplikation (Nibble-Marke) ;Stelle des Multiplikanden

BREG_ADR EQU R2 ;Adresse fuer BREG KONSTANTE EQU R3 ;Halbbyte des Multiplikators ZWSUM_LSB EQU R4 ;Summierregister LSB ZWSUM_MSB EQU R5 ; " MSB M_CNTR EQU R6 ;Stellenzaehler Multiplikand ENDE EQU CREG+PRODUKT ;Speichergrenze ; CSEG ; ; ************************************************* ; * Initialisierung * ; ************************************************* ; MUL_BCD:MOV R0,#CREG ;Register fuer Produkt MOV R2,#PRODUKT ;loeschen CLR A ; M00: MOV @R0,A ; INC R0 ; DJNZ R2,M00 ; MOV AREG_PNTR,#AREG ;Pointer fuer AREG,BREG und MOV CREG_PNTR,#CREG ;CREG setzen MOV BREG_ADR,#BREG ; MOV M_CNTR,A ;Stellenzaehler loeschen CLR ABIT ;Stellenbits loeschen CLR BBIT ; ; ; ************************************************* ; * Eine Stelle des Multiplikators rechtsbuendig * ; * in <KONSTANTE> abspeichern. * ; ************************************************* ; M0: MOV B,CREG_PNTR ;CREG_PNTR abspeichern MOV A,BREG_ADR ;BREG_ADR --> R1(CREG_PNTR) MOV R1,A ; MOV A,@R1 ;<BREG_ADR> --> Accu JNB BBIT,M1 ;Sprung, falls unteres Halbbyte SWAP A ;Accu swappen M1: ANL A,#0FH ;oberes Halbyte ausblenden MOV KONSTANTE,A ;Accu --> <KONSTANTE> MOV CREG_PNTR,B ;CREG_PNTR restaurieren ; ; ************************************************* ; * Multiplikation von <KONSTANTE> mit einer * ; * Stelle des Multiplikanden und Abspeichern des * ; * stellenrichtigen Ergebnisses in <ZWSUM_LSB> * ; * und <ZWSUM_MSB>. * ; ************************************************* ; M2: MOV A,M_CNTR ;Pruefen, ob unteres Halbbyte oder RRC A ;oberes Halbbyte des Multiplikanden MOV A,@AREG_PNTR ; JNC M3 ;Sprung, falls unteres Halbbyte SWAP A ;Accu swappen M3: ANL A,#0FH ;oberes Halbbyte ausblenden MOV B,KONSTANTE ;<KONSTANTE> --> B MUL AB ; MOV B,#10 ;Ergebnis aufteilen in DIV AB ;Zehner- und Einer-Stelle JB ABIT,M4 ;Sprung, falls ABIT=1 SWAP A ;Accu swappen

**16 **17

M4:

ADD MOV SJMP MOV MOV SWAP MOV

A,B ZWSUM_LSB,A M5 ZWSUM_MSB,A A,B A ZWSUM_LSB,A

;nieder- und hoeherwertige Stelle ;in <ZWSUM_LSB> abspeichern ; ;hoeherwertige Stelle abspeichern ;niederwertigere Stelle ;linksbuendig ;in <ZWSUM_LSB> abspeichern

; ; ; ; ; ; M5:

************************************************* * Addition von <ZWSUM_LSB> und <ZWSUM_MSB> auf * * Produktregister CREG. * ************************************************* MOV MOV ADD DA MOV JNB INC MOV ADDC DA MOV JNC INC CJNE SJMP MOV ADD DA MOV JC MOV INC B,CREG_PNTR ;CREG_PNTR abspeichern A,@CREG_PNTR ;<ZWSUM_LSB> zu @<CREG_PNTR> A,ZWSUM_LSB ;aufaddieren (BCD) A ; @CREG_PNTR,A ; ABIT,M6 ;Sprung, falls ABIT=0 CREG_PNTR ;naechstes CREG-Register A,@CREG_PNTR ;<ZWSUM_LSB>+CY zu @<CREG_PNTR> A,ZWSUM_MSB ;aufaddieren (BCD) A ; @CREG_PNTR,A ; M9 ;Sprung, falls kein Ueberlauf CREG_PNTR ;naechstes CREG-Register CREG_PNTR,#ENDE,M8;CREG-Bereich ueberschritten ? M9 ; A,#1 ;Uebertrag zu @<CREG_PNTR> A,@CREG_PNTR ;aufaddieren (BCD) A ; @CREG_PNTR,A ; M7 ;Sprung, falls erneut Ueberlauf CREG_PNTR,B ;CREG_PNTR restaurieren M_CNTR ;Naechste Multiplikandenstelle

**18

**19

M6: M7: M8:

**20

M9: ; ; ; ; ; ; M10:

************************************************* * Steuerung von ABIT, BBIT, AREG_PNTR, M_CNTR, * * BREG_ADR und CREG_PNTR * ************************************************* CJNE MOV MOV CPL SETB JB CLR INC CJNE SJMP MOV CLR SUBB MOV JMP CPL JB INC JB M_CNTR,#MANZ,M12;Letzte Stelle des Multiplikanden ? M_CNTR,#0 ;Stellenzaehler zuruecksetzen AREG_PNTR,#AREG ;AREG_PNTR zuruecksetzen BBIT ;Naechste Stelle des Multiplikators ABIT ; BBIT,M11 ;Sprung, falls Stelle mit oberem Halbbyte ABIT ;Stelle mit unterem Halbbyte BREG_ADR ;BREG_PNTR erhoehen BREG_ADR,#CREG,M11;Multiplikation beendet ? MEXIT ; A,CREG_PNTR ;Startwert fuer CREG_PNTR C ;berechnen und laden A,#MULTIPLIKAND-1; CREG_PNTR,A ; M0 ; ABIT ; ABIT,M13 ; CREG_PNTR ;CREG_PNTR erhoehen, falls ABIT=0 ABIT,M14 ;

M11:

M12: M13:

M14: M15:

JNB SJMP JNB INC JMP

BBIT,M15 M2 BBIT,M2 AREG_PNTR M2

; ; ; ;AREG_PNTR erhoehen, falls ABIT u. BBIT=0 ;oder ABIT u. BBIT=1 ;

; MEXIT: RET

$EJECT ;************************************************************************ ;* BCD - DIVISIONSPROGRAMM D I V _ B C D * ;************************************************************************ ;* Mit dem Programm D I V _ B C D wird eine Division von BCD* ;* Zahlen ausgefuehrt : N-Byte / N-Byte * ;* Dividend, Divisor und das Ergebnis der Division, Quotient und * ;* Rest, haben die gleiche Stellenanzahl, welche mit <ANZ_BYTE> * ;* definiert wird (z.B. 6 BCD-Stellen : ANZ_BYTE = 3). * ;* speicher ist im Beispiel (2 Byte/2 Byte) folgend belegt: * ;* Die Wertigkeit der Bytes steigt mit hoeherer Adresse. Die be* ;* noetigte Anzahl Bytes an Datenspeicher berechnet sich aus : * ;* 1 Registerbank + (<ANZ_BYTE>*4) * ;* Das Ergebnis der Division befindet sich in Quotient und Rest * ;* mit CY=0. Bei einem Fehler (Divisor=0) wird die Division nicht * ;* ausgefuehrt und Carry gesetzt (CY=1). * ;************************************************************************ ; ANZ_BYTE EQU 4 ;Anzahl Bytes der BCD-Zahl ANZ_NIBBLE EQU ANZ_BYTE * 2 ;BCD-Stellenanzahl ; DSEG ;Datensegment : ANZ_BYTE * 4 DIVIDEND: DS ANZ_BYTE ;Register fuer Dividend DIVISOR: DS ANZ_BYTE ; " " Divisor QUOTIENT: DS ANZ_BYTE ; " " Quotient REST: DS ANZ_BYTE ; " " Rest ; BYTE_CNTR EQU R2 ;Bytezaehler NIBBLE_CNTR EQU R3 ;Stellenzaehler HREG1 EQU R4 ;Hilfsregister 1 HREG2 EQU R5 ; " 2 ; CSEG ; ; ************************************************* ; * Initialisierung * ; ************************************************* ; DIV_BCD:MOV BYTE_CNTR,#ANZ_BYTE;Pruefen, ob Divisor=0 MOV R0,#DIVISOR ; CZERO: CJNE @R0,#00H,LOE0 ;Sprung, falls Divisor-Byte <> 0 INC R0 ; DJNZ BYTE_CNTR,CZERO ; SJMP DIV_ERR ;Divisor=0 : keine Division moeglich ; LOE0: CLR A ;Loeschen der Ergebnisregister MOV R0,#QUOTIENT ;Quotient und Rest LOE1: MOV @R0,A ; INC R0 ; CJNE R0,#QUOTIENT+ANZ_NIBBLE,LOE1 ; MOV NIBBLE_CNTR,#ANZ_NIBBLE ;Nibble-Zaehler laden

; ; ; ; ; ; ; DVD:

************************************************* * Shift Halbbyte : Dividend + Rest nach links * * MSHB des Dividenden --> LSHB des Rest und * * LSHB des Dividenden * ************************************************* MOV MOV MOV CALL MOV ORL MOV MOV CALL R0,#DIVIDEND ; BYTE_CNTR,#ANZ_BYTE; HREG1,#0 ;Shift Dividend mit LSHB=<HREG1>=0 SHIFT ; A,HREG1 ;Ueberlaufendes Halbbyte in <HREG1> DIVIDEND,A ;an LSHB-Stelle des Dividenden bringen R0,#REST ;Shift Rest mit BYTE_CNTR,#ANZ_BYTE;LSHB=<HREG1> SHIFT ;

; ; ; ; ;

************************************************* * Pruefen, ob Rest > Divisor * ************************************************* CLR MOV MOV MOV MOV SUBB INC INC DJNZ MOV JC C ; BYTE_CNTR,#ANZ_BYTE;Byteanzahl und R0,#REST ;Adressen laden R1,#DIVISOR ; A,@R0 ; A,@R1 ;Subtraktion Rest - Divisor R0 ;Adressen erhoehen R1 ; BYTE_CNTR,COMP ;Vergleich beendet ? HREG1,#0 ;Ergebniszaehler fuer Subtraktion=0 DV3 ;Sprung, falls Rest < Divisor

COMP:

; ; ; ; ; ; ; ; ; ; DV1:

************************************************* * Division Rest:Divisor durch fortgesetzte Sub- * * traktion Rest-Divisor * * Ergebnis : <HREG1> Quotient (0-9) und Rest * ************************************************* MOV MOV MOV CLR CALL JC INC SJMP MOV MOV CALL MOV MOV MOV SETB CALL R0,#REST ;Adressen und Byteanzahl laden R1,#DIVISOR ; BYTE_CNTR,#ANZ_BYTE; F0 ;Steuerbit loeschen SUBB_BCD ;Subtraktion Rest-Divisor DV2 ;Sprung, falls Ergebnis negativ HREG1 ;Ergebniszaehler erhoehen DV1 ; R0,#REST ;Division beendet: Rest korrigieren BYTE_CNTR,#ANZ_BYTE;Adressen und Byteanzahl laden ZEHNER_CPL ;Zehner-Komplement des Rest bilden R0,#REST ;Adressen und Byteanzahl laden R1,#DIVISOR ; BYTE_CNTR,#ANZ_BYTE; F0 ;Steuerbit setzen SUBB_BCD ;Divisor-Rest --> Rest

DV2:

; ;

*************************************************

; ; ; ; DV3:

* Shift Ergebnis der Division <HREG1> an LSHB * * des Quotienten. * ************************************************* R0,#QUOTIENT ;Adresse und Byteanzahl laden BYTE_CNTR,#ANZ_BYTE; SHIFT ;Shift Quotient NIBBLE_CNTR,DVD ;gesamte Division beendet ? C ;kein Fehler aufgetreten DIV_EX ; C ;Divisionsfehler : Divisor=0 ! ;

MOV MOV CALL DJNZ CLR SJMP DIV_ERR:SETB DIV_EX: RET

$EJECT ;************************************************************************ ;* * ;* Unterprogramm S H I F T : * ;* * ;* Im Unterprogramm SHIFT werden Halbbytes um 4 Bits nach links * ;* (zu hoeherer Wertigkeit) geschoben. <HREG1> wird als nieder* ;* wertigstes Halbbyte eingesetzt und dann das hoechstwertigste * ;* Halbbyte in <HREG1> abgespeichert. In R0 wird die Adresse des * ;* LSB und in R2 die Byteanzahl uebergeben. * ;* * ;************************************************************************ ; SHIFT: MOV A,@R0 ;Byte in Accu laden, SWAP A ;swappen und MOV HREG2,A ;in HREG2 abspeichern ANL A,#0F0H ;Halbbyte ausblenden und ORL A,HREG1 ;mit HREG1 verknuepft MOV @R0,A ;abspeichern MOV A,HREG2 ;Ueberlauf ANL A,#0FH ;ausblenden und MOV HREG1,A ;abspeichern INC R0 ;Adresse naechstes Byte DJNZ BYTE_CNTR,SHIFT ;Letztes Byte ? RET ; $EJECT ; ; ; ; ; ; ; ; ;

************************************************************* * Library LCD * * Subroutines for Controlling of Liquit Cristall Displays * * Version: 1.1 * * Date: 29.12.1994 * ************************************************************* ************************************************************* * Constants * ************************************************************* EQU 0F000H ;m gl. Adr 1xxx xxxx xxxx xxx0B um LCD-Mod

IR_ADR ul anzusprechen ; ;

************************************************************* * Routine: Clear Display *

; ;

* Description: l scht LCD-Display und setzt Cursor an Pos.1 * ************************************************************* ACC ACC,#01H WRITE_IR ACC

CLEAR_DISPLAY: PUSH MOV CALL POP RET ; ; ;

;Befehl (Clear Display)=#01H

************************************************************* * Routine: Display On * ************************************************************* ACC ACC,#0CH WRITE_IR ACC

DISPLAY_ON: PUSH MOV CALL POP RET ; ; ;

;Befehl (Display On)=#0CH

************************************************************* * Routine: Display On * ************************************************************* ACC ACC,#08H WRITE_IR ACC

DISPLAY_OFF: PUSH MOV CALL POP RET ; ; ; ; ; ;

;Befehl (Display Off=#08H

************************************************************* * Routine: Check Busy-Flag des LCD-Controllers * * Description: pr ft, ob Busy-Flag gesetzt ,d.h. LCD* * Controller noch nicht bereit f r n chsten * * Befehl ist * ************************************************************* ;IR auslesen ;IR.7=Busy-Flag ;warten bis (Busy-Flag)=0

CHECK_BUSY_FLAG: MOV DPTR,#(IR_ADR+2) CBF_1: MOVX A,@DPTR JB ACC.7,CBF_1 RET ; ; ; ; ; WRITE_IR: PUSH PUSH PUSH CALL DPH DPL ACC CHECK_BUSY_FLAG

************************************************************* * Routine: Write To Instruction-Register (IR) <- (ACC) * * Description: schreibt Akkuinhalt ins Befehlsregister des * * LCD-Controllers mit der Adresse IR_ADR * *************************************************************

POP MOV MOVX POP POP RET ; ; ; ; READ_IR: PUSH PUSH CALL MOVX POP POP RET ; ; ; ; ; WRITE_DR: PUSH PUSH PUSH CALL POP DEC MOVX POP POP RET ; ; ; ; READ_DR: PUSH PUSH CALL INC MOVX POP POP RET ; ; ;

ACC DPTR,#IR_ADR @DPTR,A DPL DPH

************************************************************* * Routine: Read Instruction-Register (ACC) <- (IR) * * Description: liest Befehlsregister in den Akkumulator ein * ************************************************************* DPH DPL CHECK_BUSY_FLAG A,@DPTR DPL DPH

************************************************************* * Routine: Write To Data-Register (DR) <- (ACC) * * Description: schreibt Akkuinhalt ins Datenregister des * * LCD-Controllers mit Adresse IR_ADR+1=DR_ADR * ************************************************************* DPH DPL ACC CHECK_BUSY_FLAG ACC DPL ;Adr(Data-Register)=Adr(Instruction-Reg.)+2-1 @DPTR,A DPL DPH

************************************************************* * Routine: Read Data-Register (ACC) <- (DR) * * Description: liest Datenregister in den Akkumulator ein * ************************************************************* DPH DPL CHECK_BUSY_FLAG DPTR A,@DPTR DPL DPH

************************************************************* * Routine: Initialize Display * * Description: initialisiert LCD-Controller f r 8-Bit Daten-*

; ;

* transfer, 2-zeilig, Cursor aus * ************************************************************* R0,#4 R0,ID_2 ID_4 A,#38H DPTR,#IR_ADR @DPTR,A R2,#1FH R1,#0FFH R1,$ R2,ID_3 ID_1 A,#38H WRITE_IR A,#00000001B WRITE_IR A,#00001100B WRITE_IR A,#00000110B WRITE_IR ;Z hler zur Initialisierung ;der Wert 38H mu 3mal mit zeitl. Verz ger;ung in IR geschrieben werden ;Anzeige wird mit 8 Datenbits und 2 Zeilig ;betrieben

INIT_DISPLAY: MOV ID_1: DJNZ JMP ID_2: MOV MOV MOVX MOV ID_3: MOV DJNZ DJNZ JMP ID_4: MOV CALL MOV CALL MOV CALL MOV CALL RET ; ; ; ; ;

;Anzeige l schen (01H) ;Display ein, Cursor aus (0CH) ;Eingabe Mode (06H)

************************************************************* * Routine:DISPLAY_TEXT (LCD-Anzeige-RAM) <- ((Text-Pointer))* * Description: Text, der ber Text-Pointer adressiert ist, * * wird ins Anzeige-RAM des LCD-Controllers transferiert. * *************************************************************

DISPLAY_TEXT: PUSH ACC PUSH 07 MOV A,#10000000B CALL WRITE_IR DT_2: tes JZ DT_END CALL WRITE_DR INC R7 CJNE R7,#16D,DT_3 MOV A,#11000000B esse 40H CALL WRITE_IR JMP DT_3 DT_3: DT_END: CJNE R7,#32D,DT_2 POP 07 POP ACC RET ;0 markiert Textende ;Zeichen ausgeben MOV R7,#00H MOV A,R7 MOVC A,@A+DPTR ;Adresse im Anzeige-RAM = 0 setzen

;in DPTR steht Anfangsadresse des Ausgabetex

;1. Zeichen in der 2. Zeile des LCD hat Adr

; ; ; ; ; ; ; ;

************************************************************* * Routine: DISPLAY_NUMBER * * Description: R1 enth lt die Adresse des LSBCD * * R6 enth lt die Stelle des Kommas * * R7 enth lt die Byteanzahl der Zahl, die * * ins Anzeige-RAM des LCD-Contr. transf. wird. * * (z.B. 4 Byte = 8 BCD-Stellen) * ************************************************************* BSEG

FLAG_NO_LEADING_ZERO: DBIT 1 ausgeben CSEG

;H -> dann Nullen als 30H ausgeben ,L -> als 20H

DISPLAY_NUMBER: CLR FLAG_NO_LEADING_ZERO MOV A,#11000000B ;schreibt in die 2. Zeile CALL WRITE_IR MOV A,R7 ;Zeiger auf MSBCD+1 richten ADD A,R1 MOV R1,A DN_1: BCD) ANL A,#11110000B SWAP A CJNE A,#00H,DN_4 esetzt, JB FLAG_NO_LEADING_ZERO,DN_4 MOV A,#20H ;dann diese Null nicht angezeigen, da sie vor der SJMP DN_5 ;ersten g ltigen Ziffer steht DN_4: SETB FLAG_NO_LEADING_ZERO ;dieses Bit wird gesetzt, sobald erstes von Null versch. Zeichen ;erkannt wird und sorgt daf r, das kommende Nullen a ls Ziffer ausgegeben werden ;und wird gesetzt, beim ersten Zeichen vor dem Kom ma ADD A,#30H ;BCD-Code in ASCII-Code wandeln DN_5: CALL WRITE_DR ;Zahl anzeigen DJNZ R6,DN_2 MOV A,#2EH CALL WRITE_DR DN_2: DN_8: ;Kommastelle erreicht ->J, dann Komma ausgeben ;ASCII-Code des Kommas (bzw. Punktes) ;h herwertiges BCD ausmaskieren ;falls gleich und Flag 'keine f hrende Null' nicht g DEC R1 MOV A,@R1 ;R1 enth lt Adresse der zwei BCD-Zahlen (1 Byte = 2

CJNE R6,#01,DN_8 ;erstes Zeichen vor dem Komma erreicht SETB FLAG_NO_LEADING_ZERO MOV A,@R1 ANL A,#00001111B CJNE A,#00H,DN_6 ;niederwertiges BCD ausmaskieren ;falls gleich und Flag 'keine f hrende Null' nicht g

esetzt, JB FLAG_NO_LEADING_ZERO,DN_6 MOV A,#20H ;dann diese Null nicht angezeigen, da sie vor der SJMP DN_7 ;ersten g ltigen Ziffer steht

DN_6: SETB FLAG_NO_LEADING_ZERO ;dieses Bit wird gesetzt, sobald erstes von Null versch. Zeichen ;erkannt wird und sorgt daf , das kommende Nullen al s Ziffer ausgegeben werden ADD A,#30H ;BCD-Code in ASCII-Code wandeln DN_7: CALL WRITE_DR DJNZ R6,DN_3 MOV A,#2EH CALL WRITE_DR DN_3: ;Kommastelle erreicht ->J, dann Komma ausgeben ;ASCII-Code des Kommas (bzw. Punktes)

CJNE R6,#01,DN_9 ;erstes Zeichen vor dem Komma erreicht SETB FLAG_NO_LEADING_ZERO DJNZ R7,DN_1 RET ************************************************************* * End of Library LCD * *************************************************************

DN_9: ; ; ;

$EJECT %*DEFINE (ADDBCD (SUMMAND_1,SUMMAND_2,BYTEANZAHL_)) ( MOV R0,#%SUMMAND_1 MOV R1,#%SUMMAND_2 MOV R2,#%BYTEANZAHL_ CALL ADD_BCD ) %*DEFINE (DIVIDE (DIVIDEND_,DIVISOR_,QUOTIENT_)) ( MOV DIVIDEND ,%DIVIDEND_ ;DIVIDEND (LSB) MOV DIVIDEND+1,%DIVIDEND_+1 ; MOV DIVIDEND+2,%DIVIDEND_+2 ; MOV DIVIDEND+3,%DIVIDEND_+3 ;DIVIDEND (MSB) MOV DIVISOR ,%DIVISOR_ ;DIVISOR (LSB) MOV DIVISOR+1,%DIVISOR_+1 ; MOV DIVISOR+2,%DIVISOR_+2 ; MOV DIVISOR+3,%DIVISOR_+3 ;DIVISOR (MSB) CALL DIV_BCD ;Division ausf hren MOV %QUOTIENT_ ,QUOTIENT ;QUOTIENT (LSB) MOV %QUOTIENT_+1,QUOTIENT+1 ; MOV %QUOTIENT_+2,QUOTIENT+2 ; MOV %QUOTIENT_+3,QUOTIENT+3 ;QUOTIENT (MSB) ) %*DEFINE (DIVIDE_CONSTANT (DIVIDEND_,CONST_3,CONST_2,CONST_1,CONST_0,QUOTIENT_)) ( MOV DIVIDEND ,%DIVIDEND_ ;DIVIDEND (LSB) MOV DIVIDEND+1,%DIVIDEND_+1 ; MOV DIVIDEND+2,%DIVIDEND_+2 ; MOV DIVIDEND+3,%DIVIDEND_+3 ;DIVIDEND (MSB) MOV DIVISOR ,#%CONST_0 ;DIVISOR (LSB) MOV DIVISOR+1,#%CONST_1 ;

MOV MOV CALL MOV MOV MOV MOV )

DIVISOR+2,#%CONST_2 DIVISOR+3,#%CONST_3 DIV_BCD %QUOTIENT_ ,QUOTIENT %QUOTIENT_+1,QUOTIENT+1 %QUOTIENT_+2,QUOTIENT+2 %QUOTIENT_+3,QUOTIENT+3

; ;DIVISOR (MSB) ;Division ausf hren ;QUOTIENT (LSB) ; ; ;QUOTIENT (MSB)

%*DEFINE (MULTIPLY (MULTIPLIKAND_,MULTIPLIKATOR_)) ( MOV AREG ,%MULTIPLIKAND_ ;MULTIPLIKAND (LSB) MOV AREG+1,%MULTIPLIKAND_+1 ; MOV AREG+2,%MULTIPLIKAND_+2 ;MULTIPLIKAND (MSB) MOV BREG ,%MULTIPLIKATOR_ ;MULTIPLIKATOR (LSB) MOV BREG+1,%MULTIPLIKATOR_+1 ; MOV BREG+2,%MULTIPLIKATOR_+2 ;MULTIPLIKATOR (MSB) CALL MUL_BCD ;Multiplikation ausf hren; Produkt st eht ab CREG (LSB) ) %*DEFINE (MULTIPLY_CONSTANT (MULTIPLIKAND_,CONST_2,CONST_1,CONST_0)) ( MOV AREG ,%MULTIPLIKAND_ ;MULTIPLIKAND (LSB) MOV AREG+1,%MULTIPLIKAND_+1 ; MOV AREG+2,%MULTIPLIKAND_+2 ;MULTIPLIKAND (MSB) MOV BREG ,#%CONST_0 ;KONSTANTE (LSB) MOV BREG+1,#%CONST_1 ; MOV BREG+2,#%CONST_2 ;KONSTANTE (MSB) CALL MUL_BCD ;Multiplikation ausf hren; Produkt st eht ab CREG (LSB) ) %*DEFINE (SUBTRACT (MINUEND_,SUBTRAHEND_)) ( CLR F0 MOV R0,#%MINUEND_ MOV R1,#%SUBTRAHEND_ MOV R2,#04H ;4 Bytes = 8 BCD CALL SUBB_BCD ;falls Carry=1, dann Ergebnis negativ ) %*DEFINE (SUBTRACT_CONSTANT (MINUEND_,CONST_2,CONST_1,CONST_0)) ( CLR F0 MOV CONST ,#%CONST_0 ;SUBTRAHEND (LSB) MOV CONST+1,#%CONST_1 ; MOV CONST+2,#%CONST_2 ;SUBTRAHEND (MSB) MOV R0,#%MINUEND_ MOV R1,#CONST MOV R2,#04H ;4 Bytes = 8 BCD CALL SUBB_BCD ;falls Carry=1, dann Ergebnis negativ )

%*DEFINE (CONVERT_BIN_TO_BCD (BIN,BCD)) ( ;Parameter BIN = IAdresse der 16Bit-Bin rz ahl MOV BINLSB,%BIN ;" BCD = IAdresse der 3Byte-BCDZahl MOV BINMSB,%BIN+1 CALL BIN_TO_BCD MOV %BCD,BCDLSB MOV %BCD+1,BCDMSB MOV %BCD+2,#00H MOV %BCD+3,#00H ) $EJECT ;**************************************************************************** ;* M E A S U R E _ A N D _ C A L C U L A T E * ;* * ;* wird pro Minute einmal aufgerufen (k nnte auch durch Setzen des Flags * ;* Measure_&_Calculate aufgerufen werden) * ;* Subroutine mit die beiden Temperatursensoren R_TEMP_1/2 und berechnet * ;* daraus die VORLAUF_TEMP u. RUECKLAUF_TEMP, TEMP_DIFFERENZ, WAERME, * ;* WAERMELEISTUNG, VOLUMEN * ;* Berechnung wird abgebrochen, wenn TEMP_DIFFERENZ=0 u./o. VOL_COUNTER=0 * ;* (enth lt Volumen/Minute) * ;* Berechnung wird ebenfalls abgebrochen, wenn bei der Temperaturmessung * ;* Time-Out auftritt (FLAG_TEMP_ERROR wird gesetzt -> Messung ung ltig, * ;* Temp-Sensor defekt o. nicht angeschlossen) * ;*--------------------------------------------------------------------------* ;* Parameter: >/VORLAUF_TEMP/, /RUECKLAUF_TEMP/, /TEMP_DIFFERENZ/, /WAERME/* ;* /WAERMELEISTUNG/, /VOLUMEN/ * ;* Flags: >/ERROR_TEMP/> * ;* Max.-Stack: -* ;**************************************************************************** DISCHARGE_COMP BIT P1.0 DISCHARGE_TEMP_1 BIT P1.1 r entladen DISCHARGE_TEMP_2 BIT P1.2 entladen CHARGE_C BIT P1.3 KEY_DRIVELINE BIT P1.4 n) COMPARATOR BIT P3.3 dauermessung) DSEG T_COMP T_TEMP_1 B) T_TEMP_2 B) R_TEMP_1 mat) (LSB) R_TEMP_2 at) (LSB) CONST ten) DS DS DS DS DS DS 4 4 4 4 4 4 ;Zeitkonstante R_COMP*K*C (LSB) T_COMP+1=(MSB) ;Zeitkonstante R_TEMP_1*K*C (LSB) T_TEMP_1+1=(MS ;Zeitkonstante R_TEMP_2*K*C (LSB) T_TEMP_2+1=(MS ;Widerstand des PT100-Sensors im Vorlauf (BCD-For ;Widerstand des PT100-Sensors im R cklauf (BCD-Form ;Zwischenspeicher f r Konstante (z.B. W rmekoeffizien ;Ausgang - 'H': C wird ber R_Compare entladen ;Ausgang - 'H': C wird ber Vorlauf-Temperatursenso ;Ausgang - 'H': C wird ber R cklauf-Temperatursensor ;Ausgang - 'L': l dt Kondensator ;Ausgang - 'L': Taste aktiv (kann Interrupt ausl se ;Eingang : Torsteuerung des Timer1 (Perioden

; ; ; ; ; ; ; ; ; ;

CSEG ************************************************************* * Macro: Zeitkonstantenmessung * * bergabe-Parameter: R_ = entl dt C ber R_ * * R ckgabe-Parameter: (T_) = LSB Zeitkonst. R_C - Glied * * (T_+1) = MSB Zeitkonst. " " * * Description: * * Version: 1.2 * * Date: 3.1.95 * * Check: * *************************************************************

%*DEFINE (MEASURE (R_,T_)) ( CLR CHARGE_C MOV R2,#20D zu laden MOV R3,#50H DJNZ R3,$ DJNZ R2,$-4 SETB CHARGE_C MOV TL1,#00H MOV TH1,#00H SETB SETB Timer starten JB CLR CLR MOV MOV ) TR1 %R_ COMPARATOR,$ TR1 %R_ %T_,TL1 %T_+1,TH1

;Kondensator laden ;bei 1.843MHz ca. 20msec Verz gerung um Kondensator ;bei Verwendung von C=100uF

;Timer r cksetzen ;Zeitkonstante prop. zur Timerwert ;Entladung des Kondensators ber Widerstand R_ und ;wartet das Komp.ausg 'L'->Ende der Messung ;Entladung stoppen ;T_ (LSB) und T_+1 (MSB) der Zeitkonstante ;T_*Konstante=R_*C

MEASURE_AND_CALCULATE: ;Mess-Hardware initialisieren CLR DISCHARGE_COMP CLR DISCHARGE_TEMP_1 CLR DISCHARGE_TEMP_2 CLR CHARGE_C ssung kann Taste keinen Int. ausl sen SETB COMPARATOR ort-FlipFlop

;Fets ausschalten ; " ; " ;Taste ausgel st werden) nur w hrend Temp.me ;wird als Eingang verwendet -> 'H' ins P

;vor Messung Timer f r Periodendauermessung vorbereiten CLR TR1 ;Timer1 stoppen CLR TF1 ;Anforderungsbit l schen (war durch ser. Mode gesetz t) MOV IE,#10001000B eststellen zu k nnen ANL TMOD,#0FH ORL TMOD,#90H Comparatorausgang (P3.3) SETB KEY_DRIVELINE ;nur Timer1-Int freigeben, um TEMP_SENSOR_FEHLER f ;alle Timer1-Modebits l schen ;Timer1 als 16Bit-Timer mit Tor ffnung durch TR1 und ;Taste deaktivieren ;mit Zeitkonstante T_COMP ;mit Zeitkonstante T_TEMP_1

;Messung der 3 Zeitkonstanten %MEASURE (DISCHARGE_COMP ,T_COMP) %MEASURE (DISCHARGE_TEMP_1,T_TEMP_1)

%MEASURE (DISCHARGE_TEMP_2,T_TEMP_2) ;mit Zeitkonstante T_TEMP_2 %CONVERT_BIN_TO_BCD (T_COMP,T_COMP) ;convertiert 16 bit-Timerwer t in 3 Byte BCD-Zahl, %CONVERT_BIN_TO_BCD (T_TEMP_1,T_TEMP_1) ;d.h. 6 stellige BCD-Zahl %CONVERT_BIN_TO_BCD (T_TEMP_2,T_TEMP_2) ;nach Messung Timer1 wieder f r ser. Int einstellen und Kond. laden CLR CHARGE_C ;Kondensator laden MOV R2,#20D ;bei 1.843MHz ca. 20msec Verz gerung um Kondensator zu laden MOV DJNZ DJNZ SETB R3,#50H R3,$ R2,$-4 CHARGE_C ;bei Verwendung von C=100uF

CLR IE1 ;Interrupt1-Anforderungsbit wurde bei Periodendaue rmessung gesetzt MOV IE,#10010111B ;alle Interrupts bis auf Timer1-Interrupt freigebe n ANL TMOD,#0FH ORL TMOD,#20H MOV TH1,#-4 H1=252=-4 SETB TR1 MOV SCON,#01010000B ;Start Timer 1 ;UART Mode 1, Empf nger freigeben ;alle Timer1-Modebits l schen ;Timer 1: Auto-Reload Mode ;Baudrate=fosz/(32*12*(256-TH1)) -> ;fosz=11.059MHz/6 und Baudrate=1200 -> T

CLR KEY_DRIVELINE ;Taste aktivieren JNB FLAG_TEMP_ERROR,M_T_1 ringen CLR FLAG_TEMP_ERROR nicht g ltig CLR DISCHARGE_COMP ULATE-Routine RET ch die alten Temperaturwerte ;falls Fehler aufgetreten, dann Messung ;-> Sprung zum Ende der MEASURE_AND_CALC ;Messung nicht g ltig, es gelten automatis ;falls kein Fehler aufgetreten ist, bersp

;Berechnung der Vorlauftemperatur M_T_1: %MULTIPLY_CONSTANT (T_TEMP_1,01H,00H,00H) ;berechnet R_COMP*T_TEMP*100 =PRODUKT %DIVIDE (CREG,T_COMP,R_TEMP_1) ;berechnet PRODUKT/T_COMP=R_ TEMP_1*100 CLR C IE) %SUBTRACT_CONSTANT (R_TEMP_1,01H,00H,25H) EMP-R(0K))/ JNC M_T_14 IE) MOV R_TEMP_1, #00H n Ergebnis null setzen MOV R_TEMP_1+1,#00H p. gemessen werden MOV R_TEMP_1+2,#00H >0C .. 90C sinnvoll MOV R_TEMP_1+3,#00H M_T_14: ;Berechnet mittels TEMP=(R_T ;(Steigung der PT100-KENNLIN ;falls Ergebnis negativ, dan ;d.h. es k nnen keine neg. Tem ;Messung nur im Bereich von ;(Steigung der PT100-KENNLIN

%MULTIPLY_CONSTANT (R_TEMP_1,00H,10H,00H) ;entspricht Mult. mit 1000

%DIVIDE_CONSTANT (CREG,00H,00H,03H,85H,VORLAUF_TEMP);berechnet Temp. i n 0.01C ;Berechnung der R cklauftemperatur %MULTIPLY_CONSTANT (T_TEMP_2,01H,00H,00H) ;berechnet R_COMP*T_TEMP*100 =PRODUKT %DIVIDE (CREG,T_COMP,R_TEMP_2) TEMP_2*100 CLR C %SUBTRACT_CONSTANT (R_TEMP_2,01H,00H,36H) EMP-R(0K))/ JNC M_T_13 IE) MOV R_TEMP_2, #00H n Ergebnis null setzen MOV R_TEMP_2+1,#00H p. gemessen werden MOV R_TEMP_2+2,#00H >0C .. 90C sinnvoll MOV R_TEMP_2+3,#00H M_T_13: ;Berechnet mittels TEMP=(R_T ;(Steigung der PT100-KENNLIN ;falls Ergebnis negativ, dan ;d.h. es k nnen keine neg. Tem ;Messung nur im Bereich von ;berechnet PRODUKT/T_COMP=R_

%MULTIPLY_CONSTANT (R_TEMP_2,00H,10H,00H) ;entspricht Mult. mit 100 %DIVIDE_CONSTANT (CREG,00H,00H,03H,85H,RUECKLAUF_TEMP) ;Berechnung der Temperaturdifferenz MOV TEMP_DIFFERENZ ,VORLAUF_TEMP MOV TEMP_DIFFERENZ+1,VORLAUF_TEMP+1

;Werte umspeichern (LSB) ;damit Var. f r Subtr richtig ; ;(MSB)

belegt MOV TEMP_DIFFERENZ+2,VORLAUF_TEMP+2 MOV TEMP_DIFFERENZ+3,VORLAUF_TEMP+3 nz JNC M_T_12 egativ, dann Tempsensoren vertauscht-> MOV TEMP_DIFFERENZ ,VORLAUF_TEMP tauschen MOV TEMP_DIFFERENZ+1,VORLAUF_TEMP+1 MOV TEMP_DIFFERENZ+2,VORLAUF_TEMP+2 MOV TEMP_DIFFERENZ+3,VORLAUF_TEMP+3 MOV VORLAUF_TEMP ,RUECKLAUF_TEMP MOV VORLAUF_TEMP+1 ,RUECKLAUF_TEMP+1 MOV VORLAUF_TEMP+2 ,RUECKLAUF_TEMP+2 MOV VORLAUF_TEMP+3 ,RUECKLAUF_TEMP+3 MOV RUECKLAUF_TEMP ,TEMP_DIFFERENZ MOV RUECKLAUF_TEMP+1,TEMP_DIFFERENZ+1 MOV RUECKLAUF_TEMP+2,TEMP_DIFFERENZ+2 MOV RUECKLAUF_TEMP+3,TEMP_DIFFERENZ+3 MOV TEMP_DIFFERENZ ,VORLAUF_TEMP MOV TEMP_DIFFERENZ+1,VORLAUF_TEMP+1 belegt MOV TEMP_DIFFERENZ+2,VORLAUF_TEMP+2 MOV TEMP_DIFFERENZ+3,VORLAUF_TEMP+3 %SUBTRACT (TEMP_DIFFERENZ,RUECKLAUF_TEMP) nz ;falls Temperaturdifferenz n ;dann Vor-u. R cklauf-Temp ver

%SUBTRACT (TEMP_DIFFERENZ,RUECKLAUF_TEMP) ;berechnet Temperaturdiffere

;Werte umspeichern (LSB) ;damit Var. f r Subtr richtig ; ;(MSB) ;berechnet Temperaturdiffere

;Updating des Volumenwertes M_T_12: MOV A,#00H r/Min und/oder Temperaturdifferenz = 0 CJNE A,VOL_COUNTER,M_T_6 alte Werte behalten ihre G ltigkeit SJMP M_T_8 Null) M_T_6: rt um MOV BINLSB,VOL_COUNTER CALL BIN_TO_BCD MOV AREG, BCDLSB MOV AREG+1,BCDMSB MOV AREG+2,#00H MOV BREG ,#00H MOV BREG+1,#00H MOV BREG+2,#00H %ADDBCD (VOLUMEN,AREG,06D) lumen JNC M_T_11 Error_Flag setzen SETB FLAG_VOL_ERROR lauf dokumentiert CLR C M_T_11: ;falls CLR EX0 MOV BINMSB,#00H

;falls Volumenstrom = 0 Lite ;dann Berechnung abbrechen ( ;bis auf W rmeleistung -> wird

;wandelt bin. Volumen/Min-Wert in BCD-We

;addiert Volumen/Meintervall zum Gesamtvo berlauf bei Addition aufgetreten,

;!!!! evtl. Meldung ins EEPROM, damit ber

;berechnet Volumenstrom*Temperaturdifferenz (CREG) %MULTIPLY (AREG,TEMP_DIFFERENZ) MOV VOL_COUNTER,#00H ;nachdem Volumenz hler ausgelesen wurde, s ofort zur cksetzen (s. INT0) SETB EX0 MOV CJNE CJNE CJNE MOV MOV MOV MOV RET A,#00H A,TEMP_DIFFERENZ,M_T_7 ;falls Tempdifferenz=0 (evtl. < 1K) dann A,TEMP_DIFFERENZ+1,M_T_7 A,TEMP_DIFFERENZ+2,M_T_7 WAERMELEISTUNG, #00H ;W rmeleistung Null setzen WAERMELEISTUNG+1,#00H WAERMELEISTUNG+2,#00H WAERMELEISTUNG+3,#00H

M_T_8:

;berechnet W rmekoeffizienten*Volumenstrom*Temperaturdifferenz=Teilw rmeme nge M_T_7: CLR CLR MOV ADD CY AC A,VORLAUF_TEMP+1 A,RUECKLAUF_TEMP+1 ;Carry und Akku l schen, damit BCD-Add. ok ;berechnet (Vorlauf+R cklauftemp) ;dividiert durch 10 (Nibble-Rechts-Shift ;(10=5*2; 5 ist der Abstand zwischen den

) DA A W rmekoeff.werten) SWAP A ANL A,#00001111B JNC M_T_15 CLR CY SETB ACC.4 SUBB A,#6 M_T_15: RL A eff. 2 Bytes)

;wenn CY gesetzt, ist Ergebnis >100

;Ergebnis mu gerade sein und *2 (da W rmeko

PUSH ACC INC A MOV DPTR,#WAERME_COEFFICIENT_POINTER MOVC A,@A+DPTR MOV CONST,A POP ACC MOVC A,@A+DPTR MOV CONST+1,A MOV CONST+2,#00H %MULTIPLY (CREG,CONST) ;CREG=deltaV*deltaT Const=-gemittelte Di chte*gemittelte spez. W rmekapazit t ;W rmeleistung=Teilw rmemenge/Meintervall - hier Meintervall = 60.0s -> 00H 60H %DIVIDE_CONSTANT (CREG+1,00H,00H,00H,60H,WAERMELEISTUNG) ;Einheit der W rmeleistung = [W] %DIVIDE_CONSTANT (CREG+1,00H,00H,10H,00H,CREG) ;in CREG steh t jetzt W rmemenge in kJ MOV CREG+4,#00H ;die vier h chstwertigen BCD l schen ,da sie nicht ben tigt werden MOV CREG+5,#00H JBC FLAG_CONVERGENCE,M_T_9 SETB FLAG_CONVERGENCE l ssigung der SJMP M_T_10 statistisch M_T_9: MOV AREG, #01H MOV AREG+1,#00H MOV AREG+2,#00H MOV BREG ,#00H MOV BREG+1,#00H MOV BREG+2,#00H %ADDBCD (WAERME,AREG,06D) rementieren (Konvergenz) M_T_10: memenge %ADDBCD (WAERME,CREG,06D) ;inkrementiert bei jeden 2. Mal ;Waerme um 1 ->Fehler, der durch Vernach ;Nachkommastellen entsteht, konvergiert ;gegen Null

;in AREG steht 1 -> W rmemenge um 1 kJ ink ;addiert Teilw rmemenge (CREG) zur Gesamtw r ;Berechnung Ende

M_T_END: RET $EJECT CR LF

EQU 10D EQU 13D DB DB DB DB DB DB DB DB DB DB DB DB

;ASCII-Code von Carriage-Return ;ASCII-Code von Line-Feed 'Waermemenge 'Vorlauf-Temp GJ',0 ',0DFH,'C ',0 ;0DFH

WAERME_TEXT: VORLAUF_TEMP_TEXT: entspricht RUECKLAUF_TEMP_TEXT: TEMP_DIFFERENZ_TEXT: VOLUMEN_TEXT: WAERMELEISTUNG_TEXT: SELBSTTEST_TEXT: FERNABFRAGE_TEXT: VOL_ZAEHLER_FEHLERTEXT: TEMP_SENSOR_FEHLERTEXT: START_1_TEXT: START_2_TEXT:

'Ruecklauf-Temp ',0DFH,'C ',0 'Temp-Differenz K ',0 'Volumen m3',0 'Waermeleistung kW ',0 'Selbsttest ',0 'Fernabfrage der Messdaten ',0 '-----FEHLER-----Durchflussensor ',CR,LF,0 '-----FEHLER-----Pt100-Sensor ',CR,LF,0 'WAERMEZAEHLER FH Coburg ',CR,LF,0 'Markus Stark Diplom WS 94/95 ',CR,LF,0

WAERME_SENDETEXT: DB WAERME_EINHEIT: DB VOLUMEN_SENDETEXT: DB VOLUMEN_EINHEIT: DB VORLAUF_TEMP_SENDETEXT: DB RUECKLAUF_TEMP_SENDETEXT:DB TEMPERATUR_EINHEIT: DB WAERMELEISTUNG_SENDETEXT:DB WAERMELEISTUNG_EINHEIT: DB WAERME_COEFFICIENT_POINTER: DB 42H,17H J/K/cm^3 DB 42H,07H DB 41H,95H DB 41H,82H DB 41H,75H DB 41H,68H DB 41H,60H DB 41H,53H DB 41H,46H DB 41H,37H DB 41H,29H DB 41H,20H DB 41H,12H DB 41H,04H DB 40H,96H DB 40H,88H DB 40H,80H DB 40H,70H DB 40H,60H DB 40H,50H DB 40H,40H Vollst ndigkeit) END

'Waermemenge: ',0 ' GJ',CR,LF,0 'Volumen: ',0 ' m3',CR,LF,0 'Vorlauftemperatur: ',0 'Ruecklauftemperatur: ',0 ' Grad Celsius',CR,LF,0 'Waermeleistung: ',0 ' kW',CR,LF,CR,LF,0

;spez. W rmekapazit t * Dichte von Wasser bei 0C =4.217 ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; " bei 5C " bei 10C " bei 20C

" bei 40C

" bei 60C

" bei 80C

" bei 100C

(Werte unter 15C und

ber 90C nur wegen