;------------------------------------------------------------------------- ; Krabbler für ATmega8 ;------------------------------------------------------------------------- ; dient der Entwicklung des SPI für die dargestellte Schaltung, fertig ; in der EEPROM-Initialisierung sind noch Zeilen auskommentiert, da beim Brennen das EEPROM gelöscht wird ; prüfen, ob durch Verstellen einer FUSE das Überschreiben verhindert werden kann ; Funktion : ATmega8 ist SPI-Master; wählt durch SoftwareSlaveSelect (PORT c1 oder C2) einen der ; ATTinys (PIN B0) als Slave aus, dieser antwortet über Port B1 (PIN C3); jeder Slave steuert sechs Servos ; Die Servos 1 bis 6 hängen an Slave 1, Nr. 9 bis 14 an Slave 2 ; zur Datenübertragung wird die Servonummer ins obere Nibbel des ersten Bytes gepackt, das untere Nibbel ; des Highbytes ins untere Nibbel des ersten Bytes und das Lowbyte in das zweite Byte ; ATmega8 steuert das Radarservo, das LCD-Display, treibt den Distanzsensor und berechnet die Wege ; Die Pulsdauer für das Radarservo ist interruptgesteuert ; Zur Gerätjustierung wird per Taster in den Programmiermodus umgeschaltet (LED an!) ; Dazu werden die Servos per Joystick eingestellt und die so ermittelten Pulslängen anschließend im EEPROM gespeichert; ; zu jedem der sechs Servopaare gibt es je fünf Positionen (oben-unten;vorn-Mitte-hinten) mit Low und High-Byte ; Schaltung : SPI: MOSI, SCK ATMega8 zu ATTinys, ISP und LCD-shielt lt. Datenblatt B3,B4,B5 ; ATMega8 - ATTiny2313 ; C1 - B0 ; C2 - B0 ; C3 - B1 ; ATMega8 - LCD-shield ; C0 - A0 ADC für Joystick ; D2 - RST Taster zur Umschaltung auf Programmierung ; D4 - D4 Displaycontroller-Umschaltung ; D5 - D5 Displaycontroller select ; D6 - D6 LCD-Reset ; D7 - D7 LCD-Beleuchtung ; C4: Radarservo ; Servonummern: 1 2 9 10 ; 3 4 11 12 ; 5 6 13 14 ;------------------------------------------------------------------------- ; Prozessor : ATmega8 ; Takt : 3686400 Hz ; Sprache : Assembler (GNU) ; Datum : 6.12.2012 ; Version : 1.5 ; Autor : U.S. ;------------------------------------------------------------------------- ; ; Registerfestlegungen: R0 zum Auslesen des FlashRAM und für Multiplikation ; R1 Multiplikation ; R0 + R1 Multiplikationsergebnis mul (R1h:R0l) ; R2 Nummer der aktuellen Position (1 - 30) (entspr. Index 0 bis 59 der EEPROM-Tabelle) ; R3 Servonummer ; R4 Positionstext ; R10 Transfermaske ein ; R11 Transfermaske aus ; R16 temporär ; R17 temporär 2 und Datenübergaberegister ; R18 Datenübergabe an SPI (LCD Daten und Steuerung) und an EEPROM Routinen ; R20 + R21 Übergabe eines Word (R21h:R20l) ; R22 + R23 Pulsdauer Radarservo (R23h:R22l) ; R24 + R25 Servopulsdauer (R25h:R24l) ; .include "avr.h" begin: rjmp main ; 1 POWER ON RESET rjmp ISR_Taster ; 2 Int0-Interrupt reti ; 3 Int1-Interrupt reti ; 4 TC2 Compare Match reti ; 5 TC2 Overflow reti ; 6 TC1 Capture rjmp ISR_Vergl_A ; 7 TC1 Compare Match A rjmp ISR_Vergl_B ; 8 TC1 Compare Match B reti ; 9 TC1 Overflow reti ;10 TC0 Overflow reti ;11 SPI, STC Serial Transfer Complete reti ;12 UART Rx Complete reti ;13 UART Data Register Empty reti ;14 UART Tx Complete reti ;15 ADC Conversion Complete reti ;16 EEPROM Ready reti ;17 Analog Comparator reti ;18 TWI (I²C) Serial Interface reti ;19 Store Program Memory Ready ;------------------------------------------------------------------------ ; Initialisierungen ;------------------------------------------------------------------------ main: ldi R16,hi8(RAMEND) ; Stack Initialisierung out SPH,R16 ldi R16,lo8(RAMEND) out SPL,R16 ; Ports B2-5 werden durch SPI-Init festgelegt ; PORTC0 für ADC sbi DDRC,1 ; PORTC1 als Ausgang (SS1) sbi PORTC,1 ; Pegel high sbi DDRC,2 ; PORTC2 als Ausgang (SS2) sbi PORTC,2 ; Pegel high cbi DDRC,3 ; PORTC3 als Eingang (Slave-Rückmeldung) sbi PORTC,3 ; mit Pullup sbi DDRC,4 ; PORTC4 als Ausgang für Radarservo cbi DDRD,2 ; PORTD2 als Eingang für Taster (RST an LCD-shield) sbi PORTD,2 ; mit Pullup sbi DDRD,4 ; PORTD4-7 als Ausgang für LCD-shield sbi DDRD,5 sbi DDRD,6 sbi DDRD,7 ldi R22,lo8(691) ; Timerstartwert liegt bei 1500µS (Mittelstellung) ldi R23,hi8(691) ; errechnet sich nach (= Impulsdauer * Prozessorfrequenz / Timerprescaler) ldi R16,lo8(9216) ; Timerendwert liegt bei 20ms (umgerechnet wie vorstehend) ldi R17,hi8(9216) out OCR1AH,R17 out OCR1AL,R16 ldi R16,0b00011000 ; Interrupt OCIE1A und OCIE1B eingeschaltet out TIMSK,R16 ldi R16,0b0001010 ; CTC-Mode, Prescaler 8 out TCCR1B,R16 in R16,GICR ; INT0 Interrupt an Eingang PORTD2 bei fallender Flanke sbr R16,0b01000000 out GICR,R16 in R16,MCUCR ; fallende Flanke sbr R16,0b00000010 out MCUCR,R16 ldi R16,0b00100000 ; ADC initialisieren: Port, Referenzspannung und Auflösung out ADMUX,R16 ldi R16,0b10000101 ; Modus, Interrupt und Start out ADCSRA,R16 rcall SPI_init rcall LCD_init rcall EEPROM_init ; EEPROM-Tabelle für Justierpositionen prüfen ; RAM-Tabelle der aktuellen Servopositionen anlegen rcall Warte500ms ; Pause 500 ms; warten bis die Initialisierung der Slaves sicher beendet ist ;rcall WDT_init sei ; Interrupts erlauben ;------------------------------------------------------------------------ ; Hauptprogramm-Schleife ;------------------------------------------------------------------------ mainloop: wdr ; Arbeitsmodus clr R2 ; falls anschließend PModus, dazu Merker vorbereiten sbic PORTD,7 ; Programmiermodus an? angezeigt durch eingeschaltete LCD-Beleuchtung rjmp PModus ; ja -> Programmiermodus ; Erkennung der Umgebung per Radar ; Steuerung der Servos ;welcher Slave wird angesteuert? rjmp mainloop ;------------------------------------------------------------------------ PModus: wdr ; Programmiermodus sbis PORTD,7 ; Programmiermodus an? rjmp mainloop ; nein -> Arbeitsmodus tst R2 ; erster Durchgang? brne PM_2 ; nein, dann weiter ldi R16,1 ; ja, zunächst Bildschirm aufbauen, ab Textzeile1 rcall LCD_Bildschirm_darstellen ; rcall Servos_Grundstellung;alle Servos in eine noch zu bestimmende Grundstellung bringen z.B. alle Mitte bzw. unten inc R2 ; beginnt mit Servotabellenposition Nr.1 (Servo Nr. 1 in Stellung oben) mov R3,R2 ; Servo 1 mov R4,R2 ; Servostellung 0 (oben) rcall Pos_txt ; Wort1 (oben) rcall AusEEPROM ; jetzt wird die Pulsdauer zu Position 1 aus dem EEPROM ausgelesen und in (R25h:R24l) abgelegt rcall Pulsd_aktl ; auf dem Display angezeigt und an Slave übertragen werden PM_2: rcall Progmodif rjmp PModus ;------------------------------------------------------------------------ ; Initialisierungsroutinen ;------------------------------------------------------------------------ ; SPI-Initialisierung als Master SPI_init: sbi DDRB,2 ; SS als Ausgang - wird nicht benutzt sbi DDRB,3 ; MOSI als Ausgang cbi DDRB,4 ; MISO als Eingang sbi DDRB,5 ; SCK als Ausgang ldi R16,0b01010001 ; enable SPI, Master, fosc/16 out SPCR,R16 ret ;------------------------------------------------------------------------ WDT_init: push R16 wdr ldi R16,0b00011000 ; Watchdog Startsequenz out WDTCR,R16 ldi R16,0b00001011 ; Watchdog ein ca. 100 ms out WDTCR,R16 pop R16 ret ;------------------------------------------------------------------------ LCD_init: cbi PORTD,6 ; Display reset nop nop nop sbi PORTD,6 cbi PORTD,5 ; Displaycontroller select nop nop nop sbi PORTD,5 nop nop nop ;sbi PORTD,7 ; Beleuchtung an ldi R18,0x21 ; LCD erw.Kommandos rcall LCD_Steuerungsbyte ldi R18,0xC0 ; LCD Kontrast rcall LCD_Steuerungsbyte ldi R18,0x06 ; LCD Temp. Koeffizient rcall LCD_Steuerungsbyte ldi R18,0x13 ; LCD Verst.Fakt. 1:48 rcall LCD_Steuerungsbyte ldi R18,0x20 ; Adressierungsmodus horizontal rcall LCD_Steuerungsbyte rcall LCD_leeren ldi R18,0x0C ; LCD Normalmodus rcall LCD_Steuerungsbyte cbi PORTD,5 ret LCD_leeren: ldi R18,0x0C ; LCD Normalmodus rcall LCD_Steuerungsbyte ldi R18,0x80 ; X-Koordinate auf Null rcall LCD_Steuerungsbyte ldi r18,0 rcall Halbleeren ; 1. Hälfte rcall Halbleeren ; 2. Hälfte ret Halbleeren: ldi R16,252 ; halbes Display leeren n_Ch: rcall LCD_Datenbyte dec R16 brne n_Ch ret ;------------------------------------------------------------------------ ; Interruptserviceroutinen ;------------------------------------------------------------------------ ;ISR: TIMER1 Compare Match A - 20ms abgelaufen ISR_Vergl_A:sbi PORTC,4 ; Port C.4 auf high out OCR1BH,R23 ; die aktuelle Pulsdauer ist in R22 (high) out OCR1BL,R22 ; und R21 (low) abgelegt reti ;------------------------------------------------------------------------ ;ISR: TIMER1 Compare Match B - Pulsdauer für Radarservo abgelaufen ISR_Vergl_B:cbi PORTC,4 ; Port C.4 auf low reti ;------------------------------------------------------------------------ ;ISR: INT0 für Taster Programmiermodus - wird bei Betätigung ein- bzw. ausgeschaltet ISR_Taster: push R16 ldi R16,25 ; 50 µs sind erforderlich Entprell: dec R16 ; einfache Warteroutine zum Entprellen brne Entprell ; abgezählt? sbic PORTD,7 ; war ausgeschaltet? rjmp Abschalten ; nein sbi PORTD,7 ; Einschalten rjmp ISR_T_Ende Abschalten: cbi PORTD,7 ISR_T_Ende: pop R16 reti ;------------------------------------------------------------------------ ; Unterprogramme ;------------------------------------------------------------------------ ; Warte-Routine für 500 ms (480,6 ms) Warte500ms: push R16 ldi R16,9 W500_3: push R16 ldi R16,255 W500_2: push R16 ldi R16,255 W500_1: dec R16 brne W500_1 pop R16 dec R16 brne W500_2 pop R16 dec R16 brne W500_3 pop R16 ret ;-------------------------------------------------------------------- ; Warte-Routine für 300 ms Warte300ms: push R16 ldi R16,150 w300_3: push R16 ldi R16,10 w300_2: push R16 ldi R16,255 w300_1: dec R16 brne w300_1 pop R16 dec R16 brne w300_2 pop R16 dec R16 brne w300_3 pop R16 ret ;-------------------------------------------------------------------- ; Warte-Routine für 10 ms Warte10ms: push R16 ldi R16,10 w10_3: push R16 ldi R16,5 w10_2: push R16 ldi R16,255 w10_1: dec R16 brne w10_1 pop R16 dec R16 brne w10_2 pop R16 dec R16 brne w10_3 pop R16 ret ;-------------------------------------------------------------------- ; Warte-Routine für 1 ms (1,052 ms) Warte1ms: push R16 ldi R16,1 w1_3: push R16 ldi R16,5 w1_2: push R16 ldi R16,255 w1_1: dec R16 brne w1_1 pop R16 dec R16 brne w1_2 pop R16 dec R16 brne w1_3 pop R16 ret ;------------------------------------------------------------------------ ; ein Byte übertragen per SPI, die Daten werden in R18 übergeben SPI_senden: out SPDR,R18 ; SPI Datenregister füllen und damit Übertragung starten komplett: sbis SPSR,SPIF ; Übertragung vollständig? rjmp komplett ; nein - warten ret ;------------------------------------------------------------------------ ;Joystickwerte: nach AD-Wandlung wird die Position als Wert 0-5 in R0 übergeben ;gemessene Werte daraus resultierende Grenzwerte ;ohne Betätigung 255 0: 0- 20 (links) ;gedrückt 38 1: 21- 60 (gedrückt) ;oben 186 2: 30-105 (unten) ;unten 84 3: 106-156 (rechts) ;rechts 126 4: 157-220 (oben) ;links 1 5: 221-255 (ohne Betätigung) Joystick: rcall ADCeinlesen ; abfragen clr R0 ldi R17,20 cp R16,R17 brlo J_Ende ; kleiner als der Grenzwert 0 inc R0 ldi R17,60 cp R16,R17 brlo J_Ende ; Grenzwert 1 inc R0 ldi R17,105 cp R16,R17 brlo J_Ende ; Grenzwert 2 inc R0 ldi R17,156 cp R16,R17 brlo J_Ende ; Grenzwert 3 inc R0 ldi R17,220 cp R16,R17 brlo J_Ende ; Grenzwert 4 inc R0 J_Ende: ret ;-------------------------------------------------------------------- ; digitalisiert einen Analogwert und wartet auf das Ergebnis; Rückgabewert in R16 ADCeinlesen:sbi ADCSRA,6 ; Start ADC ADCeinl2: sbic ADCSRA,6 ; Test ob fertig rjmp ADCeinl2 ; wenn nicht fertig in R16,ADCH ; Einlesen des Analogwertes ret ;------------------------------------------------------------------------ ; ein Byte an LCD senden (wird in R18 übergeben) LCD_Datenbyte: cbi PORTD,5 ; Displaycontroller selektiert sbi PORTD,4 ; Displaycontroller: Datenbyte rcall SPI_senden sbi PORTD,5 ; Displaycontroller deselektiert ret LCD_Steuerungsbyte: cbi PORTD,5 ; Displaycontroller selektiert cbi PORTD,4 ; Displaycontroller: Steuerungsbyte rcall SPI_senden sbi PORTD,5 ; Displaycontroller deselektiert ret ;-------------------------------------------------------------------- ; Word (begrenzt auf Werte unter 10000) wird auf dem Bildschirm als Dezimalwert angezeigt ; Übergabe in r21h:r20l, die Ausgabeposition wurde zuvor festgelegt (XY) LCD_Word_in_Dez: ldi R17,48 ; ASCII Null mov R0,R17 ldi R17,hi8(1000) ; Tausenderstelle ldi R16,lo8(1000) rcall LCD_WiD_Div ldi R17,48 ; ASCII Null mov R0,R17 ldi R17,0 ; Hunderterstelle ldi R16,100 rcall LCD_WiD_Div ldi R17,48 ; ASCII Null mov R0,R17 ldi R17,0 ; Zehnerstelle ldi R16,10 rcall LCD_WiD_Div ldi R17,48 ; ASCII Null mov R0,R17 add R0,R20 ; in R20 sind jetzt nur noch die Einer übrig rcall LCD_Zeichen_darstellen ret LCD_WiD_Div:cp R20,R16 ; Word größer oder gleich Vergleichswert? cpc R21,R17 brlo LCD_WiD_Aus ; nein -> Ausgabe sub R20,R16 ; ja -> subtrahieren sbc R21,R17 inc R0 ; Dezimalstelle erhöhen rjmp LCD_WiD_Div LCD_WiD_Aus:rcall LCD_Zeichen_darstellen ret ;------------------------------------------------------------------------ LCD_Zeichen_darstellen: ; ein einzelnes Zeichen wird an der zuvor festgelegten Pos. dargestellt push ZL ; die Nummer des ASCII-Zeichen ist in R0 abgelegt push ZH ; die graphische 5x7 Darstellung findet sich im Flash-RAM unter push R16 ; Datensatz+Asciiwert*5 ff. push R17 mov R16,R0 subi R16,32 ; die Asciicodes beginnen mit Leerzeichen an Nr. 32 ldi R17,5 mul R16,R17 ldi ZL,lo8(Zeichensatz) ldi ZH,hi8(Zeichensatz) add ZL,R0 adc ZH,R1 ldi R18,0x00 ; Zwischenraum zum Nachbarzeichen (eine Punktspalte) rcall LCD_Datenbyte ldi R16,5 ; fünf Spalten zu 7 Punkten LCD_Z_2: lpm R18,Z+ rcall LCD_Datenbyte dec R16 brne LCD_Z_2 pop R17 pop R16 pop ZH pop ZL ret ;------------------------------------------------------------------------ LCD_Zeile_darstellen: ; eine Zeile von 14 Zeichen wird aus dem Flashspeicher geholt push ZL ; und an der zuvor festgelegten Position (XY-Koordinaten) dargestellt push ZH ; die Nummer der Textzeile im Flashspeicher wird in R16 übergeben push R16 push R17 dec R16 ; Offset ist eins kleiner als die Nummer ldi R17,15 ; die Textstrings sind nullterminiert: 14+1 ! mul R16,R17 ; Ergebnis wird in ldi R16,14 ; 14 Zeichen sind einzulesen ldi ZL,lo8(Textzeile1) ldi ZH,hi8(Textzeile1) add ZL,R0 adc ZH,R1 LCD_Zl_2: lpm rcall LCD_Zeichen_darstellen adiw ZL,1 ;nächstes Zeichen dec R16 brne LCD_Zl_2 pop R17 pop R16 pop ZH pop ZL ret ;------------------------------------------------------------------------ LCD_Bildschirm_darstellen: ; der ganze Bildschirm wird dargestellt durch 6 aufeinander folgende Textzeilen ; die Nummer der ersten Zeile wird in r16 übergeben ldi R18,0x40 ; Bildschirmkoordinaten auf 0, zuerst die Spalte rcall LCD_Steuerungsbyte ldi R18,0x80 ; jetzt die Reihe auf 0 rcall LCD_Steuerungsbyte ldi R17,6 ; 6 Zeilen LCD_B_2: rcall LCD_Zeile_darstellen inc R16 ; nächste Zeile dec R17 ; fertig? brne LCD_B_2 ret ;------------------------------------------------------------------------ LCD_Wort_darstellen: ; ein Wort (Position) wird aus dem Flashspeicher geholt push ZL ; und an der zuvor festgelegten Position (XY-Koordinaten) dargestellt push ZH ; die Nummer des Worts im Flashspeicher wird in R16 übergeben push R16 push R17 dec R16 ; Offset ist eins kleiner als die Nummer ldi R17,7 ; die Textstrings sind nullterminiert: 6+1 ! mul R16,R17 ldi R16,6 ; 6 Zeichen sind einzulesen ldi ZL,lo8(Wort1) ldi ZH,hi8(Wort1) add ZL,R0 adc ZH,R1 LCD_W_2: lpm rcall LCD_Zeichen_darstellen adiw ZL,1 ;nächstes Zeichen dec R16 brne LCD_W_2 pop R17 pop R16 pop ZH pop ZL ret ;------------------------------------------------------------------------ ;EEPROM-Tabelle für Justierpositionen prüfen ;------------------------------------------------------------------------ EEPROM_init:ldi R24,lo8(1500) ; falls sich dort leere Werte finden (unzulässig!), ldi R25,hi8(1500) ; wird die Mittelstellung 1500(µS) eingetragen ldi R16,30 ; zu jedem der sechs Servopaare mit fünf Positionen (oben-unten;vorn-Mitte-hinten) Low und High-Bit mov R2,R16 ; R2 Zähler auf 30 (Position) EE_i2: mov R16,R2 dec R16 ; der Speicher beginnt bei 0 lsl R16 ; immer Lo- und Hi-Byte abwechselnd gespeichert (2x30 Werte) rcall EELesen ; Lo-byte lesen tst R18 ; leer? ;brne EE_i2_nP ; nein - nächste Position inc R16 ; ja rcall EELesen ; Hi-Byte lesen tst R18 ; auch leer? ;brne EE_i2_nP ; nein - nächste Position rcall InEEPROM ; ja: Mittelstellung 1500(µS) speichern EE_i2_nP: dec R2 brne EE_i2 ret ;------------------------------------------------------------------------ ; der aktuelle Wert der Servopulsdauer (R25h:R24l) wird im EEPROM abgelegt, die Position steht in R2 ;------------------------------------------------------------------------ InEEPROM: clr R17 ; AdresseH ist immer 0, da nur 60 Werte mov R16,R2 dec R16 ; der Speicher beginnt bei 0 lsl R16 ; immer Lo- und Hi-Byte abwechselnd gespeichert mov R18,R24 rcall EESchreiben inc R16 mov R18,R25 rcall EESchreiben ret ;------------------------------------------------------------------------ ; der aktuelle Wert für die Servopulsdauer (R25h:R24l) wird aus dem EEPROM geholt, die Position steht in R2 ;------------------------------------------------------------------------ AusEEPROM: clr R17 ; AdresseH ist immer 0, da nur 60 Werte mov R16,R2 dec R16 ; der Speicher beginnt bei 0 lsl R16 ; immer Lo- und Hi-Byte abwechselnd gespeichert rcall EELesen mov R24,R18 inc R16 rcall EELesen mov R25,R18 ret ;---------------------------------------------------------------------- ;Daten aus EEPROM lesen, R17:R16 = Adresse, R18 = Wert aus EEPROM ;---------------------------------------------------------------------- EELesen: out EEARH,R17 ;AdresseH out EEARL,R16 ;AdresseL sbi EECR,0 ;Leseaufforderung WarteEEL: sbic EECR,0 ;warte auf Fertigmeldung rjmp WarteEEL in R18,EEDR ;Daten übernehmen ret ;---------------------------------------------------------------------- ;Daten in EEPROM schreiben, R17:R16 = Adresse, R18 = Wert für EEPROM ;---------------------------------------------------------------------- EESchreiben:out EEARH,R17 ;AdresseH out EEARL,R16 ;AdresseL out EEDR,R18 ;Daten übergeben sbi EECR,2 ;Schreiben erlauben sbi EECR,1 ;Schreibaufforderung warteEES: sbic EECR,1 ;warten bis fertig rjmp warteEES ret ;------------------------------------------------------------------------------------------------------------ ; Pulsdauer für ein Servo übertragen, die Daten liegen in R15 (Servonummer), R24 (Lowbyte) und R25 (Highbyte) ;------------------------------------------------------------------------------------------------------------ Warte_100us:push R16 ;löwschen falls nicht gebraucht ldi R16,1 ; Anzahl der 100 µs W_100us_3: push R16 ldi R16,1 W_100us_2: push R16 ldi R16,115 W_100us_1: dec R16 brne W_100us_1 pop R16 dec R16 brne W_100us_2 pop R16 dec R16 brne W_100us_3 pop R16 ret ;------------------------------------------------------------------------------------------------------------ Bytetransfer: ; das zu sendende Byte ist in R18 abgelegt out PORTC,R10 ; Slave select Bt2: sbic PINC,3 ; Antwort v. ATTiny durch low-Signal auf PIN C3 rjmp Bt2 ; ATTiny noch nicht bereit rcall SPI_senden ; Byte senden (R18) out PORTC,R11 ; Slave deselektieren Bt3: sbis PINC,3 ; Antwort v. ATTiny durch high-Signal auf PIN C3 rjmp Bt3 ; ATTiny hat die Daten noch nicht verarbeitet ret ;------------------------------------------------------------------------------------------------------------ Daten_An_Slave: in R11,PORTC ; Portmaske sichern mov R10,R11 ldi R16,0b00000010 ; Slave 1 mov R18,R3 sbrc R18,3 ; Bit 3 gesetzt ? , d.h. Servo 9-14 (Slave 2) lsl R16 ; ja, also gesetztes Bit in Maske von C1 auf C2 schieben com r16 ; Slaveselect low-Pegel and R10,R16 ldi R16,0b00000111 and R18,R16 ; die Servonummer auf den Slave bezogen steht in den unteren 3 Bit swap R18 or R18,R25 ; das obere Nibbel in R3 und R25 ist immer 0 - zur Übertragung in ein Byte gepackt rcall Bytetransfer mov R18,R24 rcall Bytetransfer ;------------------------------------------------------------------------------------------------------------ ;------------------------------------------------------------------------------------------- ; Pulsdauer des aktuellen Servos aktualisieren: anzeigen (R25h:R24l) und an slave übertragen ;------------------------------------------------------------------------------------------- Pulsd_aktl: ldi R18,0x45 ; Zeile 6 (40h+(6-1)) - Koordinaten für LCD-Ausgabe rcall LCD_Steuerungsbyte ldi R18,0x98 ; Spalte 5 (80h+4x6) rcall LCD_Steuerungsbyte movw R20,R24 rcall LCD_Word_in_Dez ; anzeigen auf LCD rcall Daten_An_Slave ; und übertragen an Slave ret ;---------------------------------------------------------------------------------- ;auf dem LCD-Display wird der Text zur aktuellen Position angezeigt, Index in R4 ;---------------------------------------------------------------------------------- Pos_txt: push ZL ; zuerst XY-Koordinaten push ZH ldi R18,0x43 ; Zeile 4 (40h+(4-1)) (Cursorposition Zeile4 zentriert) rcall LCD_Steuerungsbyte ldi R18,0x98 ; Spalte 5 (80h+(5-1)x6) rcall LCD_Steuerungsbyte ldi R16,7 ; die Textstrings sind nullterminiert: 6+1 ! dec R4 ; Wort1 beginnt beim Index 0 mul R4,R16 ldi R16,6 ; 6 Zeichen sind einzulesen ldi ZL,lo8(Wort1) ldi ZH,hi8(Wort1) add ZL,R0 adc ZH,R1 Pos_2: lpm rcall LCD_Zeichen_darstellen adiw ZL,1 ;nächstes Zeichen dec R16 brne Pos_2 pop ZH pop ZL ret ;------------------------------------------------------------------------ ; Modifikation der in der EEPROM-Tabelle abgelegten Pulsdauern ;------------------------------------------------------------------------ Progmodif: rcall Joystick ; Joystick betätigt? ldi R16,5 cp R16,R0 ; ohne Betätigung? brne Option2 ret ; ohne Betätigung (Joystickantwort 5) Option2: rcall Warte300ms ; Prellen vermeiden dec r16 cp r16,r0 ; oben? brne Option3 adiw R24,1 ; oben: Pulsdauer verlängert (Joystickantwort 4) rcall Pulsd_aktl ; neue Pulsdauer angezeigt und an Slave gesendet ret Option3: dec r16 cp r16,r0 ; rechts? brne Option4 rcall Cursor_l ; Cursor löschen ldi R16,30 cp R16,R2 ; max. 30 brne Opt3_2 clr R2 ; fängt wieder bei 1 an Opt3_2: inc R2 rjmp Opt36 ; zweiter Teil der Prozedur, identisch für Opt. 3 und 6 Option4: dec r16 cp r16,r0 ; unten? brne Option5 sbiw R24,1 ; unten: Pulsdauer verkürzt (Joystickantwort 2) rcall Pulsd_aktl ; neue Pulsdauer angezeigt und an Slave gesendet ret Option5: dec r16 cp r16,r0 ; gedrückt? brne Option6 rcall InEEPROM ; gedrückt: aktuellen Wert im EEPROM speichern (Joystickantwort 1) ret Option6: rcall Cursor_l ; Cursor löschen dec R2 tst R2 ; darf nicht 0 werden brne Opt36 ldi R16,30 mov R2,R16 Opt36: rcall Cursor_s ; Cursor setzen rcall Pos_txt rcall AusEEPROM rcall Pulsd_aktl ; Pulsdauer angezeigt und an Slave gesendet ret ;------------------------------------------------------------------------ Cursor_l: rcall Posdat ; Cursor löschen, zunächst Koordinaten setzen ldi R16,124 ; Leerkästchen mov R0,R16 rcall LCD_Zeichen_darstellen ret Cursor_s: rcall Posdat ; Cursor setzen, zunächst Koordinaten setzen ldi R16,125 ; ausgefülltes Kästchen mov R0,R16 rcall LCD_Zeichen_darstellen ret Posdat: push ZL ; Koordinaten für den aktuellen Cursor aus dem FlashRAM holen und setzen push ZH ; Servonummer und Positionstext holen und ablegen push R16 push R17 mov R16,R2 ; die Koordinaten sind unter Positionsdaten abgelegt dec R16 ; für Nr. 1 ohne Offset lsl R16 ; immer vier Werte (s.u.) lsl R16 clr R17 ldi ZL,lo8(Positionsdaten) ldi ZH,hi8(Positionsdaten) add ZL,R16 adc ZH,R17 lpm R18,Z+ ; Zeile rcall LCD_Steuerungsbyte lpm R18,Z+ ; Spalte rcall LCD_Steuerungsbyte lpm R3,Z+ ; Servonummer lpm R4,Z ; Positionstext pop R17 pop R16 pop ZH pop ZL ret ;------------------------------------------------------------------------ Zeichensatz: .byte 0x00,0x00,0x00,0x00,0x00 ; sp .byte 0x00,0x00,0x2f,0x00,0x00 ; ! .byte 0x00,0x07,0x00,0x07,0x00 ; " .byte 0x14,0x7f,0x14,0x7f,0x14 ; # .byte 0x24,0x2a,0x7f,0x2a,0x12 ; $ .byte 0x62,0x64,0x08,0x13,0x23 ; % .byte 0x36,0x49,0x55,0x22,0x50 ; & .byte 0x00,0x05,0x03,0x00,0x00 ; ' .byte 0x00,0x1c,0x22,0x41,0x00 ; ( .byte 0x00,0x41,0x22,0x1c,0x00 ; ) .byte 0x14,0x08,0x3E,0x08,0x14 ; * .byte 0x08,0x08,0x3E,0x08,0x08 ; + .byte 0x00,0x00,0xA0,0x60,0x00 ; , .byte 0x08,0x08,0x08,0x08,0x08 ; - .byte 0x00,0x60,0x60,0x00,0x00 ; . .byte 0x20,0x10,0x08,0x04,0x02 ; / .byte 0x3E,0x51,0x49,0x45,0x3E ; 0 .byte 0x00,0x42,0x7F,0x40,0x00 ; 1 .byte 0x42,0x61,0x51,0x49,0x46 ; 2 .byte 0x21,0x41,0x45,0x4B,0x31 ; 3 .byte 0x18,0x14,0x12,0x7F,0x10 ; 4 .byte 0x27,0x45,0x45,0x45,0x39 ; 5 .byte 0x3C,0x4A,0x49,0x49,0x30 ; 6 .byte 0x01,0x71,0x09,0x05,0x03 ; 7 .byte 0x36,0x49,0x49,0x49,0x36 ; 8 .byte 0x06,0x49,0x49,0x29,0x1E ; 9 .byte 0x00,0x36,0x36,0x00,0x00 ; : .byte 0x00,0x56,0x36,0x00,0x00 ; ; .byte 0x08,0x14,0x22,0x41,0x00 ; < .byte 0x14,0x14,0x14,0x14,0x14 ; = .byte 0x00,0x41,0x22,0x14,0x08 ; > .byte 0x02,0x01,0x51,0x09,0x06 ; ? .byte 0x32,0x49,0x59,0x51,0x3E ; @ .byte 0x7C,0x12,0x11,0x12,0x7C ; A .byte 0x7F,0x49,0x49,0x49,0x36 ; B .byte 0x3E,0x41,0x41,0x41,0x22 ; C .byte 0x7F,0x41,0x41,0x22,0x1C ; D .byte 0x7F,0x49,0x49,0x49,0x41 ; E .byte 0x7F,0x09,0x09,0x09,0x01 ; F .byte 0x3E,0x41,0x49,0x49,0x7A ; G .byte 0x7F,0x08,0x08,0x08,0x7F ; H .byte 0x00,0x41,0x7F,0x41,0x00 ; I .byte 0x20,0x40,0x41,0x3F,0x01 ; J .byte 0x7F,0x08,0x14,0x22,0x41 ; K .byte 0x7F,0x40,0x40,0x40,0x40 ; L .byte 0x7F,0x02,0x0C,0x02,0x7F ; M .byte 0x7F,0x04,0x08,0x10,0x7F ; N .byte 0x3E,0x41,0x41,0x41,0x3E ; O .byte 0x7F,0x09,0x09,0x09,0x06 ; P .byte 0x3E,0x41,0x51,0x21,0x5E ; Q .byte 0x7F,0x09,0x19,0x29,0x46 ; R .byte 0x46,0x49,0x49,0x49,0x31 ; S .byte 0x01,0x01,0x7F,0x01,0x01 ; T .byte 0x3F,0x40,0x40,0x40,0x3F ; U .byte 0x1F,0x20,0x40,0x20,0x1F ; V .byte 0x3F,0x40,0x38,0x40,0x3F ; W .byte 0x63,0x14,0x08,0x14,0x63 ; X .byte 0x07,0x08,0x70,0x08,0x07 ; Y .byte 0x61,0x51,0x49,0x45,0x43 ; Z .byte 0x00,0x7F,0x41,0x41,0x00 ; [ .byte 0x55,0x2A,0x55,0x2A,0x55 ; \ .byte 0x00,0x41,0x41,0x7F,0x00 ; ] .byte 0xFC,0x20,0x40,0x40,0x3C ; ^ umdefiniert zu µ .byte 0x40,0x40,0x40,0x40,0x40 ; _ .byte 0x00,0x01,0x02,0x04,0x00 ; ' .byte 0x20,0x54,0x54,0x54,0x78 ; a .byte 0x7F,0x48,0x44,0x44,0x38 ; b .byte 0x38,0x44,0x44,0x44,0x20 ; c .byte 0x38,0x44,0x44,0x48,0x7F ; d .byte 0x38,0x54,0x54,0x54,0x18 ; e .byte 0x08,0x7E,0x09,0x01,0x02 ; f .byte 0x18,0xA4,0xA4,0xA4,0x7C ; g .byte 0x7F,0x08,0x04,0x04,0x78 ; h .byte 0x00,0x44,0x7D,0x40,0x00 ; i .byte 0x40,0x80,0x84,0x7D,0x00 ; j .byte 0x7F,0x10,0x28,0x44,0x00 ; k .byte 0x00,0x41,0x7F,0x40,0x00 ; l .byte 0x7C,0x04,0x18,0x04,0x78 ; m .byte 0x7C,0x08,0x04,0x04,0x78 ; n .byte 0x38,0x44,0x44,0x44,0x38 ; o .byte 0xFC,0x24,0x24,0x24,0x18 ; p .byte 0x18,0x24,0x24,0x18,0xFC ; q .byte 0x7C,0x08,0x04,0x04,0x08 ; r .byte 0x48,0x54,0x54,0x54,0x20 ; s .byte 0x04,0x3F,0x44,0x40,0x20 ; t .byte 0x3C,0x40,0x40,0x20,0x7C ; u .byte 0x1C,0x20,0x40,0x20,0x1C ; v .byte 0x3C,0x40,0x30,0x40,0x3C ; w .byte 0x44,0x28,0x10,0x28,0x44 ; x .byte 0x1C,0xA0,0xA0,0xA0,0x7C ; y .byte 0x44,0x64,0x54,0x4C,0x44 ; z .byte 0x00,0x06,0x09,0x09,0x06 ; { umdefiniert zu ° .byte 0x3E,0x22,0x22,0x22,0x3E ; | umdefiniert zu Leerkästchen .byte 0x3E,0x3E,0x3E,0x3E,0x3E ; } umdefiniert zu ausgefülltem Kästchen ;------------------------------------------------------------------------ ; Positionsdaten: Cursorkoordinaten, Servonummer, Wortnr ;Cursorkoordinaten für Servo 1 bis 12 Zeile und Spalte Positionsdaten: ; Zeile X (40h+(X-1)), Spalte Y (80h+(Y-1)x6) .byte 0x40, 0x80, 0x01, 0x01 .byte 0x40, 0x80, 0x01, 0x02 .byte 0x40, 0x8C, 0x02, 0x03 .byte 0x40, 0x8C, 0x02, 0x04 .byte 0x40, 0x8C, 0x02, 0x05 .byte 0x40, 0xCE, 0x0A, 0x01 .byte 0x40, 0xCE, 0x0A, 0x02 .byte 0x40, 0xC2, 0x09, 0x03 .byte 0x40, 0xC2, 0x09, 0x04 .byte 0x40, 0xC2, 0x09, 0x05 .byte 0x42, 0x80, 0x03, 0x01 .byte 0x42, 0x80, 0x03, 0x02 .byte 0x42, 0x8C, 0x04, 0x03 .byte 0x42, 0x8C, 0x04, 0x04 .byte 0x42, 0x8C, 0x04, 0x05 .byte 0x42, 0xCE, 0x0C, 0x01 .byte 0x42, 0xCE, 0x0C, 0x02 .byte 0x42, 0xC2, 0x0B, 0x03 .byte 0x42, 0xC2, 0x0B, 0x04 .byte 0x42, 0xC2, 0x0B, 0x05 .byte 0x44, 0x80, 0x05, 0x01 .byte 0x44, 0x80, 0x05, 0x02 .byte 0x44, 0x8C, 0x06, 0x03 .byte 0x44, 0x8C, 0x06, 0x04 .byte 0x44, 0x8C, 0x06, 0x05 .byte 0x44, 0xCE, 0x0E, 0x01 .byte 0x44, 0xCE, 0x0E, 0x02 .byte 0x44, 0xC2, 0x0D, 0x03 .byte 0x44, 0xC2, 0x0D, 0x04 .byte 0x44, 0xC2, 0x0D, 0x05 ; Servonummern: 1 2 9 10 ; 3 4 11 12 ; 5 6 13 14 ;------------------------------------------------------------------------ ;Definition der LCD-Texte, als Zeilen zu je 14 Zeichen Textzeile1: .string "}1| |2|" Textzeile2: .string " Puls " Textzeile3: .string "|3| |4|" Textzeile4: .string " " Textzeile5: .string "|5| |6|" Textzeile6: .string " ^S " Wort1: .string " oben " Wort2: .string " unten" Wort3: .string " vorn " Wort4: .string " Mitte" Wort5: .string "hinten"