.include "c:\avrtools\appnotes\2313def.inc" ;Empfänger-Subroutine .cseg .org 0 rjmp reset ;Reset handler reti ;External interrupt 0 reti ;External interrupt 1 reti ;Counter1 capture event rjmp compare ;Counter1 compare match rjmp timer1 ;Counter1 overflow rjmp timer0 ;Counter0 overflow rjmp serial ;UART RX complete reti ;UART Data register empty reti ;UART TX complete reti ;Analog comparator .def temp3 = r1 .def temp4 = r2 .def temp5 = r3 .def kanal_nr = r4 .def ser_pointer = r7 .def funktion = r8 .def time_out = r9 .def ist_alt = r12 .def error_cnt = r13 .def temp = r16 .def temp2 = r17 .def delta = r17 .def motor_bits = r18 .def counter = r19 .def pwm_counter = r20 .def ser_counter = r23 .def flags = r25 .equ f_start = 0 .equ f_complete = 1 .equ f_error = 2 .equ f_update = 3 ;Das Programm wurde ursprünglich für einen AT90S2333 geschrieben ;für 2313 werden folgende Registerdefinitionen benötigt: .equ UCSRB = UCR .equ UCSRA = USR .equ OCR1H = OCR1AH .equ OCR1L = OCR1AL .equ COM11 = COM1A1 .equ COM10 = COM1A0 .equ OCF1 = OCF1A .equ OCIE1 = OCIE1A .equ ser_buffer = $60 ;Empfangspuffer für die seriellen Daten .equ data_buffer = ser_buffer+14 ;umgewandelte Daten (manchester dekodiert) .equ pwm_buffer = data_buffer+8 ;PWM Werte für die 4 Ausgänge .equ analog_buffer = pwm_buffer+4 ;aktuelle Analogwerte (Empfänger) .equ pwm_alt_puffer = analog_buffer+8 ;alte PWM-Werte für Servo-Funktion .equ adresse = pwm_alt_puffer+4 ;eigene Adresse (Konstante) .equ servo_puffer = adresse+1 .equ left = 0 ;Bitdefinitionen .equ right = 1 .equ stellweg = 4 .equ servo = 5 .equ quarz = 3686400 ;Für Berechnung der Baudrate .equ baud = 2400 .equ baud_wert = (quarz/(16*baud))-1 ; Lochrasterplatine mit TLE 4205 + 2313 ; Belegung ; ; Motor 1: Richtung = PD2, Enable = PD4 ; Motor 2: PD3 PD5 ; Motor 3: PB4 PB1 ; Motor 4: PB5 PB2 ; Zur einfachen Anpassung an andere Hardware-Umgebungen ; sind alle Definitionen als Variable ausgeführt. .equ pwm_m1 = 4 .equ pwm_m2 = 5 .equ pwm_m3 = 1 .equ pwm_m4 = 2 .equ dir_m1 = 2 .equ dir_m2 = 3 .equ dir_m3 = 4 .equ dir_m4 = 5 .equ port_pwm_m1 = PORTD .equ port_pwm_m2 = PORTD .equ port_pwm_m3 = PORTB .equ port_pwm_m4 = PORTB .equ port_dir_m1 = PORTD .equ port_dir_m2 = PORTD .equ port_dir_m3 = PORTB .equ port_dir_m4 = PORTB reset: ldi temp,RAMEND out SPL,temp ldi xl,ser_buffer ;den seriellen Puffer löschen clr temp ldi temp2,$70 rloop: st x+,temp dec temp2 brne rloop ldi temp,(1< temp mov temp2,temp pop temp rcall mul14 ;den 8-Bit Wert mit dem Faktor aus dem EEPROM multiplizieren push temp ldi temp,$21 ;Offset kommt aus dem eeprom ($20=High,$21=Low) rcall read_eeprom mov temp3,temp ldi temp,$20 rcall read_eeprom mov temp4,temp pop temp add temp,temp3 ;Offset hinzuaddieren adc temp2,temp4 sts servo_puffer,temp2 ;Zuerst High-Byte sts servo_puffer+1,temp ; ret ;Dieses Unterprogramm berechnet die Motorrichtung und Geschwindigkeit (PWM-Wert) ;Parameter: ;R4 = Nummer des Kanals (0..3) ; calc_one: mov temp,kanal_nr rcall read_eeprom andi temp,$0F ;nur die unteren 4 Bit verwenden cpi temp,$04 ;Analog oder Digital-Kanal? brcc calc_digital ;Kanal-Nummer > 4 ist Digital-Kanal calc_analog: in funktion,EEDR ;nochmals die Kanal-Nummer lesen rcall get_analog ;den entsprechenden Analog-Wert lesen sbrs funktion,stellweg ;Bit 4 = 90° oder 270° rcall umrechnung ;90° Stellwegumrechnung auf jeden Fall (zum Testen) ;Ergebnis ist in temp sbrc funktion,stellweg rcall umrechnung2 ;Umwandlung des 10-Bit in einen 8-Bit-Wert rcall calculate ;PWM-Wert berechnen, Ergebnis in temp2, in motor_bits ist Maske ret calc_digital: subi temp,$04 ;Nummer bereinigen rcall get_digital ;Kanal-Nummer laden, Ergebnis in motor_bits ldi temp2,$FF ;Kanal auf Dauerbetrieb schalten ret calculate: ldi temp2,$80 ;Bei Fahrtregler-Funktion den Mittelpunkt festlegen sub temp2,temp ;Ist - Soll brcc positiv ;positiv oder negativ? neg temp2 ;wenn negativ, dann Zahl positiv machen ldi motor_bits,(1< 32 Werte) brcs calc_2 ;damit man den 0-Punkt besser findet ret calc_2: clr temp2 ;solange der Totpunkt nicht überschritten ist, auf 0 setzen ret ;Diese Routine rechnet den 10-Bit Sollwert so um, daß schlußendlich ein ;8-Bit Wert herauskommt. Nebenbei wird eine Reduzierung des Stellwegs ;auf 90° berechnet, wobei durch die 10Bit die Genauigkeit erhalten bleibt. ;in temp2:temp ist der umzurechnende Wert (temp2=High) umrechnung: cpi temp2,$02 ;Wert mit $02AA vergleichen breq um_1a brcc um_1 ;Wert ist auf jeden Fall größer brne um_2 ;Wert ist kleiner um_1a: cpi temp,$AA ;Low-Byte vergleichen brcc um_1 ;auch Low-Wert ist größer um_2: cpi temp2,$01 brcs um_3 ;Wert ist auf jeden Fall kleiner brne um_4 ;Wert liegt im richtigen Bereich cpi temp,$56 ;Low-Byte vergleichen brcs um_3 ;auch Low-Wert ist kleiner um_4: subi temp,$56 ;den Wert $0156 =342 abziehen, somit wird der sbci temp2,$01 ;Wertebereich von 0-1023 auf 0-340 verringert rjmp um_5 um_1: ldi temp,$FF ;Wert war zu groß, also auf Max. setzen clr temp2 ret um_3: clr temp ;Wert war zu klein, also auf Min. setzen clr temp2 ret um_5: mov temp3,temp ;den Wert mit 3 multiplizieren mov temp4,temp2 lsl temp ;Zuerst *2 rol temp2 add temp,temp3 ;nochmal addieren =*3 adc temp2,temp4 lsr temp2 ;zum Schluß durch 4 dividieren ror temp ;340*3/4 = 255 lsr temp2 ror temp ret ;Fertig, das Ergebnis ist in temp ;Diese Routine rechnet den 10-Bit-Analogwert in temp/temp2 (temp2=high) in einen ;8-Bit Wert in temp um (Division durch 4) umrechnung2: lsr temp2 ror temp lsr temp2 ror temp ret ;Adresse in temp, Ergebnis in temp zurück read_eeprom: cli out EEAR,temp ;Adresse in Adressregister laden sbi EECR,EERE ;EEprom lesen in temp,EEDR ;Kanal-Nummer laden sei ret ;******************** ;* In der Routine "Get_analog" wird aus dem Empfangspuffer der Analogwert mit ;* der Nummer (temp) extrahiert. temp kann Werte von 0..3 annehmen. ;* Das Ergebnis ist in temp2:temp (temp2 = High) ;* ;******************** get_analog: andi temp,$03 ;Sicherheitshalber den Parameter begrenzen ldi xl,data_buffer+2 ;Basisadresse für die Low-Bytes add xl,temp ;Zugriffsnummer des Wertes als Offset verwenden lds temp2,data_buffer+1 get_analog1: tst temp breq get_analog2 lsr temp2 lsr temp2 dec temp rjmp get_analog1 get_analog2: andi temp2,$03 ;das High-Byte korrigieren ld temp,x ;das Low-Byte lesen ret ;********************* ;* In der Routine "get_digital" wird aus dem Empfangspuffer der Digitalwert ;* mit der Nummer (Temp) gelesen. Temp = 0..3 ;* Ergebnis in Bit 0+1 von motor_bits ;********************* get_digital: andi temp,$03 ;den Parameter sicherheitshalber begrenzen lds temp2,data_buffer+6 ;die Digitalkanäle aus dem Speicher lesen get_digital_loop: tst temp breq get_digital_1 lsr temp2 lsr temp2 dec temp rjmp get_digital_loop get_digital_1: andi temp2,$03 mov motor_bits,temp2 ret ;******************** ;*Dekodierung des Manchester-Codes ;*Quelle: ser_buffer ;*Ziel : data_buffer ;******************** uebertrage: cli push xl push yl ;zunächst die Manchester-Codierung Dekodieren ldi xl,ser_buffer ;Adresse für Quell-Puffer ldi yl,data_buffer ;Adresse für Ziel-Puffer ldi temp2,$07 ;Anzahl der umzuwandelnden Bytes cbr flags,(1<