PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] Assembler-Anfänger Problem mit Timern



Pr0gm4n
15.01.2011, 18:07
Hallo zusammen,

in der Schule lernen wir in Info zur Zeit Assembler und da hab ich mir gedacht ich lern jetz mal AVR-Assembler ;)

Ich mach grad das mikrocontroller.net-tutorial durch und bin bei den timern



#define servoreg1 DDRA
#define servoreg2 DDRA
#define servoport1 PORTA
#define servoport2 PORTA
#define servopin1 PA0
#define servopin2 PA1
.def servo1 = R19
.def servo2 = R20

.include "m32def.inc"


.def tmp = R16 ; Allzweckregister
.def counter = R17 ; Counter für Timer-1-Zyklen
.def counter2 = R18 ; Counter für Timer-0-Zyklen
.equ Timer1AOVF = 200 ; 200 = 0,1ms bei prescaler 8
; 20 = 0,01ms bei prescaler 8
; 2 = 0,001ms bei prescaler 8
; 10 = 0,005ms bei prescaler 8
; 16 = 0,001ms bei prescaler 1
; 80 = 0,005ms bei prescaler 1

.org 0x000
rjmp Main
.org OC1Aaddr ; Output Compare1A Interrupt Vector Address
rjmp OC1A_interrupt
.org OVF0addr ; Overflow0 Interrupt Vector Address
rjmp OVF0_interrupt

.org INT_VECTORS_SIZE

OC1A_interrupt:
inc counter

;update servos:
cp counter, servo1
brne s2
cbi servoport1, servopin1
s2:
cp counter, servo2
brne counterreset
cbi servoport2, servopin2
counterreset:
cpi counter, 200
brne end
clr counter
sbi servoport1, servopin1
sbi servoport2, servopin2
end: reti

OVF0_interrupt:
inc counter2
cpi counter2, 255
brne end2
inc servo1
inc servo2
clr counter2
cpi servo1, 21
brne end
ldi servo1, 10
ldi servo2, 10
end2: reti


Main: ; hier beginnt das Hauptprogramm
ldi tmp, HIGH(RAMEND) ; HIGH-Byte der obersten RAM-Adresse
out SPH, tmp
ldi tmp, LOW(RAMEND) ; LOW-Byte der obersten RAM-Adresse
out SPL, tmp
clr tmp
;/*Timer 0:
ldi tmp, ( 1 << CS02 ) | ( 1 << CS00 ) ; Prescaler auf 1024
out TCCR0, tmp
;=> 61.4 Overflows in der Sekunde (bei 16 MHz)
;=> alle 16,4 ms
ldi tmp, TIMSK
ori tmp, ( 1 << TOIE0 ) ; TOIE0: Interrupt bei Timer Overflow
out TIMSK, tmp
;*/ ;Timer 0

;/*Timer 1:
ldi tmp, high( Timer1AOVF - 1 )
out OCR1AH, tmp
ldi tmp, low( Timer1AOVF - 1 )
out OCR1AL, tmp
; Prescaler auf 1 (001), 8 (010), 64 (011), 256 (100), 1024 (101)
ldi tmp, ( 1 << WGM12 ) | ( 1 << CS11 )
out TCCR1B, tmp

ldi tmp, TIMSK
ori tmp, ( 1 << OCIE1A ) ; OCIE1A: Interrupt bei Timer Compare A
out TIMSK, tmp
;*/ ;Timer 1


ldi tmp, 0xFF
out DDRA, tmp


ldi counter, 0x00
ldi counter2, 0x00

rcall init_servos

sei
loop:

rjmp loop

init_servos:
sbi servoreg1, servopin1
ldi servo1, 10
sbi servoreg2, servopin2
ldi servo2, 10
ret


Ziel war es:
2 Servos "parallel" von anschlag1 zu anschlag 2 zu fahren und wenn man dort ankommt wieder auf anschlag 1

mit timer0 sollte ich dank 16MHz und 1024 prescaler mit dem counter2 und den 256 fürn overflow von mir auf etwa 4 sekunden takte kommen bei denen im interrupt die servopositionen servo1 und servo2 inkrementiert werden, bei 10 positionen sollte das also 40s dauern, bis der wieder die richtung wechselt und zum anschlag 1 fährt.

timer1 soll dagegen die pwm übernehmen
16MHz, prescale 8, compare bei 200 --> alle 0.1 ms

ergebnis des codes sind zwei zwischen anschlag 1 und ca. 15° hin- und herbewegende servos

als board nehm ich grad weil ich nix besseres zur hand hatte das pollin funk evaluationsboard ver 1.1 mit ATMega32
die stromversorgung des servos läuft zwar auch über den spannungsregler der platine, aber nicht über den controller, der spannungsregler wird dabei weder warm noch sonstwas außergewöhnliches...

Ich hoffe ihr könnt mir helfen.

LG Roland

PS: im AVR-Studio-Debugger läuft alles ohne Probleme, die Taktzyklen sind genau so wie ich sie ausgerechnet hatte, alle 20ms ein neues signal für den servo, die länge des signals passt, auch die zeit zum "hochschalten" der position der servos stimmt...
keine ahnung was da wieder nicht geht...
danke schonmal an alle

Besserwessi
15.01.2011, 22:33
Stimmt den die Taktfrequenz bei dem Board ? Nicht das es da mit 14 MHz läuft.

Hier passiert nicht, aber mir ist aufgefallen, dass in den ISRs die Register nicht gerettet werden. Wenn da das Hauptprogramm noch was sinnvolles tun soll, gibt das Probleme.

Pr0gm4n
15.01.2011, 22:54
Hi,

ich hatte das auch zuvor mit push tmp und anschließendem pop tmp geschrieben, ist im verlauf des debuggings mal rausgeflogen, nicht dass die isr's zu lang sind und sich überschneiden oder was auch immer, keine ahnung

die frequenz sollte stimmen, hab davor schonmal n kleinen test mit timer1 gemacht, der led's im 0,5s-rhytmus blinken ließ, überprüfung mit uhr, hat genau gestimmt...
das quarz das verbaut und nach schaltplan und platinen-bahnen mit dem atmega32 verbunden is war mitgeliefert und hat die aufschrift K16.000

bin echt am verzweifeln hier -.-

LG Roland

Pr0gm4n
16.01.2011, 03:10
UPDATE:
So, ihr seht es ist schon spät und ich bin auch schon einen verfusten Controller weiter... *grml*
Naja, muss ich schnell nen taktgenerator aufbaun...

Egal, zurück zum Thema

getestet:
-externe stromversorgung für servos => gleiches ergebnis (verbundene massen etc...)
-anderer chip => gleiches ergebnis
-programm umschreiben, jetzt nurnoch led's blinken lassen im 4,...s rhytmus von timer0 wie oben
funktioniert irgendwie auch nicht -.- (code dafür siehe unten)

-Fuses umkehren, man weiß ja nie wenn man n anderes Programm hernimmt... => atmega32 verfust...
fuses für die clock stehen momentan so:
*ckopt = 1
*sut1 = 0
*sut0 = 1
*cksel3 = 1
*cksel2 = 1
*cksel1 = 1
*cksel0 = 0

wäre laut datenblatt dann "Ceramic resonator, slowly
rising power"
sollte doch passen oder nicht?
naja, was ich nich versteh is, warum es zu schnell blinkt/fährt

selbst wenn der statt den 16 MHz dann den internen takt von 1/4/8 MHz nehmen würde, das würde das ganze doch nur verlangsamen
also die LED's würden dann alle 8sec blinken...
komisch echt


.include "m32def.inc"


.def tmp = R16 ; Allzweckregister
.def counter2 = R18 ; Counter für Timer-0-Zyklen

.org 0x000
rjmp Main
.org OVF0addr ; Overflow0 Interrupt Vector Address
rjmp OVF0_interrupt

.org INT_VECTORS_SIZE

OVF0_interrupt:
inc counter2
cpi counter2, 255
brne end
in tmp, PORTD
com tmp
out PORTD, tmp
end: reti


Main: ; hier beginnt das Hauptprogramm
ldi tmp, HIGH(RAMEND) ; HIGH-Byte der obersten RAM-Adresse
out SPH, tmp
ldi tmp, LOW(RAMEND) ; LOW-Byte der obersten RAM-Adresse
out SPL, tmp
;/*Timer 0:
ldi tmp, ( 1 << CS02 ) | ( 1 << CS00 ) ; Prescaler auf 1024
out TCCR0, tmp
;=> 61.4 Overflows in der Sekunde (bei 16 MHz)
;=> alle 16,4 ms
ldi tmp, TIMSK
ori tmp, ( 1 << TOIE0 ) ; TOIE0: Interrupt bei Timer Overflow
out TIMSK, tmp
;*/ ;Timer 0


ldi tmp, 0xFF
out DDRD, tmp
ldi tmp, 0x55
out PORTD, tmp
ldi counter2, 0x00


sei
loop:

rjmp loop


LG Roland

Pr0gm4n
16.01.2011, 12:35
Hallo, also letzter Beitrag hier... endlich funktionierts ;)
Da sieht man mal wieder, ausschlafen lohnt sich...

statt


ldi tmp, TIMSK
ori tmp, ( 1 << TOIE0 ) ; TOIE0: Interrupt bei Timer Overflow
out TIMSK, tmp
[...]
ldi tmp, TIMSK
ori tmp, ( 1 << OCIE1A ) ; OCIE1A: Interrupt bei Timer Compare A
out TIMSK, tmp

wäre wohl



in tmp, TIMSK
ori tmp, ( 1 << TOIE0 ) ; TOIE0: Interrupt bei Timer Overflow
out TIMSK, tmp
[...]
in tmp, TIMSK
ori tmp, ( 1 << OCIE1A ) ; OCIE1A: Interrupt bei Timer Compare A
out TIMSK, tmp

besser gewsen... (ldi -> in) jetzt funktioniert alles wie erwünscht :-)


LG Roland