;**** A P P L I C A T I O N N O T E LCD-Anzeige ************************ ;* ;* Title: Ansteuerung 16*4 LCD über Ser.Schnittstelle ;* Display Modell 2 ;* Version: 0.6 ;* Last updated: 21.1.2001 ;* Target: AT90S2333 ;* ;* Author: Majunke Michael ;* Support E-mail: majunke@t-online.de ;* ;* Beschreibung: ;* mit diesem Programm kann ein 16*4 LCD-Display angesteuert werden.. ;* die Zeichen die an die Ser. Schnittstelle gesendet werden, gibt das Disp. ;* aus und reagiert auf Befehle.. s. Anlage.. ;* weiterhin kann das Display Daten an den Rechner senden.. ;* Einstellungen: ;* - 38400 Baud auf der ser. Seite.. ;* - Version mit XON/XOFF Protokoll und CTS ;* ;* Anmerk.: Empfangspufferfehler behoben... ;* ;* geplant: ;* Menu für Standarteinstellungen wie Baudrate u.a ;* AD-WANDLER ;* ;* GPL ;***************************************************************************** ;*** Portbelegungen ********************************************************** ;* Port - Aufgabe - Pins - Richtung ;* ;* PD0 RxD Pin 2 IN ;* PD1 TxD Pin 3 OUT ;* PD2 CTS Pin 4 OUT ;* PD3 LED 1(3) Pin 5 OUT ;* PD4 LED 2(2) Pin 6 OUT ;* PD5 LED 3(1) Pin 11 OUT ;* PD6 Taster 1 Pin 12 IN ;* PD7 Taster 2 Pin 13 IN ;* ;* PC0 Display E Pin 23 OUT ;* PC1 Display Bel. Pin 24 OUT ;* PC2 Taster 3 Pin 25 IN ;* PC3 Helligkeitssens Pin 26 IN ;* PC4 Taster 4 Pin 27 IN ;* PC5 AD-Eingang Pin 28 IN ;* ;* PB0 Display D0 Pin 14 OUT/IN ;* PB1 Display D1 Pin 15 OUT/IN ;* PB2 Display D2 Pin 16 OUT/IN ;* PB3 Display D3 Pin 17 OUT/IN ;* PB4 Display R/S Pin 18 OUT ;* PB5 Display R/W Pin 19 OUT ;* ;****************************************************************************** .DEVICE AT90S2333 ; ***** Portadressen .EQU PIND = 0x10 .EQU PORTD_DDR = 0x11 .EQU PORTD_D = 0x12 .EQU PINC = 0x13 .EQU PORTC_DDR = 0x14 .EQU PORTC_D = 0x15 .EQU PINB = 0x16 .EQU PORTB_DDR = 0x17 .EQU PORTB_D = 0x18 ; ***** I/O-Memory .EQU RAMEND = 0xDF ; Adresse SRAM-End .EQU STATUS_FLAG = 0x3F ; Status Register .EQU SP = 0x3D ; Stackpointer .EQU EEADRESS = 0x1E ; EEPROM adressregister .EQU EEDAT = 0x1D ; Datenregister .EQU EECONTR = 0x1C ; controlregister .EQU UART_UDR = 0x0C ; UART Datenregister .EQU UART_UCSRA = 0x0B ; Contr./Statusreg.A .EQU UART_UCSRB = 0x0A ; Contr./Statusreg.B .EQU UART_UBRR_L = 0x09 ; Baudratenreg. Low .EQU UART_UBRR_H = 0x03 ; Baudratenreg. High .EQU ADMUX = 0x07 ; Kanalselectregister f. AD-Wandler .EQU ADCSR = 0x06 ; AD-Controllregister .EQU ADCH = 0x05 ; AD-Data High .EQU ADCL = 0x04 ; AD-Data Low .EQU Sensor_Kanal_Hellig = 3 ; auf welchen Kanal liegt Helligkeitssensor ;* später fest eingeben da ja nicht mehr verändert wird .EQU TIMSK = 0x39 ; Timer/Counter Interupt Mask Register .EQU TIFR = 0x38 ; Timer/Counter Interupt Flag Register .EQU TCCR1A = 0x2F ; Timer/Counter1 Controll Register A 16bit .EQU TCCR1B = 0x2E ; Timer/Counter1 Controll Register B .EQU TCCR0 = 0x33 ; Timer/Counter 0 Controll Register 8bit ; ***** Variablen .EQU UART_TEILER = 12 ; Teiler nach Datenblatt einstellen, ; 12 für 38400Baud ; 51 für 9600 ; Teiler=(Mhz/Baudrate/16)-1 ; später evt. ins Flash damit über SETUP änderbar .EQU UART_CR = 0b10011000 ; UCSRB, IRQ erlaubt, Empfang/Senden erlaubt .EQU UART_CR_OFF = 0b00011000 ; int off .EQU PUFFER_LAENGE_GESAMT = 22 ; Puffer auf 22 Zeichen .EQU PUFFER_LAENGE_RESERVE = 2 ; ReserveZeichen falls CTS zu lang braucht 2 .EQU ASC_UG = 32 ; innerhalb der ASC-Spanne werden Zeichen empfangen und gepuffert .EQU ASC_OG = 126 ; von SPACE(32) bis ~(126) .EQU ASC_CODE = 0x7E ; 126d '~' Steuerzeichen, wird auch gepuffert ; -> gehe auf CODE-EMPFANG und werte nachfolg. Zeichen aus .EQU ASC_CODE_Clear = 0x43 ; 67d 'C' - für display clear .EQU ASC_CODE_LED = 0x4C ; 76d 'L' - LED Steuern 'L' an/aus/blinken .EQU ASC_CODE_BEL = 0x42 ; 66d 'B' - Beleuchtung an/aus/automatik .EQU ASC_CODE_LOCATE = 0x50 ; 80d 'P' - Cursor Position Z_S .EQU DDR_READ_DISPLAY = 0b00110000 ; Datenrichtung vordef. zum Einlesen v Display .EQU DDR_WRITE_DISPLAY = 0b00111111 ; zum Ausgeben auf Display .EQU DISPLAY_FUNK_SET = 0b00101000 ; für init_Display_ hier kann Font, .EQU DISPLAY_DISP = 0b00001100 ; Cusour usw. geändert werden, s.Datenblatt .EQU DISPLAY_CLEAR = 0b00000001 ; Befehle f. Display .. .EQU DISPLAY_EMODE = 0b00000110 .EQU DISPLAY_DDRAM_NULL = 0b10000000 .EQU Timer1_Set = 0b10000000 ; Timer1 IRQ an ;.EQU Timer_Clock_1 = 0b00000100 ; Timerfrequenz einstellen hier CK/256 .EQU Timer_Clock_1 = 0b00000011 ; Timerfrequenz einstellen hier CK/64 .EQU Timer0_Set = 0b00000010 ; Timer0 IRQ an ;.EQU Timer_Clock_0 = 0b00000100 ; Timerfrequenz einstellen hier CK/256 .EQU Timer_Clock_0 = 0b00000101 ; Timerfrequenz einstellen hier CK/1024 .EQU Timer_Aktiv_Byte_Def = 0b00000111 ; Voreinstellung welche Timer aktiv sein sollen ; Bit 0 = Beleuchtung ; Bit 1 = Taster ; Bit 2 = LED (blinken) ; Bit 3/4/5 = welche LED soll blinken - FEST ! ; Bit 6 für AD-Wandler -> später ; Bit 8 frei ; später evt. ins Flash damit über SETUP änderbar .EQU Timer_T_Counter_Time = 8 ; Nutzung zum entprellen der Taster .EQU Timer_T2_Counter_Time = 8 ; durch veringern bzw. erhöhen an eigene Taster anpassen .EQU Timer_T3_Counter_Time = 8 .EQU Timer_T4_Counter_Time = 8 ; !!!!!!! nicht über 15 !!!!!!!!!!!!!! ; evt. nur Eines für Alle (falls gleiche 4 Taster) ; ***** Register .DEF SAVE_STATUS_FLAG = r1 ; wenn INT ausgeführt, hier das StatusRegister sichern .DEF PAUSE_LANG = r2 ; für Lange Pause .DEF PUFFER_POS = r3 ; Position d. Pufferzeigers .DEF PUFFER_AKT_LAENG = r4 ; akt. anzahl v. Zeichen im Puffer (wenn Null dann Leer) .DEF C_MERK = r5 ; Cursor Position merken .DEF TASTER_PRESSED = r6 ; welcher taster wurde gedrückt ? TimerIRQ speichert ; gedrückten Taster in diesem Register .DEF Timer_T1_Counter = r7 ; Nutzung zum entprellen der Taster .DEF Timer_T2_Counter = r8 ; .DEF Timer_T3_Counter = r9 ; .DEF Timer_T4_Counter = r10 ; Erkl. bei Variablen Timer_Tx_Counter_Time ; !! später die Register aufteilen da nur ein halbes benötigt wird !! .DEF TIMER_AKTIV_BYTE = r11 ; nicht den kompletten Teiler lahm legen, ; sondern abspeichern für was (Hellig, LED usw. ) ; dieser aktiv sein soll und dann in der Timer-Routine ; überspringen ; Bit 0 = Beleuchtung ; Bit 1 = Taster ; Bit 2 = LED (blinken) ; Bit 3/4/5 = welche LED soll blinken - FEST ! ; Bit 6 für AD-Wandler -> später ; Bit 8 frei ; s.o. .DEF WORK = r16 ; allgem. verwend. .DEF WORK2 = r17 .DEF WORK_UART = r18 .DEF TEMP = r19 .DEF TEMP_DISP = r20 ; temp f. untpr. DATEN an DISP .DEF TEMP_DISP_DS = r21 ; temp f. untpr. DATEN an DISP .DEF DISPLAY_DAT = r22 ; übergabe eines Bytes an Disp_Sendxxx ; und 2. f. LocateZ_S .DEF PAUSEWERT = r23 ; die Länge der Pause .DEF PAUSE1 = r24 ; f. Schleife in PauseRoutine .DEF CODE_MERK = r25 ; für Code-Zeichen ermitteln, zw-Speicher ; SRAM -Register .DEF X_L = r26 ; AD - Hauptanwendungszweck .DEF X_H = r27 .DEF Y_L = r28 ; UART_RX_C, .DEF Y_H = r29 ; .DEF Z_L = r30 ; READ_PUFFER, .DEF Z_H = r31 ; ; ****************************************************************************** ; **** daten die ins SRAM kommen (der EmpfangsPuffer) .DSEG PUFFER: .byte PUFFER_LAENGE_GESAMT ; ****************************************************************************** ; **** daten die ins EEPROM kommen (Meldung u.a ) .ESEG ; '11111111111111113333333333333333' Intro_Meldung: .DB "..16x4 Display..Majunke..02/2001" ; ****************************************************************************** ;*** Sprunktabelle für Interrups *** .CSEG .ORG $0 Reset: rjmp Init_Reset ; Reset behandlung, Neuinitaliesieren IRQ0: reti ; IRQ1: reti ; TIMER1_CAP: reti ; TIMER1_COMP: reti ; TIMER1_OVFL: rjmp TIMER1_OL ; Timer 16bit, Helligsteuerung, LED blinken TIMER0_OVFL: rjmp TIMER0_OL ; Timer 8bit zur Tasterabfrage SPI_TRANSF_COMPL: reti ; UART_RX_COMPL: rjmp UART_RX_C ; ein zeichen wurde empfangen UART_DR_EMPTY: reti ; UART_TX_COMPL: reti ; ADC_CONV_COMPL: rjmp ADC_CONV_C ; eine AD-wandlung ist fertig EE_RDY: reti ; ANA_COMP: reti ; ;****** Routine nach Reset bzw. Neustart - Vorinitalisieren Init_Reset: cli ; Interupts aus ;*** Initialize stack pointer ;* StackPointer auf höchste Adresse im SRAM legen ldi WORK, RAMEND ; SP auf RAM_END_Adresse out SP, WORK ; und setzen ;*** I/O-Pins in Schaltung auf defin. Werte einstellen ; Port D ldi WORK,0b00111110 ; Rxd/TxD/cts/Led1-3/taster1-2 Richtung s. tabelle out PORTD_DDR,WORK ; AusgabeRichtung - DataDIR Port D ldi WORK,0b11111000 ; LED/CTS aus .. Taster pull-up out PORTD_D,WORK ; Daten - Data Port D ; Port C ldi WORK,0b00000011 ; E/Bel./taster3/helligkeit/taster4/ad Richtung out PORTC_DDR,WORK ; Ausgaberichtung - DataDIR Port C ldi WORK,0b00010101 ; Bel. aus / E high out PORTC_D,WORK ; Daten - DataDIR Port C ; Port B ldi WORK,DDR_READ_DISPLAY ; Datenricht. zum lesen LESEN v. Display out PORTB_DDR,WORK ; Ausgaberichtung - DataDIR Port B ldi WORK,0b111111 ; out PORTB_D,WORK ; Daten - Data Port B ; UART - Einstellen ldi WORK,UART_TEILER ; Baudratenteiler out UART_UBRR_L,WORK ; low-teil clr WORK out UART_UBRR_H,WORK ; h-teil ldi WORK,UART_CR ; Betriebsart des UART out UART_UCSRB,WORK ; Puffer Variablen setzen ldi WORK, PUFFER mov PUFFER_POS, WORK ; Adresse v. Puffer in Reg. clr PUFFER_AKT_LAENG ; akt. Größe (zeichenanzahl) löschen clr C_MERK ; Akt. CursorPosition löschen ; Taster und Timerpuffer clr TASTER_PRESSED ; kein Taster gedrückt ; Tasterentprellzeiten einstellen ldi WORK, Timer_T_Counter_Time mov Timer_T1_Counter, WORK mov Timer_T2_Counter, WORK mov Timer_T3_Counter, WORK mov Timer_T4_Counter, WORK ; Timer1 Standart ANSCHALTEN clr WORK ; Reg 1A einstellen betriebsart 16bit Counter out TCCR1A, WORK ; ldi WORK,Timer_Clock_1 ; Reg 1B einstellen Frequenz = Einstellung oben out TCCR1B, WORK ldi WORK, Timer1_Set ; Timer1 OverflowInterupt AN out TIMSK, WORK ; Timer0 Standart ANSCHALTEN ldi WORK,Timer_Clock_0 ; TCCR0 einstellen Frequenz = s. Einstellung oben out TCCR0, WORK in WORK, TIMSK ; Timer 0 AN ori WORK, Timer0_Set out TIMSK, WORK ; Welche Routinen sollen in den Timern durchlaufen werden ldi WORK, Timer_Aktiv_Byte_Def ; timer start init mov TIMER_AKTIV_BYTE, WORK ; **** Main ******************************************************************** ; **** ***** Start: rcall Init_Display ;*** Initalisieren des Display rcall Intro ;*** Intro anzeigen sei ; schalte IRQs zu ldi WORK,17 ; sende ein XON (asc17) - Display bereit zum out UART_UDR,WORK ; Zeichenempfang Start_SerIn: ;*** starte Hauptschleife rcall Taster_Abfrage ; Abfrage nach gedrückten Tasten tst PUFFER_AKT_LAENG ; ist ein Zeichen im Puffer ? breq Start_SerIn ; ja rcall Read_Puffer ; dann lese das Zeichen aus Puffer Code_Empfang: ; und Werte es aus ... cpi DISPLAY_DAT,ASC_CODE ; ist es das Code-Einleitungs-Zeichen ? breq Code_Locate_Cursor ; ja, dann CODE-Behandlung rjmp Main_Send_Data_MIT_LOC ; sonst ausgeben ALS NORMALER TEXT ; *** Befehl Locate Z_S ****** Code_Locate_Cursor: tst PUFFER_AKT_LAENG ; ist ein Zeichen im Puffer ? Befehlszeichen holen breq Code_Locate_Cursor ; nein ? dann warte -> sonst auswerten rcall Read_Puffer ; ***************** clr CODE_MERK cpi DISPLAY_DAT,ASC_CODE_LOCATE ; ist es das Code-Zeichen f. Locate ? brne Code_Clear_Display ; nein, -> test next ->else Code ; Eigentliche Code für Locate Z_S Code_Locate_Z: tst PUFFER_AKT_LAENG ; ist ein Zeichen im Puffer ? Zeile breq Code_Locate_Z ; nein ? dann warte rcall Read_Puffer ; sonst lesen und entsprechend auswerten subi DISPLAY_DAT,48 ; aus ASC Zahl machen - ZEILE cpi DISPLAY_DAT,4 ; über 3 ?? brlo Code_Locate_W1 ; außerhalb dann ABBRUCH,keine ZEICHENAUSGABE rjmp End_SerIn ; (rjmp weil sprungweite zu kurz) Code_Locate_W1: swap DISPLAY_DAT ; Zeile Zwischenspeichern und weier Spalte ermitteln mov TEMP, DISPLAY_DAT ; Zeile an richtige Position f. AusgabeFunktion Code_Locate_S: ; 2 Zahlen müssen eingelesen werden für Spalte !! tst PUFFER_AKT_LAENG ; ist ein Zeichen im Puffer ? breq Code_Locate_S ; nein ? dann warte rcall Read_Puffer ; sonst lesen und entsprechend auswerten subi DISPLAY_DAT,48 ; aus ASC Zahl machen - SPALTE*(10hoch1) cpi DISPLAY_DAT,2 ; über 1 ?? Spalte bis max ->16 Zeichen brlo Code_Locate_W2 ; außerhalb dann ABBRUCH,keine ZEICHENAUSGABE rjmp End_SerIn ; ( rjmp weil sprungweite zu kurz) Code_Locate_W2: tst DISPLAY_DAT breq Code_Locate_S2 ; Null dann direkt 2. Wert lesen, ori CODE_MERK, 10 ; sonst 10hoch1 dazu Code_Locate_S2: tst PUFFER_AKT_LAENG ; und 10hoch0 lesen breq Code_Locate_S2 ; nein ? dann warte rcall Read_Puffer ; sonst lesen und entsprechend auswerten subi DISPLAY_DAT,48 ; aus ASC Zahl machen - SPALTE*(10hoch0) cpi DISPLAY_DAT,10 ; über 0-15 ? F brlo Code_Locate_W3 ; außerhalb dann ABBRUCH,keine ZEICHENAUSGABE rjmp End_SerIn ; (rjmp weil sprungweite zu kurz) Code_Locate_W3: add DISPLAY_DAT, CODE_MERK or DISPLAY_DAT, TEMP ; und Zeile zu SPlate in ein Byte f. Funktion rcall locateZ_S ; LOCATE Z_S rjmp End_SerIn ; und end ; *** Befehl CLS ************ Code_Clear_Display: cpi DISPLAY_DAT,ASC_CODE_CLEAR ; ist es das Code-Zeichen für CLEAR_DISPLAY brne Code_LED_Steuer ; nein, dann auf nächsten Befehlswort testen ldi DISPLAY_DAT,DISPLAY_CLEAR ; sonst Clear Display rcall Disp_Send_Code clr DISPLAY_DAT ; und auf position eins rcall locateZ_S rjmp End_SerIn ; und ENDE ohne Zeichenausgabe ; *** Befehl um LEDs zu steuern *********** ; fehlt noch blinken ..... Code_LED_Steuer: cpi DISPLAY_DAT,ASC_CODE_LED ; ist es das Code-Zeichen für LED ON/OFF brne Code_Beleucht_Display ; nein, dann test auf nächsten Befehl Code_LED_Nr: ; erwarte welche LED verändert werden soll tst PUFFER_AKT_LAENG ; ist ein Zeichen im Puffer ? breq Code_LED_Nr ; nein ? dann warte rcall Read_Puffer ; sonst lesen und entsprechend auswerten subi DISPLAY_DAT,48 ; aus ASC Zahl machen cpi DISPLAY_DAT,3 ; welche LED ? 0-2 brlo Code_LED_w ; außerhalb der LEDs dann ABBRUCH,keine ZEICHENAUSGABE rjmp End_SerIn ; (rjmp weil sprunglänge zu kurz) Code_LED_w: mov CODE_MERK, DISPLAY_DAT ; Merke die Nummer und weiter zu -> teste ob LED an/AUS ldi TEMP,8 ; schiebe die LED-Nummer auf richtigen Port two_h: ; 2hochLED-Nummer tst CODE_MERK breq n_two_h lsl TEMP dec CODE_MERK rjmp two_h n_two_h: mov CODE_MERK,TEMP Code_LED_Zustand: ; und soll LED AN o. AUS sein tst PUFFER_AKT_LAENG ; ist ein Zeichen im Puffer ? breq Code_LED_Zustand ; nein ? dann warte rcall Read_Puffer ; sonst lesen und entsprechend auswerten cpi DISPLAY_DAT, 48 ; Null '0' ? dann weiter ob AN oder blinken brne Code_LED_Nr_ANorBlink in DISPLAY_DAT, PORTD_D ; Zustand ? CTS usw nicht verändern or DISPLAY_DAT,CODE_MERK ; jew. bit setzen out PORTD_D,DISPLAY_DAT com TEMP ; entpsr. bit in Timer-REgister löschen and TIMER_AKTIV_BYTE, TEMP ; damit led blinken ausgeschalten wird rjmp End_SerIn Code_LED_Nr_ANorBlink: cpi DISPLAY_DAT, 49 ; '1' ? dann LED AN sonst blinken setzen brne Code_LED_Nr_Blink in DISPLAY_DAT, PORTD_D ; Zustand ? CTS usw nicht verändern com CODE_MERK ; Complement (neg.) and DISPLAY_DAT,CODE_MERK ; UND jew. bit löschen out PORTD_D,DISPLAY_DAT com TEMP ; entpsr. bit in Timer-REgister löschen and TIMER_AKTIV_BYTE, TEMP ; damit led blinken ausgeschalten wird rjmp End_SerIn ; end Code_LED_Nr_Blink: cpi DISPLAY_DAT, 50 ; '2' ? dann LED Blinken sonst ende brne End_SerIn or TIMER_AKTIV_BYTE, TEMP ; entpsr. bit in Timer-REgister setzen damit LED blinkt rjmp End_SerIn ; abfrage in Timer0 IRQ ; *** Befehl für Beleuchtungssteuerung ***** ; *** manuelle Steuerung(~B0/1) oder Automatik nach LDR (~B2) Code_Beleucht_Display: cpi DISPLAY_DAT,ASC_CODE_BEL ; ist es das Code-Zeichen f. Beleuchtung brne Main_Send_Data_MIT_LOC ; nein, dann end Code_Beleucht_Z: ; hole den Zustand den Beleuchtung bekommen soll tst PUFFER_AKT_LAENG ; ist ein Zeichen im Puffer ? breq Code_Beleucht_Z ; nein ? dann warte rcall Read_Puffer ; sonst lesen und entsprechend auswerten cpi DISPLAY_DAT,48 ; ist es '0' brne Code_Beleucht_ONorAUTO ; nein, dann Beleuchtung AN oder AUTOmatik mov WORK , TIMER_AKTIV_BYTE ; Timerfunktion übergehen ohne Timer abzuschalten andi WORK, 0b11111110 ; Bit 1 ausschalten (Beleuchtung) mov TIMER_AKTIV_BYTE , WORK cbi PORTC_D,1 ; und Beleuchtung AUS rjmp End_SerIn ; und ENDE ohne Zeichenausgabe Code_Beleucht_ONorAUTO: ; Beleuchtung An oder Automatik cpi DISPLAY_DAT,49 ; ist es '1' für Beleuchtung AN oder höher f. AUTOmatik ? brne Code_Beleucht_AUTO ; nein dann Automatik einschalten sonst Beleuchtung an mov WORK , TIMER_AKTIV_BYTE ; Timerfunktion übergehen ohne Timer abzuschalten andi WORK, 0b11111110 ; Bit 1 ausschalten (Beleuchtung) mov TIMER_AKTIV_BYTE , WORK sbi PORTC_D,1 ; und Beleuchtung AN rjmp End_SerIn ; und ENDE ohne Zeichenausgabe Code_Beleucht_AUTO: ; Automatik einschalten cpi DISPLAY_DAT,50 ; ist es '2' für Beleuchtung AUTO brne Code_Beleucht_Fail ; nein dann Ende ohne Funktion mov WORK , TIMER_AKTIV_BYTE ; Timerfunktion für Beleuchtung aktivieren ori WORK, 0b00000001 ; Bit 1 anschalten (Beleuchtung) mov TIMER_AKTIV_BYTE , WORK Code_Beleucht_Fail: rjmp End_SerIn ; und ENDE ohne Zeichenausgabe ; ********************** Main_Send_Data_MIT_LOC: ; ********************** ; ** überspringen der 'toten' Bereiche des Displays, ; ** damit alle Zeichen umlaufend angezeigt werden falls kein Positionsbefehl ; ** vom Benutzer kommt ; !!! standart wenn keine besonderen Befehle kommen !!! push DISPLAY_DAT ; rette Zeichen mov DISPLAY_DAT,C_MERK ; Positionier Cursor entsprechend akt. Cursorposition rcall locateZ_S inc DISPLAY_DAT ; erhöhe akt. Cursorposition andi DISPLAY_DAT,0x3F ; bis max. 64 Zeichen (wenn anderes Display anpassen) mov C_MERK,DISPLAY_DAT ; in C_Merk (akt. Cursorposit.) pop DISPLAY_DAT ; und Zeichen wieder nach Display_Dat ; ********************** Main_Send_Data_Ohne_LOC: ; Cursor wird über Befehle(LOCATE des Benutzers) positioniert rcall Disp_Send_Data End_SerIn: clr DISPLAY_DAT ; löschen und zurück rjmp Start_SerIn ; **** End-Main **************************************************************** ; ******* Unterprogrammaufrufe ************************************************** ; ****************************************************************************** ; ****************************************************************************** ; ****** Timer1 Überlauf Interuptroutine *************************************** ; ****** Welche Routinen ausgeführt werden sollen, steht im Register *********** ; ****** TIMER_AKTIV_BYTE .. nur wenn dort entspr. Bit gesetzt wird z.B. die *** ; ****** Helligkeitsfühler abgefragt ******************************************* ; ****** ; ****************************************************************************** TIMER1_OL: ; push SAVE_STATUS_FLAG in SAVE_STATUS_FLAG,STATUS_FLAG ; Rette StatusRegister da es verändert wird !! ; *********** BIT 0 in TIMER_AKTIV_BYTE ; *** messen des Helligkeitsfühlers und danach Beleuchtung steuern mov X_L, TIMER_AKTIV_BYTE ; soll Beleuchtautom. ausgeführt werden ? sbrs X_L, 0 ; also bit 0 gesetzt ? rjmp No_Timer_Beleucht ; nein dann weiter zu nächster Aufg. bzw. Ende ldi X_L, Sensor_Kanal_Hellig ; Kanal zum Messen an dem Helligkeitsfühler out ADMUX, X_L ldi X_L, 0b11011110 ; AD-Wandler initaliesieren und 1x messen out ADCSR, X_L No_Timer_Beleucht: ; *********** BIT 1 in TIMER_AKTIV_BYTE in Timer0 ! ; *********** BIT 2 in TIMER_AKTIV_BYTE (Unterbits 3/4/5) ; *** LEDs blinken mov X_L, TIMER_AKTIV_BYTE ; soll LED-Blink-Test genrell ausgeführt werden ? sbrs X_L, 2 ; also bit 1 gesetzt ? rjmp No_LED_Blink ; nein dann weiter zu nächster Aufg. bzw. Ende andi X_L,0b00111000 ; ausfiltern der 3 LED-Bits sbrs X_L, 3 ; led 0 blinken lassen ? set = aus rjmp LED_Blink_led1 ; nein dann test ob Led1 in WORK, PORTD_D ; blinken sbrs WORK, 3 rjmp l_on4 cbi PORTD_D, 3 rjmp Led_Blink_led1 l_on4: sbi PORTD_D, 3 Led_Blink_led1: sbrs X_L, 4 rjmp Led_Blink_led2 in WORK, PORTD_D sbrs WORK, 4 rjmp l_on5 cbi PORTD_D, 4 rjmp Led_Blink_led2 l_on5: sbi PORTD_D, 4 Led_Blink_led2: sbrs X_L, 5 rjmp No_LED_Blink in WORK, PORTD_D sbrs WORK, 5 rjmp l_on6 cbi PORTD_D, 5 rjmp No_LED_Blink l_on6: sbi PORTD_D, 5 No_LED_Blink: out STATUS_FLAG,SAVE_STATUS_FLAG ; und Flags in orig. zustand ; pop SAVE_STATUS_FLAG reti ; *** End Timer1 Überlauf ****************************************************** ; ****************************************************************************** ; ****** Timer0 Überlauf Interuptroutine *************************************** ; ****** Benutzt für Abgfagezeit der Taster ************************************ TIMER0_OL: push WORK ; push SAVE_STATUS_FLAG in SAVE_STATUS_FLAG,STATUS_FLAG ; Rette StatusRegister da es verändert wird !! ; *********** BIT 1 in TIMER_AKTIV_BYTE testen ; *** wenn gesetzt dann Tasterroutine ausführen ; *** Wenn eine Taste gedrückt wurde, wird das im Register TASTER_PRESSED ; *** vermerkt und ein entsprechendes Bit gesetzt ; *** Bit 0=T1 1=T2 2=T3 4=T4 mov WORK, TIMER_AKTIV_BYTE ; sollen Taster abgefragt werden ? sbrs WORK, 1 ; also bit 0 gesetzt ? rjmp No_Timer_Taster ; nein dann weiter zu nächster Aufg. bzw. Ende ; *** Wurde Taster 1 gedrückt dann setze Bit in TASTER_PRESSED entsprechend ?? in WORK, PIND ; lese INPUT-Pins ein sbrc WORK, 6 ; Taster 1 gedrückt ? rjmp tast2_test ; nicht gedrückt dann nächsten testen dec Timer_T1_Counter ; Entprellzähler veringern brne tast2_test ; nur wenn einmal abgelaufen nächter Tdruck möglich mov WORK, TASTER_PRESSED ; dann setzte bit 0 = 1 ori WORK, 0b1 ; im Register das in Hauptschleife abefragt wird mov TASTER_PRESSED, WORK ldi WORK, Timer_T_Counter_Time ; und Entprellzähler wieder zurücksetzen mov Timer_T1_Counter, WORK ; *** Wurde Taster 2 gedrückt dann setze Bit in TASTER_PRESSED entsprechend ?? tast2_test: in WORK, PIND sbrc WORK, 7 ; Taster 2 gedrückt ? rjmp tast3_test ; nicht gedrückt test next dec Timer_T2_Counter ; Entprellzähler veringern brne tast3_test ; nur wenn einmal abgelaufen nächter Tdruck möglich mov WORK, TASTER_PRESSED ori WORK, 0b10 ; dann setzte bit 0 = 2 mov TASTER_PRESSED, WORK ldi WORK, Timer_T_Counter_Time ; und Entprellzähler wieder zurücksetzen mov Timer_T2_Counter, WORK ; *** Wurde Taster 3 gedrückt dann setze Bit in TASTER_PRESSED entsprechend ?? tast3_test: in WORK, PINC sbrc WORK, 2 ; Taster 3 gedrückt ? rjmp tast4_test ; nicht gedrückt test next dec Timer_T3_Counter ; Entprellzähler veringern brne tast4_test ; nur wenn einmal abgelaufen nächter Tdruck möglich mov WORK, TASTER_PRESSED ori WORK, 0b100 ; dann setzte bit 0 = 4 mov TASTER_PRESSED, WORK ldi WORK, Timer_T_Counter_Time ; und Entprellzähler wieder zurücksetzen mov Timer_T3_Counter, WORK ; *** Wurde Taster 4 gedrückt dann setze Bit in TASTER_PRESSED entsprechend ?? tast4_test: in WORK, PINC sbrc WORK, 4 ; Taster 4 gedrückt ? rjmp end_tast_test ; nicht gedrückt test next dec Timer_T4_Counter ; Entprellzähler veringern brne end_tast_test ; nur wenn einmal abgelaufen nächter Tdruck möglich mov WORK, TASTER_PRESSED ori WORK, 0b1000 ; dann setzte bit 0 = 8 mov TASTER_PRESSED, WORK ldi WORK, Timer_T_Counter_Time ; und Entprellzähler wieder zurücksetzen mov Timer_T4_Counter, WORK ; *** Keine Tastendruck ermittelt end_tast_test: No_Timer_Taster: out STATUS_FLAG,SAVE_STATUS_FLAG ; und Flags in orig. zustand ; pop SAVE_STATUS_FLAG pop WORK reti ; *** End Timer1 Überlauf ****************************************************** ; ****************************************************************************** ; ****** AD-Wandlung komplett IRQ-Routine ************************************** ADC_CONV_C: ; push SAVE_STATUS_FLAG in SAVE_STATUS_FLAG,STATUS_FLAG ; Rette StatusRegister da es verändert wird !! in X_L, ADCL ; immer zuerst CL ! auslesen - Messwert in X_H, ADCH ; dann CH sonst hängt AD-Wandler fest ; steuere die Beleuchtung anhand des Messwertes lsr X_L ; oberen Wert in X_L packen sbrc X_H, 0 ; aus 10bit - 8bit machen ori X_L, 128 lsr X_L sbrc X_H, 1 ori X_L, 128 ; fertige Messwert in X_H, PORTC_D ; Art Hysterese sbrc X_H, 1 rjmp Bel_Is_On cpi X_L, 120 brlo Bel_AN cbi PORTC_D, 1 rjmp Bel_END Bel_Is_On: cpi X_L, 130 brlo Bel_AN cbi PORTC_D, 1 rjmp Bel_END Bel_AN: sbi PORTC_D, 1 Bel_END: out STATUS_FLAG,SAVE_STATUS_FLAG ; und Flags in orig. zustand ; pop SAVE_STATUS_FLAG reti ; *** end AD-Wandlung komplett *********************************************** ; ****************************************************************************** ; ****** Intro nach Reset ****************************************************** ; ***** -- Register *************************************************** ; ***** zwischenspeicher : TEMP ****************** ; ***** kommt EEPROM-Adresse rein : WORK2 *************** ; ***** übergabe des Wertes an Display : DISPLAY_DAT *********** ; ***** PAUSE länge : PAUSEWERT ************* ; ***** Display löschen : DISPLAY_DAT *********** ; ***** -- Variblen *************************************************** ; ***** Intro_Meldung-Adresse EEPROM : Intro_Meldung ********* ; ***** EEProm-Adresse : EEADRESS ************** ; ***** EEProm-Controll-Reg. : EECONTR *************** ; ***** EEProm-Daten Reg. : EEDAT ***************** ; ***** -- Routinen *************************************************** ; ***** Daten an Displ. senden : Disp_Send_Data ******** ; ***** Code an Displ. senden : Disp_Send_Code ******** ; ***** Pause : Delay_X *************** ; ********************************************************************* Intro: ; ersten 32 Zeichen aus EEPROM ausgeben ldi WORK2,Intro_Meldung ; ausgeben der IntroMeldung aus EEPROM ldi TEMP,33 ; Zähler für die 32 Zeichen Intro_Start: out EEADRESS,WORK2 ; setze EEPROM-Adresse auf Null sbi EECONTR,0 ; setze das Daten gelsene werden sollen in DISPLAY_DAT,EEDAT ; und schiebe die Daten nach DISPLAY_DAT wait_for_intern_uart: in WORK_UART, UART_UCSRA ; warten auf UART, sonst zeichen verschluckt sbrs WORK_UART, 5 ; ist UDRE gesetzt dann weiter rjmp wait_for_intern_uart out UART_UDR, DISPLAY_DAT ; auch nach TxD schicken, Test der ser. Ausgabe rcall Disp_Send_Data ; wo sie angezeigt werden inc WORK2 ; erhöhe EEPROM-ADRESSE um 1 dec TEMP ; und veringer Zeichenzähler um 1 brne Intro_Start ; wenn alle Zeichen gesendet Ende ldi PAUSEWERT, 70 ; 50 mal 25ms warten = 1,75sec rcall Delay_X_long ldi DISPLAY_DAT,DISPLAY_CLEAR ;** Clear Display rcall Disp_Send_Code ldi DISPLAY_DAT,DISPLAY_DDRAM_NULL ;** und DDRAM auf NULL rcall Disp_Send_Code ret ; *** End Intro ******************************************************* ; ********************************************************************* ; **** UART *********************************************************** ; **** Interuptbehandlung nachdem ein Zeichen empfangen *************** ; **** in Puffer speichern u.CTS/XOFF entspr. setzen, w Puffer voll *** ; **** puffert nur ASC(32-126) !!! ************************************ ; ***** -- Register *************************************************** ; ***** Allg. : WORK_UART *( ab r16)********* ; ***** schreiben in RAM : r28,r29 Y_L,Y_H ******* ; ***** Pufferposisition und Größe : 2x unter r16 **************** ; ***** zwischenspeicher : TEMP *(ab r16)********* ; ***** in Stack gesichert !****** ; ***** zwischenspeicher : WORK *(ab r16)********* ; ***** in Stack gesichert !****** ; ***** -- Routinen *************************************************** ; ***** DD-RAM ADresse an Display : Disp_Send_Code ******** ; ********************************************************************* UART_RX_C: ; push SAVE_STATUS_FLAG in SAVE_STATUS_FLAG,STATUS_FLAG ; Rette StatusRegister da es verändert wird !! ; teste ob es ein Fehler war der Empfangen wurde in WORK_UART,UART_UCSRA ; Status einlesen sbrs WORK_UART,4 ; wenn bit=1 dann ein FramError u. 'jmp Read' rjmp SAVE_CHAR ; wird überspr. , wenn kein Fehler ab zu Zeichen lesen in WORK_UART,UART_UDR ; nur wenn FrameError, UDR muß gelesen werden damit IRQ frei wird reti ; EXIT SAVE_CHAR: ; Zeichen einlesen u. in Puffer speichern in WORK_UART,UART_UDR ; lese UDR - Zeichen, gib int frei ; Code Zeichen ~ wird auch gepuffert, sonst -> ; was war es für Zeichen ? nur Zeichen 32-127 wird gepuffert !!!! ; wenn ä/ö/ü usw. benötigt, dann noch anpassen !!!!!!!!!!!!!!!!!! cpi WORK_UART,ASC_CODE ; Code einleitungszeichen ? breq SAVE_C cpi WORK_UART, ASC_UG ; Zeichen ab SPACE speichern in Puffer brlo End_UART_RX cpi WORK_UART, ASC_OG ; obere Grenze für Zeichen die gesp. werden brsh End_UART_RX ; und weiter mit speichern in SRAM (Puffer) SAVE_C: mov Y_L,PUFFER_POS ; Akt. Pufferpos. lesen clr Y_H st Y+,WORK_UART ; schreibe Zeichen in Puffer(SRAM) an entsp. Posit. mov PUFFER_POS,Y_L inc PUFFER_AKT_LAENG ; akt. PufferLänge = PufferLänge + 1 ldi Y_H, PUFFER_LAENGE_GESAMT-PUFFER_LAENGE_RESERVE ; Schutz vor Überlauf cp PUFFER_AKT_LAENG,Y_H ; PUFFER_LAENGE auf Puffer Voll ? brlt End_UART_RX ; dann CTS / od. XOFF aktiv machen sonst P_überlauf sbi PORTD_DDR,2 ; Port_D-CTS auf Ausgabe sbi PORTD_D,2 ; und CTS aktiv damit keine Daten mehr kommen ldi WORK_UART,19 out UART_UDR, WORK_UART ; XOFF senden ldi Y_H, PUFFER_LAENGE_GESAMT+1 ; BUFFERÜBERLAUF doch passiert ? cp PUFFER_AKT_LAENG,Y_H brlo End_UART_RX ; dann RESET rcall Init_Reset End_UART_RX: out STATUS_FLAG,SAVE_STATUS_FLAG ; und Flags in orig. zustand ; pop SAVE_STATUS_FLAG reti ; *** End UART_RX_C *************************************************** ; ********************************************************************* ; **** Tasterbehandlung *********************************************** ; **** hier stehen die Ereignisse die ausgeführt werden wenn ein Taster ; **** gedrückt wurde ************************************************* Taster_Abfrage: push DISPLAY_DAT push WORK ; push SAVE_STATUS_FLAG ; in SAVE_STATUS_FLAG,STATUS_FLAG ; Rette StatusRegister da es verändert wird !! tst TASTER_PRESSED breq No_Tast_press ; *** Aufgabe für Taster 1 pressed_taster_1: mov WORK, TASTER_PRESSED ; wurde Taster 1 gedrückt ??? cpi WORK, 1 brne pressed_taster_2 ; nein dann test next andi WORK, 0b11111110 ; ja dann mache Bit frei f. nächsten Druck mov TASTER_PRESSED, WORK ldi DISPLAY_DAT, 'T' ; und erfülle Aufgabe out UART_UDR, DISPLAY_DAT ; T1 senden ldi DISPLAY_DAT, '1' out UART_UDR, DISPLAY_DAT ;prelltest ; in WORK, PORTD_D ; sbrs WORK, 3 ; rjmp l_on ; cbi PORTD_D, 3 ; rjmp No_Tast_press ; l_on: ; sbi PORTD_D, 3 ; *** Aufgabe für Taster 2 ; w.o. pressed_taster_2: mov WORK, TASTER_PRESSED cpi WORK, 2 brne pressed_taster_3 andi WORK, 0b11111101 mov TASTER_PRESSED, WORK ldi DISPLAY_DAT, 'T' out UART_UDR, DISPLAY_DAT ldi DISPLAY_DAT, '2' out UART_UDR, DISPLAY_DAT ;prelltest ; in WORK, PORTD_D ; sbrs WORK, 4 ; rjmp l_on1 ; cbi PORTD_D, 4 ; rjmp No_Tast_press ; l_on1: ; sbi PORTD_D, 4 ; *** Aufgabe für Taster 3 ; w.o pressed_taster_3: mov WORK, TASTER_PRESSED cpi WORK, 4 brne pressed_taster_4 andi WORK, 0b11111011 mov TASTER_PRESSED, WORK ldi DISPLAY_DAT, 'T' out UART_UDR, DISPLAY_DAT ldi DISPLAY_DAT, '3' out UART_UDR, DISPLAY_DAT ;prelltest ; in WORK, PORTD_D ; sbrs WORK, 5 ; rjmp l_on2 ; cbi PORTD_D, 5 ; rjmp No_Tast_press ; l_on2: ; sbi PORTD_D, 5 ; *** Aufgabe für Taster 4 ; w.o pressed_taster_4: mov WORK, TASTER_PRESSED cpi WORK, 8 brne No_Tast_Press andi WORK, 0b11110111 mov TASTER_PRESSED, WORK ldi DISPLAY_DAT, 'T' out UART_UDR, DISPLAY_DAT ldi DISPLAY_DAT, '4' out UART_UDR, DISPLAY_DAT ;prelltest ; in WORK, PORTD_D ; sbrs WORK, 3 ; rjmp l_on3 ; cbi PORTD_D, 3 ; rjmp No_Tast_press ; l_on3: ; sbi PORTD_D, 3 No_Tast_press: ; out STATUS_FLAG,SAVE_STATUS_FLAG ; und Flags in orig. zustand ; pop SAVE_STATUS_FLAG pop WORK pop DISPLAY_DAT ret ; ********************************************************************* ; ********************************************************************* ; **** zeichen aus Puffer lesen und Puffer-Zeiger enstpr. Posit. ****** ; **** und CTS/XOFF entspr. setzen, falls an war ********************** ; ***** -- Register *************************************************** ; ***** Ausgabe des gelesenen Wertes : DISPLAY_DAT *( ab r16)* ; ***** Lesen aus RAM : r30,r31 Z_L,Z_H ******* ; ***** Pufferposisition und Größe : 2x unter r16 **************** ; ***** zwischenspeicher : TEMP *(ab r16)********* ; ***** in Stack gesichert !****** ; ***** zwischenspeicher : WORK *(ab r16)********* ; ***** in Stack gesichert !****** ; ***** -- Routinen *************************************************** ; ***** DD-RAM ADresse an Display : Disp_Send_Code ******** ; ********************************************************************* READ_PUFFER: push TEMP ; zum test push WORK ldi Z_L,UART_CR_OFF ; UART - Einstellen das kein Int out UART_UCSRB,Z_L ; beim auslesen ausgelöst wird tst PUFFER_AKT_LAENG ; Puffer leer ? also lange null breq End_leer ; dann ende ldi Z_L,PUFFER ; 1.Zeichen aus Puffer lesen clr Z_H ; aus SRAM ld DISPLAY_DAT, Z ; und nach DISPLAY_DAT (vorerst!-evt. extraReg.) mov WORK, PUFFER_AKT_LAENG ; sichern dec WORK dec PUFFER_AKT_LAENG ; Pufferlänge minus 1 breq End_jetzt_leer ; ist länge jetzt 0 ? (also puffer leer) READ_Loop: ; Puffer schieben (später evt. andere Art) ldd TEMP, Z+1 ; lese nächstes Zeichen st Z+, TEMP dec WORK brne READ_Loop End_jetzt_leer: clr TEMP st Z, TEMP ; 1.Zeichen löschen mov PUFFER_POS,Z_L End_leer: mov WORK, PUFFER_AKT_LAENG ; mache Puffer erstmal etwas leer bevor CTS frei wird cpi WORK, 2 ; brge End_E ; ; muß ERST dafor angeschalten werden, sont evt überlappungen I/O ldi Z_L,UART_CR ; Betriebsart des UART auf AN out UART_UCSRB,Z_L sbi PORTD_DDR,2 ; ansonsten cts aus cbi PORTD_D,2 ; damit neue Zeichnen kommen können ldi WORK, 17 ; XON out UART_UDR,WORK End_E: ldi Z_L,UART_CR ; Betriebsart des UART auf AN out UART_UCSRB,Z_L pop WORK pop TEMP ret ; *** End Read_Puffer************************************************** ; ********************************************************************* ; ***** setzt DD-RAM ADRESSE auf angegeb. Position ******************** ; ***** locate Zeile, Spalte als HEX_ZAHL ***************************** ; ***** bsp. locate mit übergabe 0x23 -> 2Zeile, 3Spalte ************** ; ***** Zeile 0-3, Spalte 0-F !! *** KEINE FEHLERAUSWERTUNG !!!!! ***** ; ***** ; ***** -- Register *************************************************** ; ***** übergabe des Wertes : DISPLAY_DAT *( ab r16)* ; ***** zwischenspeicher : TEMP *(ab r16)********* ; ***** in Stack gesichert !****** ; ***** -- Routinen *************************************************** ; ***** DD-RAM ADresse an Display : Disp_Send_Code ******** ; ********************************************************************* LocateZ_S: push DISPLAY_DAT ; rette mov C_MERK,DISPLAY_DAT ; setze Merkposition tst DISPLAY_DAT ; ZP -Zeile,Spalte hex breq loc ; Zeile,Spalte ist Null dann direkt zum Ende push TEMP ; retten damit nur ein REG belegt mov TEMP,DISPLAY_DAT ; rette Wert swap DISPLAY_DAT ; Zeile in untere Bits.. andi DISPLAY_DAT,0x0f ; Zeile filtern (Sp. löschen) breq loc_S ; Z=0 ? Zeile = 0 dec DISPLAY_DAT ; -1 Z1 breq loc_Z1 ; ist es Null ? dann war Zeile = 1 dec DISPLAY_DAT ; -1 Z2 breq loc_Z2 ; ist es Null ? dann war Zeile = 2 ldi DISPLAY_DAT,0x50 ; Zeilenstart , hier Zeile = 3 rjmp loc_S loc_Z2: ldi DISPLAY_DAT,0x10 ; Zeilenstart rjmp loc_S loc_Z1: ldi DISPLAY_DAT,0x40 ; Zeilenstart rjmp loc_S loc_S: ; und SPalte addieren andi TEMP,0x0f ; Spalte filtern (Zeile. löschen) or DISPLAY_DAT, TEMP ; dann addieren pop TEMP ; Wiederherstellen loc: ori DISPLAY_DAT,DISPLAY_DDRAM_NULL ; und Basis dazu rcall Disp_Send_Code ; ergibt DDRAM-ADresse pop DISPLAY_DAT ret ; *** end LocateZ_S *************************************************** ; ********************************************************************* ; ***** Sende Commando oder Daten an das Display ********************** ; ***** -- Register *************************************************** ; ***** übergabe des Wertes : DISPLAY_DAT *********** ; ***** zwischenspeicher : TEMP_DISP ************* ; ***** Verknüpfung ent Dat/Code : TEMP_DISP_DS ********** ; ***** PAUSE länge : PAUSEWERT ************* ; ***** zu and. arbeiten : WORK ****************** ; ***** -- Variblen *************************************************** ; ***** Display auf Empfang setzen : DDR_WRITE_DISPLAY ***** ; ***** -- Ports ****************************************************** ; ***** PortB -DDR : PORTB_DDR ************* ; ***** PortB -Daten : PORTB_D *************** ; ***** -- Routinen *************************************************** ; ***** den E-Puls senden : Send_E_Puls *********** ; ***** Pause : Delay_X *************** ; ********************************************************************* ; *** für Datensenden muß R/S H Disp_Send_Data: ldi TEMP_DISP_DS,16 ; R/S auf H für Daten (f. spät. or) rjmp Disp_Send ; *** für Codesenden muß R/S L Disp_Send_Code: clr TEMP_DISP_DS ; R/S auf L für Code ; *** Sende Daten Disp_Send: ; das Display-Busy abfragen ob Display bereit ldi TEMP_DISP, DDR_READ_DISPLAY ; lesen von Display einstellen out PORTB_DDR, TEMP_DISP ldi TEMP_DISP, 0b101111 ; Code lesen v. Display u. EingangsPull-up an out PORTB_D, TEMP_DISP Disp_Busy_Wait: sbi PORTC_D, 0 ; E auf High nop ; warte kurz bis Display Daten sendet nop nop in TEMP_DISP, PINB ; und einlesen cbi PORTC_D, 0 ; E auf Low nop nop rcall Send_E_Puls ; unteren 4Bits lesen (werden aber nicht benötigt) bst TEMP_DISP, 3 ; Busyflag bit nach T schieben brtc Disp_Ready ; T=0 ? dann Display bereit f. nächste Daten ; sbrs TEMP_DISP, 3 ; rjmp Disp_Ready nop ; sonst warte noch mind. 1µS nop nop nop nop rjmp Disp_Busy_Wait Disp_Ready: ; Weiter da Display Brereit ldi WORK,UART_CR_OFF ; UART - Einstellen das kein Int out UART_UCSRB,WORK ; beim auslesen ausgelöst wird ldi WORK,DDR_WRITE_DISPLAY ; Portrichtung zum schreiben auf display out PORTB_DDR,WORK cbi PORTB_D,5 ; R/W auf L damit Displ. auf Empfang geht ; denn 8bit-WErt in 2x4bit Wert umwandeln um senden mov TEMP_DISP, DISPLAY_DAT ; sichere übergeb. Wert swap DISPLAY_DAT ; tausche Nibbles, damit obere hälfte zuerst gesendet andi DISPLAY_DAT,0x0f ; lösche obere Hälfte or DISPLAY_DAT,TEMP_DISP_DS ; und setze wieder R/S out PORTB_D,DISPLAY_DAT ; ausgeben an Ports rcall Send_E_Puls ; und Displ. übernimmt Daten durch E-Impuls andi TEMP_DISP,0x0f ; jetzt noch den LOW-Teil der ja im gesicht. TEMP steht or TEMP_DISP,TEMP_DISP_DS ; R/S wieder setzen out PORTB_D,TEMP_DISP ; ... rcall Send_E_Puls ; ... ldi WORK,UART_CR ; UART - wieder an out UART_UCSRB,WORK ; ret ;*** End Daten/Code senden ******************************************* ; ******************************************************************** ; ***** Display initalisieren **************************************** ; ***** s. Datenblatt zum Display ************************************ ; ***** -- Register ************************************************** ; ***** zu allg. arbeiten : WORK ( ab r16) ******* ; ***** PAUSE länge : PAUSEWERT ( ab r16) ** ; ***** übergabe eine Wertes an Display : DATEN_DAT ( ab r16) ** ; ***** -- Variblen ************************************************** ; ***** Display auf Empfang setzen : DDR_WRITE_DISPLAY **** ; ***** setzen der Modi s. Datenblatt, : DISPLAY_FUNK_SET ***** ; ***** werte vordef. am Anfang des : DISPLAY_DISP ********* ; ***** programmes : DISPLAY_CLEAR ******** ; ***** : DISPLAY_EMODE ******** ; ***** -- Ports ***************************************************** ; ***** PortB -DDR : PORTB_DDR ************ ; ***** PortB -Daten : PORTB_D ************** ; ***** -- Routinen ************************************************** ; ***** den E-Puls senden : Send_E_Puls ********** ; ***** Pause : Delay_X ************** ; ******************************************************************** Init_Display: ldi WORK,DDR_WRITE_DISPLAY ; Portrichtung zum schreiben auf display out PORTB_DDR,WORK ;*** ab hier siehe datenblatt ldi PAUSEWERT, 170 ; 170 x ca. 100us = ca. 17ms rcall Delay_X ; Pause mind. 15ms ;* ERSTE (4bit) sequ. laut datenblatt ldi WORK, 0b000011 out PORTB_D, WORK rcall Send_E_Puls ; mit E_PULS datenübernahme ldi PAUSEWERT, 50 ; 5ms rcall Delay_X ; und eine Pause mind. 4ms ;* ZWEITE ; da Ports schon gesetzt kann auf nochmal. setzen verzichtet werden ; und einfach mit den Pausen und E_pulsen fortgefahren werden rcall Send_E_Puls ; E_PULS datenübernahme ldi PAUSEWERT, 20 ; 2ms rcall Delay_X ; und eine Pause ;* DRITTE sequ. laut datenblatt rcall Send_E_Puls ; E_PULS datenübernahme ldi PAUSEWERT, 20 ; zwar nicht angeb. aber nötig ! rcall Delay_X ; und eine Pause ;* VIERTE sequ. laut datenblatt cbi PORTB_D,0 ; einfach bit 0 löschen rcall Send_E_Puls ; E_PULS datenübernahme ldi PAUSEWERT, 20 ; w.o. rcall Delay_X ; und eine Pause ;** ab hier ist auf 4bit umgeschalten !!! und es muß dem Display mitgeteilt ;* werden das Code kommt !!! ;** funktions-set ldi DISPLAY_DAT, DISPLAY_FUNK_SET rcall Disp_Send_Code ; routine zum CODE an Displ. zu senden ;** display an ldi DISPLAY_DAT,DISPLAY_DISP rcall Disp_Send_Code ;** Clear Display ldi DISPLAY_DAT,DISPLAY_CLEAR rcall Disp_Send_Code ;** Entry-Mode-Set ldi DISPLAY_DAT,DISPLAY_EMODE rcall Disp_Send_Code ; DD-RAM auf NULL ldi DISPLAY_DAT,DISPLAY_DDRAM_NULL rcall Disp_Send_Code ret ; *** End Display initalisieren ************************************** ; ******************************************************************** ; ***** sende E-Puls damit Displ. Daten übernimmt ******************** ; ***** -- Ports ***************************************************** ; ***** PortC -DDR : PORTC_DDR ************ ; ***** PortC -Daten : PORTC_D ************** ; ******************************************************************** Send_E_Puls: sbi PORTC_D,0 ; E auf HIGH nop ; ... nop ; kurz E halten nop ; ... cbi PORTC_D,0 ; und E wieder LOW ret ; *** End E-Puls senden ********************************************** ; ******************************************************************** ; ***** Pause von ca. 100us bis 6.4sec / bei 8Mhz ******************** ; ***** ; ******** innere Pause Delay_X : (bei 8Mhz u. Fakt=1 ca. 100us)*** ; ******** -- Register *********************************************** ; ***** Übergebener Wert, die Länge d.P.: PAUSEWERT ************ ; ***** Faktor : 1-255 ergibt 100us-25ms , 0 maximum ***************** ; ***** äußerer Schleifen Zähler : PAUSE1 (>=r16) ******* ; ***** ; ******** Große Pause Delay_X_long :(bei 8Mhz u. Fakt=1 ca. 25ms )*** ; ******** -- Register *********************************************** ; ***** Übergebener Wert, die Länge d.P.: PAUSEWERT ************ ; ***** Faktor : 1-255 ergibt 25ms-6,4sec , 0 maximum **************** ; ***** zus. zu PAUSE1 noch das Register PAUSE_LANG, welches ********* ; ***** nicht direkt beschrieben werden kann (unter r16) ************* ; ******************************************************************** Delay_X_long: ; Schleife Pause Lang mov PAUSE_LANG,PAUSEWERT ; (indirk.Reg) Wert sichern clr PAUSEWERT ; clr damit Delay_X auf max läuft rjmp Dlong ; und beginn Schleife Delay_X: ; Schleife Pause Klein ldi PAUSE1,1 ; wenn kl.Pause muß PAUSE_LANG (r0) mov PAUSE_LANG,PAUSE1 ; so sein, das Gr.Schleife u. nicht durchlaufen wird !! Dlong: ; die äußere Schleife clr PAUSE1 ; 256 durchläufe Loop1: ; die innere Schleife dec PAUSE1 brne Loop1 ; ** dec PAUSEWERT brne Dlong ; ** dec PAUSE_LANG brne Dlong ; ** ret ; *** End Pause ****************************************************** ; *** End Unterprogramme *******************************************************