list p=PIC16f876 ;************************************************************** ; ; ; Die Software unterliegt den Bedingungen der ; ; GNU GENERAL PUBLIC LICENSE ; Version 2, June 1991 ; ; Ich übernehmen KEINE Verantwortung für irgendwelche ; Schäden, die durch die Verwendung des Flightloggers ; entstehen. ; ; ;************************************************************** ; ;* Pinbelegung ;* ---------------------------------- ;* PORTA: 0 analog IN (Poll ADC je 2 sek) .. Differenzdrucksensor ;* 1 - ;* 2 - ;* 3 - ;* 4 - ;* 5 - ;* 6 N/A ;* 7 N/A ;* ;* PORTB: 0 LCD Display E ;* 1 LCD Display R/W ;* 2 LCD Display RS ;* 3 digital IN (Interrupt) .. DCF Takt ;* 4 digital IN (Interrupt) .. ON/OFF ;* 5 digital IN (Interrupt) .. Rotary Encoder Taster ;* 6 digital IN (Interrupt) .. Rotary Encoder A ;* 7 digital IN (Interrupt) .. Rotary Encoder B ;* ;* PORTC: 0 Schwingkreis Uhrenquarz, Timer1 ;* 1 Schwingkreis Uhrenquarz, Timer1 ;* 2 - ;* 3 - ;* 4 digital OUT .. LCD Display D4 ;* 5 digital OUT .. LCD Display D5 ;* 6 RS 232, digital OUT .. LCD Display D6 ;* 7 RS 232, digital OUT .. LCD Display D7 ;* ;************************************************************** ; ; (c)TOBIK 06/2003 ; ; GNU GENERAL PUBLIC LICENSE ; Version 2, June 1991 ; ; Verwendet Material von www.sprut.de ; ; FlightLogger - Erfassung von Flugzeiten ; Module ; - Spannungsversorgung Sparbetrieb (OFF) und Normalbetrieb (ON) ; + Entscheidung ON/OFF durch Abfrage von RB4 ; - Prozessor im Sparbetrieb als Quarzuhr ; + Stellen der Uhrzeit nach Einschalten des Sparbetriebs und ; falls Rotary gedrückt beim Einschalten des Normalbetriebs ; - Differenzdruckschalter, später evtl. Drucksensor (Differenzmessung Staudruck-Statischer Druck) ; - LCD Display (Anzeige der Flüge) ; - Rotary Encoder mit Taster zum Blättern im Flugbuch und Konfiguration ; - noch nicht implementiert: Datenübertragung über RS232/IR (Flugzeiten) ; - noch nicht implementiert: DCF77 Funkuhr zum autom. Stellen der Quarzuhr ; ; TOBIK 07/2003 ; - Umstellung von Differenzdruckschalter auf Differenzdrucksensor am ADC RA0 ; + bei jedem Timer1 Interrupt (aller 2 sec) wird eine ADC Messung gestartet ; + Auswertung der Messung im ADC Interrupt ; + Entscheidung Airborne durch Vergleich mit Schwellwert airspeed_schwelle ; + Schwellwert wird im EEPROM gespeichert und ist im Setup einstellbar ; (Istwert airspeed wird im Setup zum Vergleich angezeigt) ; ; TOBIK 18.07.03 ; - Summe Flugzeit akt. Tag / Pilot implementiert ; Wird beim Setup Pilot dahinter angezeigt. ; ; Geplant Anzeige von Checklisten ; Checkliste Start ; - Gurt ; - Tür ; - Schirm ; - Höhenmesser ; - Frequenz ; - Leerlauf ; - Magnet ; - Pumpe ; - Prop frei ; - Start ; - Klappen ein ; - Prop Start ; - Magnetcheck ; - Transponder 0021 ; Checkliste Gegenanflug ; - Prop Start ; - Pumpe ; - Klappen aus ; - Landung ; - Transponder aus ; - Klappen ein ; Prozessor 16F876, 4 Mhz ; ;********************************************************** ; Includedatei für den 16F876 einbinden #include ERRORLEVEL -302 ;SUPPRESS BANK SELECTION MESSAGES ; Configuration festlegen: ; Power on Timer, kein Watchdog, XT-Oscillator, kein Brown out, kein LV-programming __CONFIG _PWRTE_ON & _WDT_OFF & _XT_OSC & _BODEN_OFF & _LVP_OFF ;******************************************************** ; Variablen festlegen w_copy Equ 0x20 ; Backup für Akkuregister s_copy Equ 0x21 ; Backup für Statusregister p_copy equ 0x22 ; Backup für PcLath Register ;16 Bit Rechenregister xw0 equ 0x23 ; xw1 equ 0x24 ; f0 equ 0x25 ; f1 equ 0x26 ; counter equ 0x27 ; Fehler equ 0x28 ; ST equ 0x29 ; SZ equ 0x2A ; SH equ 0x2B ; SE equ 0x2C ; LcdStatus equ 0x2D ; LcdDaten equ 0x2E ; time_sec equ 0x30 ; time_hour equ 0x31 ; time_min equ 0x32 ; date_day equ 0x33 ; date_month equ 0x34 ; date_year equ 0x35 ; rotary_code equ 0x36 ; last read rotary encoder code rotary_code_alt equ 0x37 rotary_diff equ 0x38 rotary_key_alt equ 0x39 loops_mul equ 0x3A loops_ee equ 0x3B loops_rotary equ 0x3C loops_wait equ 0x3D ; timer1 für wait loops_wait2 equ 0x3E ; timer2 für wait airspeed_schwelle equ 0x3F vcc_on equ 0x40 autom_status equ 0x41 cursor_pos equ 0x42 pilot_index equ 0x43 airborne equ 0x44 airborne1 equ 0x45 airborne2 equ 0x46 airspeed equ 0x47 eeprom_addr equ 0x48 ; EEPROM address flash_addr_h equ 0x49 ; FLASH read/write address high part flash_addr_l equ 0x4A ; FLASH read/write address low part flash_data_h equ 0x4B ; FLASH read/write data high part flash_data_l equ 0x4C ; FLASH read/write data low part log_index equ 0x50 ; log_tail equ 0x51 ; log_head equ 0x52 ; log_date_day equ 0x53 ; log_date_month equ 0x54 ; log_date_year equ 0x55 ; log_start_hour equ 0x56 ; log_start_min equ 0x57 ; log_land_hour equ 0x58 ; log_land_min equ 0x59 ; log_dauer_hour equ 0x5A ; log_dauer_min equ 0x5B ; log_pilot equ 0x5C ; sum_flugzeit_hour equ 0x60; sum_flugzeit_min equ 0x61; #define STATUS_STANDBY D'00' ; #define STATUS_PILOT D'01' ; Pilot einstellen #define STATUS_LOG D'02' ; Logbuch ansehen #define STATUS_MAX STATUS_LOG #define STATUS_SET B'10000000' #define STATUS_SET_DAY STATUS_SET + D'01' ; Zeit stellen - Tag #define STATUS_SET_MONTH STATUS_SET + D'02' ; Zeit stellen - Monat #define STATUS_SET_YEAR STATUS_SET + D'03' ; Zeit stellen - Jahr #define STATUS_SET_HOUR STATUS_SET + D'04' ; Zeit stellen - Stunden #define STATUS_SET_MINUTE STATUS_SET + D'05' ; Zeit stellen - Minuten #define STATUS_SET_SCHWELLE STATUS_SET + D'06' ; Schwellwert speed für ADC #define STATUS_SET_MAX STATUS_SET_SCHWELLE #define ROTARY_PORT PORTB #define ROTARY_CODE_SHIFT 0x6; ; Wieviel Bits ist die rotary maske im Byte nach links verschoben? #define ROTARY_CODE_MASK B'11000000' #define ROTARY_KEY_MASK B'00100000' #define ROTARY_KEY_BIT 0x5 #define VCC_ON_MASK B'00010000' #define VCC_ON_BIT 0x4 #define FLASH_FLIGHTLOG_BASIS B'00011100' #define TRUE 1 #define FALSE 0 #define LCD_OFFSET_LINE1 0x00 #define LCD_OFFSET_LINE2 0x40 ; für LCD-Pins #define LcdE PORTB,0 ; enable Lcd #define LcdRs PORTB,2 ; Daten Lcd (nicht control) #define LcdRw PORTB,1 ;3 ; read Lcd #define LcdPort PORTC ; Datenbus des LCD (obere 4 Bit) ;******************************************************** ; EEPROM Data #define EEDATA_PILOT_0 H'00' #define EEDATA_PILOT_1 H'08' #define EEDATA_PILOT_2 H'10' #define EEDATA_PILOT_3 H'18' #define EEDATA_LOGO_0 H'20' #define EEDATA_LOGO_1 H'30' #define EEDATA_STAT_LANDED H'40' #define EEDATA_STAT_AIRBORNE H'48' #define EEDATA_HEAD H'50' #define EEDATA_TAIL H'51' #define EEDATA_SCHWELLE_STAU H'52' #define EEDATA_DUMMY3 H'53' #define EEDATA_DUMMY4 H'54' #define EEDATA_DUMMY5 H'55' #define EEDATA_DUMMY6 H'56' #define EEDATA_DUMMY7 H'57' org H'2100' ; Initialize EEPROM Data de "TOBIK " de "BORCHI " de "TK+BP " de "GAST " de "TOBIKs FlightLog" de "(c)07/2003 V1.01" de " PARKEN " de "FLIEGEN " de 0 ; HEAD Logbuch de 0 ; TAIL Logbuch de D'80' ; Schwelle Stau Druck de 0 ; Dummy 3 de 0 ; Dummy 4 de 0 ; Dummy 5 de 0 ; Dummy 6 de 0 ; Dummy 7 ;******************************************************** ; Einsprungpunkt org 0 goto Init ;******************************************************** ; Interrupt Service Routine org 4 Intvec movwf w_copy ; w retten swapf STATUS, w ; STATUS retten clrf STATUS movwf s_copy movf PCLATH, w ; PCLATH retten movwf p_copy clrf PCLATH ; Bank 0 ; hier folgt die eigentliche Interrupt-Routine Int_serv ; Timer 1 Interrupt Int_serv_timer1 btfss PIR1, TMR1IF ; falls TMR1IF gesetzt... goto Int_serv_timer1_fertig ; ...übergehe Sprung zu nächstem Int_serv_xxx bcf PIR1, TMR1IF ; Interrupt-Flag löschen ; Aller 2 Sekunden: Falls Vcc = ON -> Messung (ADC) Staudruck anschieben Int_serv_timer1_poll_stau movfw vcc_on ; falls vcc_on aus andlw VCC_ON_MASK bz Int_serv_timer1_poll_stau_fertig ; abbruch, sonst ... bsf ADCON0, 0 ; ADC einschalten bsf ADCON0, 2 ; ADC neu starten Int_serv_timer1_poll_stau_fertig ; Uhrzeit und Datum im 2-Sekunden-Takt inkrementieren Int_serv_timer1_time incf time_sec, f incf time_sec, f ; wir haben einen 2-Sekunden-Takt movlw D'60' xorwf time_sec, w bnz Int_serv_timer1_fertig ; sec < 60 -> fertig movlw D'0' movwf time_sec incf time_min, f movlw D'60' xorwf time_min, w bnz Int_serv_timer1_fertig ; min < 60 -> fertig movlw D'0' movwf time_min incf time_hour, f movlw D'24' xorwf time_hour, w bnz Int_serv_timer1_fertig ; std < 24 -> fertig movlw D'0' movwf time_hour incf date_day, f ; Überlauf Tag ? call Days_per_month ; Ergebnis in w addlw 1 xorwf date_day, w bnz Int_serv_timer1_fertig movlw D'1' movwf date_day incf date_month, f movlw D'13' xorwf date_month, w bnz Int_serv_timer1_fertig movlw D'1' movwf date_month incf date_year, f Int_serv_timer1_fertig ; Bei jedem Interrupt ; Poll Betriebsspannung ??? Int_serv_portB_vcc_on movfw PORTB ; falls Spannung ein andlw VCC_ON_MASK bz Int_serv_portB_vcc_on_update movfw vcc_on ; und vcc_on aus andlw VCC_ON_MASK bnz Int_serv_portB_vcc_on_update movlw VCC_ON_MASK movwf vcc_on movlw STATUS_STANDBY movwf autom_status call Set_Options_If_Key_Pressed ; Falls Taste am Rotary, dann Einstellungen call InitLcd ; dann Initialisiere LCD call Ausgabe_Copyright ; und Anzeige Copyright Int_serv_portB_vcc_on_update movfw PORTB ; vcc_on := PortB-VccOn andlw VCC_ON_MASK skpnz movwf vcc_on Int_serv_portB_vcc_on_fertig ; ADC Interrupt Int_serv_ADC btfss PIR1, ADIF ; falls TMR1IF gesetzt... goto Int_serv_ADC_Fertig ; ...übergehe Sprung zu nächstem Int_serv_xxx bcf PIR1, ADIF ; Interrupt-Flag löschen bcf ADCON0, 0 ; ADC ausschalten movfw airborne2 ; airborne2 -> airborne1 movwf airborne1 movlw TRUE movwf airborne2 ; airborne2 := TRUE movfw ADRESH ; ADC Result High Byte movwf airspeed movfw airspeed_schwelle subwf airspeed, w ; - Schwellwert btfss STATUS,C ; falls kleiner Null dann überspringe nächsten Befehl clrf airborne2 ; airborne2 := FALSE movfw airborne2 xorwf airborne1, w ; if (airborne2 != airborne1) bnz Int_serv_ADC_Fertig ; Abbruch movfw airborne1 ; if (airborne2 == airborne1 == airborne) xorwf airborne, w ; Abbruch bz Int_serv_ADC_Fertig movfw airborne1 ; airborne2 == airborne1 -> airborne movwf airborne bz Int_serv_ADC_Landed Int_serv_ADC_airborne call Started goto Int_serv_ADC_Fertig Int_serv_ADC_Landed call Landed Int_serv_ADC_Fertig ; PortB verändert Interrupt Int_serv_portB btfss INTCON, RBIF ; falls RBIF gesetzt ... goto Int_serv_portB_fertig ; ... übergehe Sprung zu nächstem Int_serv_xxx bcf INTCON, RBIF ; Interrupt-Flag löschen call Rotary_Get_Direction ; Rückgabewert in rotary_diff (-1=down, 1=up) movfw rotary_diff skpz call Rotary_Rotated ; Rotary wurde gedreht -> Ereignisbehandlung movfw PORTB ; Doppelte Events ausfiltern andlw ROTARY_KEY_MASK xorwf rotary_key_alt, w bz Int_serv_portB_fertig movfw PORTB ; Status merken andlw ROTARY_KEY_MASK movwf rotary_key_alt movfw PORTB ; Nur drücken zählt, loslassen wird ignoriert andlw ROTARY_KEY_MASK bnz Int_serv_portB_fertig ; falls Bit gesetzt (Pull-Up) ignorieren call Rotary_Key ; Tastendruck erkannt -> Ereignisbehandlung Int_serv_portB_fertig Int_serv_dcf Int_serv_serial movfw vcc_on ; falls Vcc == on bz Int_end ; -> fertig call AnzeigeLCD ; Anzeige aktualisieren Int_end clrf PORTA clrf PORTB clrf PORTC Int_restore movf p_copy, w ; PCLATH zurück movwf PCLATH swapf s_copy, w ; STATUS zurück movwf STATUS swapf w_copy, f ; w zurück mit flags swapf w_copy, w retfie ;******************************************************** ; Das Programm beginnt mit der Initialisierung Init ; ADC initialisieren bsf STATUS, RP0 ; Bank1 movlw B'00001110' ; Ergebnis linksbündig in ADRESH und ADRESL ; RA0 = Analog, Vref+ = Vdd, Vref- = Vss movwf ADCON1 ; bcf STATUS, RP0 ; Bank1 movlw B'01000001' ; ADC = aus, ADC Takt auf 1,25-5 Mhz movwf ADCON0 ; ; Pull UPs bsf STATUS, RP0 ; Bank 1 movlw B'10000010' ; pull-up PortB off, Prescaler TMR0 1:8 movwf OPTION_REG ; Möglichst alle Ports auf Output stellen damit ; während Sleep definierte Potentiale anliegen movlw B'00000001' ; PortA Bit 0 input (Sensor) (0..OUT, 1..IN) movwf TRISA movlw B'11110000' ; PortB Bits 4..7 input (Vdd detection, Rotary) movwf TRISB movlw B'00000000' ; PortC 4..7 outputs (LCD) movwf TRISC bcf STATUS, RP0 ; Bank 0 clrf PORTB movlw D'0' movwf time_hour ; Timer 1 bsf T1CON, TMR1CS ; RCO/1 als Takteingang bsf T1CON, T1OSCEN ; RC0/1 als Schwingkreis bcf T1CON, T1CKPS0 ; Vorteiler 1:1 bcf T1CON, T1CKPS1 ; Vorteiler 1:1 bsf T1CON, T1SYNC ; Synchronisation mit Prozessortakt aus bsf T1CON, TMR1ON ; Timer 1 aktiv ;Uhrzeit initialisieren 01.01.01 00:00 movlw 1 movwf date_day movwf date_month movwf date_year movlw 0 movwf time_hour movwf time_min movwf time_sec ;Variablen initalisieren bsf vcc_on, VCC_ON_BIT clrf pilot_index clrf airborne clrf airborne1 clrf airborne2 movlw EEDATA_HEAD ; Pointer Anfang Flightlog aus dem EEPROM laden movwf eeprom_addr call EEPROM_Load movwf log_head movlw EEDATA_TAIL ; Pointer Ende Flightlog aus dem EEPROM laden movwf eeprom_addr call EEPROM_Load movwf log_tail movlw EEDATA_SCHWELLE_STAU ; Schwelle aus dem EEPROM laden movwf eeprom_addr call EEPROM_Load movwf airspeed_schwelle ;Setze Status Einstellungen falls Taste beim Einschalten gedrückt call Set_Options ;Display initialisieren call InitLcd call Ausgabe_Copyright ; Interrupts für Uhren-Schwingkreis an RC0/RC1 (Timer1) zulassen ; Interrupts für Messung (ADC) Staudruck zulassen ; Interrupts für Peripherie (PortB Signale) zulassen Init_Interrupts bcf PIR1, TMR1IF ; Clear interrupt flag Timer1 bcf PIR1, ADIF ; Clear interrupt flag ADC bsf STATUS, RP0 ; Bank 1 bsf PIE1, TMR1IE ; Set interrupt Timer1 enabled bsf PIE1, ADIE ; Set interrupt ADC enabled bcf STATUS, RP0 ; Bank 0 bsf INTCON, PEIE ; Peripheral interrupts enabled bsf INTCON, RBIE bsf INTCON, GIE ; Interrupts general enabled Mainloop bsf INTCON, GIE ; Interrupts wieder erlauben sleep goto Mainloop AnzeigeLCD movfw autom_status xorlw STATUS_LOG bz Mainloop_Ausgabe_Log movfw autom_status xorlw STATUS_SET_SCHWELLE bz Mainloop_Ausgabe_Set_Schwelle Mainloop_Ausgabe_Standard call Ausgabe_goto00 ; Cursor -> 0,0 ; Tag movf date_day, w ; Tag nach W movwf f0 call B2D ; Wandlung in dezimal nach ST,SH,SH,SE call Ausgabe_2ziffern; anzeigen am LCD movlw '.' call OutLcdDaten ; Monat movf date_month, w ; Monat nach W movwf f0 call B2D ; Wandlung in dezimal nach ST,SH,SH,SE call Ausgabe_2ziffern; anzeigen am LCD movlw '.' call OutLcdDaten ; Jahr movf date_year, w ; Jahr nach W movwf f0 call B2D ; Wandlung in dezimal nach ST,SH,SH,SE call Ausgabe_2ziffern; anzeigen am LCD ; Stunde movlw D'11' call Ausgabe_gotoW ; Cursor -> 0,11 movf time_hour, w ; Stunde nach W movwf f0 call B2D ; Wandlung in dezimal nach ST,SH,SH,SE call Ausgabe_2ziffern; anzeigen am LCD movlw ':' call OutLcdDaten ; Minute movf time_min, w ; Minute nach W movwf f0 call B2D ; Wandlung in dezimal nach ST,SH,SH,SE call Ausgabe_2ziffern; anzeigen am LCD ; Sekunde ; movlw LCD_OFFSET_LINE2 + D'9' ; call Ausgabe_gotoW ; Cursor -> 1,9 ; movf time_sec, w ; Sekunde nach W ; movwf f0 ; call B2D ; Wandlung in dezimal nach ST,SH,SH,SE ; call Ausgabe_2ziffern; anzeigen am LCD ; Pilot call Ausgabe_goto10 ; Cursor -> 1,0 movfw pilot_index ; w = pilot_index * 8 movwf f0 movlw D'8' call Mul8 movwf eeprom_addr ; eeprom_add = w (Adresse des Strings) movlw D'8' movwf loops_ee ; Länge des Strings = 8 call Ausgabe_EEString movfw autom_status xorlw STATUS_PILOT bnz Ausgabe_Flugstatus Ausgabe_Sum_Flugzeit call Get_Flugzeit ; Flugzeit Stunde movlw LCD_OFFSET_LINE2 + D'9' call Ausgabe_gotoW ; Cursor -> 1,11 movlw B'11110110' ; S call OutLcdDaten movlw ' ' call OutLcdDaten movf sum_flugzeit_hour, w ; Stunde nach W movwf f0 call B2D ; Wandlung in dezimal nach ST,SH,SH,SE call Ausgabe_2ziffern; anzeigen am LCD movlw '.' call OutLcdDaten ; Flugzeit Minute movf sum_flugzeit_min, w ; Minute nach W movwf f0 call B2D ; Wandlung in dezimal nach ST,SH,SH,SE call Ausgabe_2ziffern; anzeigen am LCD goto Mainloop_Cursor ; Flug-Status Ausgabe_Flugstatus movlw LCD_OFFSET_LINE2 + D'9' call Ausgabe_gotoW ; Cursor -> 1,9 movfw airborne ; Auswahl des n-ten Strings im Array movwf f0 movlw D'8' call Mul8 ; w = airborne {0,1} * 4 addlw EEDATA_STAT_LANDED ; w = w + Adresse erster String im Array movwf eeprom_addr ; eeprom_add = w (Adresse des Strings) movlw D'7' movwf loops_ee ; Länge des Strings = 7 call Ausgabe_EEString goto Mainloop_Cursor Mainloop_Cursor cursor_pilot movlw B'00001100' ; display on, cursor off, blinken off call OutLcdControl movfw autom_status xorlw STATUS_PILOT bnz cursor_set_schwelle movlw LCD_OFFSET_LINE2 movwf cursor_pos goto cursor_move cursor_set_date movf autom_status, w andlw STATUS_SET ; falls bit 7 nicht gesetzt -> kein SET-STATUS bz Ausgabe_LCD_Fertig movf autom_status, w ; cursor_pos = autom_status andlw B'01111111' movwf cursor_pos movlw 1 subwf cursor_pos, f ; cursor_pos = cursor_pos - 1 movlw D'3' movwf f0 movf cursor_pos, w call Mul8 movwf cursor_pos andlw B'00011000' ; if (cursor_pos > 7) bz cursor_move movlw D'2' ; cursor_pos = cursor_pos + 2 addwf cursor_pos, f cursor_move movf cursor_pos, w ; set cursor_pos call Ausgabe_gotoW movlw B'00001111' ; display on, cursor on, blinken on call OutLcdControl goto Ausgabe_LCD_Fertig Mainloop_Ausgabe_Set_Schwelle call Ausgabe_goto00 ; Cursor -> 1,0 movlw 'S' call OutLcdDaten movlw 'c' call OutLcdDaten movlw 'h' call OutLcdDaten movlw 'w' call OutLcdDaten movlw 'e' call OutLcdDaten movlw 'l' call OutLcdDaten movlw 'l' call OutLcdDaten movlw 'e' call OutLcdDaten movlw ' ' call OutLcdDaten movlw 'S' call OutLcdDaten movlw 'p' call OutLcdDaten movlw 'e' call OutLcdDaten movlw 'e' call OutLcdDaten movlw 'd' call OutLcdDaten call Ausgabe_goto10 ; Cursor -> 1,0 movlw 'S' call OutLcdDaten movlw 'o' call OutLcdDaten movlw 'l' call OutLcdDaten movlw 'l' call OutLcdDaten movlw ':' call OutLcdDaten movfw airspeed_schwelle movwf f0 call B2D ; Wandlung in dezimal nach ST,SH,SH,SE call Ausgabe_3ziffern; anzeigen am LCD movlw ' ' call OutLcdDaten movlw 'I' call OutLcdDaten movlw 's' call OutLcdDaten movlw 't' call OutLcdDaten movlw ':' call OutLcdDaten movfw airspeed movwf f0 call B2D ; Wandlung in dezimal nach ST,SH,SH,SE call Ausgabe_3ziffern; anzeigen am LCD cursor_set_schwelle movfw autom_status xorlw STATUS_SET_SCHWELLE bnz cursor_set_date movlw LCD_OFFSET_LINE2 + D'5' movwf cursor_pos goto cursor_move goto Ausgabe_LCD_Fertig Mainloop_Ausgabe_Log movlw B'00001100' ; display on, cursor off, blinken off call OutLcdControl call Ausgabe_goto00 ; Cursor -> 0,0 ; Log Datum Tag movfw log_date_day ; Tag nach W movwf f0 call B2D ; Wandlung in dezimal nach ST,SH,SH,SE call Ausgabe_2ziffern; anzeigen am LCD movlw '.' call OutLcdDaten ; Log Datum Monat movfw log_date_month ; Monat nach W movwf f0 call B2D ; Wandlung in dezimal nach ST,SH,SH,SE call Ausgabe_2ziffern; anzeigen am LCD movlw '.' call OutLcdDaten ; Log Datum Jahr movfw log_date_year ; Jahr nach W movwf f0 call B2D ; Wandlung in dezimal nach ST,SH,SH,SE call Ausgabe_2ziffern; anzeigen am LCD ; Log Pilot movlw ' ' call OutLcdDaten movfw log_pilot ; w = log_pilot * 8 movwf f0 movlw D'8' call Mul8 movwf eeprom_addr ; eeprom-adresse = w (Adresse des Strings) movlw D'4' movwf loops_ee ; Länge des Strings = 8 call Ausgabe_EEString ; Log Index movlw ' ' call OutLcdDaten movfw log_index ; Minute nach W movwf f0 call B2D ; Wandlung in dezimal nach ST,SH,SH,SE call Ausgabe_2ziffern; anzeigen am LCD ; Log Start Stunde call Ausgabe_goto10 ; Cursor -> 1,0 movfw log_start_hour ; Stunde nach W movwf f0 call B2D ; Wandlung in dezimal nach ST,SH,SH,SE call Ausgabe_2ziffern; anzeigen am LCD ; Log Start Minute movlw ':' call OutLcdDaten movfw log_start_min ; Minute nach W movwf f0 call B2D ; Wandlung in dezimal nach ST,SH,SH,SE call Ausgabe_2ziffern; anzeigen am LCD ; Log Landung Stunde movlw '-' call OutLcdDaten movfw log_land_hour ; Stunde nach W movwf f0 call B2D ; Wandlung in dezimal nach ST,SH,SH,SE call Ausgabe_2ziffern; anzeigen am LCD ; Log Landung Minute movlw ':' call OutLcdDaten movfw log_land_min ; Minute nach W movwf f0 call B2D ; Wandlung in dezimal nach ST,SH,SH,SE call Ausgabe_2ziffern; anzeigen am LCD ; Log Dauer Stunde movfw log_dauer_hour ; Stunde nach W movwf f0 call B2D ; Wandlung in dezimal nach ST,SH,SH,SE call Ausgabe_2ziffern; anzeigen am LCD ; Log Dauer Minute movlw ':' call OutLcdDaten movfw log_dauer_min ; Minute nach W movwf f0 call B2D ; Wandlung in dezimal nach ST,SH,SH,SE call Ausgabe_2ziffern; anzeigen am LCD movlw D'11' + LCD_OFFSET_LINE2 call Ausgabe_gotoW movlw ' ' call OutLcdDaten movlw D'14' ; set cursor_pos call Ausgabe_gotoW movlw B'00001111' ; display on, cursor on, blinken on call OutLcdControl goto Ausgabe_LCD_Fertig Ausgabe_LCD_Fertig return ;********************************************************************* ;Setzt Status Einstellungen falls Taste am Rotary Encoder gedrückt ; Zum Aufruf während Erststart und beim Einschalten ; @param PORTB .. Port des Rotary Encoders ; @return autom_status .. STATUS_SET_DAY falls Taste gedrückt, sonst unverändert Set_Options_If_Key_Pressed movfw PORTB andlw ROTARY_KEY_MASK movwf rotary_key_alt btfsc PORTB, ROTARY_KEY_BIT ; Taste ist gedrückt return Set_Options movlw STATUS_SET_DAY movwf autom_status ; -> Status "Zeit stellen" return ;********************************************************************* ;Ermittelt die Drehrichtung des Encoders ; - Abfrage des aktuellen Encoder Codes am Port ; - 00 und 11 können gerastet werden und bewirken ein inc/dec ; - 01 und 10 sind Übergangscodes und werden nur gemerkt ; - Vergleich mit letztem Code ; ; XOR | 01 | 10 ; ----+-----------+-------- ; 00 | 01 Down | 10 Up ; 11 | 10 Up | 01 Down ; ; ; @param rotary_code .. letzter bekannter Code ; @return rotary_diff .. +1/-1 -> Up/Down ; Rotary_Get_Direction movf rotary_code, w ; rotary_code -> rotary_code_alt movwf rotary_code_alt movf ROTARY_PORT, w ; Neuen Code am Port abholen und movwf rotary_code ; in rotary_code merken movlw ROTARY_CODE_SHIFT ; bis Anschlag nach rechts schieben movwf loops_rotary Rotary_Get_Direction_Shift rrf rotary_code, f decfsz loops_rotary, f ; loops complete? goto Rotary_Get_Direction_Shift ; no, go again movlw B'00000011' andwf rotary_code, f movf rotary_code_alt, w xorwf rotary_code, w bz Rotary_Get_Direction_None Rotary_Get_Direction_Test11 movlw B'00000001' ; Test 01 xorwf rotary_code, w bz Rotary_Get_Direction_None ; keine Rotation bei 01 Rotary_Get_Direction_Test00 movlw B'00000010' ; Test 10 xorwf rotary_code, w bz Rotary_Get_Direction_None ; keine Rotation bei 10 Rotary_Get_Direction_Dir movf rotary_code_alt, w xorwf rotary_code, w andlw B'00000001' bz Rotary_Get_Direction_Up Rotary_Get_Direction_Down movlw -1 ; DOWN movwf rotary_diff return Rotary_Get_Direction_Up movlw 1 ; UP movwf rotary_diff return Rotary_Get_Direction_None movlw 0 ; NONE movwf rotary_diff return ;********************************************************************* ;Rotary-Encoder wurde gedreht ; Diese Routine wird aus dem PortB Interrupt gerufen ; @param rotary_diff .. Drehrichtung und Distanz der Bewegung (-1/0/1) ; @return time_*/date_* .. Neue Uhrzeit/Datum Rotary_Rotated Rotary_Ro_status_log movlw STATUS_LOG xorwf autom_status, w bnz Rotary_Ro_status_pilot movfw rotary_diff addwf log_index, f Rotary_Ro_status_log_lower btfss rotary_diff, 7 ; falls Differenz negativ goto Rotary_Ro_status_log_upper movfw log_tail ; Test untere Grenze addlw -1 xorwf log_index, w skpnz incf log_index, f Rotary_Ro_status_log_upper btfsc rotary_diff, 7 ; falls Differenz positiv goto Rotary_Ro_status_log_read_flash movfw log_head ; Test obere Grenze addlw 1 xorwf log_index, w skpnz decf log_index, f Rotary_Ro_status_log_read_flash call Decode_Flight_Log Rotary_Ro_status_pilot movlw STATUS_PILOT xorwf autom_status, w bnz Rotary_Ro_status_set_day movfw rotary_diff addwf pilot_index, f Rotary_Ro_status_pilot_lower movlw -1 ; Test überlauf Unten xorwf pilot_index, w bnz Rotary_Ro_status_pilot_upper movlw 3 movwf pilot_index Rotary_Ro_status_pilot_upper movlw D'4' ; Test überlauf Oben xorwf pilot_index, w bnz Rotary_Ro_status_set_day movlw 0 movwf pilot_index Rotary_Ro_status_set_day movlw STATUS_SET_DAY xorwf autom_status, w bnz Rotary_Ro_status_set_month movf rotary_diff, w addwf date_day, f Rotary_Ro_status_set_day_lower movlw 0 ; Test überlauf Unten xorwf date_day, w bnz Rotary_Ro_status_set_day_upper movlw D'31' movwf date_day Rotary_Ro_status_set_day_upper movlw D'32' ; Test überlauf Oben xorwf date_day, w bnz Rotary_Ro_status_set_month movlw 1 movwf date_day Rotary_Ro_status_set_month movlw STATUS_SET_MONTH xorwf autom_status, w bnz Rotary_Ro_status_set_year movf rotary_diff, w addwf date_month, f Rotary_Ro_status_set_month_lower movlw 0 ; Test überlauf Unten xorwf date_month, w bnz Rotary_Ro_status_set_month_upper movlw D'12' movwf date_month Rotary_Ro_status_set_month_upper movlw D'13' ; Test überlauf Oben xorwf date_month, w bnz Rotary_Ro_status_set_year movlw 1 movwf date_month Rotary_Ro_status_set_year movlw STATUS_SET_YEAR xorwf autom_status, w bnz Rotary_Ro_status_set_hour movf rotary_diff, w addwf date_year, f Rotary_Ro_status_set_year_lower movlw -1 ; Test überlauf Unten xorwf date_year, w bnz Rotary_Ro_status_set_year_upper movlw D'31' movwf date_year Rotary_Ro_status_set_year_upper movlw D'32' ; Test überlauf Oben xorwf date_year, w bnz Rotary_Ro_status_set_hour movlw 0 movwf date_year Rotary_Ro_status_set_hour movlw STATUS_SET_HOUR xorwf autom_status, w bnz Rotary_Ro_status_set_min movf rotary_diff, w addwf time_hour, f Rotary_Ro_status_set_hour_lower movlw -1 xorwf time_hour, w ; Test überlauf Unten bnz Rotary_Ro_status_set_hour_upper movlw D'23' movwf time_hour Rotary_Ro_status_set_hour_upper movlw D'24' ; Test überlauf Oben xorwf time_hour, w bnz Rotary_Ro_status_set_min movlw 0 movwf time_hour Rotary_Ro_status_set_min movlw STATUS_SET_MINUTE xorwf autom_status, w bnz Rotary_Ro_status_set_schwelle movf rotary_diff, w addwf time_min, f movf time_sec, w xorwf time_sec, f Rotary_Ro_status_set_min_lower movlw -1 xorwf time_min, w ; Test überlauf Unten bnz Rotary_Ro_status_set_min_upper movlw D'59' movwf time_min Rotary_Ro_status_set_min_upper movlw D'60' ; Test überlauf Oben xorwf time_min, w bnz Rotary_Ro_status_set_schwelle movlw 0 movwf time_min Rotary_Ro_status_set_schwelle movlw STATUS_SET_SCHWELLE xorwf autom_status, w bnz Rotary_Ro_status_set_sch_fertig movf rotary_diff, w addwf airspeed_schwelle, f Rotary_Ro_status_set_sch_lower movlw -1 xorwf airspeed_schwelle, w ; Test überlauf Unten bnz Rotary_Ro_status_set_sch_upper movlw D'254' movwf airspeed_schwelle Rotary_Ro_status_set_sch_upper movlw D'255' ; Test überlauf Oben xorwf airspeed_schwelle, w bnz Rotary_Ro_status_set_sch_fertig movlw 0 movwf airspeed_schwelle Rotary_Ro_status_set_sch_fertig Rotary_Ro_status_set_fertig return ;********************************************************************* ;Rotary-Encoder-Taste wurde gedrückt ; Diese Routine wird aus dem PortB Interrupt gerufen ; @return status .. Neuer Status Rotary_Key incf autom_status, f ; status := status + 1 movlw STATUS_MAX + 1 xorwf autom_status, w skpnz clrf autom_status ; status := 0 movlw STATUS_SET_MAX + 1 xorwf autom_status, w bnz Rotary_Key_Check_Log_Status ; falls status = STATUS_SET_MAX + 1 (Fertig SET) clrf autom_status ; status := 0 movlw EEDATA_SCHWELLE_STAU ; Schwelle Airspeed im EEPROM speichern movwf eeprom_addr ; Adresse in die gespeichert wird movfw airspeed_schwelle ; Daten zum Speichern call EEPROM_Save Rotary_Key_Check_Log_Status movlw STATUS_LOG xorwf autom_status, w bnz Rotary_Key_No_Log_Status Rotary_Key_Log_Status movfw log_head movwf log_index call Decode_Flight_Log Rotary_Key_No_Log_Status return ;********************************************************************* ;Decodiere kompletten Flight Log (4 Worte) ; @param log_index .. Index des FlightLogs im FLASH ; @return log_date_* .. Datum ; @return log_start_* .. Uhrzeit Start ; @return log_land_* .. Uhrzeit Landung ; @return log_pilot .. Pilot Decode_Flight_Log movlw FLASH_FLIGHTLOG_BASIS ; High-Adresse der zu ladenden FLASH Speicherzelle movwf flash_addr_h movfw log_index ; Low--Adresse der zu ladenden FLASH Speicherzelle movwf flash_addr_l call FLASH_Load call FDate_Decode ; Decode in log_date_* incf flash_addr_h, f call FLASH_Load call FTimePilot_Decode ; Decode des Starts (Ergebnis in Landung!!!) movfw log_land_hour ; Verschieben des Ergebnis von Landung nach Start movwf log_start_hour movfw log_land_min movwf log_start_min incf flash_addr_h, f call FLASH_Load call FTimePilot_Decode ; Decode Landung incf flash_addr_h, f call FLASH_Load call FDetails_Decode ; Decode Details ; Falls airborne und log_index == aktueller Flug movfw airborne andlw 1 bz Calc_Diff movfw log_index xorwf log_head, w bnz Calc_Diff ; dann Landung mit der aktuellen Zeit und Pilot füllen movfw pilot_index movwf log_pilot movfw time_hour movwf log_land_hour movfw time_min movwf log_land_min ;Differenz zwischen zwei Zeitenpunkten bilden ; @param log_start_* ; @param log_land_* ; @return log_dauer_* Calc_Diff movfw log_start_hour ; Stunde subwf log_land_hour, w movwf log_dauer_hour ; Dauer = Landung - Start movfw log_start_min ; Minute subwf log_land_min, w movwf log_dauer_min ; Dauer = Landung - Start btfss log_dauer_min, 7 ; Falls Dauer Minuten negativ, Übertrag berechnen goto Calc_Diff_Fertig ; sonst Abbruch movlw D'60' ; Übertrag berechnen addwf log_dauer_min, f ; Minute = 60 + negative Minuten decf log_dauer_hour, f ; Stunde = Stunde - 1 Calc_Diff_Fertig return ;********************************************************************* ;Get Summe Flugzeit Heute ; @param pilot_index .. Pilot für welchen die Summe gebildet wird ; @param date_* .. Datum für welches die Summe gebildet wird ; @return sum_flugzeit_* .. Summe Flugzeit (hour, min) ; @return sum_flugzeit_min .. Summe Flugzeit Minuten Get_Flugzeit clrf sum_flugzeit_hour ; result = 0; clrf sum_flugzeit_min movfw log_head movwf log_index ; log_index = head Get_Flugzeit_Loop_Sum movfw log_index ; if (log_index == log_tail) xorwf log_tail, w skpnz return ; return call Decode_Flight_Log ; Lese Flug aus EEProm in log_date_*, log_pilot ; und berechnet log_dauer_* movfw date_day ; if (Datum != heute) xorwf log_date_day, w skpz return movfw date_month xorwf log_date_month, w skpz return movfw date_year xorwf log_date_year, w skpz return ; return movfw pilot_index ; if (log_pilot != pilot_index) xorwf log_pilot, w bnz Get_Flugzeit_Loop_Sum_Continue ; continue ; Summe Flugzeit += Flugdauer movfw log_dauer_min addwf sum_flugzeit_min, f movfw log_dauer_hour addwf sum_flugzeit_hour, f ; Überlauf behandeln movlw D'60' subwf sum_flugzeit_min, w bnc Get_Flugzeit_Loop_Sum_Continue ; kein Überlauf subwf sum_flugzeit_min, f incf sum_flugzeit_hour, f Get_Flugzeit_Loop_Sum_Continue decf log_index, f goto Get_Flugzeit_Loop_Sum ;********************************************************************* ;Start des Flugzeuges ; @param date_* .. Datum ; @param time_* .. Uhrzeit ; @param pilot_index .. Pilot Started ; Überprüfung auf Erststart movfw log_head ; falls log_head == 0 bnz Started_kein_ersttart xorwf log_tail, w ; und log_head == log_tail bnz Started_kein_ersttart movlw 1 movwf log_head ; dann log_head := 1 movwf log_tail ; und log_tail := 1 goto Started_write_eedata Started_kein_ersttart incf log_head, f movfw log_head xorwf log_tail, w skpnz incf log_tail, f ; HEAD und TAIL in EEPROM schreiben Started_write_eedata movlw EEDATA_HEAD ; Adresse in die gespeichert wird movwf eeprom_addr movfw log_head ; Daten zum Speichern call EEPROM_Save movlw EEDATA_TAIL ; Adresse in die gespeichert wird movwf eeprom_addr movfw log_tail ; Daten zum Speichern call EEPROM_Save movfw log_head movwf flash_addr_l movlw FLASH_FLIGHTLOG_BASIS movwf flash_addr_h call FDate_Encode ; Datum codieren und call FLASH_Save ; in FLASH schreiben incf flash_addr_h, f call FTimePilot_Encode ; Uhrzeit codieren und call FLASH_Save ; in FLASH schreiben clrf flash_data_l ; Landezeit und Details initialisieren clrf flash_data_h incf flash_addr_h, f call FLASH_Save ; in FLASH schreiben incf flash_addr_h, f call FLASH_Save ; in FLASH schreiben return ;********************************************************************* ;Landung des Flugzeuges ; @param date_* .. Datum ; @param time_* .. Uhrzeit ; @param pilot_index .. Pilot Landed ; HEAD und TAIL in EEPROM schreiben movfw log_head movwf flash_addr_l movlw FLASH_FLIGHTLOG_BASIS + 2 movwf flash_addr_h call FTimePilot_Encode ; Uhrzeit codieren und call FLASH_Save ; in FLASH schreiben incf flash_addr_h, f call FDetails_Encode ; Uhrzeit codieren und call FLASH_Save ; in FLASH schreiben return ;********************************************************************* ;Datum zum Speichern im FLASH codieren ; data_high data_low ; ----------------------------- ; 5 4 3 2 1 0 7 6 5 4 3 2 1 0 ; J Tag______ Jahr___ Monat__ ; ; @param date_* .. Datum ; @return flash_data_l .. data low byte ; @return flash_data_h .. data high byte FDate_Encode movfw date_year movwf flash_data_h ; Jahr in data_high movwf flash_data_l ; Jahr in data_low swapf flash_data_l, f ; Nibbles in data_low austauschen (Bits 0..3 des Jahres sind jetzt in Bits 4..7 von data_low) movlw B'11110000' andwf flash_data_l, f ; Alle Bits im low-nibble ausblenden/löschen movfw date_month andlw B'00001111' ; Bits 0..3 des Monats iorwf flash_data_l, f ; in data_low einblenden rlf flash_data_h, f ; Ein Bit nach links (Bit 4 des Jahres ist jetzt in Bit 5 von data_high) movlw B'00100000' andwf flash_data_h, f ; Alle Bits ausser Bit 5 in data_high ausblenden/löschen movfw date_day andlw B'00011111' ; Bits 0..4 des Tages iorwf flash_data_h, f ; in data_high einblenden return ;********************************************************************* ;Datum nach Lesen aus dem FLASH decodieren ; data_high data_low ; ----------------------------- ; 5 4 3 2 1 0 7 6 5 4 3 2 1 0 ; J Tag______ Jahr___ Monat__ ; ; @param flash_data_l .. data low byte ; @param flash_data_h .. data high byte ; @return log_date_* .. Datum FDate_Decode movfw flash_data_l movwf log_date_month ; data_low in Monat movwf log_date_year ; data_low in Jahr swapf log_date_year, f ; swap nibbles in Jahr movlw B'00001111' andwf log_date_month, f ; Bits 4..7 ausblenden aus Monat andwf log_date_year, f ; Bits 4..7 ausblenden aus Jahr movfw flash_data_h movwf log_date_day ; data_high in Tag movlw B'00011111' ; Bits 5..7 ausblenden aus Tag btfsc flash_data_h, 5 ; Falls in data_high das Bit 5 gesetzt ist bsf log_date_year, 4 ; Bit 4 im Jahr setzen return ;********************************************************************* ;Uhrzeit und Pilot zum Speichern im FLASH codieren ; data_high data_low ; ----------------------------- ; 5 4 3 2 1 0 7 6 5 4 3 2 1 0 ; P Stunde___ Pil Minute_____ ; ; @param time_* .. Uhrzeit ; @param pilot_index .. Pilot ; @return flash_data_l .. data low byte ; @return flash_data_h .. data high byte FTimePilot_Encode movfw time_min andlw B'00111111' ; Bits 0..5 der Minute movwf flash_data_l movfw time_hour andlw B'00011111' ; Bits 0..4 der Stunde movwf flash_data_h ; nach data_high btfsc pilot_index, 0 ; Falls beim Pilot das Bit 0 gesetzt ist bsf flash_data_l, 6 ; Bit 6 in data_low setzen btfsc pilot_index, 1 ; Falls beim Pilot das Bit 1 gesetzt ist bsf flash_data_l, 7 ; Bit 7 in data_low setzen btfsc pilot_index, 2 ; Falls beim Pilot das Bit 2 gesetzt ist bsf flash_data_h, 5 ; Bit 5 in data_high setzen return ;********************************************************************* ;Uhrzeit und Pilot nach Lesen aus dem FLASH decodieren ; data_high data_low ; ----------------------------- ; 5 4 3 2 1 0 7 6 5 4 3 2 1 0 ; P Stunde___ Pil Minute_____ ; ; @param flash_data_l .. data low byte ; @param flash_data_h .. data high byte ; @return log_land_* .. Uhrzeit ; @return pilot_index .. Pilot FTimePilot_Decode movfw flash_data_l movwf log_land_min ; data_low in Minute movlw B'00111111' andwf log_land_min, f ; Bits 6..7 ausblenden aus Minute movfw flash_data_h ; data_high in Stunde movwf log_land_hour movlw B'00011111' andwf log_land_hour, f ; Bits 5..7 ausblenden aus Stunde clrf log_pilot btfsc flash_data_l, 6 ; Falls in data_high das Bit 5 gesetzt ist bsf log_pilot, 0 ; Bit 2 beim Pilot setzen btfsc flash_data_l, 7 ; Falls in data_high das Bit 5 gesetzt ist bsf log_pilot, 1 ; Bit 2 beim Pilot setzen btfsc flash_data_h, 5 ; Falls in data_high das Bit 5 gesetzt ist bsf log_pilot, 2 ; Bit 2 beim Pilot setzen return ;********************************************************************* ;Flug-Details zum Speichern im FLASH codieren ; data_high data_low ; ----------------------------- ; 5 4 3 2 1 0 7 6 5 4 3 2 1 0 ; - - - - - - - - - - - - - - ; ; Achtung: Bisher wurden keine Details definiert ; - geplant sind Preis (Euro/Cent) oder Preis-Index ; ; @return flash_data_l .. data low byte ; @return flash_data_h .. data high byte FDetails_Encode clrf flash_data_h clrf flash_data_l return ;********************************************************************* ;Flug-Details nach Lesen aus dem FLASH decodieren ; data_high data_low ; ----------------------------- ; 5 4 3 2 1 0 7 6 5 4 3 2 1 0 ; - - - - - - - - - - - - - - ; ; Achtung: Bisher wurden keine Details definiert ; - geplant sind Preis (Euro/Cent) oder Preis-Index ; ; @param flash_data_l .. data low byte ; @param flash_data_h .. data high byte FDetails_Decode return ;********************************************************************* ;Tage pro Monat ; @param date_month .. Monat ; @param date_year .. Schaltjahr ??? ; @return w .. Anzahl der Tage Days_per_month movlw D'2' ; Test Februar xorwf date_month, w bnz Days_per_month_test_30 movlw B'00000011' ; Februar ! andwf date_year, w ; Test Schaltjahr bz Days_per_month_schaltjahr movlw D'28' ; Kein Schaltjahr return Days_per_month_schaltjahr movlw D'29' return Days_per_month_test_30 ; Monate mit 30 Tagen movlw D'4' ; April xorwf date_month, w bz Days_per_month_30 movlw D'6' ; Juni xorwf date_month, w bz Days_per_month_30 movlw D'9' ; September xorwf date_month, w bz Days_per_month_30 movlw D'11' ; November xorwf date_month, w bz Days_per_month_30 Days_per_month_31 movlw D'31' return Days_per_month_30 movlw D'30' return ;***************************************************** ;8 bit Multiplikation f0 := f0 * w ;@param w .. Multiplikator ;@param f0 .. Multiplikator ;@return w .. Ergebnis ;@return f0 .. Ergebnis Mul8 movwf loops_mul bnz Mul8_ok movlw 0 movwf f0 Mul8_ok movf f0, w Mul8_loop decf loops_mul, f skpnz goto Mul8_fertig addwf f0, f ; cursor_pos = cursor_pos * 3 goto Mul8_loop Mul8_fertig movf f0, w return ;***************************************************** ;16 bit Adition, C-Flag bei Überlauf gesetzt Add16 ; 16-bit add: f := f + xw movf xw0,W ; xw0 nach W addwf f0,F ; f0 := f0 + xw0 movf xw1,W ; xw1 nach W btfsc STATUS,C ; fall ein Überlauf auftrat: incfsz xw1,W ; xw1+1 nach W addwf f1,F ; f1 := f1 + xw1 return ; fertig ;***************************************************** ; 16 Bit Subtraktion, bei Überlauf (neg. Ergebnis) ist C gesetzt Sub16 ; 16 bit f:=f-xw clrf Fehler ; extraflags löschen movf xw0, w ; f0:=f0-xw0 subwf f0, f btfsc STATUS,C goto Sub16a movlw 0x01 ; borgen von f1 subwf f1, f btfss STATUS,C bsf Fehler, C ; Unterlauf Sub16a movf xw1,w ; f1:=f1-xw1 subwf f1 ,f btfss STATUS,C bsf Fehler, C ; Unterlauf bcf STATUS, C ; C-Flag invertieren btfsc Fehler, C bsf STATUS, C return ;***************************************************** ; Wandlung einer Binärzahl (< 100) in eine Dezimalzahl ; Die Binärzahl steht in f1,f0 ; die Dezimalstellen werden in ; ST (tausender), ; SH (hunderter), ; SZ (zehner) und ; SE (einer) gespeichert im BCD-Code B2D ; Test auf tausender 1000d = 0x03E8 movlw 0x03 movwf xw1 movlw 0xE8 movwf xw0 call B2Da movwf ST ; Test auf hunderter 100d = 0x0064 clrf xw1 movlw 0x64 movwf xw0 call B2Da movwf SH ; Test auf zehner 10d = 0x000A clrf xw1 movlw 0x0A movwf xw0 call B2Da movwf SZ movfw f0 movwf SE return B2Da clrf counter B2Sb incf counter, f ; wie oft abgezogen? call Sub16 ; f:=f-xw btfss STATUS, C ; zu oft abgezogen? goto B2Sb ; nein: noch einmal call Add16 ; f:=f+xw decf counter, w ; weil immer 1 zuviel gezählt wird return ;***************************************************** ;Speichern eines Flash Wortes ; @param flash_addr_h .. High-Adresse der zu speichernden FLASH Speicherzelle ; @param flash_addr_l .. Low--Adresse der zu speichernden FLASH Speicherzelle ; @param flash_data_h .. High-Daten ; @param flash_data_l .. Low--Daten FLASH_Save MOVFW flash_addr_h ; High Teil der Adresse nach w BSF STATUS, RP1 ; BCF STATUS, RP0 ; EEADR und EEDATA liegen in der Bank 2 MOVWF EEADRH ; High Teil der Adresse 120h ist 1h BCF STATUS, RP1 ; Bank 0 MOVFW flash_addr_l ; BSF STATUS, RP1 ; Bank 2 MOVWF EEADR ; Low Teil der Adresse 120h ist 20h BCF STATUS, RP1 ; Bank 0 MOVFW flash_data_h ; BSF STATUS, RP1 ; Bank 2 MOVWF EEDATH ; High Teil des Datenworts 204h ist 2h BCF STATUS, RP1 ; Bank 0 MOVFW flash_data_l ; BSF STATUS, RP1 ; Bank 2 MOVWF EEDATA ; Low Teil des Datenworts 204h ist 4h BSF STATUS, RP0 ; EECON1 liegt in der Bank 3 BSF EECON1, EEPGD ; wir wollen Programmspeicher beschreiben BSF EECON1, WREN ; nun ist Schreiben erlaubt BCF INTCON, GIE ; verbieten aller Interrupts ; Die folgenden 7 Zeilen müssen genau so im Code stehen!!! MOVLW 0x55 ; MOVWF EECON2 ; schreibe 55h nach EECON2 MOVLW 0xAA ; MOVWF EECON2 ; schreibe AAh nach EECON2 BSF EECON1, WR ; starte den Schreibzyklus NOP NOP ; BSF INTCON, GIE ; Interrupts wieder erlauben BCF STATUS, RP1 ; Bank 0 BCF STATUS, RP0 ; return ;***************************************************** ;Laden eines FLASH Wortes (14 bit) ; @param flash_addr_h .. High-Adresse der zu ladenden FLASH Speicherzelle ; @param flash_addr_l .. Low--Adresse der zu ladenden FLASH Speicherzelle ; @return flash_data_h .. High-Daten ; @return flash_data_l .. Low--Daten FLASH_Load MOVFW flash_addr_h ; High Teil der Adresse 120h ist 1h BSF STATUS, RP1 ; BCF STATUS, RP0 ; EEADR liegt in der Bank 2 MOVWF EEADRH ; den schreibe ich in EEADRH BCF STATUS, RP1 ; Bank 0 MOVFW flash_addr_l ; Low-Teil der Adresse 120h ist 20h auslesen BSF STATUS, RP1 ; Bank 2 MOVWF EEADR ; den schreibe ich in EEADR BSF STATUS, RP0 ; EECON1 liegt in der Bank 3 BSF EECON1, EEPGD ; ich möchte aus dem Programm-Speicher lesen BSF EECON1, RD ; EEPROM Leseprozeß starten NOP NOP BCF STATUS, RP0 ; EEDATA liegt in der Bank 2 MOVF EEDATA, W ; die unteren 8 Bit Programm Zelle nach W kopieren BCF STATUS, RP1 ; Bank 0 MOVWF flash_data_l ; und irgentwohin retten BSF STATUS, RP1 ; Bank 2 MOVF EEDATH, W ; die oberen 6 Bit Programm Zelle nach W kopieren BCF STATUS, RP1 ; Bank 0 MOVWF flash_data_h ; return ;***************************************************** ;Speichern eines EEPROM Bytes ; @param eeprom_addr .. Adresse der zu speichernden EEPROM Speicherzelle ; @param w .. Daten EEPROM_Save BCF PIR2, EEIF ; Flag "Fertig mit EEPROM schreiben" löschen BSF STATUS, RP1 ; BCF STATUS, RP0 ; EEADR und EEDATA liegen in der Bank 2 MOVWF EEDATA ; Zu schreibende Daten aus w BCF STATUS, RP1 ; Bank0 MOVFW eeprom_addr ; BSF STATUS, RP1 ; Bank2 MOVWF EEADR ; Adresse die beschrieben werden soll BSF STATUS, RP0 ; EECON1 liegt in der Bank 3 BCF EECON1, EEPGD ; wir wollen Datenspeicher beschreiben BSF EECON1, WREN ; nun ist Schreiben erlaubt BCF INTCON, GIE ; verbieten aller Interrupts ; Die folgenden 5 Zeilen müssen genau so im Code stehen!!! MOVLW 0x55 ; MOVWF EECON2 ; schreibe 55h nach EECON2 MOVLW 0xAA ; MOVWF EECON2 ; schreibe AAh nach EECON2 BSF EECON1, WR ; starte den Schreibzyklus ; EEPROM_Save wird nur aus der Interrupt-Service-Routine gerufen. ; GIE wird am Ende der ISR wieder eingeschaltet... ; BSF INTCON, GIE ; Interrupts wieder erlauben BCF STATUS, RP1 ; Bank 0 BCF STATUS, RP0 ; EEPROM_Save_In_Progress BTFSS PIR2, EEIF GOTO EEPROM_Save_In_Progress return ;***************************************************** ;Laden eines EEPROM Bytes ; @param eeprom_addr .. Adresse der zu ladenden EEPROM Speicherzelle ; @return w .. Daten EEPROM_Load MOVFW eeprom_addr ; ich möchte die EEPROM-Zelle Nr. eeprom_addr auslesen (Bank 0!!!) BSF STATUS, RP1 ; BCF STATUS, RP0 ; EEADR liegt in der Bank 2 MOVWF EEADR ; dazu schreibe ich die Adresse 10h in EEADR BSF STATUS, RP0 ; EECON1 liegt in der Bank 3 BCF EECON1, EEPGD ; ich möchte aus dem Daten-Speicher lesen BSF EECON1, RD ; EEPROM Leseprozeß starten BCF STATUS, RP0 ; EEDATA liegt in der Bank 2 MOVF EEDATA, W ; Die Daten der EEPROM Zelle nach W kopieren bcf STATUS, RP0 ; Bank 0 bcf STATUS, RP1 ; return ;***************************************************** ;Ausgabe eines Strings aus dem EEPROM am LCD ; @param loops_ee .. Länge des String ; @param eeprom_addr .. Adresse des Strings im EEPROM ; @return none Ausgabe_EEString call EEPROM_Load ; Lade EEData in w call OutLcdDaten incf eeprom_addr, f decfsz loops_ee, f ; loops complete? goto Ausgabe_EEString; no, go again return ;***************************************************** ; Ausgabe des Begrüßungstextes auf dem Display Ausgabe_Copyright call Ausgabe_goto00 ; Logo 1 movlw D'16' ; Länge des Strings = 16 movwf loops_ee ; -> loops movlw EEDATA_LOGO_0 ; Adresse des Strings movwf eeprom_addr ; -> eeprom_addr call Ausgabe_EEString call Ausgabe_goto10 ; Logo 2 movlw D'16' ; Länge des Strings = 16 movwf loops_ee ; -> loops movlw EEDATA_LOGO_1 ; Adresse des Strings movwf eeprom_addr ; -> eeprom_addr call Ausgabe_EEString ; 5 Sekunden warten movlw .4 ; outer loop adjustment variable movwf f0 Init_Wait_Copyright movlw D'250' ; 250 ms Pause nach dem Einschalten movwf loops_wait call WAIT decfsz f0, f ; outer loops complete? goto Init_Wait_Copyright ; no, go again return ;***************************************************** ;Setzen der Cursor-Position ;@param w .. Position ; --------------------------------------------------- ; | 00 01 02 03 04 05 06 07 | 08 09 10 11 12 13 14 15 | ; | 64 65 66 67 68 69 70 71 | 72 73 74 75 76 77 78 79 | ; --------------------------------------------------- ;@see LCD_OFFSET_LINE1 ;@see LCD_OFFSET_LINE2 Ausgabe_gotoW iorlw B'10000000' call OutLcdControl return ;***************************************************** ;Löschen des Displays und ;setzen des Cursors auf 1. Zeile, 1. Spalte Ausgabe_goto00 movlw B'00000001' ; clear + home call OutLcdControl ; movlw LCD_OFFSET_LINE1 ; 1. Zeile ; call Ausgabe_gotoW return ;***************************************************** ;Setzen des Cursors auf 2. Zeile, 1. Spalte Ausgabe_goto10 movlw LCD_OFFSET_LINE2 ; 2. Zeile call Ausgabe_gotoW return ;***************************************************** ;Anzeige der Ziffer am LCD ; input w .. Ziffer im BCD-Code Ausgabe_Ziffer iorlw '0' call OutLcdDaten return ;***************************************************** ;Anzeige von 2 Ziffern am LCD ; input: SZ, SE .. Ziffern im BCD-Code Ausgabe_2ziffern movfw SZ call Ausgabe_Ziffer movfw SE call Ausgabe_Ziffer return ;***************************************************** ;Anzeige von 3 Ziffern am LCD ; input: SH, SZ, SE .. Ziffern im BCD-Code Ausgabe_3ziffern movfw SH call Ausgabe_Ziffer movfw SZ call Ausgabe_Ziffer movfw SE call Ausgabe_Ziffer return ;***************************************************** ;Anzeige von 4 Ziffern am LCD ; input: ST, SH, SZ, SE .. Ziffern im BCD-Code ;Ausgabe_4ziffern ; movfw ST ; call Ausgabe_Ziffer ; movfw SH ; call Ausgabe_Ziffer ; movfw SZ ; call Ausgabe_Ziffer ; movfw SE ; call Ausgabe_Ziffer ; return ;***************************************************** ;+++LCD-Routinen************************************** ;***************************************************** ;LCD initialisieren, Begrüßung ausgeben InitLcd movlw D'255' ; 250 ms Pause nach dem Einschalten movwf loops_wait call WAIT movlw B'00110000' ; 1 movwf LcdPort bsf LcdE nop bcf LcdE movlw D'50' ; 50 ms Pause movwf loops_wait call WAIT movlw B'00110000' ; 2 call Control8Bit movlw B'00110000' ; 3 call Control8Bit movlw B'00100000' ; 4 call Control8Bit movlw B'00000001' ; display löschen call OutLcdControl movlw B'00101000' ; 5 function set, 4-bit 2-zeilig, 5x7 call OutLcdControl movlw B'00001000' ; 6 display off call OutLcdControl movlw B'00000110' ; 7 entry mode, increment, disable display-shift call OutLcdControl movlw B'00000011' ; 8 cursor home call OutLcdControl movlw B'00001100' ; 9 display on, cursor off, blinken off call OutLcdControl return ;***************************************************** ; ein Steuerbyte 8-bittig übertragen Control8Bit movwf LcdPort bsf LcdE nop bcf LcdE movlw D'10' movwf loops_wait call WAIT return ;***************************************************** ; darauf warten, daß das Display bereit zur Datenannahme ist LcdBusy bsf STATUS, RP0 ; make Port B4..7 input movlw B'11110000' iorwf TRISC, f bcf STATUS, RP0 BusyLoop bcf LcdRs bsf LcdRw ; Lesen bsf LcdE nop movf LcdPort, w movwf LcdStatus bcf LcdE nop bsf LcdE ; Enable nop bcf LcdE btfsc LcdStatus, 7 ; teste bit 7 goto BusyLoop bcf LcdRw bsf STATUS, RP0 ; make Port B4..7 output movlw B'00001111' andwf TRISC, f bcf STATUS, RP0 return ;***************************************************** ; aus W ein Byte mit Steuerdaten zum Display übertragen OutLcdControl movwf LcdDaten call LcdBusy movf LcdDaten, w andlw H'F0' movwf LcdPort ; Hi-teil Daten schreiben bsf LcdE nop bcf LcdE ; Disable LcdBus swapf LcdDaten, w andlw H'F0' movwf LcdPort ; Lo-teil Daten schreiben bsf LcdE nop bcf LcdE ; Disable LcdBus movlw H'0F' ; Hi-teil auf 0 zurücksetzen andwf LcdPort, f return ;***************************************************** ; aus W ein Datenbyte zum Display übertragen OutLcdDaten movwf LcdDaten call LcdBusy movf LcdDaten, w andlw H'F0' movwf LcdPort ; Hi-teil Daten schreiben bsf LcdRs ; Daten bsf LcdE ; Enable LcdBus nop bcf LcdE ; Disable LcdBus swapf LcdDaten, w andlw H'F0' movwf LcdPort ; Lo-teil Daten schreiben bsf LcdRs ; Daten bsf LcdE nop bcf LcdE ; Disable LcdBus bcf LcdRs ; movlw H'0F' ; Hi-teil auf 0 zurücksetzen andwf LcdPort, f return ;***************************************************** ;Zeitverzögerung um loops_wait * 1 ms ; 4 MHz externer Takt bedeutet 1 MHz interner Takt ; also dauert 1 ms genau 1000 Befehle ; 100 Schleifen a 10 Befehle sind 1000 Befehle = 1 ms WAIT top movlw .100 ; timing adjustment variable (1ms) movwf loops_wait2 top2 nop ; sit and wait nop nop nop nop nop nop decfsz loops_wait2, F ; inner loops complete? goto top2 ; no, go again decfsz loops_wait, F ; outer loops complete? goto top ; no, go again retlw 0 ; yes, return from subWAIT ;***************************************************** end ;*****************************************************