PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Assembler Motorsteuerung



H3llGhost
10.10.2007, 09:10
Hallo Leute,

mit folgendem Code habe ich ja beide Motoren auf vorwärts geschaltet:



[...]
sbi DDRD, DDD4
sbi DDRB, DDB1
sbi PORTB, PORTB1

sbi DDRB, DDB2
sbi PORTB, PORTB2
sbi DDRB, DDB4
[...]


Warum darf ich keinen Port dazuschalten?
Und wie kann ich zwischen zwei Geschwindigkeiten ohne großen Quelltext wechseln?

Für den rückwärtsgang brauche ich ja einfach nur D4 auf D5 ändern und B4 auf B5 ändern oder?
Und für Bremse einfach die D4 und D5 bzw. B4 und B5 schalten oder?

damaltor
10.10.2007, 17:38
was heisst "keinen port dazuschalten"?
zum ändern der geschiwindigkeit musst du an der stelle was ändern, wo auch die geschwindigkeit definiert ist. wie ich das sehe, hat du die motoren-pwm vollständig umgangen, kann das sein? normalerweise werden die motoren pwm-gesteuert.

H3llGhost
10.10.2007, 17:45
PWM?! ...
Was ist das? :D

Mit den Ports meinte ich folgendes:
Wenn ich dann noch sbi PORTD, PORTD4 benutze dann läuft garnichts mehr ...
Deswegen die Frage nach den Ports ...

damaltor
10.10.2007, 17:55
PWM bedeutet PulsWeitenModulation. das lässt sich etwa folgendermaßen kurz beschreiben:

ein signal mit konstanter frequenz (!!!) wird an die motoren gelegt. wenn dieses signal 50% high und 50% low ist, bekommen die motoren zur hälfte der zeit strom und zur hälfte der zeit keinen strom. da sie recht träge sind, und die frequenz sehr hoch, merkt man das nicht, es sieht so aus als würden die motoren mit halber kraft fahren.

um schneller zu fahren, wird das tastsignal verändert, z.B. 80% high und 20% low. die motoren fahren mit 80%iger kraft.

um langsamer zu fahren, andersrum: etwa 20% high und 80% low. macht 20% der höchstgecshwindigkiet.

diese pwm kann der avr intern generieren - allerdings nicht ganz unkompliziert. du kannst sehen, wie das funktioniert, indem du dir die beiden funktionen MotorSpeed() und MotorDir() aus der asuro-library mal ansiehst.

mit deiner ansteuerung von oben bekommen die motoren entweder dauerstrom (100%) oder keinen strom (0%), deshalb ist die geschwindigkeit auf diese weise nicht regelbar.

weitere infos: http://de.wikipedia.org/wiki/PWM

pwms werden recht oft verwendet: zum steuern von motoren, zum dimmen von leds (die ja eben eigentlich nur ein oder ausgecshaltet werden können, aber durch die pwm "gedimmt" werden), und auch oft übersehen in der steuerung der mikrowelle: 3 sekunden an, 3 sekunden aus = 50% der leistung. ist halt ne seeehr langsame frequenz, aber das prinzip ist das gleiche.

was du mit den ports meinst, verstehe ich leider nicht.

H3llGhost
10.10.2007, 21:14
Aber das ist doch nicht mit Assembler kombinierbar oder?

izaseba
10.10.2007, 21:38
Hallo, warum soll PWM nicht mit asm kombinierbar sein ?

Schau mal hier (https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=10291&postdays=0&postorder=asc&start=22)

Das Programm ganz unten auf der Seite, aber vorsicht, fremde (und nach ein paar Wochen) auch eigene asm Programme zu lesen bereitet Schmerzen ;-)

Gruß Sebastian

damaltor
10.10.2007, 21:44
im endeffekt wird der C-code, den man tippt, vom compiler auch nur in assembler umgesetzt, welcher dass für den prozesser assembliert wird...

H3llGhost
10.10.2007, 21:48
@izaseba:
Danke für den Tipp ...
Jetzt kann ich nur sagen: WAS???
Erklärst du mir das mal alles ... :D
Wir sind fleißige Besucher von deiner Seite ...
Ich, meine Klasse und der Lehrer ... (ja ich weiß der Esel zuerst!)
Fehlen mir nicht dann noch Teile?


.include "motoren.asm"
.include "LED.asm"

:D

@damaltor:
Ja schon, aber wir sollen im Moment NUR in Assembler schreiben ...

izaseba
10.10.2007, 22:09
Wir sind fleißige Besucher von deiner Seite ...

Danke für die Blumen, so was tut gut, dann mache ich das alles doch nicht um sonst...
Es gibt auch schon wieder ein Update, leider noch Offline, vielleicht lade es am WE hoch.


Fehlen mir nicht dann noch Teile?
Wo Du das sagst... Ups, na wo sind sie denn?
Ich kann morgen gucken, wo ich sie habe, aber so wild ist es nicht.
Ich habe fast jede Zeile kommentiert, schaue mal :


;PWM einstellen
ldi tmp,(1<<WGM10) | (1<<COM1A1) | (1<<COM1B1)
out TCCR1A,tmp
ldi tmp,(1<<CS11)
out TCCR1B,tmp

damit wird Timer1 in PWM Mode eingestellt und auf die Ausgänge geschaltet.


; DDR für Motor Rechts und Statusled green
ldi tmp,(1<<PB0) |(1<<PB1) | (1<<PB2) | (1<<PB5) | (1<<PB4)
out DDRB,tmp
;DDR für Motor Links,Statusled red, LED für Linienverfolgung und LEDs
;Odometrie und Backleds
ldi tmp,(1<<PD2) | (1<<PD4) | (1<<PD5) | (1<<PD6) | (1<<PD7)
out DDRD,tmp

Das dürfte wohl klar sein...


sbi PORTB,fwd
sbi PORTD,fwd
damit wird der Vorwärtsgang eingelegt ;-) (schaue bei equ nach fwd)
Wenn Du jetzt OCR1A und OCR1B Register mit Werten zwischen 0-255 belegst fährt er naja bei 0 wohl nicht, aber je größer die Werte um so schneller...

Gruß Sebastian

EDIT:
Sagmal, was gibt es heute für Schulen, warum durfte ich damals keinen Asuro programmieren :-(
Ne, ich durfte noch einen SPS mit solch einem blödem Handprogrammiergerät, wo man eben 4 Zeilen Code gesehen hat beglücken ](*,) Habt Ihr das gut ...

H3llGhost
10.10.2007, 22:23
Wie kommst du eigentlich dazu, dass jetzt zu programmieren?

Kann ich deine Codebeispiele einfach in meinen Code einfügen oder wie sieht das aus?
Mir reicht ja schon ein einfacher Code für Vorwärts und Rückwärtsfahren für den Asuro, denn ich habe keinen Bock deinen großen Code wieder denen vorzustellen, denn ich muss das immer dann ... ](*,)

Und das macht besonders Spaß, wenn man nicht alles weiß ... :D

izaseba
10.10.2007, 22:40
Wie kommst du eigentlich dazu, dass jetzt zu programmieren?
???
Wie ich dazu komme ?
Indem ich auf

Erklärst du mir das mal alles
^^das da antworte und mit hilfe von STRG/c und STRG/v aus dem Programm, das in dem Link vorgestellt wurde, ein paar Zeilen kopiere, die für das Fahren zuständig sind.


Und das macht besonders Spaß, wenn man nicht alles weiß ...

Ja gut, dann lass ich Dich damit dann alleine, sonst weißt Du zu viel ;-)

H3llGhost
10.10.2007, 22:56
Vielen Dank ... xD
Ich wollte eigentlich nur kurz und knapp wissen wie ich nun das PWM benutze ... ;)
Würdest du mir da trotzdem helfen wollen?

izaseba
10.10.2007, 23:20
Ich wollte eigentlich nur kurz und knapp wissen wie ich nun das PWM benutze ...
Wenn jemand Hilfe braucht, und ich ev. die Antwort weiß, helfe ich natürlich,

Nur ich habe schon alles gesagt, was man zu PWM sagen konnte ^ da oben
ober was möchtest Du noch wissen ?

H3llGhost
10.10.2007, 23:39
Wie wende ich das an?
Ganz einfach ...

Bei folgendem Code:


sbi DDRB, DDB1
sbi PORTB, PORTB1

sbi DDRB, DDB2
sbi PORTB, PORTB2
sbi DDRB, DDB4
sbi DDRD, DDD4

damaltor
11.10.2007, 01:12
bei diesem code.. gar nicht. damit werden nämlich die pins der motoren dauerhaft auf high und low gesetzt, und das willst du ja nicht mehr. dein code wird duch den pwm code ersetzt.

H3llGhost
11.10.2007, 10:17
Und der lautet?! ... :D

@izaseba:

Dein Code ist so nicht funktionstüchtig, da mir ein paar Funktionen fehlen ... :(
Vielleicht kannst du ja mal einen kleine Version davon schreiben ... ;)
Nur für das Vorwärtsfahren ... :)

damaltor
12.10.2007, 00:17
der lautet... so wie du ihn oben bekommen hast... :)

A.Hoffmann
12.10.2007, 11:47
Hallo H3IIGhost.

Ich habe das so Verstanden.
Die PWM Funktion im ASURO wird von dem Timer 1 des ATmega8 übernnommen. Er wird so Programmiert, dass an den H - Brücken eine Frequenz von ca zwei KHz anliegt. Durch die Werte in den beiden Registern OCR1AL bzw. OCR1BL wird der high Anteil einer Periode festgelegt. je höher dieser Wert 0 - 255 desto schneller fährt der ASURO.
Lese dazu auch die Beschreibung des PWM - Modus im Datenblatt des ATmega8. Und Versuche die Funktion der H - Brücken im ASURO zu Verstehen.
Ansonsten sieh dir mal dieses Programm an.

MfG
A.Hoffmann




.include "m8def.inc"

.def temp = r16 ; Arbeitsregister


.cseg

.org 0x000
rjmp Prog_Initial ; Interruptvektoren überspringen
reti ; INT0addr - Externer Interrupt 0
reti ; INT1addr - Externer Interrupt 1
reti ; OC2addr - Output Compare2
reti ; OVF2addr - Overflow2
reti ; ICP1addr - Input Capture1
reti ; OC1Aaddr - Output Compare1A
reti ; OC1Baddr - Output Compare1B
reti ; OVF1addr - Overflow1
reti ; OVF0addr - Overflow0
reti ; SPIaddr - SPI
reti ; URXCaddr - USART Receive Complete
reti ; UDREaddr - USART Data Register Empty
reti ; UTXCaddr - USART Transmit Complete
reti ; ADCCaddr - Analog Digital wandler
reti ; ERDYaddr - EEPROM
reti ; ACIaddr - Analog Comparator
reti ; TWIaddr - Two - Wire Interface
reti ; SPMaddr - SPM complete


Prog_Initial:

;************************************************* *****************************
; Stack Pointer setzen *
;************************************************* *****************************

ldi temp, LOW(RAMEND) ; Stack Pointer low
out SPL, temp ; setzen
ldi temp, HIGH(RAMEND) ; Stack Pointer high
out SPH, temp ; setzen


;************************************************* *****************************
;* Init_Timer1 8 Bit PWM an den Output Compare Pins OC1A und OC1B *
;************************************************* *****************************

; Compare Output Mode
; Clear OC1A / OC1B on Compare Match when up - counting.
; Set OC1A / OC1B on Compare Match when downcounting
; Waveform Generation Mode
; PWM , Phase Correct, 8 Bit
; Prescaler Divisions Factor = 8
; PWM Frequenz = 1,953 Khz


ldi temp, (1 << WGM10) | (1 << COM1A1) | (1 << COM1B1)
out TCCR1A, temp
ldi temp, (1 << CS11)
out TCCR1B, temp


;************************************************* *****************************
;* Init_Motor_Rechts: *
;************************************************* *****************************

sbi DDRB, DDB2 ; PWM Ausgang
sbi DDRB, DDB4 ; Richtungs und
sbi DDRB, DDB5 ; Funktions Steuerung
sbi PORTB, PORTB4 ; Motor im
sbi PORTB, PORTB5 ; Leerlauf
ldi temp, 0x00
out OCR1BH, temp
out OCR1BL, temp

;************************************************* *****************************
;* Init_Motor_Links: *
;************************************************* *****************************

sbi DDRB, DDB1 ; PWM Ausgang
sbi DDRD, DDD4 ; Richtungs und
sbi DDRD, DDD5 ; Funktions Steuerung
sbi PORTD, PORTD4 ; Motor im
sbi PORTD, PORTD5 ; Leerlauf
ldi temp, 0x00
out OCR1AH, temp
out OCR1AL, temp


;************************************************* *****************************
;* Init LEDs *
;************************************************* *****************************

sbi DDRB, DDB0 ; Duo LED grün
sbi DDRD, DDD2 ; Duo LED rot
cbi PORTB, PORTB0 ; aus
cbi PORTD, PORTD2 ; schalten
sbi DDRD, DDD6 ; Front LED
cbi PORTD, PORTD6 ; aus
sbi DDRD, DDD7 ; Back LEDs
cbi PORTD, PORTD7
sbi DDRC, DDC0
sbi DDRC, DDC1
cbi PORTC, PORTC1
cbi PORTC, PORTC1 ; ausschalten

;********************** Interrupts erlauben ******************************
sei



;**************** Ende Init **********************************************

Prog_Run:
rcall planlos
loop:
rjmp loop


;************************************************* ****************************
;* planlos herumfahren *
;************************************************* ****************************

planlos:


rcall M_L_Leerlauf ; Motoren in
rcall M_R_Leerlauf ; Leerlauf schalten
ldi temp,150 ; Wert für PWM 0 - 255
out OCR1AL, temp ; für den linken Motor
out OCR1BL, temp ; und für den rechten Motor
rcall M_L_Vorwaerts ; beide Motoren
rcall M_R_Vorwaerts ; Vorwärts

;oder Rückwärts
;rcall M_L_Rueckwaerts
;rcall M_R_Rueckwaerts

;oder im Kreis
;rcall M_L_Rueckwaerts
;rcall M_R_Vorwaerts
ret


;************************************************* *****************************
;* Motor rechts Rückwärts *
;************************************************* *****************************
M_R_Rueckwaerts:
cbi PORTB, PORTB4 ; PB4 = 0
sbi PORTB, PORTB5 ; PB5 = 1
ret

;************************************************* *****************************
;* Motor rechts Vorwärts *
;************************************************* *****************************
M_R_Vorwaerts:
sbi PORTB, PORTB4 ; PB4 = 1
cbi PORTB, PORTB5 ; PB5 = 0
ret

;************************************************* *****************************
;* Motor rechts Leerlauf *
;************************************************* *****************************
M_R_Leerlauf:
sbi PORTB, PORTB4 ; PB4 = 1
sbi PORTB, PORTB5 ; PB5 = 1
ret

;************************************************* *****************************
;* Motor rechts Bremsen *
;************************************************* *****************************
M_R_Bremsen:
cbi PORTB, PORTB4 ; PB4 = 0
cbi PORTB, PORTB5 ; PB5 = 0
ret

;************************************************* *****************************
;* Motor links Rückwärts *
;************************************************* *****************************
M_L_Rueckwaerts:
cbi PORTD, PORTD4 ; PD4 = 0
sbi PORTD, PORTD5 ; PD5 = 1
ret

;************************************************* *****************************
;* Motor links Vorwärts *
;************************************************* *****************************
M_L_Vorwaerts:
sbi PORTD, PORTD4 ; PD4 = 1
cbi PORTD, PORTD5 ; PD5 = 0
ret

;************************************************* *****************************
;* Motor links Leerlauf *
;************************************************* *****************************
M_L_Leerlauf:
sbi PORTD, PORTD4 ; PD4 = 1
sbi PORTD, PORTD5 ; PD5 = 1
ret

;************************************************* ****************************
;* Motor links Bremsen *
;************************************************* ****************************
M_L_Bremsen:
cbi PORTD, PORTD4 ; PD4 = 0
cbi PORTD, PORTD5 ; PD5 = 0
ret

H3llGhost
15.10.2007, 14:34
Danke erstmal für das Programm.
Nur würden mich ein paar Funktionen interessieren.

Warum werden OCR1AH, OCR1AL, OCR1BH und OCR1BL auf 0 gesetzt?

Und was wird hier gemacht?


ldi temp, (1 << WGM10) | (1 << COM1A1) | (1 << COM1B1)
out TCCR1A, temp
ldi temp, (1 << CS11)
out TCCR1B, temp

A.Hoffmann
15.10.2007, 16:50
Guten Tag.

Das zurücksetzten der Register an dieser Stelle ist nicht unbedingt notwendig. Wenn diese Register aber auf NULL gesetzt sind, bleiben die Motoren immer stehen. Egal ob die Motorbrücken in den Leerlauf oder den Bremsmodus geschaltetet sind.
Und was wird hier gemacht ?
Der Timer 1 des Atmega8 unterstützt direkt die Puls Weiten Modulation. Damit werden dann die Motorbrücken angesteuert und die Motoren in ihrer Leistung reguliert.
Dafür muß er aber erst in den gewünschten Betiebsmodus geschaltet werden. Un genau das macht dieser Programmteil. In welchen Betriebsmodus der Timer geschaltet wird, steht über dem Programmteil. Die Register TCCR1A und TCCR1B können nicht über sbi Anweisungen angesprochen werden, sie liegen außerhalb des Adressbereichs der mit diesn Anweisungen erreicht werden kann. Deswegen weden sie über eine out Anweisung Adresiert.

MfG
A.Hoffmann

H3llGhost
15.10.2007, 20:24
Danke erstmal für die Erklärung ... ;)
Und was wird hiermit angesprochen:



(1 << WGM10) | (1 << COM1A1) | (1 << COM1B1)

damaltor
15.10.2007, 23:34
WGM10, COM1A1 und COM1B1 sind eigentlich zahlenwerte. diese sind schon vorher defineirt wurden (in einer der INCLUDE-dateien). dabei geht es um bestimmte bits, zB ist das bit WGM10 glaube ihc das bit 0, com1a1 das bit 6. man könnte also auch schreiben 1<<0 | 1<<6 usw.

diese namen sienen nur der übersichtlichkeit, so weiss man ohne nachzusehen WELCHE bits nun gesetzt wurden. ist ja auch einfach im sicherungskasten namen daneben zu shreiben als sich zu merken, dass sicherung nummer 23 für die steckdosen in der küche sind =)

das | (oder) dient der verknüpfung, es werden also alle 3 angesprochenen bits mit einem mal gesetzt.

H3llGhost
16.10.2007, 12:19
Also könnte ich auch folgendes dafür schreiben:



ldi temp, (1 << WGM10)
out TCCR1A, temp
ldi temp, (1 << COM1A1)
out TCCR1A, temp
ldi temp, (1 << COM1B1)
out TCCR1A, temp

A.Hoffmann
16.10.2007, 12:49
Hallo H3IIGhost
Lass es mich einmal so sagen, im Prinzip ja, aber am Ende deines Programms ist nur das Bit für COM1B1 gesetzt. Du überschreibst das Register TCCR1A immer wieder.
damaltor hat es richtig Beschrieben. WGM10 , COM1A1 und COM1B1 stehen für Bitpositionen. Sie sind in der Definitationsdatei m8def.inc zum ATmega8 beschrieben.
z.B
.equ WGM10 = 0
Der Ausdruck steht also für den Wert 0, unabhängig davon auf was er angewendet werden soll. Wenn der Assembler auf einen solchen Ausdruck trifft, durchsucht er die include dateien nach diesem Ausdruck. Und wenn er ihn findet, dann ersetzt er ihn durch den zugeordneten Wert. Du könntest auch WGM10 = 0 durch Otto10 = 0 ersetzen, das Ergebnis wäre das Gleiche. Genau so Verhält es sich auch mit COM1A1 = Bitposition 7 und COM1B1 = Bitposition 5. So ist also WGM10 ein synonym für 0. Der Ausdruck in dieser Zeile besagt also, setzte im Register temp
( synonym für r16 ) an der Bitposition 0 eine 1. Danch führe eine ODER Verknüpfung an den Bitpositionen 5 und 7 mit dem Register temp durch.
Diese Anweisung kann ersetzt werden durch
ldi temp, 0xA1
oder
ldi temp, 0b10100001
Das Ergebnis ist immer gleich. Die Bits 0 - 5 - 7 werden auf 1 gesetzt und die andern Bits bleiben auf 0.
Es ist nur nicht mehr so einfach zu Verstehen, was da gemacht wird.
Diese ODER Verknüpfung fehlt noch in deinem Programm.

MfG
A.Hoffmann