Pfad: Home => AVR-Übersicht => Anwendungen => Funkfernsteuerung ATtiny26 => Software
PCM-Encoder ATtiny26

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