PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : WICHTIG: ATMega32 Programmierung



Technik97
14.07.2011, 10:37
hallo,
ich habe diesen Thread schon mal gemacht, aber jetzt habe ich gemerkt das es hier
ein assembler Forum gibt.
ich bin grade am Programmieren des ATMega32.
Mein Programm soll folgendes erfüllen:
1.der Roboter soll gerade fahren
2. und wenn er gegen die taster vorne fährt sich ein bisschen dreht
Bei mir ist das Problem, dass er am Anfang grade aus fährt und wenn der
Roboter gegen was fährt auf einmal rückwärts fährt
damit ihr euch das angucken könnt, ist hier der Programmiercode:
Code:


.NOLIST ; List-Output unterdrücken
.INCLUDE <m32def.inc> ; das gibt es für jeden Controllertyp
.LIST ; List-Output wieder aufdrehen
.CSEG ; was nun folgt, gehört in den FLASH-Speicher


.def tmp = r16
.def count0 = r17
.def count1 = r18
.def count2 = r19
.def compare_value = r23
.def reload = r24
.def softcounter = r25
.def sollwert = r20
.def pulseMotor2 = r21
.def calc = r22
.def sollwert_M1 = r0
.def pulseMotor1 = r1
.def compare_value_M1 = r2

.equ LED = PC7
.equ Taster4 = PD2
.equ Taster6 = PD3
.equ PWM_1 = PD4
.equ PWM_2 = PD5
.equ Pulse1 = PB0
.equ Pulse2 = PB2
.equ Richtung1 = PB1
.equ Richtung2 = PB3
.EQU clk = PA4
.EQU richtung = PA5
.EQU strom = PA6



;------------------------------------------------------
; Warteschleife ca. 1 ms multipliziert
; mit dem übergebenen Parameter
;------------------------------------------------------

.MACRO warten
ldi count0, @0 ; Lade direkten Wert in R17 1 Zyklus
LOOP2: ldi count1, 100 ; Lade direkten Wert in R18 1 Zyklus
LOOP1: ldi count2, 52 ; Lade direkten Wert in R19 1 Zyklus
LOOP0: dec count2 ; Dekrementiere R19 -> Z ist gesetzt, wenn R19 == 0
; 1 Zyklus
brne LOOP0 ; Teste Zero Flag (Z)
; 1 Zyklus, wenn wahr, 2 Zyklen, wenn falsch
dec count1 ; Dekrementiere R18 -> Z ist gesetzt, wenn R18 == 0
; 1 Zyklus
brne LOOP1 ; Teste Zero Flag (Z)
; 1 Zyklus, wenn wahr, 2 Zyklen, wenn falsch
dec count0 ; Dekrementiere R17 -> Z ist gesetzt, wenn R17 == 0
; 1 Zyklus
brne LOOP2 ; Teste Zero Flag (Z)

.ENDM

.MACRO warten10msMalX
ldi count0, @0 ; Lade direkten Wert in R17 1 Zyklus
LOOP2: ldi count1, 226 ; Lade direkten Wert in R18 1 Zyklus
LOOP1: ldi count2, 235 ; Lade direkten Wert in R19 1 Zyklus
LOOP0: dec count2 ; Dekrementiere R19 -> Z ist gesetzt, wenn R19 == 0
; 1 Zyklus
brne LOOP0 ; Teste Zero Flag (Z)
; 1 Zyklus, wenn wahr, 2 Zyklen, wenn falsch
dec count1 ; Dekrementiere R18 -> Z ist gesetzt, wenn R18 == 0
; 1 Zyklus
brne LOOP1 ; Teste Zero Flag (Z)
; 1 Zyklus, wenn wahr, 2 Zyklen, wenn falsch
dec count0 ; Dekrementiere R17 -> Z ist gesetzt, wenn R17 == 0
; 1 Zyklus
brne LOOP2 ; Teste Zero Flag (Z)

.ENDM



;------------------------------------------------------
; Start Adresse 0000
;------------------------------------------------------
RESET:
jmp INIT ; springen nach "INIT"

;------------------------------------------------------
; ISR VECTORS
;------------------------------------------------------
.ORG 0x002
jmp EXTERN0 ;Interruptvektor für INT0, hier
;spring das Programm hin, wenn an Pin D.2 ein Flankenübergang
;erfolgt.
.ORG 0x004
jmp EXTERN1 ;Interruptvektor für INT1, hier
;spring das Programm hin, wenn an Pin D.3 ein Flankenübergang
;erfolgt.
.ORG 0x006
jmp EXTERN2 ;Interruptvektor für INT2, hier
;spring das Programm hin, wenn an Pin B.2 ein Flankenübergang
;erfolgt.

.ORG 0x012
jmp Timer1OVF ;Interruptvektor für Timer1, hier
;spring das Programm hin, wenn Timer 1 überläuft



.ORG INT_VECTORS_SIZE ; dadurch haben wir für die Vektoren Platz gelassen
INIT:
;------------------------------------------------------
; INITIALIZE
;------------------------------------------------------
ldi tmp,high(RAMEND) ;Stack Pointer setzen
out SPH,tmp ; "RAMEND" ist in m32def.inc (s.o.) festgelegt
ldi tmp,low(RAMEND) ;
out SPL,tmp ;


;------------------------------------------------------
; eigene Initialisierungen
;------------------------------------------------------

LDI tmp, 0
LDI tmp, (1<<PWM_1)|(1<<PWM_2) ; PWM Bits auf eins
OUT DDRD, tmp ; das kommt ins Control-Register f. PortD
; dadurch sind Pullups an Port an
LDI tmp, 0
LDI tmp, (1<<Richtung1)|(1<<Richtung2) ; Richtungs Bits auf eins
OUT DDRB, tmp ; das kommt ins Control-Register f. PortB
; dadurch sind Pullups an Port an



ldi tmp, 255
out DDRC, tmp
out PortC, tmp


; Timer Register werden belegt
; Timer 1
in tmp, TCCR1A
ldi tmp, (1<<COM1A1)|(1<<COM1A0)|(1<<COM1B1)|(1<<COM1B0)|(1<<WGM10);
out TCCR1A, tmp
in tmp, TCCR1B
ldi tmp, (1<<WGM12)|(1<<CS12)|(0<<CS11)|(0<<CS10) ;Vorteiler ist 256
out TCCR1B, tmp


; Timer 0
in tmp, TCCR0
ldi tmp,(1<<CS02) | (1<<CS01) ;Externe Clock, fallende Flanke
out TCCR0,tmp ;Register TCCR0 ist für die Clock


in tmp, MCUCR ;MCU Control Register einlesen
ldi tmp, (1<<ISC11)|(1<<ISC01) ;Interrupt Sense Control
out MCUCR, tmp ;für INT0 und INT1 auf fallende Flanke
in tmp, GICR ;General Interrupt Control Register einlesen
ldi tmp, (1<<INT2)|(1<<INT1)|(1<<INT0) ;Externe Interrupts 0, 1 und 2 an
out GICR, tmp
in tmp, TIMSK ;Timer Interrupt Mask Register einlesen
ldi tmp, (1<<TOIE1) ;Timer 1 Overflow IR an
out TIMSK, tmp


sei ;Interrupts allgemein zulassen

ldi compare_value, 40 ;PWM erst mal auf 50%
ldi tmp, 50
mov compare_value_M1, tmp
ldi reload, 39 ;T1 Overflow erfolgt nach 217 * 256 * 62,5 ns
;-> Interrupt alle 3,427 ms
ldi softcounter, 144 ;-> für 2 Hz Samplerate nur alle 144 Interrupts
; Zähler auslesen und zurücksetzen
ldi pulseMotor2, 0
out TCNT1L, reload
sbi PortD, Taster4 ;erst mal eine 1 auf die Taster
sbi PortD, Taster6 ;damit die fallende Flanke
;den IR auslöst.
sbi PortB, Pulse1
sbi PortB, Pulse2

sbi PortB, Richtung1
sbi PortB, Richtung2

sbi DDRA,clk ;clk Pin als Ausgang
sbi DDRA,richtung ;richtung Pin als Ausgang
sbi DDRA,strom ;strom Pin als Ausgang
sbi PORTA,clk ;clk Bit setzen
cbi PORTA,richtung ;Richtung vorgeben
sbi PORTA,strom ;Richtung vorgeben


ldi sollwert, 20


;------------------------------------------------------
; HAUPTSCHLEIFE
;------------------------------------------------------
Hauptschleife:

sbis PINA, PA0
call change_left
sbis PINA, PA1
call change_dir
sbis PINA, PA2
call change_right



rjmp Hauptschleife ; immer wiederholen

Ende:
rjmp Ende

;------------------------------------------------------
; ISR Extern0
;------------------------------------------------------
EXTERN0:

; Erst mal alles auf den Stack

PUSH tmp ;benutzte Register speichern
IN tmp, SREG ;Statusregister retten
PUSH tmp ;

;Hier kommt unsere eigentliche Bearbeitung
;
warten 1 ;1 ms warten, da Taster prellt

;Richtung umkehren
sbi PortB, Richtung1
sbi PortB, Richtung2
warten10msMalX 40
;Kurve einleiten
cbi PortB, Richtung2
warten10msMalX 20
;und wieder gerade
cbi PortB, Richtung1

in tmp, GIFR
ldi tmp, (1<<INTF0) ;durch Prellen des Tasters wurde schon
out GIFR, tmp ;ein neuer Interrrupt getriggert
;manuelles setzen des Flags verhindert
;eine erneute Ausführung der Routine
;nach dem Rücksprung

; Jetzt Register vom Stack wiederholen
POP tmp ;Statusregister wiederherstellen
OUT SREG, tmp ;
POP tmp ;benutzte Register wiederherstellen

RETI ;Rücksprung

;------------------------------------------------------
; ISR Extern1
;------------------------------------------------------
EXTERN1:

; Erst mal alles auf den Stack
PUSH tmp ;benutzte Register speichern
IN tmp, SREG ;Statusregister retten
PUSH tmp ;

;Hier kommt unsere eigentliche Bearbeitung
warten 1 ;1 ms warten, da Taster prellt
;Richtung umkehren
sbi PortB, Richtung1
sbi PortB, Richtung2
warten10msMalX 40
;Kurve einleiten
cbi PortB, Richtung1
warten10msMalX 20
;und wieder gerade
cbi PortB, Richtung2

in tmp, GIFR
ldi tmp, (1<<INTF1) ;durch Prellen des Tasters wurde schon
out GIFR, tmp ;ein neuer Interrrupt getriggert
;manuelles setzen des Flags verhindert
;eine erneute Ausführung der Routine
;nach dem Rücksprung

; Jetzt Register vom Stack wiederholen
POP tmp ;Statusregister wiederherstellen
OUT SREG, tmp ;
POP tmp ;benutzte Register wiederherstellen

RETI ;Rücksprung

;------------------------------------------------------
; ISR Extern2
;------------------------------------------------------
EXTERN2:

; Erst mal alles auf den Stack
PUSH tmp ;benutzte Register speichern
IN tmp, SREG ;Statusregister retten
PUSH tmp ;

;Hier kommt unsere eigentliche Bearbeitung
inc pulseMotor2

; Jetzt Register vom Stack wiederholen
POP tmp ;Statusregister wiederherstellen
OUT SREG, tmp ;
POP tmp ;benutzte Register wiederherstellen

RETI ;Rücksprung
;------------------------------------------------------
; ISR Timer1 Overflow
;------------------------------------------------------
Timer1OVF:
dec softcounter
brne go_back

; Erst mal alles auf den Stack
PUSH tmp ;benutzte Register speichern
IN tmp, SREG ;Statusregister retten
PUSH tmp ;

;Hier kommt unsere eigentliche Bearbeitung
mov tmp, pulseMotor2
call regelung_M2
com tmp ;Zählerstand auf
out PortC, tmp ;LEDs ausgeben

ldi tmp, 0
out TCNT2, tmp
out TCNT0, tmp
ldi pulseMotor2, 0
out TCNT1L, reload
ldi softcounter, 144



; Jetzt Register vom Stack wiederholen
POP tmp ;Statusregister wiederherstellen
OUT SREG, tmp ;
POP tmp ;benutzte Register wiederherstellen
go_back:
RETI ;Rücksprung

;------------------------------------------------------
; Unterprogramm Regelung Motor 2 nach Sollwert
;------------------------------------------------------
regelung_M2:

push tmp

mov sollwert_M1, pulseMotor2 ;aktuelle Pulse sind Sollwert für Motor1
in pulseMotor1, TCNT0 ;pulse für Motor1 festhalten

clc
cp sollwert, pulseMotor2
brne checkDirection
call regelung_M1
pop tmp
ret
checkDirection:
brcs langsamer ;Carry gesetzt, wenn pulseMotor2 > Sollwert
schneller:
mov calc, sollwert
sub calc, pulseMotor2 ;Pulse vom Sollwert abziehen
mov tmp, compare_value ;schauen, ob Maximaldrehzahl schon erreicht
clc
add tmp, calc ;Regelabweichung addieren
brcs back ;größer 255
mov calc, tmp ;Ergebnis der Addition in calc
mov compare_value, calc
out OCR1AL, compare_value ;compare Wert schreiben
call regelung_M1
pop tmp
ret
langsamer:
mov calc, pulseMotor2
sub calc, sollwert ;Sollwert von Pulsen abziehen
mov tmp, compare_value ;schauen, ob Minimaldrehzahl schon erreicht
sub tmp, calc ;Regelabweichung subtrahieren
mov calc, tmp ;Ergebnis der Subtraktion in calc
ldi tmp, 55
clc ;carry löschen
cp calc, tmp ;schauen, ob calc (eigentlich neuer compare_value)
brcs back ;kleiner 55
mov compare_value, calc ;wenn nicht, übernehmen
out OCR1AL, compare_value ;compare Wert schreiben
back:
call regelung_M1
pop tmp
ret

;------------------------------------------------------
; Unterprogramm Regelung Motor 1 nach Motor 2
;------------------------------------------------------

regelung_M1:

push tmp
clc

cp sollwert_M1, pulseMotor1
brne checkDirection_M1
pop tmp
ret
checkDirection_M1:
brcs langsamer_M1 ;Carry gesetzt, wenn pulseMotor2 > Sollwert
schneller_M1:
mov calc, sollwert_M1
sub calc, pulseMotor1 ;Pulse vom Sollwert abziehen
mov tmp, compare_value_M1 ;schauen, ob Maximaldrehzahl schon erreicht
clc
add tmp, calc ;Regelabweichung addieren
brcs back_M1 ;größer 255
mov calc, tmp ;Ergebnis der Addition in calc
mov compare_value_M1, calc
out OCR1BL, compare_value_M1 ;compare Wert schreiben
pop tmp
ret
langsamer_M1:
mov calc, pulseMotor1
sub calc, sollwert_M1 ;Sollwert von Pulsen abziehen
mov tmp, compare_value_M1 ;schauen, ob Minimaldrehzahl schon erreicht
sub tmp, calc ;Regelabweichung subtrahieren
mov calc, tmp ;Ergebnis der Subtraktion in calc
ldi tmp, 55
clc ;carry löschen
cp calc, tmp ;schauen, ob calc (eigentlich neuer compare_value)
brcs back_M1 ;kleiner 55
mov compare_value_M1, calc ;wenn nicht, übernehmen
out OCR1BL, compare_value_M1 ;compare Wert schreiben
back_M1:
pop tmp
ret

change_left:
call step
;Richtung umkehren

cbi PortB, Richtung1
cbi PortB, Richtung2
warten10msMalX 20
;Kurve einleiten
sbi PortB, Richtung2
warten10msMalX 10
;und wieder gerade
sbi PortB, Richtung1
ret

change_right:
call step
cbi PortB, Richtung1
cbi PortB, Richtung2
warten10msMalX 20
;Kurve einleiten
sbi PortB, Richtung1
warten10msMalX 10
;und wieder gerade
sbi PortB, Richtung2
ret

change_dir:
call step
;Richtung umkehren
cbi PortB, Richtung1
cbi PortB, Richtung2
ret

step:
sbis PORTA,CLK ;prüfe, ob CLK gesetzt ist
rjmp aus ;dann überspringe diese Zeile
cbi PORTA,CLK ;und schalte CLK ein
warten10msMalX 10
ret
aus:
sbi PORTA,CLK ;CLK war gesetzt -> ausschalten
warten10msMalX 10
ret


ich habs jetzt auch geschafft EXTERN1 richtig zu programmieren.
Ich hab folgendes geändert:

cbi PortB, Richtung1
cbi PortB, Richtung2
warten10msMalX 40
;Kurve einleiten
sbi PortB, Richtung1
warten10msMalX 20
;und wieder gerade
sbi PortB, Richtung2

ich programmiere in AVR Studio 4
danke schon im Vorraus,
mit freundlichen Grüßen, technik97


Kollege, für Code solltest du auch das Code-Tag verwenden (PicNIck, Mod)
"Quote" ist für Zitate