Code:
; Sicherung vom 21jan08, 13:46 nach Datei servo1_servoplatine-gut.asm
;===================================================================================
;* Target MCU : ATtiny13
;* Target Hardware : Servotester-Platine, Servo auf PB3, Poti auf PB4
;* Target cpu-frequ. : 9,6 MHz, interner Oszillator
;===================================================================================
;*Versionsgeschichte:
;====================
;x1599 21jan08 12ff Version für die "Servoplatine" adaptiert
; dazu ISR+adc+servo1-x30-gut.asm abgeändert.
;
;* Aufgabenstellung
;* ISR zum Testen von einem Servo mit der Servotester-Platine
; Servo über getrennte Leitung, max. 1 A, vom Labornetzteil versorgt
; Portbelegung, Schaltung auszugsweise (übernomm. v. srv-adc+pwm-x29b.asm)
;
; Vcc(6V LNT) -----------------------------------------Vcc-Servo1
;
; Vcc -----------tiny13-Vcc
; |
; | tiny13-PB3=pin2----------------+---Signal-Servo1
; | |
; | + - - (poti1->ADC) - - +
; | |
; | tiny13-PB4--------+
; | V
; | +--------+
; +-------------------+ 25klin +----+
; +--------+ |
; |
; GND---------------------------------------+----------GND-Servo1
;
;* ===============================================
; ######### Original war: ISR+adc+servo1-x30-gut.asm
;===================================================================================
; Speicherbelegung
;r14 low-Byte der ADC-Wandlung (lsb)
;r15 high-Byte der ADC-Wandlung: Beide ergeben einen Wert zwischen 0...1023
;r16 Mehrzweck, high-Byte in Pausen "pause_an", "pause_aus", "led_ende" u.ä.
;r17 low-Byte in Pausen, s.o.
;
;r18 -- --
;r19 -- --
;r20 -- --
;
;r21 Byte Steuerbyte. Es werden nur Bits ausgewertet
; "Rampe" an-aus, 1=Rampe an, bit 1 = Servo 1 , bit 5 = Servo 2
; Übernahme Rampenwert, 1=Daten wurden noch nicht übernommen vom
; Hauptprogramm in die ISR, 0=ISR hat Daten abgeholt und zwar
; bit 2 = Servo 1 , bit 6 = Servo 2
;r22 1/2 Word lsb Zeitwert Rampe aus auf-ab-Rechnerei im Hauptprogramm
;r23 1/2 Word msb zu r26
;r24 1/2 Word LSB Zeitwert Rampe aus ADC/Poti im Hauptprogramm
;r25 1/2 Word MSB wird vom r14/15 geholt und zurechtgerechnet
;
;r26 1/2 Word LSB GESAMTDAUER Servoimpuls MUSS in r26/27 sein wegen sbiw
;r27 1/2 Word MSB Zeitwert für GESAMTDAUER Servoimpuls, etwa 500 Takte ?
;
;r28 1/2 Word lsb LSB RampenCOUNTER Servo1, wird in ISR runtergezählt
;r29 1/2 Word msb MSB Counter stammt vom ADC
;r30 1/2 Word lsb LSB Auf-ab-COUNTER Servo2, wird in ISR runtergezählt
;r31 1/2 Word msb MSB
;
;===================================================================================
#include "tn13def.inc"
; Interrupthandler-Tabelle (aus ATTiny13_doc2535.pdf, Seite 42)
; Address Code Labels ; Comments
.org 0x0000 rjmp anfang ; Reset Handler
;.org 0x0003 rjmp isr_x13 ;TIMO_OVF = Timer0 Overflow Handler
.org 0x0006 rjmp isr_ctc ; IRS für Timer0 CompareA Handler
;
;===================================================================================
; Deklarationen für den Praeprozessor
; Konstanten ####### evtl. auch keine Konstanten definiert
;
#define a r16 ;Kurzbezeichung für Allzweckregister r16
;
; Anschlussbelegung, vgl. srv-adc+pwm-x29b.asm
#define servo1 3 ;Servo 1 auf Port PB3
#define potiadc 2 ;Poti 1 am Port PB4 geht auf ADC-Kanal 2
;
;Festwerte und div. Daten für adcdat etc ====>
#define adcpsc 7 ; =7 ==> Clock/128, 9,6 MHz werden 75 kHz, vgl. doc, S93
;#define adcdat 3 ;Dummywert vom ADC ###>>> "Nur" 8Bit-Wandlung ! ? !
#define msges 5000 ;Gesamtzeit der Rampe: 5000 ISR-Zyklen sind 20 ms
#define mstest 500 ;Test ergibt mit mstest 500 und tmprs 40: für 2,0 ms
; das heisst: 4 µs Interrupt-Abstand (Fehler +4%)
#define msmin 180 ;Minimalwert für Rampe: 0,5 ms
#define tmrprs 38 ;Preset im Timer-Register (hoffentlich für CTC)
;
;===================================================================================
; Hauptprogramm
;===================================================================================
;
anfang:
rcall mc_init ;Initialisiere den Mikrocontroller
rcall isr_ini ;Initialisiere die ISR
rcall adcinit ;ADC initialisieren
;
sei ; .. Interrupts allgemein zulassen im Hauptprogramm
anfang2:
rcall adc_hol ;Hole Daten vom ADC in Register low=r14 + high=r15
;
rjmp anfang2
;
;===================================================================================
; Prozeduren
;===================================================================================
;
adc_hol: ;=== Hole Daten vom ADC, wird erst NACH der Wandlung verlassen
;Nach Wandlung sind die Werte in; L=r14,H=r15
ldi r16,potiadc ;Poti ist auf ADC-Kanal 2. >> Kanal 0 = Pin1=PB5,
; K1(ADC1)=Pin7=PB2, K2=Pin3=PB4 und K3=Pin2=PB3
rcall rdadc ;ADC auslesen
ret ;=====----->>>>>
;
rdadc: ;=== Hole Daten vom ADC in die Register low=r14 + high=r15
out admux,r16 ;vgl.doc2535, S 79
sbi admux,adlar ;Result left adjusted ==> NUR 8-Bit-Wandlung
sbi adcsra,adsc ;Wandlung starten
adrdy: ;=== Warte bis ADC fertig ist ==> ZWEI Wandlngen durchführen
sbic adcsra,adsc ;Skip if bit is cleared => dann ADC fertig
rjmp adrdy ; .. wenn nicht fertig, warten
adrdyb:
sbic adcsra,adsc ;Erst zweite Wandlung bringt korrektes Erbebnis,
rjmp adrdyb ; vgl. doc2535, sonst könnte alter Wert da sein.
; Dies dann, ###===>>> nur WENN der Kanal umgeschaltet wurde.
; in r14,adcl ;Daten einlesen, zuerst Low-Byte - nicht bei adlar
in r15,adch ;vgl. oben ADMUX (out 3), ADSC
ret ;=====----->>>>>
;
;===================================================================================
; Initialisierungprozeduren, für µC, ADC und Timer-ISR
;===================================================================================
;
mc_init: ;=== Initialisiere Mikrocontroller
; PB0 (servo1) + PB3 (servo2) = Ausgang, PB4 (poti1) = ADC-Eingang
ldi r16,0b00001000 ;Ausgang (1) auf PB3, Eingang (0) auf PB4
out ddrb,r16 ;Datenrichtungsbits setzen, Port ist Ausgang
ldi r16,0b11100111 ;Datenrichtungsbits setzen
out portb,r16 ; und initialisieren
ret ;=====----->>>>>
;
adcinit: ;=== Initialisiere ADC und hole Daten
ldi a,adcpsc ;Setze adpsc0,1,2 => Clock/128, siehe define
out adcsra,a ;Lade prescaler ==> 75 kHZ, siehe define
sbi admux,potiadc ;Wandlung vom Kanal ADC2 = PB4 = potiadc
sbi admux,adlar ;Result left adjusted ==> NUR 8-Bit-Wandlung
sbi adcsra,aden ;AD en-able einschalten
sbi adcsra,adsc ;Wandlung zum Initialisieren starten
;
adrdy_in1: ;=== Warte bis ADC fertig ist ==> ZWEI Wandlngen durchführen
sbic adcsra,adsc ;Skip if bit is cleared => dann ADC fertig
rjmp adrdy_in1 ; .. wenn nicht fertig, warten
adrdy_in2: ;=== Warte bis ADC fertig ist ==> ZWEI Wandlngen durchführen
sbic adcsra,adsc ;Skip if bit is cleared => dann ADC fertig
rjmp adrdy_in2 ; .. wenn nicht fertig, warten
;
ldi r16,0b00000000 ;Dummy-Muster
mov r14,r16 ;Muster nach r14
mov r15,r16 ; .. und nach r15
sbi adcsra,aden ;AD en-able einschalten
sbi adcsra,adsc ;Wandlung zum Initialisieren starten
ret ;=====----->>>>>
;
;
isr_ini: ;=== Initialisierung der ISR (war mal isrinit_x15)
;
;;Timer Register werden belegt
ldi a,(1<<wgm01) ;prescaler ist 1, waveform = CTC
out tccr0a,a ;Register TCCR0 ist für den Prescaler zuständig
ldi a,(1<<cs00) ;prescaler ist 1 => kein Prescaling, Abstand zum
out tccr0b,a ; nächsten Interrupt bestimmt der
; CTC-Prescaler tmrprs
ldi a,(1<<ocie0a) ;Hier Interrupts nach CTC eingeschaltet
out timsk0,a ;Register TIMSK ist dafür zuständig
ldi a,tmrprs ;Hier wird der Timer vorgeladen. Er läuft dann
out TCNT0,a ; .. tmrprs mal durch bevor ein Interrupt auftritt
out ocr0a,a ;Preset tmrprs in OCR0A
; .. Interrupts allgemein zulassen im Hauptprogramm
; ret ;=====----->>>>>
;
;
;===================================================================================
; Interrupt-Service-Routine
;#######>>>>> Muss real nicht zuerst der (letzte) PC gepusht werden ?
;===================================================================================
;
;
isr_ctc: ;=== Immer wieder Veränderungen
;
sbiw r27:r26,1 ;Pointer von 5000 runterzählen
; für EINEN Servoimpuls von 20 ms
breq i_neu ; .. und Spezialfall "null" ==> Daten umschaufeln
; und Rampe einschalten. WENN keine neuen Daten da
; sind, dann alte Daten nehmen :(
;
; Jetzt wird nachgesehen, ob eine der Rampen ausgeschaltet werden muss. Das steht
; im Portbit ddrb
;
isr_nn: ;=== Zähler der ISR steht nicht auf Null
s1_pran: ;=== Servo1: Prüfe, ob Rampe ist an
in r20,portb
sbrs r20,servo1 ;Ist Rampe von servo1 an?
rjmp i_raus ;Wenn Rampe nicht an ist, dann gleich raus
;
sbiw r29:r28,1 ;Decrementiere Rampenwert
brne i_raus ;weiter, wenn noch nicht Null zu servo2
cbi portb,servo1 ; Sonst Lösche Rampe für Servo1
;
rjmp i_raus
sbiw r29:r28,1
breq i_neu
rjmp i_raus
i_neu: ;Daten neu in Register und port servo1 umschalten
ldi r28,low(msmin)
ldi r29,high(msmin)
; mov r17,r15 ;Es ist adlar gesetzt, das ADCLH ist in r15
ldi r18,0
add r28,r15
adc r29,r18
;Und ADC-Wert gleich nochmal draufaddieren
; aber nur die Hälfte
clc ;Clear carry für anschliessende Division /2
ror r15 ;
add r28,r15
adc r29,r18
;
ldi r26,low(msges) ;Loopgrenzen für Gesamtloop 20 msec
ldi r27,high(msges)
sbi portb,servo1 ; Und setze Rampe für Servo1. FERTIG
;
i_raus:
reti ;=====----->>>>>
;
;===================================================================================
; Ende des Quellcodes
;===================================================================================
Lesezeichen