PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Assembler und Odometrie



H3llGhost
26.09.2007, 15:19
Hallo Leute,

ich wollte die Odometrie benutzen, zum Initialisieren benutze ich:



.include "m8def.inc"


SBI PORTD, PORTD7
SBI DDRD, DDD7

CBI PORTC, PORTC0
CBI PORTC, PORTC1
CBI DDRC, DDC0
CBI DDRC, DDC1


Ist das richtig?

Nun ist mein Problem wie aktiviere ich den Eingang ...
Normalerweise mit dem Befehl IN aber wie wende ich ihn dann an?

EDIT:

Habe nun folgendes geschrieben:



.include "m8def.inc"


SBI PORTD, PORTD7
SBI DDRD, DDD7
SBI DDRD, DDD6

CBI PORTC, PORTC0
CBI PORTC, PORTC1
CBI DDRC, DDC0
CBI DDRC, DDC1

main: sbi PORTD, PORTD6
sbic PORTC0, 1
cbi PORTD, PORTD6
RJMP main


Aber die Front-LED leuchtet durchgehend ...
Was habe ich falsch gemacht?
Bzw. falsch gedacht?

Rofo88
26.09.2007, 16:16
Nachdem Du deine LED ausgeschalten hast mit cbi PORTD, PORTD6 springst Du wieder zum Anfang der Schleife wo Du die LED sofort wieder einschaltest mit sbi PORTD, PORTD6. Wenn Du in nem Zimmer den Lichtschalter schnell ein- und ausschaltest wirds da auch nicht dunkel.
8-[

A.Hoffmann
26.09.2007, 16:24
Hallo zusammen.

Auserdem hat der PORTD6 da nicht zu suchen, denn er hat nichts
mit der Odometrie zu tun.
Sondern mit dem Linienverfolger.

MfG
A.Hoffmann

H3llGhost
26.09.2007, 16:52
Hallo ...

danke für eure Antworten ...
Ich habe folgendes vor:

Drehe ich an einem Rad soll vorne die Front-LED an bzw. ausgehen.
Fertig!

@Rofo88:
Wie würdest du denn das Programm schreiben auf Basis von meiner Version?

Rofo88
26.09.2007, 17:41
main: sbic PINC, 1
rjmp ein
cbi PORTD, 6
rjmp end
ein: sbi PORTD, 6
end: RJMP main

Wenn Du mit dem AVR Studio arbeitest versuchs mal mit dem Debugger.


MfG

A.Hoffmann
26.09.2007, 17:58
Hallo H3IIGhost.

Dazu mußt du die Radumdrehung erkennen.
Das was du bisher gemacht hast, ist nur die Vorbereitung für
die Odometrie Messung.
Du muß also noch den Analog - Digitalkonverter auswerten, um eine
Bewegung des Rades zu erkennen.
Schau dir doch mal die Beispielfunktion in der Orginal C - Lib an.
void OdometrieData(unsigned int *data)
Wenn du dir ein C - Projekt mit dieser Lib anlegst, kannst du dir auch
den Assembler -Code im Disassembler anschauen.
Ich würde dir auch empfehlen, diesen Code zu Benutzen.
Mit den normalen Assembler Anweisungen gibt es jede menge Probleme
mit dem ADC.

MfG
A.Hoffmann

A.Hoffmann
26.09.2007, 18:49
Hallo
Versuche es einmal damit.
Wenn du an dem rechten Rad drehst, müsste sich der gewünschte Efekt
einstellen.



.include "m8def.inc"

.def rBin1H = r0
.def rBin1L = r1
.def temp = r16 ; Arbeitsregister
.def temp2 = r17 ; Arbeitsregister
.def schwarzL = r18 ; Schwellwert für schwarz
.def schwarzH = r19
.def weisL = r20 ; Schwellwert für weiß
.def weisH = r21




.equ CLOCK = 8000000


.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 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


sei ; Interrupts erlauben



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

Prog_Run:
rcall odometrie_led_on
rcall odo_ticks_rechts
rjmp Prog_Run






;************************************************* *****************************
; Odometrie Sensor Ticks Rechts *
;************************************************* *****************************

odo_ticks_rechts:



ldi schwarzL, 0x8A
ldi schwarzH, 0x02
ldi weisL, 0xC2
ldi weisH, 0x01



weis: ; schwarz -> weiß übergang
rcall odometrie_r
cp rBin1L, weisL ; compare aktuellen Wert
cpc rBin1H, weisH ; mit weiß
brlo wtiksplus3 ; branch wenn < schwellwert weiß
rjmp weis ; nein weiter warten

wtiksplus3:
rcall front_led_on
schwarz: ; weiß -> schwarz Übergang
rcall odometrie_r
cp rBin1L, schwarzL ; compare aktuellen Wert
cpc rBin1H, schwarzH ; mit schwarz
brsh wtiksplus4 ; branch wenn => schwellwert schwarz
rjmp schwarz ; nein weiter warten
wtiksplus4:
rcall front_led_off
rjmp weis



;************************************************* *****************************
; Odometrie LED On *
;************************************************* *****************************

odometrie_led_on:


cbi DDRC, DDC0 ; Richtungs Steuerung
cbi DDRC, DDC1 ; C= + C1 = INPUT
sbi PORTD, PORTD7 ; Odometrie LED On
ret


;************************************************* *****************************
; Odometrie Sensor Rechts *
;************************************************* *****************************

odometrie_r:




;ADMUX = (1 << REFS0) | WHEEL_RIGHT AVCC reference with external capacitor
LDI R30,0x27 ;Load immediate
LDI R31,0x00 ;Load immediate
LDI R24,0x40 ;Load immediate
STD Z+0,R24 ;Store indirect with displacement

;ADCSRA |= (1 << ADSC); // Start conversion
LDI R26,0x26 ;Load immediate
LDI R27,0x00 ;Load immediate
LDI R30,0x26 ;Load immediate
LDI R31,0x00 ;Load immediate
LDD R24,Z+0 ;Load indirect with displacement
ORI R24,0x40 ;Logical OR with immediate
ST X,R24 ;Store indirect


;while (!(ADCSRA & (1 << ADIF))) wait for conversion complete
lab2:
LDI R30,0x26 ;Load immediate
LDI R31,0x00 ;Load immediate
LDD R24,Z+0 ;Load indirect with displacement
CLR R25 ;Clear Register
ANDI R24,0x10 ;Logical AND with immediate
ANDI R25,0x00 ;Logical AND with immediate
SBIW R24,0x00 ;Subtract immediate from word
BREQ lab2 ;Branch if equal

;ADCSRA |= (1 << ADIF) clear ADCIF
LDI R26,0x26 ;Load immediate
LDI R27,0x00 ;Load immediate
LDI R30,0x26 ;Load immediate
LDI R31,0x00 ;Load immediate
LDD R24,Z+0 ;Load indirect with displacement
ORI R24,0x10 ;Logical OR with immediate
ST X,R24 ;Store indirect

;**************** Daten sichern und weiter Verarbeiten *********************

;data[1] = ADCL + (ADCH << 8);

in rBin1L, ADCL ; Ergebnis
in rBin1H, ADCH ; sichern
ret ;Subroutine return

;************************************************* *****************************
;* Front LED Ein *
;************************************************* *****************************
front_led_on:
sbi PORTD, PORTD6
ret

;************************************************* *****************************
;* Front LED Aus *
;************************************************* *****************************
front_led_off:
cbi PORTD, PORTD6
ret





MfG
A.Hoffmann

H3llGhost
26.09.2007, 19:11
Äh ...
danke danke, A.Hoffmann, mein Freund ... ;) ...
Aber da weiß mein Lehrer doch sofort, dass ich das nicht gemacht habe ... :D

Was machen eigentlich folgende Befehle:
reti, .equ, .cseg, .org, etc.

Was ist der Stack Pointer?
Und ich steige im Moment nicht wirklich durch das Programm durch ... :D

Gibt es das vielleicht auch als Version, wie ich die habe?!
So in die Richtung?

EDIT:

Habe nicht das Programm von Roffo88 gesehen ...

@Roffo88: Danke! Sowas Einfaches habe ich mir erstmal vorgestellt ... ;)

@A.Hoffmann: Nochmals danke für deine Mühe, werde nur mir deinen Code anschauen ... und selber versuchen das auf das zweite Rad zu übertragen ...

EDIT2:

Danke Roffo88 habe ich nun eine erweiterte Version geschrieben.
Die steuert die Status-LED an:



.include "m8def.inc"

SBI PORTD, PORTD7
SBI DDRD, DDD7
SBI DDRD, DDD2
SBI DDRB, DDB0

CBI PORTC, PORTC0
CBI PORTC, PORTC1
CBI DDRC, DDC0
CBI DDRC, DDC1

main: sbic PINC, 1
rcall ein1
cbi PORTD, 2

sbic PINC, 0
rcall ein2
cbi PORTB, 0

rjmp main

ein1: sbi PORTD, 2
ret

ein2: sbi PORTB, 0
ret

A.Hoffmann
26.09.2007, 20:02
Guten Abend zusammen.

Eine Beschreibung der Assembler Anweisungen und dirktiven, findest
du auf www.atmel.com. Gib dort in das Suchfenster doc1022 ein.
Ansonsten soll dir das Programm nur als Beispiel dienen.
Es gibt bstimmt bessere Lösungen, aber um eins wirst du nicht herumkommen du mußt mit dem Analog - Digtalwandler arbeiten.
Sonst kannst du keine Radbewegung erkennen.

MfG
A.Hoffmann

H3llGhost
26.09.2007, 20:12
Hallo,

leider ist ja die Anleitung auf Englisch und die Beispiele sind dürftig!
Danke nochmals für das Programm.
Ich wollte ja noch keine Bewegung selber messen, sondern einfach nur überprüfen, ob schwarz oder weiß unter dem Sensor ist und das halt dann ausgeben.
Oder weiß jemand wo man eine deutsche Beschreibung der Befehle bekommt?

Rofo88
26.09.2007, 20:19
Schaue mal hier nach

http://www.avr-asm-tutorial.net/avr_de/beginner/index.html

H3llGhost
26.09.2007, 20:33
Danke sowas habe ich gesucht ...
Nun wäre noch eine pdf-Version davon schön ... :-P

A.Hoffmann
26.09.2007, 20:43
Hallo
Das Programm macht genau das, es schaut nach, ob sich sich ein
weißes oder ein schwarzes Feld der Segmentscheibe vor dem Sensor
befindet. Da der Sensor aus einer IR - Led und einem Phototransistor
besteht, kannst du ihn nur mit dem ADC auswerten. Er gibt kein Digitales Signal ab, das man mittels eines Eingabeports einlesen kann.

MfG
A.Hoffmann

damaltor
26.09.2007, 20:50
Was machen eigentlich folgende Befehle:
reti, .equ, .cseg, .org, etc.

reti: beendet eine interruptroutine und aktiviert die interrupts weider. die interrupts sind grundsätzlich die ersten paar befehle im flash speicher, tritt ein reset auf springt der prozessor an die entsprechende stelle und führt den dort stehenden code aus. damit also bei den interrupts nichts groß passiert, werden diese sofort beim ausführen mit reti beendet.

.equ ist kein assembler befehl, sondern meldet dem compiler, dass das wort was danach steht, die zahl bedeutet. .EQU ZEHN 10 heisst als dass überall wo ZEHN steht mit 10 gerechnet wird.

.cseg ist ebenfalls kein assemblerbefehl, sondern sagt dem compiler dass hier das code-segment beginnt (im unterschied zum datensegment)

.org st auch kein asm-befehl. mit diesem befehl wird beschrieben, welche flash-adresse hier ist. also beginnt das programm beim anfang des flash-bereichs - an der adresse 0x00.

merke: alle befehle die mit einem punkt beginnen, werden nicht compiliert, und sind keine asm-befehle, sondern dienen der steuerung des compilers (bzw sagt man auf dieser ebene nicht compiler, sondern "Der Assembler" und nicht compilieren, sondern "assemblieren".)



Was ist der Stack Pointer?


dazu zuerst: der stack ("haufen, stapel") ist ein stapel, auf den variablen abgelegt werden können. diese variablen können dann in der umgekehrten reihenfolge wieder abgerufen werden - also wie wenn man zeitungen auf einen haufen legt, kann man nur von oben wieder runternehmen.das prinzip nennt sich "LAST IN FIRST OUT" oder LIFO (im gegensatz zu einer art warteschlange, FIRST IN FIRST OUT oder FIFO).

der stack wird benutzt, um z.B. bei verwendung von unterfunktionen oder interrupts den aktuellen systemzustand oder wichtige variablen, welche nicht verändert werden dürfen, zu "retten". dazu werdeen diese auf den stack geschoben (mit der assembler anweisung PUSH) und nach beendigung der interruptroutine wiederhergestellt (mit dem befehl POP).
technisch gesehen stapelt der prozessor rückwärts, das unterste element des stapels liegt am letzten bytes des RAM speichers, und jedes neue element wird quasi davorgelegt.
damit der prozessor weiss, an welcher stelle er nun gerade ist, welche stelle nun gerade gelesen oder geschrieben werden darf, gibt es den stack pointer - ein zeiger (pointer) der auf das oberste stack element zeigt. da mann diesen nicht zwingenderweise am ende des rams beginnen lassen muss, muss man ihn initialisieren - dabei wird der low-wert der letzten speicheradresse (also die hinteren 8 bit), welche den namen RAMEND trägt, in den zeiger SPL (stack pointer low) und der high teil (also die vorderen 8 bit) in den zeiger SPH (stack pointer high).

damit ist dann festgelegt, welche stelle im ram das unterste element des stacks aufnimmt, das nächste element ist dann an der stelle davor usw.

um die werte weider zu lesen, muss dann der stack abgebaut werden, also alle werte bis zu dem gewünschten wert werden heruntergePOPt.