Hallo zusammen, ich habe das Problem, das der Attiny26-16 den rcall Befehl nicht mag, er bleibt da immer hängen. Ich benutze AtmelStudio 6.0 und schreibe in asm. Das Programm läuft ohne Probleme auf dem ATtiny13-20 mit rcall. Wenn ich die Unterprogramme ins Hauptprogramm hole, läuft auch der ATtiny26. Die inc. Datei habe ich natürlich umgestellt. Programmieren läst sich der ATtiny 26 ohne probleme. Keine Fehlermeldung. Hoffe es kann mir bei diesem Problem jemand weiterhelfen. l.g. Achim
Achim schrieb: > Hoffe es kann mir bei diesem Problem jemand weiterhelfen. ohne Programm sicher nicht
Schon mal ins Datenblatt geschaut, ob der rcall im Mikrocode vorhanden ist?
Walter S. schrieb: > ohne Programm sicher nicht Doch, der Tiny13 initialisiert seinen Stackpointer per Hardware beim Reset, beim Tiny26 muss man den Stackpointer von Hand initialisieren. Achim schrieb: > Wenn ich > die Unterprogramme ins Hauptprogramm hole, läuft auch der ATtiny26. Eben, das deutet darauf hin, dass der Stackpointer nicht initialisiert ist... ...
Den Befehl gibt es, geht auch wenn ich ihn nur ein mal aufrufe, aber beim zweiten mal aus einem billigen Blikprogramm mit zwei LED bleib er stehen. .include "tn26def.inc" rjmp Anfang Anfang: ldi r16,0xff out ddra,r16 ldi r16,0x18 out ddrb,r16 Schleife: ldi r16,0x10 out portb,r16 ;Warte: ldi r17,255 Warte1: ldi r18,255 Warte2: dec r18 brne Warte2 dec r17 brne Warte1 ;ret ;Rücksprung ;rcall Warte ldi r16,0x0 out portb,r16 ;Pause: ldi r17,255 Pause1: ldi r18,255 Pause2: dec r18 brne Pause2 dec r17 brne Pause1 ;ret ;Rücksprung ;rcall Pause ldi r16,0x8 out portb,r16 ;Warte: ldi r17,255 Warte3: ldi r18,255 Warte4: dec r18 brne Warte4 dec r17 brne Warte3 ;ret ;Rücksprung ;rcall Warte ldi r16,0x0 out portb,r16 ;Pause: ldi r17,255 Pause3: ldi r18,255 Pause4: dec r18 brne Pause4 dec r17 brne Pause3 ;ret ;Rücksprung ;rcall Pause rjmp Schleife
Hi Hannes hatte Recht: >Eben, das deutet darauf hin, dass der Stackpointer nicht initialisiert >ist... MfG Spess
Achim schrieb: > Wie initaliesiert man einen Stckpionter? Man setzt SPL und ggf. SPH auf RAMEND. ...
Hi
>Wie initaliesiert man einen Stckpionter?
Für den ATTiny26:
ldi r16,Low(RAMEND)
out SPL,r16
MfG spess
Hallo Hannes, könnten Sie mir das bitte als asm vorschreiben, da ich nicht weiß, was SPL, SPH und Ramend ist. Ich übe erst seit zwei Wochen mit dem ATtiny13, doch da geht es super. Mir haben nur die ein und Ausgänge nicht gereicht. l.g. Achim
Danke Spess53, werde ich mal so probieren. Das ganze soll mal eine Schrittmotorsteuerung werden, wenns fertig ist. Mit 3 ATtiny13 geht es schon. l.g. Achim
Achim schrieb: > könnten Sie mir das bitte als asm vorschreiben, Hat Spess bereits gemacht. > da ich nicht weiß, was SPL, SPH und Ramend ist. Dann könnte man diese Begriffe als Suchbegriffe im Datenblatt-PDF benutzen. ...
Werde es auf jeden fall nachlesen, will ja wissen was die Befehle machen. Ich danke euch beiden für eure Hilfe. PS: Bin Modellbauer, Eisenbahn, Spur Z, 46Jahre.
So läuft das Programm optimal.
1 | .include "tn26def.inc" |
2 | |
3 | rjmp Anfang |
4 | |
5 | Anfang: |
6 | ldi r16,low(Ramend) ;Einfügen für rcall |
7 | out sp,r16 ;Einfügen für rcall |
8 | ldi r16,0x18 |
9 | out ddrb,r16 |
10 | |
11 | Schleife: |
12 | ldi r16,0x10 |
13 | out portb,r16 |
14 | rcall Warte |
15 | ldi r16,0x0 |
16 | out portb,r16 |
17 | rcall Warte |
18 | ldi r16,0x8 |
19 | out portb,r16 |
20 | rcall Warte |
21 | ldi r16,0x0 |
22 | out portb,r16 |
23 | rcall Warte |
24 | rjmp Schleife |
25 | |
26 | Warte: |
27 | ldi r17,255 |
28 | Warte1: |
29 | ldi r18,255 |
30 | Warte2: |
31 | dec r18 |
32 | brne Warte2 |
33 | dec r17 |
34 | brne Warte1 |
35 | ret |
Danke für die hilfe.
Achim schrieb: > Bin Modellbauer, Eisenbahn, Spur Z, Ich mag's ein bissel größer, beschränke mich aber mehr auf die Elektronik und Elektrik, mit dem Bauen von Modellen habe ich es nicht so... http://www.hanneslux.de/ Da findest Du vielleicht ein paar nützliche Tipps betreffs Einstieg in AVR-Assembler. > 46Jahre. Das war ein schönes Alter, ist aber schon verdammt lange her... ;-) ...
he...was soll ich denn erst sagen mit meine 78 Jahre! Spur H0 Fleischmann mit Roco kombiniert. Anlage voll elektronisch ausgerüstet mit uralten ATARI in GFA-Basic. Zwei Tiny2313 steuern einen Märklin-Kran und Container-Kran von Brawa. Interessant, was Achim da vorzeigt. Grüße Rolf
Hallo Achim, ich habe mir nochmal Deinen Quelltext angeschaut, und da ist mir was merkwürdiges aufgefallen. im Anfang ldi r16,0x18 ;0b0001 1000 out ddrb,r16 ;also PORTB,PB4 + PB3 = Output in der Schleife kommt nach dem zweiten rcall ldi r16,0x8 ;das wäre 0b1000 0000 out portb,r16 aber Du hast doch im Anfang im Datenrichtungs-Register PB7 garnicht als Output gesetzt, oder? Evtl. kann auch ich einen Denkfehler haben! Grüße Rolf
Rolf H. schrieb: > ldi r16,0x8 ;das wäre 0b1000 0000 No. Genau lesen. Da ist eine führende 0 nicht geschrieben worden. 0x8 ist dasselbe wie 0x08 Und gerade bei Hex-Zahlen (oder auch Binärzahlen) die eine starke Affinität zur Bitdarstellung haben, ist es unklug, führende 0-en wegzulassen. Führt auf lange Sicht praktisch immer zu derartigen Missverständnissen. An dieser Stelle ist es besser die führenden 0-en zu schreiben und so wieder in das 8-Bit Schema zu kommen, welches zentral für die Arbeit auf Bitebene ist. Nicht alles, was technisch erlaubt ist, ist programmiertaktisch sinnvoll.
Rolf H. schrieb: > ldi r16,0x8 ;das wäre 0b1000 0000 > out portb,r16 Ne Rolf, ldi r16,0x8 ;ist 0b0000 1000 und damit Ok.
Noch besser wäre es allerdings, das ganze so zu schreiben ldi r16, (1<<PB4) | (1<<PB3) out ddrb,r16 bzw. ldi r16, (1<<PB4) out portb,r16 Denn jetzt stehen die Bitnamen direkt dort und kein Mensch muss mehr überlegen, welche Bits sich eigentlich hinter 0x18 bzw. 0x8 verstecken.
Karl Heinz Buchegger schrieb: > Noch besser wäre es allerdings, das ganze so zu schreiben > > ldi r16, (1<<PB4) | (1<<PB3) > out ddrb,r16 > > > bzw. > > ldi r16, (1<<PB4) > out portb,r16 Und noch besser ist es direkt sprechende Namen zu verwenden. ldi r16, SIGNAL1
Helmut Lenzen schrieb: > Und noch besser ist es direkt sprechende Namen zu verwenden. > > ldi r16, SIGNAL1 Absolut. Und die Moral von der Geschichte: Man kann alleine durch unterschiedliche Schreibweisen steuern, wie gut oder schlecht ein Code zu lesen bzw. zu verstehen ist. Und das sogar mit relativ wenig Aufwand, der einen riesen Unterschied ausmachen kann.
Karl Heinz Buchegger schrieb: > ldi r16, (1<<PB4) > > out portb,r16 Hast Recht Karl Heinz Buchegger, das werde ich mir mal angewöhnen. Wieder was gelernt! Grüße Rolf
Karl Heinz Buchegger schrieb: >> Und noch besser ist es direkt sprechende Namen zu verwenden. > >> > >> ldi r16, SIGNAL1 dann muß ich aber doch am Anfang PB4 als SIGNAL1 definieren. Macht man das mit .equ PB4=SIGNAL
Rolf H. schrieb: > Karl Heinz Buchegger schrieb: >>> Und noch besser ist es direkt sprechende Namen zu verwenden. >> >>> >> >>> ldi r16, SIGNAL1 > > > dann muß ich aber doch am Anfang PB4 als SIGNAL1 definieren. Ja und? Spätestens wenn die LED wegen Hardware Problemen vom Pin PB4 auf PB2 'umziehen' muss, bist du froh drüber, wenn du nur an einer Stelle die neue Belegung einträgst und nicht quer durch das ganze Programm hirschen und alle relevanten Hex-Zahlen finden und anpassen musst. > Macht man das mit .equ PB4=SIGNAL fast a) anders rum. In den meisten Programmiersprachen steht immer links vom = das Ergebnis und rechts davon, wie man zu diesem Ergebnis kommt. b) so wie das verwendet wird, muss da stehen .equ SIGNAL1 = (1<<PB4) Nur dann ist ldi r16, (1<<PB4) und ldi r16, SIGNAL1 auch gleichwertig.
Karl Heinz Buchegger schrieb: > ldi r16, (1<<PB4) > > out portb,r16 richtig wäre es aber wenn: ldi r16,0x8 ;0x08 = 0b0000 1000 out portb,r16 ldi r16, (1<<PB3) ;oder hab ich wieder nen Denkfehler? Grüße Rolf
Rolf H. schrieb: > Karl Heinz Buchegger schrieb: >> ldi r16, (1<<PB4) >> >> out portb,r16 > > richtig wäre es aber wenn: > > ldi r16,0x8 ;0x08 = 0b0000 1000 > out portb,r16 > > > ldi r16, (1<<PB3) ;oder hab ich wieder nen Denkfehler? Ne. stimmt schon. Ich hab jetzt nicht auf die Pin-Nummern geachtet. Vergleich mal mit
1 | .include "tn26def.inc" |
2 | |
3 | .equ LED_PORT = PORTB |
4 | .equ LED_DDR = DDRB |
5 | |
6 | .equ LEFT_LED = (1<<PB4) |
7 | .equ RIGHT_LED = (1<<PB3) |
8 | |
9 | rjmp Anfang |
10 | |
11 | Anfang: |
12 | ldi r16,low(Ramend) |
13 | out sp,r16 |
14 | |
15 | ldi r16, LEFT_LED | RIGHT_LED |
16 | out LED_DDR, r16 |
17 | |
18 | Main: |
19 | ldi r16, LEFT_LED |
20 | out LED_PORT, r16 |
21 | rcall Warte |
22 | ldi r16, 0x0 |
23 | out LED_PORT, r16 |
24 | rcall Warte |
25 | ldi r16, RIGHT_LED |
26 | out LED_PORT, r16 |
27 | rcall Warte |
28 | ldi r16, 0x0 |
29 | out LED_PORT, r16 |
30 | rcall Warte |
31 | rjmp Main |
32 | |
33 | Warte: |
34 | ldi r17,255 |
35 | Warte1: |
36 | ldi r18,255 |
37 | Warte2: |
38 | dec r18 |
39 | brne Warte2 |
40 | dec r17 |
41 | brne Warte1 |
42 | ret |
Spielt es jetzt wirklich noch eine große Rolle, wo die LDE angeschlossen ist? Nicht wirklich. Wenn die eine LED (sagen wir mal die rechte) nicht an PB3 angeschlossen ist, sondern an PB2, dann änder ich einfach
1 | ... |
2 | .equ RIGHT_LED = (1<<PB2) |
3 | ... |
und fertig. Den Rest der Programmanpassung macht der Assembler. Und das ist noch lange nicht alles, was man in diesem Programm verbessern kann. Zb. sollten einem die 'Komplett'-Zugriffe auf den Port ein Dorn im Auge sein. Mittels
1 | ldi r16, LEFT_LED |
2 | out LED_PORT, r16 |
verändert man ja nicht nur den einen Pin, sondern alle anderen Pins gleich mit! Solange man nur 1 oder 2 LED an einem Port hat, mag das ja noch angehen. Aber wenn du 3 LED, 2 Summer, und 3 Taster am Port hängen, dann wirds aufwändig, das immer alles im Kopf zu behalten, welcher Pin jetzt gerade wie stehen muss und welchen Wert man daher an das Port-Register zuweisen muss, damit wieder alles stimmt. Genau aus dem Grund gibt es die SBI und CBI Instruktionen, mit denen man tatsächlich nur 1 Bit und nicht mehr manipuliert.
1 | .include "tn26def.inc" |
2 | |
3 | .equ LED_PORT = PORTB |
4 | .equ LED_DDR = DDRB |
5 | |
6 | .equ LEFT_LED = PB4 |
7 | .equ RIGHT_LED = PB3 |
8 | |
9 | rjmp Anfang |
10 | |
11 | Anfang: |
12 | ldi r16,low(Ramend) |
13 | out sp,r16 |
14 | |
15 | ldi r16, (1<<LEFT_LED) | (1<<RIGHT_LED) |
16 | out LED_DDR, r16 |
17 | |
18 | Main: |
19 | sbi LED_PORT, LEFT_LED |
20 | rcall Warte |
21 | cbi LED_PORT, LEFT_LED |
22 | rcall Warte |
23 | |
24 | sbi LED_PORT, RIGHT_LED |
25 | rcall Warte |
26 | cbi LED_PORT, RIGHT_LED |
27 | rcall Warte |
28 | |
29 | rjmp Main |
30 | |
31 | Warte: |
32 | ldi r17,255 |
33 | Warte1: |
34 | ldi r18,255 |
35 | Warte2: |
36 | dec r18 |
37 | brne Warte2 |
38 | dec r17 |
39 | brne Warte1 |
40 | ret |
Aber: All das steht ja auch mehr oder weniger im AVR-Tutorial Wenn auch nicht in den Feinheiten von Anfang an.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.