Forum: Mikrocontroller und Digitale Elektronik Fehler Sprungtabelle


von Björn (Gast)


Lesenswert?

Hallo Leute,

ich bin neu in der µC Programmierung und ich arbeite mich rein. Ich habe 
das Kapitel "Sprungtabelle" gelesen und denke, auch verstanden...

Ich möchte mit meinem Programm eine 7-Segment-Anzeige ansteuern, klappt 
nicht so wie ich will ;)

Beim Reset soll ein 'n' angezeigt werden, bei mir ist es aber eine 9, 
welche ich gar nicht im Quelltext so stehen habe, da ich nur von 'r' bis 
'7' gehe.
Die Ausgabe ist normalerweise i.O., habe alle Zeichen separat getestet.

Ich nutze einen ATmega8 (myAVR USB MK2) und myAVR Workpad.
Zudem habe ich alles Störende auskommentiert, sodass der µC eigentlich 
gleich in den zweiten Eintrag springen sollte. Ist eigentlich ein 
einfaches Programm, ist schon enttäuschend, das selbst das nicht klappt. 
Hier der Quelltext(ab 'main', Ausgabe aufs Wesentliche gekürzt):

;Start, Power ON, Reset
main:  ldi  r16,lo8(RAMEND)
  out  SPL,r16
  ldi  r16,hi8(RAMEND)
  out  SPH,r16
  sbi  DDRB,5  ;Port B.5 für 'a'
  sbi  DDRC,0  ;Port C.0 für 'b'
  sbi  DDRC,1  ;Port C.0 für 'c'
  sbi  DDRC,2  ;Port C.0 für 'd'
  sbi  DDRC,3  ;Port C.0 für 'e'
  sbi  DDRC,4  ;Port C.0 für 'f'
  sbi  DDRC,5  ;Port C.0 für 'g'
  cbi  DDRD,2  ;Port D.2 Eingang Taster1
  sbi  PORTC,2 ;Port D.2 Pull-Up
  cbi  DDRD,3  ;Port D.3 Eingang Taster2
  sbi  PORTC,3 ;Port D.3 Pull-Up
  ldi  r17,1   ;Neutral als Voreinstellung
;----------------------------------------------------------------------- 
-
mainloop:  wdr
          ;sbis  DDRD,2  ;Taster1 gedrückt
          ;rcall  RUNTER
          ;sbis  DDRD,3  ;Taster2 gedrückt
          ;rcall  HOCH
          ;'switch'-Anweisung ----------------------------
          ;cpi  r17,9
          ;brsh  mainloop
          ldi  r30,Tabelle
          ldi  r31,Tabelle
          add  r30,r17
          ldi  r16,0
          adc  r31,r16
          ijmp
Tabelle:  rjmp  R_GANG
          rjmp  NEUTRAL
          rjmp  EINS
          rjmp  ZWEI
          rjmp  DREI
          rjmp  VIER
          rjmp  FUENF
          rjmp  SECHS
          rjmp  SIEBEN
; Anzeige runterschalten------------------------------------------------
RUNTER:  cpse  r17,0  ;R-Gang ist schon eingelegt
  dec  r17
  ret
; Anzeige hochschalten--------------------------------------------------
HOCH:  cpse  r17,8  ;7. Gang ist schon eingelegt
  inc  r17
  ret
; Ausgabe aktueller Gang (lange Version)--------------------------------
R_GANG:  sbi  PORTB,5  ;'a'
         sbi  PORTC,0  ;'b'
         sbi  PORTC,1  ;'c'
         sbi  PORTC,2  ;'d'
         cbi  PORTC,3  ;'e'
         sbi  PORTC,4  ;'f'
         cbi  PORTC,5  ;'g'
         rjmp  ENDE
NEUTRAL: sbi  PORTB,5  ;'a'
         sbi  PORTC,0  ;'b'
         cbi  PORTC,1  ;'c'
         sbi  PORTC,2  ;'d'
         cbi  PORTC,3  ;'e'
         sbi  PORTC,4  ;'f'
         cbi  PORTC,5  ;'g'
         rjmp  ENDE
EINS:    sbi  PORTB,5  ;'a'
         cbi  PORTC,0  ;'b'
         cbi  PORTC,1  ;'c'
         sbi  PORTC,2  ;'d'
         sbi  PORTC,3  ;'e'
         sbi  PORTC,4  ;'f'
         sbi  PORTC,5  ;'g'
         rjmp  ENDE
ZWEI:    cbi  PORTB,5  ;'a'
        .
        .
         cbi  PORTC,4  ;'f'
         cbi  PORTC,5  ;'g'
         rjmp  ENDE
SIEBEN:  cbi  PORTB,5  ;'a'
         cbi  PORTC,0  ;'b'
         cbi  PORTC,1  ;'c'
         sbi  PORTC,2  ;'d'
         sbi  PORTC,3  ;'e'
         sbi  PORTC,4  ;'f'
         sbi  PORTC,5  ;'g'
ENDE:    ldi  r30,mainloop
         ldi  r31,mainloop
         ijmp


Wo liegt mein Fehler?
Für Eure hilfe bin ich im voraus dankbar.

MfG
Björn

von Coder (Gast)


Lesenswert?

Der Hauptfehler dürfte sein das du es in ASM versuchst, C wäre viel 
einfacher, übersichtlicher und schneller zu coden.

von Uwe (Gast)


Lesenswert?

Hi!
>         ldi  r30,Tabelle
>         ldi  r31,Tabelle
ändern in:
         ldi  r30,low(Tabelle)
         ldi  r31,high(Tabelle)
dann sollte es eigentlich passen.

>    ldi  r30,mainloop
>    ldi  r31,mainloop
da natürlich auch.

Viel Erfolg, Uwe

von Björn (Gast)


Lesenswert?

Danke für die schnelle Antwort. Ich habe es geändert, aber das Problem 
ist immer noch gleich, obwohl diesmal ein anderes (wildes) Zeichen 
dargestellt wird. Ich habe so meine Entwicklungsumgebung in Verdacht.
1 zu 1 konnte ich es nicht angeben, konnte es aber als
1
    
2
ldi  r30,lo8(Tabelle)
3
ldi  r31,hi8(Tabelle)
eingeben. Half, wie schon gesagt, nicht.

Zumindest lese ich aus der Antwort von Uwe, dass es im Prinzip richtig 
ist.
Melde mich, wenn ich es gelöst bekommen habe.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Björn schrieb:
> dargestellt wird. Ich habe so meine Entwicklungsumgebung in Verdacht.
1
ldi  r30,lo8(2*Tabelle)
2
ldi  r31,hi8(2*Tabelle)
Der Flash wird Wordweise addressiert...

von Uwe (Gast)


Lesenswert?

Hi!
habe jetzt kein Datenblatt da, aber:
> cpse  r17,0
geht das nicht blos mit Registern?
also cpse r17,r16 (r16 hat ja 0)
oder eben
RUNTER:  cpi  r17,0  ;R-Gang ist schon eingelegt
         brne EndeR
         dec  r17
EndeR:   ret

Viel Erfolg, Uwe

von Karl H. (kbuchegg)


Lesenswert?

Sieh dir hier

  cbi  DDRD,2  ;Port D.2 Eingang Taster1
  sbi  PORTC,2 ;Port D.2 Pull-Up
  cbi  DDRD,3  ;Port D.3 Eingang Taster2
  sbi  PORTC,3 ;Port D.3 Pull-Up

mal an, welche PORT Pins du auf 1 schaltest :-)


Sag mal sind dir die sbi und cbi nicht auf den Wecker gegangen? Für 
sowas macht man doch keine Sprungtabelle sondern eine Datentabelle (ok, 
bei dir 2 Tabellen, weil du die LED auf 2 Ports verstreut hast)!

http://www.mikrocontroller.net/articles/AVR-Tutorial:_7-Segment-Anzeige


(und benutze das AVR-Studio. Das hat einen schönen Debugger, mit dem du 
dein Programm in Einzelschritten durchgehen kannst und nachsehen kannst 
was passiert, welche Register wie verändert werden, welche Portpins 
welchen Zustand haben. Damit hört dann das Stochern im Nebel auf, warum 
ein Programm nicht das tut, was du dir vorstellst)

von Michael B. (mb_)


Lesenswert?

Zu den ganzen bereits beschriebenen Fehlern, wuerde ich sagen ist deine 
Sprungtabellenaddition auch noch Fehlerhaft. rjmp ist 2 byte breit, also 
wuerde ich sagen muss man offset*2 addieren. Das heisst folgenden code:

          add  r30,r17
          ldi  r16,0
          adc  r31,r16

aendern in:
          mov  r16,r17
          lsl  r16
          add  r30,r16
          ldi  r16,0
          adc  r31,r16

von Ben (Gast)


Lesenswert?

> Der Hauptfehler dürfte sein das du es in ASM versuchst,
> C wäre viel einfacher, übersichtlicher und schneller zu coden.

wenn man sich schon coder nennt sollte man die vorteile von assembler 
gerade bei µCs zu schätzen wissen. nichts gegen C, aber ich würd das 
auch in assembler schreiben.

mal eine frage an den threadstarter:
kannst du deine schaltung noch ändern? wenn du alle 7 segmente deiner 
anzeige auf einen einzelnen port legst kannst du alle mit zwei befehlen 
bedienen. brauchst dann nur das entsprechene byte als ganzes auf den 
port zu schreiben, alle bits auf einmal. kannst dafür auch die binäre 
schreibweise verwenden, dann ist das für dich besser zu verstehen.

also z.b.
LDI R16, 0b01010101
OUT PORTn, R16

0b01010101 ist das gleiche wie 0x55 oder dezimal 85.

von Karl H. (kbuchegg)


Lesenswert?

Ben schrieb:
>> Der Hauptfehler dürfte sein das du es in ASM versuchst,
>> C wäre viel einfacher, übersichtlicher und schneller zu coden.
>
> wenn man sich schon coder nennt sollte man die vorteile von assembler
> gerade bei µCs zu schätzen wissen. nichts gegen C, aber ich würd das
> auch in assembler schreiben.

Nichts gegen Assembler, aber dazu ist mir die Anwendung nicht 
zeitkritisch genug :-)
Warten wir ab, bis er zu dem Punkt kommt an dem er realisiert, dass die 
Taster entprellt werden müssen :-)

von Stephan H. (stephan-)


Lesenswert?

Karl Heinz,

wo ist der Unterschied ?? Taster müssen entprellt werden.
Dazu muß man doch nur wissen WIE es geht. Die Sprache ist dabei völlig 
wurscht.
Aber wie Ben schon sagte, man sollte Hardwarenah arbeiten.
zB. Die Anzeige auf einen Port um dann mit 1 oder 2 Befehlen fertig zu 
sein.
Das ist ja bei den Tastern nicht anders. Dann isses in ASM und in C nur 
halb so schwer.

von Ben (Gast)


Lesenswert?

> Warten wir ab, bis er zu dem Punkt kommt an dem er realisiert,
> dass die Taster entprellt werden müssen :-)
das kann er ja in hardware machen - dafür wäre selbst C nicht langsam 
genug ;)

ein kleiner kondi über den tastern reicht ja dank der internen pullups 
meistens schon. einfacher zu lösen ists aber wenn er nach einer 
veränderung einfach n takte wartet bis der nächste tastendruck 
angenommen wird.

von Björn (Gast)


Lesenswert?

Vielen Dank für die vielen Antworten, echt ein super Forum!

Nun funktioniert es, habe es wie folgt geändert:
Zuerst habe ich 'AVR Studio' installiert und 'myAVR ProgTool' zum 
Brennen, da ich ein Entwicklungsboard von myAVR verwende.
Daher kann ich z.Z. nicht alle PINs des jeweiligen Ports im vollen 
Umfang nutzen, da immer nur sechs Pins raus geführt sind, finde ich z.Z. 
gar nicht so schlimm :) (@Ben, @Karl heinz Buchegger)

@Karl heinz Buchegger: Oh wie peinlich. Da fällt mir das Sprichwort ein: 
Manchmal sieht man den Wald vor lauter Bäumen nicht. Habe ich gleich in
1
cbi  DDRD,2   ;Port D.2 Eingang Taster1
2
sbi  PORTD,2  ;Port D.2 Pull-Up
3
cbi  DDRD,3   ;Port D.3 Eingang Taster2
4
sbi  PORTD,3  ;Port D.3 Pull-Up
geändert. Vielen Dank für den Hinweis :)

@Uwe
> cpse  r17,0
Ja, das geht so nicht, werde ich ändern, hatte AVR Studio schon 
angemahnt :)

Hier ist nochmal die funktionierende Sprungtabelle, habe es auch mit 
verschiedenen Voreinstellungen getestet:
1
main:      ldi  r16,low(RAMEND)
2
           .
3
           .
4
           ldi  r17,2  ;Zweiter Gang als Voreinstellung
5
;------------------------------------------------------------------------
6
mainloop:  wdr
7
           ; sbis   DDRD,2  ;Taster1 gedrückt
8
           ; rcall  RUNTER
9
           ; sbis   DDRD,3  ;Taster2 gedrückt
10
           ; rcall  HOCH
11
           ; 'switch'-Anweisung ----------------------------
12
           ; cpi    r17,(9)
13
           ; brsh   mainloop
14
           ldi  r30,low(Tabelle)  ;AVR Studio konform
15
           ldi  r31,high(Tabelle)
16
           add  r30,r17
17
           ldi  r16,0
18
           adc  r31,r16
19
           ijmp  
20
Tabelle:   rjmp  R_GANG
21
           rjmp  NEUTRAL
22
           rjmp  EINS
23
           rjmp  ZWEI
24
           rjmp  DREI
25
           rjmp  VIER
26
           rjmp  FUENF
27
           rjmp  SECHS
28
           rjmp  SIEBEN
29
           .
30
           .
31
; Ausgabe aktueller Gang (lange Version) -----------------------------
32
           .
33
           .
34
ZWEI:      cbi  PORTB,5  ;'a'
35
           cbi  PORTC,0  ;'b'
36
           sbi  PORTC,1  ;'c'
37
           cbi  PORTC,2  ;'d'
38
           cbi  PORTC,3  ;'e'
39
           sbi  PORTC,4  ;'f'
40
           cbi  PORTC,5  ;'g'
41
           rjmp  ENDE
42
           .
43
           .
44
ENDE:      ldi  r30,low(mainloop)
45
           ldi  r31,high(mainloop)
46
           ijmp

@Ben: Das mit den n-Takten oder eine ähnliche Lösung hatte ich auch 
schon im Hinterkopf. Bei der Taktfrequenz des ATmega8 und einem 
Tastendruck habe ich praktisch nur zwei Gänge: 'r' oder '7', je nachdem 
welchen Taster ich drücke :)

Nochmals vielen Dank für die vielen Tipps.
Björn

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.