Forum: Mikrocontroller und Digitale Elektronik Register miteinander vergleichen - Assambler - my avr


von Anfänger09 (Gast)


Lesenswert?

Hallo,
habe hier ein Atmel ATmega8 auf dem AVR Board.

Programmie mit my AVRWorkpad.

Zu meinem problemchen.

Lese den Poti ein  und wandle ihn digital um lege dies auf r16.
dann schieb ich mir (rol) r 16, das mir nur noch 2 bits bleiben (0+1)
D.h. theoretisch 2 ausgänge mit 4 zuständen!

Dies funktioniert auch alles ohne probleme.

Nun möchte ich bei keinem ausgang ein unterprogramm ansteuern...
bei Ausgang 1 ein unterprogramm und bei Ausgang 2 ein unterprogramm 
ansteuern.

Dazu wollte ich einfach 2 register verlgleichen


ldi r20,0b00000000 ; Wert zum vergleichen bei keinem ausgang
cp r16,20
brlt TEST
TEST: sbi PORTD,0

ldi r20,0b00000001 ; Wert zum vergleichen bei keinem ausgang
cp r16,20
brlt TEST1
TEST1: sbi PORTD,1

ldi r20,0b00000011 ; Wert zum vergleichen bei keinem ausgang
cp r16,20
brlt TEST2
TEST2: sbi PORTD,2

aber irgendwie funktioniert das ganze so nicht ...
wo ist mein fehler ???

vielen dank

von Karl H. (kbuchegg)


Lesenswert?

brlt   ist der falsche Branch

Ich hab zwar das was du machen willst, wahrscheinlich nicht richtig 
verstanden (auch deswegen, weil 'Ausgang' ein anderwertig mit Bedeutung 
beladener Begriff ist), aber ich denke du willst eigentlich auf 
Gleichheit testen: breq. Oder auf Ungleichheit: brne

  ldi  r20,0b00000000 ; Wert zum vergleichen bei keinem ausgang
  cp   r16,r20
  breq Kein_Ausgang


Noch ein Hinweis: Ein Branch wird genommen, wenn eine Bedingung erfüllt 
ist. breq macht also einen Sprung, wenn das (in deinem Fall) 
vorhergehende Vergleichsergebnis 'gleich' lautet.

Völlig sinnlos ist aber das hier:
1
       ldi r20,0b00000000 ; Wert zum vergleichen bei keinem ausgang
2
       cp r16,20
3
       brlt TEST
4
5
TEST:  sbi PORTD,0
6
7
       ldi r20,0b00000001 ; Wert zum vergleichen bei keinem ausgang
8
       cp r16,20
9
       brlt TEST1
10
11
TEST1: sbi PORTD,1

Gehs von oben durch: Wenn lt, wird nach TEST gesprungen. Aber was 
passiert, wenn brlt nicht springt? Genau. Es geht ebenfalls bei TEST 
weiter. Quintessenz: Egal wie der Test ausgeht, es geht immer bei TEST 
weiter.

(Und tu dir selbst einen Gefallen, und rücke die Anweisungen ein. Dann 
sieht man näcmlich viel besser wo Labels, also potentielle Sprungziele, 
sind. Und wenn du auf eine Sequenz...
1
         ....
2
         brXX  Label
3
Label:   ....

... stößt, dann ist irgendwas faul, weil der branch (oder auch ein rjmp) 
sinnlos ist und sich nichts verändern würde, wenn man ihn einfach 
rausnimmt
)

von Uhu U. (uhu)


Lesenswert?

Wie wärs denn mit

   cp   r16,r20

statt

   cp   r16,20

?

von Anfänger09 (Gast)


Lesenswert?

So dann versuche ich das Ganze nocheinmal zu erklären.
ich habe einen Poti.
mit diesem möchte ich einen motordrezhal steuern.

Dies soll aber nur stufig geschehen (3 Stufen + Aus).

Der Motor braucht ein pulsierendes signal zum drehen (schrittmotor)

leider bekomme ich nicht hin die zu realisieren? wo liegt mein fehler ?

Hier mein bisheriges programm:


VIELEN DANK FÜR JEGLICHE HILFE:

;----------------------------------------------------------------------- 
-
;Reset and Interrupt vector             ;VNr.  Beschreibung
  rjmp  main  ;1     POWER ON RESET
  reti    ;2     Int0-Interrupt
  reti    ;3     Int1-Interrupt
  reti    ;4     TC2 Compare Match
  reti    ;5     TC2 Overflow
  reti    ;6     TC1 Capture
  reti    ;7     TC1 Compare Match A
  reti    ;8     TC1 Compare Match B
  reti    ;9     TC1 Overflow
  reti    ;10    TC0 Overflow
  reti    ;11    SPI, STC Serial Transfer Complete
  reti    ;12    UART Rx Complete
  reti    ;13    UART Data Register Empty
  reti    ;14    UART Tx Complete
  rjmp  onADC  ;15    ADC Conversion Complete
  reti    ;16    EEPROM Ready
  reti    ;17    Analog Comparator
  reti    ;18    TWI (I²C) Serial Interface
  reti    ;19    Store Program Memory Ready
;----------------------------------------------------------------------- 
-
;Start, Power ON, Reset
main:
  ldi  r16,lo8(RAMEND)
  out  SPL,r16
  ldi  r16,hi8(RAMEND)
  out  SPH,r16
  ldi  r16,0b11111111  ;Festlegung als Ausgang von PORTB
  out  DDRB,r16
  sei
  sbi  DDRD,2
  sbi  DDRD,3
  sbi  DDRD,4
  sbi  DDRD,5
;----------------------------------------------------------------------- 
-
;AD Wandlereinstellungen aktivierung

  ldi  r16,0b00100000
  out  ADMUX,r16
  ldi  r25,0b11011101
  out  ADCSRA,r25
;----------------------------------------------------------------------- 
-
;Analogwert auswerten

  in  r17,ADCL  ; Analogwert wird abgelegt
  in  r16,ADCH  ; Analogwert wird abgelegt
  lsr  r16  ; schieben um 1 nach rechts ( geteilt durch 2)
  lsr  r16
  lsr  r16
  lsr  r16
  lsr  r16
  lsr  r16
  out  PORTB,r16  ; Register 16 wird auf port B ausgegebn

  ldi  r20,0b00000000  ; Auswertung für Tempo1
  cp  r16,r20
  breq  TEMPO1

  ldi  r20,0b00000001  ; Auswertung für Tempo2
  cp  r16,r20
  breq  TEMPO2

  ldi  r20,0b00000010  ; Auswertung für Tempo3
  cp  r16,r20
  breq  TEMPO3

  ldi  r20,0b00000011  ; Auswertung für AUS
  cp  r16,r20
  breq

;-----------------------------------------------------------------------
TEMPO1:  ;Unterprogramm  "Drehzahl1"
  ;sbi   PORTD,4  ;Motor an
  push  r24  ;Inhalt von Register r24 kellern
  push  r25  ;Inhalt von Register r25 kellern
  push  r26  ;Inhalt von Register r246 kellern
  ldi  r26,0x01  ;0x10 ins Arbeitregister r26 laden
loop1:  ldi  r25,0x06  ;0xFF ins Arbeitregister r25 laden
loop2:  ldi  r24,0xFF  ;0xFF ins Arbeitregister r24 laden
loop3:  subi  r24,0x06  ;Registerinhalt in r24 um 1 vermindern
  brcc  loop3  ;wiederhole solange bis Flag C in r24 =1
  subi  r25,0x01  ;Registerinhalt in r25 um 1 vermindern
  brcc  loop2  ;wiederhole solange bis Flag C in r25 =1
  subi  r26,0x01  ;Registerinhalt in r26 um 1 vermindern
  brcc  loop1  ;wiederhole solange bis Flag C in r26 =1
  pop  r26  ;Inhalt von Register r26 entkellern
  pop  r25  ;Inhalt von Register r25 entkellern
  pop  r24  ;Inhalt von Register r24 entkellern
  cbi  PORTD,4  ;Motor aus
  rjmp  main
;-----------------------------------------------------------------------
;Unterprogramm  "Drehzahl1"
TEMPO2:  sbi  PORTD,4  ;Motor an
  push  r24  ;Inhalt von Register r24 kellern
  push  r25  ;Inhalt von Register r25 kellern
  push  r26  ;Inhalt von Register r246 kellern
  ldi  r26,0x01  ;0x10 ins Arbeitregister r26 laden
loop21:  ldi  r25,0x06  ;0xFF ins Arbeitregister r25 laden
loop22:  ldi  r24,0xFF  ;0xFF ins Arbeitregister r24 laden
loop23:  subi  r24,0x10  ;Registerinhalt in r24 um 1 vermindern
  brcc  loop23  ;wiederhole solange bis Flag C in r24 =1
  subi  r25,0x01  ;Registerinhalt in r25 um 1 vermindern
  brcc  loop22  ;wiederhole solange bis Flag C in r25 =1
  subi  r26,0x01  ;Registerinhalt in r26 um 1 vermindern
  brcc  loop21  ;wiederhole solange bis Flag C in r26 =1
  pop  r26  ;Inhalt von Register r26 entkellern
  pop  r25  ;Inhalt von Register r25 entkellern
  pop  r24  ;Inhalt von Register r24 entkellern
  cbi   PORTD,4  ;Motor aus
  rjmp  main

;-----------------------------------------------------------------------
TEMPO3:  ;Unterprogramm  "Drehzahl1"
  sbi  PORTD,4  ;Motor an
  push  r24  ;Inhalt von Register r24 kellern
  push  r25  ;Inhalt von Register r25 kellern
  push  r26  ;Inhalt von Register r246 kellern
  ldi  r26,0x01  ;0x10 ins Arbeitregister r26 laden
loop31:  ldi  r25,0x06  ;0xFF ins Arbeitregister r25 laden
loop32:  ldi  r24,0xFF  ;0xFF ins Arbeitregister r24 laden
loop33:  subi  r24,0x16  ;Registerinhalt in r24 um 1 vermindern
  brcc  loop33  ;wiederhole solange bis Flag C in r24 =1
  subi  r25,0x01  ;Registerinhalt in r25 um 1 vermindern
  brcc  loop32  ;wiederhole solange bis Flag C in r25 =1
  subi  r26,0x01  ;Registerinhalt in r26 um 1 vermindern
  brcc  loop31  ;wiederhole solange bis Flag C in r26 =1
  pop  r26  ;Inhalt von Register r26 entkellern
  pop  r25  ;Inhalt von Register r25 entkellern
  pop  r24  ;Inhalt von Register r24 entkellern
  cbi  PORTD,4  ;Motor aus
  rjmp  main

;-----------------------------------------------------------------------

onADC:

  cli
  sbi  ADCSRA,6  ;Bit 6 startet Konvertierung beim drehen am Poti
  sei
  reti

von Otto (Gast)


Lesenswert?

Hänge Dein Programm bitte als .asm an.

Das lässt sich doch nicht ohne Fehler compilieren oder?

Ich sehe da mehrere Punkte, an denen das scheitert.

Otto

von spess53 (Gast)


Lesenswert?

Hi

Als erstes solltest du dir angewöhnen in den Kommentaren zu beschreiben 
warum du etwas machst. Einen push oder pop-Befehl zu kommentieren ist 
recht sinnfrei. Auch sollten die Kommentare den Befehlen entsprechen.
 Als Nächstes erleichtert eine Formatierung, wie sie Karl-Heinz 
vorgeschlagen hat, die Lesbarkeit ungemein.

 ldi  r20,0b00000000  ; Auswertung für Tempo1
  cp  r16,r20
lässt sich durch 'tst r16' ersetzen

  ldi  r20,0b00000001  ; Auswertung für Tempo2
  cp  r16,r20

lässt sich durch 'cpi r16,1' ersetzen

  subi  r26,0x01  ;Registerinhalt in r26 um 1 vermindern
  brcc  loop21  ;wiederhole solange bis Flag C in r26 =1

da benutzt man besser:
  dec r26
  brne loop21

Warum springst du mit 'rjmp  main' wieder an den Programmanfang mit der 
Initialisierung?

>;Analogwert auswerten

>  in  r17,ADCL  ; Analogwert wird abgelegt
>  in  r16,ADCH  ; Analogwert wird abgelegt

Woher weisst du, wann der ADC fertig ist?

ADEN ADSC ADFR ADIF ADIE
>  ldi  r25,0b11011101
>  out  ADCSRA,r25

Sollte besser mit Bitnamen erfolgen:

  ldi  r25,1<<ADN|...|1<<ADPS2|1<<ADPS0
  out  ADCSRA,r25



...................


MfG Spess

von Johannes M. (johnny-m)


Lesenswert?

cli und sei im Interrupt Handler sind Unsinn. Das macht die 
Controller-Hardware automatisch. Ansonsten solltest Du auch im 
Interrupt Handler die ADC-Datenregister auslesen! Dazu ist der Interrupt 
schließlich da. Und den ADC im Interrupt Handler von Hand starten ist 
auch überflüssig. Nimm den Free-Running-Mode, dann geht auch das 
automatisch.

Bevor ich es vergesse:
Empfehlenswerte Literatur:
AVR-Tutorial
Bitmanipulation
Formatierung im Forum

von spess53 (Gast)


Lesenswert?

Hi

>cli und sei im Interrupt Handler sind Unsinn. Das macht die

Da ist noch mehr Unsinn:

>  ldi  r16,0b00100000
>  out  ADMUX,r16

1. Damit (0b00XXXXXX) schaltest du die internen Referenzspannungen ab. 
Fall jetzt nichts an AREF hängt ist deine Referenzspannung 0V.

2. Mit 0bXX1XXXXXX stzt du ADLAR (Left Adjust). Damit befinden sich die 
höherwertigsten 8 Bit in ADCH. In der 'Auswertung' schiebst du ADCH 6x 
nach rechts um die obersten 2 Bits zu erhalten. Mit ADLAR=0 bräuchtest 
du lediglich ADCH auswerten.

MfG Spess

von Andrew Z. (anfaenger09)


Angehängte Dateien:

Lesenswert?

hab noch etwas weiter gemacht doch leider finde ich den fehler nicht

bekomme es hier leider nicht besser eingerückt:

wie geschrieben steuere über einen ausgang eine schrittmotorplatine an.
diese braucht ein pulsierendes signal, damit der motor sich dreht.

;+----------------------------------------------------------------------
.include  "AVR.H"
;----------------------------------------------------------------------- 
-
;Reset and Interrupt vector             ;VNr.  Beschreibung
  rjmp  main  ;1     POWER ON RESET
  reti    ;2     Int0-Interrupt
  reti    ;3     Int1-Interrupt
  reti    ;4     TC2 Compare Match
  reti    ;5     TC2 Overflow
  reti    ;6     TC1 Capture
  reti    ;7     TC1 Compare Match A
  reti    ;8     TC1 Compare Match B
  reti    ;9     TC1 Overflow
  reti    ;10    TC0 Overflow
  reti    ;11    SPI, STC Serial Transfer Complete
  reti    ;12    UART Rx Complete
  reti    ;13    UART Data Register Empty
  reti    ;14    UART Tx Complete
  rjmp  onADC  ;15    ADC Conversion Complete
  reti    ;16    EEPROM Ready
  reti    ;17    Analog Comparator
  reti    ;18    TWI (I²C) Serial Interface
  reti    ;19    Store Program Memory Ready
;----------------------------------------------------------------------- 
-
;Start, Power ON, Reset
main:
  ldi  r16,lo8(RAMEND)
  out  SPL,r16
  ldi  r16,hi8(RAMEND)
  out  SPH,r16

;Ausang festlegen
  sbi   DDRC,4  ;Ausgang für Motor- braucht pulsierendes signal

;AD Wandlereinstellungen aktivierung
  ldi  r18,0b00100000
  out  ADMUX,r18
  ldi  r19,0b11011101
  out  ADCSRA,r19

;Statusregister konfigurieren
  ldi  r20,0b11111111  ;Bit 7   Global Interrupt Enable
  out  SREG,r20  ;Bit 6   Bit Copy Storage
      ;Bit 5   Half Carry Flag
      ;Bit 4   Sign Bit
      ;Bit 3   Two’s Complement Overflow Flag
      ;Bit 2   Negative Flag
      ;Bit 1   Zero Flag
      ;Bit 0   Carry Flag
;----------------------------------------------------------------------- 
-
;Analogwert auswerten
;Hier soll der Analogwert voom Poti (Eingang C0) digitalisiert und 
minimiert werden
onADC:
  cli
  sbi  ADCSRA,6  ;Bit 6 startet Konvertierung beim drehen am Poti
  sei
  in  r21,ADCL  ; Analogwert wird abgelegt
  in  r22,ADCH  ; Analogwert wird abgelegt
  lsr  r22  ; schieben um 1 nach rechts ( geteilt durch 2)
  lsr  r22
  lsr  r22
  lsr  r22
  lsr  r22
  lsr  r22
  out   ADMUX,r18
  sbi  ADCSRA,6

;---------------------------
;Hier soll die Auswahl erfolgen, welche fest Drezahl ausgwählt wird.
;Hierzu soll das digitalisierte und minimierte Signal vom Poti (Eingang 
C0)
;mit festen Werten im r23 verglichen werden.

  ldi  r23,0b00000000  ; Auswertung für Tempo1
  cp  r22,r23
  breq  lapp1
  rjmp  TEMPO1
lapp1:
  ldi  r23,0b00000001  ; Auswertung für Tempo2
  cp  r22,r23
  breq  lapp2
  rjmp  TEMPO2

lapp2:
  ldi  r23,0b00000010  ; Auswertung für Tempo3
  cp  r22,r23
  breq  main
  rjmp  TEMPO3


;-----------------------------------------------------------------------
;Hier wird der Motor für einen Zeitraum X ein dann wieder ausgeschaltet
;Unterprogramm  "Drehzahl1"

TEMPO1:  sbi  PORTC,4  ;Motor an
  push  r24  ;Inhalt von Register r24 kellern
  push  r25  ;Inhalt von Register r25 kellern
  push  r26  ;Inhalt von Register r246 kellern
  ldi  r26,0x01  ;0x10 ins Arbeitregister r26 laden
loop1:  ldi  r25,0x05  ;0xFF ins Arbeitregister r25 laden
loop2:  ldi  r24,0xFF  ;0xFF ins Arbeitregister r24 laden
loop3:  subi  r24,0x06  ;Registerinhalt in r24 um 1 vermindern
  brcc  loop3  ;wiederhole solange bis Flag C in r24 =1
  subi  r25,0x01  ;Registerinhalt in r25 um 1 vermindern
  brcc  loop2  ;wiederhole solange bis Flag C in r25 =1
  subi  r26,0x01  ;Registerinhalt in r26 um 1 vermindern
  brcc  loop1  ;wiederhole solange bis Flag C in r26 =1
  pop  r26  ;Inhalt von Register r26 entkellern
  pop  r25  ;Inhalt von Register r25 entkellern
  pop  r24  ;Inhalt von Register r24 entkellern
  cbi  PORTC,4  ;Motor aus
  rjmp  main
;-----------------------------------------------------------------------
;Hier wird der Motor für einen Zeitraum X ein dann wieder ausgeschaltet
;Unterprogramm  "Drehzahl1"

TEMPO2:  sbi  PORTC,4  ;Motor an
  push  r24  ;Inhalt von Register r24 kellern
  push  r25  ;Inhalt von Register r25 kellern
  push  r26  ;Inhalt von Register r246 kellern
  ldi  r26,0x01  ;0x10 ins Arbeitregister r26 laden
loop21:  ldi  r25,0x15  ;0xFF ins Arbeitregister r25 laden
loop22:  ldi  r24,0xFF  ;0xFF ins Arbeitregister r24 laden
loop23:  subi  r24,0x10  ;Registerinhalt in r24 um 1 vermindern
  brcc  loop23  ;wiederhole solange bis Flag C in r24 =1
  subi  r25,0x01  ;Registerinhalt in r25 um 1 vermindern
  brcc  loop22  ;wiederhole solange bis Flag C in r25 =1
  subi  r26,0x01  ;Registerinhalt in r26 um 1 vermindern
  brcc  loop21  ;wiederhole solange bis Flag C in r26 =1
  pop  r26  ;Inhalt von Register r26 entkellern
  pop  r25  ;Inhalt von Register r25 entkellern
  pop  r24  ;Inhalt von Register r24 entkellern
  cbi  PORTC,4  ;Motor aus
  rjmp  main

;-----------------------------------------------------------------------
;Hier wird der Motor für einen Zeitraum X ein dann wieder ausgeschaltet
;Unterprogramm  "Drehzahl1"

TEMPO3:  sbi  PORTC,4  ;Motor an
  push  r24  ;Inhalt von Register r24 kellern
  push  r25  ;Inhalt von Register r25 kellern
  push  r26  ;Inhalt von Register r246 kellern
  ldi  r26,0x01  ;0x10 ins Arbeitregister r26 laden
loop31:  ldi  r25,0x50  ;0xFF ins Arbeitregister r25 laden
loop32:  ldi  r24,0xFF  ;0xFF ins Arbeitregister r24 laden
loop33:  subi  r24,0x16  ;Registerinhalt in r24 um 1 vermindern
  brcc  loop33  ;wiederhole solange bis Flag C in r24 =1
  subi  r25,0x01  ;Registerinhalt in r25 um 1 vermindern
  brcc  loop32  ;wiederhole solange bis Flag C in r25 =1
  subi  r26,0x01  ;Registerinhalt in r26 um 1 vermindern
  brcc  loop31  ;wiederhole solange bis Flag C in r26 =1
  pop  r26  ;Inhalt von Register r26 entkellern
  pop  r25  ;Inhalt von Register r25 entkellern
  pop  r24  ;Inhalt von Register r24 entkellern
  cbi  PORTC,4  ;Motor aus
  rjmp  main

;-----------------------------------------------------------------------

von spess53 (Gast)


Lesenswert?

Hi

>hab noch etwas weiter gemacht doch leider finde ich den fehler nicht

Wenn es nur 'den' Fehler gäbe. Aber, entschuldige bitte, dein 'Programm' 
strotzt vor Fehlern.

>;Statusregister konfigurieren
>  ldi  r20,0b11111111  ;Bit 7   Global Interrupt Enable
>  out  SREG,r20  ;Bit 6   Bit Copy Storage
>      ;Bit 5   Half Carry Flag.....

Wo hast du den den Unsinn her? Es gibt normalerweise keinen Grund SREG 
zu initialisieren oder zu manipulieren. Als Anfänger schon garnicht.

Du hast eine Interruptroutine 'OnADC' aber nirgen ein 'RETI', statt 
dessen springst du wieder nach 'main'. Stacküberlauf garantiert.

Dein 'Main' ist keine Schleife. Dein Programm läuft lustig von Main über 
OnADC und dem Rest hin und her.

..........

Versuch mal das 'Programm' in überschaubare Funktionen zu bringen, die 
du dann in Unterprogramme verpackst und bei Bedarf aufrufst.

MfG Spess

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.