Pfad: Home =>
AVR-Übersicht =>
Anwendungen =>
Funkfernsteuerung ATtiny26 => Software
Software für die Funkfernsteuerung mit ATtiny26
;
; **********************************************
; * PCM-Encoder 4-Kanal mit Trimmung *
; * fuer ATtiny26, Version 1 Juli 2011 *
; * (C)2011 by http://www.avr-asm-tutorial.net *
; **********************************************
;
; ACHTUNG! Den internen RC-Oszillator durch
; Programmieren der richtigen Fuses von 1 MHz
; auf 4 MHz Takt umstellen!
;
; Include-Datei fuer den AVR-Typ
.NOLIST
.INCLUDE "tn26def.inc" ; Headerdatei fuer ATtiny26
.LIST
;
; ============================================
; H A R D W A R E I N F O R M A T I O N E N
; ============================================
;
; Schaltbild
; ___________
; 1 / |20
; MOSI O--|PB0 PA0|--O ADC0 Kanal1
; MISO O--|PB1 PA1|--O ADC1 Kanal2
; SCK O--|PB2 AT PA2|--O ADC2 Kanal3
; Ausgang O--|PB3 PA3|--O AREF
; VCC O--|VCC tiny GND|--O GND
; GND O--|GND AVC|--O AVCC
; Trim 4 ADC7 O--|PB4 26 PA4|--O ADC3 Kanal4
; --|PB5 PA5|--O ADC4 Trim 1
; --|PB6 PA6|--O ADC5 Trim 2
; RESET O--|RES PA7|--O ADC6 Trim 3
; 10|____________|11
;
; ============================================
; S O F T W A R E D E S I G N
; ============================================
;
; Software-Timing ohne Interrupts und Timer
;
; Der Prozessor laeuft mit vier MHz Takt aus dem internen
; kalibrierten RC-Generator. Die Fuses sind entsprechend
; zu setzen!
;
; PCM-Signal
; Kanal 1 Kanal 2 Kanal 3 Kanal 4 Synchronsignal
; 500µs 300-
; ___ 1700___ ___ ___ ___ __
; __| 1 |___| 2 |____| 3 |____| 4 |____| S |___...____|
; AD0 AD4 AD1 AD5 AD2 AD6 AD3 AD7 Umrechnen
;
; Kanalsignalausgabe- und Messperiode
; -----------------------------------
; Die vier Kanaele starten mit einem 500 us langen Impuls
; am Ausgang. Waehrend dieser Zeit wird am AD-Wandler ein
; Eingang gewandelt und nach Beendigung des Impulses das
; Ergebnis gelesen und im SRAM gespeichert. Dann folgt
; eine Ruhezeit zwischen 800-500=300 und 2200-500=1700 us.
; Waehrend der Ruhezeit wird der naechste AD-Kanal gewan-
; delt und nach Beendigung der Pause das Ergebnis eingele-
; sen. Nach der Ausgabe der vier Kanaele sind alle acht
; Eingaenge umgewandelt und stehen im SRAM ab sAdRes.
;
; Synchronsignalausgabe und Umrechnungsperiode
; --------------------------------------------
; Der letzte Kanal wird mit einem 500 us langen Synchron-
; signal abgeschlossen. Waehrend der nachfolgenden langen
; Pause werden die AD-Werte in Zeiten umgewandelt:
; - Der Wert am Kanaleingang wird mit 38.437 multipliziert
; (ADC * 1.200 * 65.536 / 1023 / 2 = ADC * 38.437), das
; Ergebnis durch 65.536 geteilt, gerundet und mit zwei
; multipliziert.
; - Der Wert am Trimeingang des gleichen Kanals wird mit
; 12.813 multipliziert (ADC * 200 * 65.536 / 1023 =
; ADC * 12.813), durch 65.536 geteilt und gerundet.
; - Der Wert aus der zweiten Berechnung wird zum ersten
; Wert addiert und die Zeit zur Ausfuehrung des Start-
; impulses (503 us) abgezogen.
; - Die Dauer des inaktiven Teils des Synchronsignals
; wird durch Abziehen der Dauer der vier Kanaele, der
; Dauer von fuenf Startsignalen und der Dauer, die die
; Umrechnung aller Kanaele benoetigt, von 20.000 us
; berechnet.
; - Die Ergebnisse der Umrechnung werden in das SRAM ab
; sCtr geschrieben.
;
; AD-Umwandlungstiming
; --------------------
; Die AD-Umwandlung erfolgt bei 4 MHz Takt mit einem
; Vorteiler von 64. Fuer eine Wandlung werden 13 * 64
; Takte benoetigt = 832 Takte = 208 us@4 MHz.
; Es stehen mindestens 800-500-5 = 295 us zur Verfuegung.
;
; ============================================
; P O R T S U N D P I N S
; ============================================
;
; Namen fuer Hardware-Ports und Pins
.equ pOutP = PORTB ; Output Port
.equ pOutD = DDRB ; Portrichtung
.equ bOutP = PORTB3 ; Portpin Output
;
; ================================================
; K O N S T A N T E N Z U M E I N S T E L L E N
; ================================================
;
.equ Invert = 0 ; 1: Signal invertiert ausgeben
.equ cOn = 400 ; Dauer Startsignal
.equ cBase = 800 ; Mindestdauer Signal
.equ cMain = 1000 ; us Zeitvariation Hauptpotentiometer
.equ cTrim = 400 ; us Zeitvariation Trimmpotentiometer
;
; =======================================================
; F E S T E + A B G E L E I T E T E K O N S T A N T E N
; =======================================================
;
.equ cClock = 4000000 ; Prozessortakt 4 MHz
.equ cBaseA = cBase-cOn-12 ; Mindestdauer minus Startimpulsdauer
.equ cMainM = (65536*cMain+511)/1023 ; Multiplikator fuer AD1
.equ cTrimM = (65536*cTrim+511)/1023 ; Multiplikator fuer AD2
;
; ============================================
; R E G I S T E R D E F I N I T I O N E N
; ============================================
;
; R0 verwendet fuer Kanalmutiplexer
; R1..R10 verwendet fuer Multiplikationen
; Frei: R11..R15
.def rmp = R16 ; Vielzweckregister
.def rRL = R17 ; LSB Rechenregister fuer Zeitumrechnung
.def rRH = R18 ; dto., MSB
; Frei: R17..R23
.def rCL = R24 ; LSB Timerzaehler
.def rCH = R25 ; MSB Timerzaehler
; Verwendet: R27:R26 X als Zeiger AD-Messung
; Verwendet: R29:R28 Y als Zeiger fuer Zaehler
; Verwendet: R31:R30 Z als Zeiger
;
; ============================================
; S R A M D E F I N I T I O N E N
; ============================================
;
.DSEG
.ORG SRAM_START
;
sAdRes: ; Speicher fuer gemessene Werte
.byte 16 ; acht Kanaele zu je zwei Bytes
sCtr: ; Speicher fuer Zaehldauern
.byte 10 ; Dauer inaktive Zeiten, 4 Kanaele + Synchronrest
;
; ==============================================
; R E S E T V E K T O R
; ==============================================
;
.CSEG
.ORG $0000
rjmp Main ; Reset-Vektor
;
; ============================================
; H A U P T P R O G R A M M I N I T
; ============================================
;
Main:
; Init Stapel fuer Unterprogramme
ldi rmp,LOW(RAMEND) ; setze Stapelzeiger
out SP,rmp
; Init Portausgang fuer Signalausgang
sbi pOutD,bOutP ; Richtung Ausgangsport
; Messe alle acht Kanaele erstmals
ldi XH,HIGH(sAdRes) ; Zeiger in SRAM
ldi XL,LOW(sAdRes)
clr R0 ; channel multiplexer
MainAdc:
out ADMUX,R0
ldi rmp,(1<<ADEN)|(1<<ADSC)|(1<<ADPS2)|(1<<ADPS1)
out ADCSR,rmp ; start conversion
MainAdcWait:
sbic ADCSR,ADSC ; warten auf conversion fertig
rjmp MainAdcWait
in rmp,ADCL ; lese Ergebnis
st X+,rmp ; schreibe in SRAM
in rmp,ADCH
st X+,rmp
inc R0
cpi XL,LOW(sAdRes+16) ; acht Kanaele gelesen?
brcs MainAdc ; naechsten Kanal lesen
ldi rmp,HIGH(20000) ; init erste Synch-Zeit
sts sCtr+9,rmp
ldi rmp,LOW(20000)
sts sCtr+8,rmp
;
; ============================================
; P R O G R A M M - S C H L E I F E
; ============================================
;
.equ cRestSynch = 374 ; Zeitbedarf fuer nachfolgende Berechnungen
Loop:
; rechne Kanalergebnisse um
ldi ZH,HIGH(sAdRes) ; Zeiger auf AD-Ergebnisse
ldi ZL,LOW(sAdRes)
ldi YH,HIGH(sCtr) ; Zeiger auf Zaehler
ldi YL,LOW(sCtr)
Calc:
ld R5,Z+ ; lese ADC Ergebnis in R5:R6
ld R6,Z+
rcall MultK ; multipliziere
mov rRL,R9 ; Kopiere LSB Multiplikationsergebnis
mov rRH,R10 ; dito, MSB
ld R5,Z+ ; lese zugehoerigen Trim-Kanal
ld R6,Z+
rcall MultT ; Multipliziere
add rRL,R9 ; addiere Trim zu Dauer
adc rRH,R10
ldi rmp,LOW(cBaseA) ; Addiere Basisdauer
add rRL,rmp
ldi rmp,HIGH(cBaseA)
adc rRH,rmp
st Y+,rRL ; speichere im SRAM
st Y+,rRH
cpi ZL,LOW(sAdRes+16) ; weitere Umrechnung?
brcs Calc ; weiter berechnen
; Berechne Restzeiten
ldi YH,HIGH(sCtr) ; Zeiger auf Kanalergebnis
ldi YL,LOW(sCtr)
ldi ZH,HIGH(20000-5*cOn-cRestSynch-65) ; Restzeit
ldi ZL,LOW(20000-5*cOn-cRestSynch-65)
Rest:
ld rRL,Y ; lese berechneten Wert
ldd rRH,Y+1
sub ZL,rRL ; ziehe von Gesamtzeit ab
sbc ZH,rRH
st Y+,rRL ; schreibe Restzeit in SRAM
st Y+,rRH
cpi YL,LOW(sCtr+8) ; alle vier Kanaele umgerechnet?
brcs Rest ; nein, weiter
rcall Delay ; Rest der Delayzeit
sts sCtr+8,ZL ; speichere Restzeit
sts sCtr+9,ZH
ldi YH,HIGH(sCtr) ; Zeiger auf Delayzeit
ldi YL,LOW(sCtr)
ldi XH,HIGH(sAdRes) ; Zeiger auf ADC Speicher
ldi XL,LOW(sAdRes)
clr R0 ; Multiplexzeiger fuer ADC auf Anfang
nop
nop
nop
Kanal:
out ADMUX,R0 ; Kanal waehlen
ldi rmp,(1<<ADEN)|(1<<ADSC)|(1<<ADPS2)|(1<<ADPS1)
out ADCSR,rmp ; start conversion
nop ; 1T, Verzoegerung
nop ; 1T
rcall SignalOn ; Kanalstartsignal senden
in rmp,ADCL ; Ergebnis lesen
st X+,rmp
in rmp,ADCH
st X+,rmp
inc R0 ; naechster AD-Kanal
out ADMUX,R0 ; Kanal waehlen
ldi rmp,(1<<ADEN)|(1<<ADSC)|(1<<ADPS2)|(1<<ADPS1)
out ADCSR,rmp ; start conversion
rcall Delay ; Wartezeit bei inaktivem Signal
in rmp,ADCL ; Ergebnis lesen
st X+,rmp
in rmp,ADCH
st X+,rmp
inc R0 ; naechster AD-Kanal
cpi YL,LOW(sCtr+8) ; vier Kanaele ausgegeben?
brcs Kanal ; nein, weiter
nop
nop
nop
nop
nop
nop
rcall SignalOn ; Synch-Signal ausgeben
rjmp loop ; Zurueck nach Loop
;
; ============================================
; U N T E R P R O G R A M M E
; ============================================
;
; Signal fuer cOn µs ausgeben
SignalOn:
.equ nOn = cOn - 1; Schleifendurchlaeufe fuer Start-Signal
; 3T fuer RCALL
ldi rCH,HIGH(nOn) ; 1T, Zaehler auf Anfang
ldi rCL,LOW(nOn) ; 1T
.if Invert==1
cbi pOutP,bOutP ; 2T, invertiert Signal setzen
.else
sbi pOutP,bOutP ; 2T, normales Signal setzen
.endif
SignOnNext:
sbiw rCL,1 ; Zaehler runterzaehlen
brne SignOnNext ; 1T/2T weiterzaehlen
; Anzahl Takte Schleife = (nOn-1) * 4 + 3 + 5
; = 4 * (nOn + 1)
nop ; 1T, Verzoegerung
nop ; 1T
nop ; 1T
.if Invert==1
sbi pOutP,bOutP ; 2T, invertiert Signal setzen
.else
cbi pOutP,bOutP ; 2T, normales Signal setzen
.endif
ret ; 4T, fertig, zurueck
; Gesamtzeit = (cSign+3) us
;
; Verzoegerung gemaess berechneter Zeit fuer den Kanal
; - X zeigt auf Kanaldurchlaeufe im SRAM
;
Delay:
; 3T fuer RCALL
ld rCL,Y+ ; 2T, Zaehler auf Anfangswert im SRAM
ld rCH,Y+ ; 2T
DelayNext:
sbiw rCL,1 ; 2T, herunter zaehlen
brne DelayNext ; 1T/2T, noch ein Durchlauf
nop ; 1T, Verzoegerung
nop ; 1T
ret ; 4T, fertig
; Takte gesamter Durchlauf = 7 + 4*(nX-1) + 3 + 6
; = 4 * nX + 12
; nX = (Zeit - 12) / 4
;
; Multiplikation 16 * 10 Bit und mit 2
; - R2:R1 enthaelt 16-Bit-Multiplikator / 2
; - R6:R5 enthaelt 10-Bit-Zahl
; - Ergebnis ist in R10:R9:R8:R7
MultK:
; rcall-Aufruf = 3T
ldi rmp,LOW(cMainM) ; Multiplikator in R2:R1
mov R1,rmp
ldi rmp,HIGH(cMainM)
mov R2,rmp
clr R3 ; 1T, loesche die oberen zwei Byte
clr R4 ; 1T
clr R7 ; 1T, loesche Ergebnis
clr R8 ; 1T
clr R9 ; 1T
clr R10 ; 1T
ldi rmp,10 ; 1T, 10 Durchlaeufe
; Summe = 14 Takte mit Aufruf
MultKNext:
lsr R6 ; 1T, schiebe unterstes Bit in Carry
ror R5 ; 1T
brcs MultKAdd ; 1T/2T, addiere zum Ergebnis
nop ; 1T, Verzoegerung
nop ; 1T
nop ; 1T
rjmp MultKM2 ; 2T, multipliere mit zwei
; Summe Zweig = 8 Takte
MultKAdd:
add R7,R1 ; 1T, addiere zum Ergebnis
adc R8,R2 ; 1T
adc R9,R3 ; 1T
adc R10,R4 ; 1T
; Summe Zweig = 8 Takte
MultKM2:
lsl R1 ; 1T, schiebe Multiplikator links
rol R2 ; 1T
rol R3 ; 1T
rol R4 ; 1T
dec rmp ; 1T
brne MultKNext ; 1T/2T, wiederhole
; Summe von Next bis hier: 14T letzter Lauf, 15 bei Sprung
rol R8 ; 1T, round
adc R9,rmp ; 1T
adc R10,rmp ; 1T
nop ; 1T, Verzoegerung
nop ; 1T
nop ; 1T
ret ; 4T, fertig
; Zeitbedarf Gesamt = 14 + 15*15 + 1*14 + 10 = 263 Takte
; bei 4 MHz Takt = 65,75 µs
;
; Multiplikation 16 * 10 Bit
; - R2:R1 enthaelt 16-Bit-Multiplikator
; - R6:R5 enthaelt 10-Bit-Zahl
; - Ergebnis ist in R10:R9:R8:R7
MultT:
; rcall-Aufruf = 3T
ldi rmp,LOW(cTrimM) ; Multiplikator in R2:R1
mov R1,rmp
ldi rmp,HIGH(cTrimM)
mov R2,rmp
clr R3 ; 1T, loesche die oberen zwei Byte
clr R4 ; 1T
clr R7 ; 1T, loesche Ergebnis
clr R8 ; 1T
clr R9 ; 1T
clr R10 ; 1T
ldi rmp,10 ; 1T, 10 Durchlaeufe
; Summe = 14 Takte mit Aufruf
MultTNext:
lsr R6 ; 1T, schiebe unterstes Bit in Carry
ror R5 ; 1T
brcs MultTAdd ; 1T/2T, addiere zum Ergebnis
nop ; 1T, Verzoegerung
nop ; 1T
nop ; 1T
rjmp MultTM2 ; 2T, multipliere mit zwei
; Summe Zweig = 8 Takte
MultTAdd:
add R7,R1 ; 1T, addiere zum Ergebnis
adc R8,R2 ; 1T
adc R9,R3 ; 1T
adc R10,R4 ; 1T
; Summe Zweig = 8 Takte
MultTM2:
lsl R1 ; 1T, schiebe Multiplikator links
rol R2 ; 1T
rol R3 ; 1T
rol R4 ; 1T
dec rmp ; 1T
brne MultTNext ; 1T/2T, wiederhole
; Summe von Next bis hier: 14T letzter Lauf, 15 bei Sprung
rol R8 ; 1T, runden
adc R9,rmp ; 1T
adc R10,rmp ; 1T
ret ; 4T, fertig
; Zeitbedarf Gesamt = 14 + 15*15 + 1*14 + 7 = 260 Takte
; bei 4 MHz Takt = 65 µs
;
; Ende Quellcode
; Copyright
.db " (C)2010 by Gerhard Schmidt " ; menschenlesbar
.db " C(2)10 0ybG reahdrS hcimtd " ; wortgerecht
;
An den Seitenanfang
©2011 by http://www.avr-asm-tutorial.net