kann mir jemand helfen, wie man die tabelle im Assembler programmiert und die liest. hab folgendes vor. ich will ein wert durch tastendrücken, wie bei einer uhr einlesen und über 7 segment anzeige anzeigen lassen. hat jemand ideen, wie man sowas macht. danke im voraus
Hallo kuku, ein Beispiel für eine Tabelle: Laden der Tabellenwerte: ======================== ldi ZH,high(t_text<<1) ;test - text ldi ZL,low(t_text<<1) ; lpm ;load program memory mov temp,S ;in R0(=S) Positionieren auf das nächste Element: ====================================== inc ZL Tabelle: ======== t_text: .db "Dies sind Deine Daten!" Gruss Otto
geht natürlich auch mit Zahlen: .db 0x00,0x01,0x0A,0xFF ; Dummy - Daten Otto
Hallo Otto, danke für dein Antwort. Ich habe die Tabelle in Quellcode implimentiert. Kann alle Werte der Tabelle auslesen und auf das Port ausgeben. Weitere Frage, wenn ich einen bestimmten Wert der Tabelle auslesen will, wie soll ich hier vorgehen. In deinem Beispiel wird nur ZL inkrementiert, und was ist mit dem ZH, warum wird ZH nicht verändert. Gruss kuku
@kuku >Weitere Frage, wenn ich einen bestimmten Wert der Tabelle auslesen will, >wie soll ich hier vorgehen. ldi zl, low(t_text+offset) ldi zh, high(t_text+offset) lpm >In deinem Beispiel wird nur ZL inkrementiert, und was ist mit dem ZH, >warum wird ZH nicht verändert. Schlechte Programmierung. Normalerweise muss es immer eine 16 Bit Operation sein. ldi r16,low(increment) add zl,r16 ldi r16,high(increment) adc zh,r16 (4 Worte, 4 Takte) oder wenn man nur um 1 erhöhen will, einfach einen Dummyzugriff mit Postincrement machen, spart Speicher und ist schneller ld r16,z+ (1 wort, 2 Takte) MFG Falk
es gibt noch "adiw" und "sbiw", auch jeweils 1 Word, 2 Takte, aber eine Konstante 0-63, @kuku (Gast): aber warum schau ich ins "instruction Set" und nicht du ? ;)
>Schlechte Programmierung. Normalerweise muss es >immer eine 16 Bit Operation sein. Wenn die Tabelle die richtige Basisadresse hat und auf maximal 256 Elemente zugegriffen wird ? Es war: >ein Beispiel für eine Tabelle: Otto
@Jörg X. (Gast):"instruction Set" ist auf Englisch, und ich habe gewaltige Probleme damit. Wenn jemand mir einen Link geben würde, wo man das alles in deutsche Sprache nachlesen kann. Das wäre super. kuku
kuku wrote: > @Jörg X. (Gast):"instruction Set" ist auf Englisch, und ich habe > gewaltige Probleme damit. Ohne Englisch wird es nix werden. Ich hatte auch nie Englisch-Unterricht. Ich habe mich mittels Wörterbuch durch die Datenblätter gewühlt. Inzwischen brauche ich das Wörterbuch immer seltener. > Wenn jemand mir einen Link geben würde, wo man das alles in deutsche > Sprache nachlesen kann. Das wäre super. Befehlssatz auf Deutsch gibt's bei ELEKTOR. Das Buch "AVR-Mikrocontroller-Praxis" von Volpe ist nichts Anderes als eine (fehlerhafte) Übersetzung des Befehlssatzes. Kostet etwa 40 Euro. Falls Du mein (gebrauchtes und korregiertes) haben willst, wird es geringfügig billiger. Nun zum Thema: Meine Routine, die im Multiplex die Bitmuster in das Display schreibt, sieht so aus:
1 | setseg: ;UP, setzt Segmente am Display |
2 | ldi zl,low(bimu*2) ;Z-Pointer auf Anfang |
3 | ldi zh,high(bimu*2) ;der Tabelle mit Bitmustern |
4 | add zl,wl ;Zahlenwert addieren |
5 | adc zh,null ;evtl. Übertrag auch |
6 | lpm wl,z ;Bitmuster aus Flash holen |
7 | out segport,wl ;und an Segment-Port ausgeben |
8 | ret ;zurück... |
9 | |
10 | |
11 | bimu: ;Bitmuster für Display-Segmente |
12 | .db 0b01000001,0b01011111 ;0, 1 |
13 | .db 0b00110001,0b00010101 ;2, 3 |
14 | .db 0b00001111,0b10000101 ;4, 5 |
15 | .db 0b10000001,0b01011101 ;6, 7 |
16 | .db 0b00000001,0b00000101 ;8, 9 |
Der Zahlenwert wird dem Unterprogramm im Register "wl" übergeben. Das Unterprogramm richtet den Zeiger auf das benötigte Element der Tabelle (bimu) ein, holt das Bitmuster und gibt es an dem Port (segport) aus, an dem die Segmente angeschlossen sind. Man hole sich also den benötigten Zahlenwert (der jeweiligen Anzeigestelle), achte dabei darauf, dass er nicht kleiner als 0 und größer als 9 sein kann, und rufe diese Routine auf. Fertig... ...
@Otto >>Schlechte Programmierung. Normalerweise muss es >>immer eine 16 Bit Operation sein. >Wenn die Tabelle die richtige Basisadresse hat >und auf maximal 256 Elemente zugegriffen wird ? Das stand da aber nirgendwo. >Es war: >>ein Beispiel für eine Tabelle: Ja, ein schlechtes, oder zumindest unvollständiges. Dutzende Anfänger machen das 1:1 nach und schreien dann hier rumm wenns klemmt. -> Nicht gut. MfG Falk
Hab die Routine mit Offset von Falk ausprobiert, kann die Werte einlesen, in richtigen reinfolge, aber nicht die, die ich eingentlich haben will. In hex-Datei liegen die Werte der Tabelle am Ende, eingelesen wird irgenwo von der mitte. Wieso, hab noch nicht rausgefunden. Es könnte vielleicht am meinem Quellcode liegen. Die Routine von Hannes Lux funktioniert einwandfrei. Ich bedanke mich bei Otto, Falk, Jörg X. und Hannes Lux, die mir bei Lösung des Problems geholfen haben. Hoffentlich hab ich keinen vergessen. MfG kuku
@kuku >eingelesen wird irgenwo von der mitte. Wieso, hab noch nicht >rausgefunden. Es könnte vielleicht am meinem Quellcode liegen. Dann lass mal sehen. Aber möglichst als Anhang. MFG Falk
Hallo Falk. Hier ist das Quellcode. Für jede Verbesserung bin ich dankbar. kuku
Dein µC hält nicht einfach an, nur weil den Source Code zu Ende ist. Der macht weiter und interpretiert jedes Byte das ihm im Flash unterkommt als Befehl.
1 | mov temp,r0 ;in R0 |
2 | |
3 | ;******************************************************* |
4 | ;Ausgabe am Port B |
5 | out portb, temp |
6 | |
7 | ;******************************************************* |
8 | ;Testtabelle: |
9 | ;7-Segment anzeige mit gemeinsamen Kathode |
10 | ;
|
11 | ; a |
12 | ; ----- |
13 | ; f| g |b |
14 | ; ----- |
15 | ; e| d |c * |
16 | ; ----- |
17 | ; abcdefg* |
18 | tab: .db 0b11111100 ;0 |
19 | .db 0b01100010 ;1 |
20 | .db 0b11011010 ;2 |
21 | .db 0b11110010 ;3 |
Insbesondere macht der µC nach out portb, temp weiter und holt sich den nächsten Befehl. Der Binärcode dieses Befehls lautet 0b11111100 und mit dem Instruction Set könnte man jetzt auch rauskriegen, was dieser Befehl machet. Egal. Wenn dieser Befehl abgearbeitet ist, kommt der nächste drann. Sein Binärcode lautet 0b01100010. Wieder: Mit dem Instruction Set könnte man rauskriegen was das für ein Befehl ist. Wenn dein Programm soweit abgearbeitet ist, dass es für den µC nichts mehr zu tun gibt, musst du ihn trotzdem beschäftigen. Und wenn es nur eine Endlosschleife ist, in der du ihn gefangen hälst. Zum Thema Tabelle: ldi ZH,high(tab+1) ldi ZL,low(tab+1) Du hast nicht richtig acht gegeben. Sonst wär dir aufgefallen, dass die Adressangabe bei den gezeigten Beispielen immer verdoppelt wird (also einen Faktor *2 enthält). setseg: ;UP, setzt Segmente am Display ldi zl,low(bimu*2) ;Z-Pointer auf Anfang ldi zh,high(bimu*2) ;der Tabelle mit Bitmustern add zl,wl ;Zahlenwert addieren adc zh,null ;evtl. Übertrag auch lpm wl,z ;Bitmuster aus Flash holen out segport,wl ;und an Segment-Port ausgeben ret ;zurück...
Danke, hab Verbessert. Funktioniert. ich bin halt Anfänger. ich wußte, daß das so kompliziert ist, aber wie es aussieht, ist es noch schlimmer.
kuku wrote: > Danke, hab Verbessert. Funktioniert. > ich bin halt Anfänger. ich wußte, daß das so kompliziert ist, aber wie > es aussieht, ist es noch schlimmer. Wenn dir das kompliziert vorkommt: Warum tust du dir dann Assembler an? Nicht falsch verstehen: Ich bin ein starker Verfechter der Fraktion, die einen Einstieg mit Assembler befürwortet. Aber ansonsten nehm ich für sowas C. Da kümmert sich der Compiler um all die kleinen Details
1 | #include <avr/io.h> |
2 | #include <stdtypes.h> |
3 | |
4 | uint8_t Digits[] = { 0b11111100, // 0 |
5 | 0b01100010, // 1 |
6 | 0b11011010, // 2 |
7 | 0b11110010, // 3 |
8 | 0b01100110, // 4 |
9 | 0b10110110, // 5 |
10 | 0b10111110, // 6 |
11 | 0b11100000, // 7 |
12 | 0b11111110, // 8 |
13 | 0b11110110, // 9 |
14 | 0b11101110, // A |
15 | 0b00111110, // b |
16 | 0b10011100, // C |
17 | 0b01111010, // d |
18 | 0b10011110, // E |
19 | 0b10001110, // F |
20 | 0b00100000, // i |
21 | 0b00101010, // n |
22 | 0b00101110, // h |
23 | };
|
24 | |
25 | int main() |
26 | {
|
27 | DDRB = 0b11111111; |
28 | |
29 | PORTB = Digits[0]; |
30 | |
31 | while( 1 ) { |
32 | }
|
33 | }
|
Kein Problem mit der Größe der Interrupt Tabelle, den Tabellenzugriff macht dir der Compiler korrekt und wenn du die Endlos-while Schleife vergisst, dann fängt dich das gcc-C-System auf und ergänzt die auch noch für dich. Ganz abgesehen davon, dass du den Eiertanz um die Register- belegung los bist.
@Karl heinz Buchegger >Wenn dir das kompliziert vorkommt: >Warum tust du dir dann Assembler an? >Aber ansonsten nehm ich für sowas C. Da kümmert sich der >Compiler um all die kleinen Details Naja, aber gerade auch in C gibt es MEHR als genug Möglichkeiten, sich als Anfänger in den Fuss zu schiessen. Als ich damals mit C angefangen habe konnte ich bereits sehr gut programmieren, in Pascal, Basic, Assembler. Was ich geflucht habe . . . 8-0 Teufel und Belzebub. MfG Falk
Falk wrote: > > Naja, aber gerade auch in C gibt es MEHR als genug Möglichkeiten, sich > als Anfänger in den Fuss zu schiessen. Ja klar. Das ist ja das schöne daran :-) Aber in C musst du wenigstens noch 'den Abzug betätigen', in Assembler reicht es schon wenn man einmal kurz wegschaut :-) > Als ich damals mit C angefangen habe konnte ich bereits sehr gut > programmieren, in Pascal, Basic, Assembler. > Was ich geflucht habe . . . 8-0 Fluchen ist die Sprache die alle Programmierer beherrschen. > > Teufel und Belzebub. Drum ist ein Bund Knoblach am Monitor nie verkehrt.
@kuku: Ein wichtiger Hinweis noch: Bitte in einer Tabelle im Flash darauf achten, dass jede Zeile eine gerade (durch zwei teilbare) Anzahl von Bytes enthält. Beachtet man das nicht, fügt der Assembler von sich aus Nullbytes ein. Der Grund dafür ist, dass der Flash wordorentiert adressiert ist (ein Word sind zwei Bytes, also 16 Bit), der LPM-Zugriff aber byteorientiert erfolgt (derhalb wird die Adresse ja auch verdoppelt, siehe Beschreibung des Befehls LPM). Achja, Z-Pointer muss auf Adresse * 2 (Adresse mal 2), nicht auf Adresse mal 2 plus 1, das geht daneben. ...
@Hannes Lux >Achja, Z-Pointer muss auf Adresse * 2 (Adresse mal 2), >nicht auf Adresse mal 2 plus 1, das geht daneben. Das +1 ist doch Absicht, er will auf die einzelnen Elemente zugreifen. MFG Falk
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.