Hallo Spess, Hannes Lux u. Karl Heinz, ich bin dabei, ein mit Bascom erstelltes Programm im Jahr 2011 auf Assembler umzusetzen. Eine Art Maske für den Tiny13 hatte ich mir schon vorab erstellt und das ohne Fehler. Und jetzt hänge ich an zwei .EQU xxx Befehlen, wo ich nicht weiter komme Hier die Quelldatei: ; Projekt-Name: Projekttiny13 Datum: 29.02.2012 ; Datei: Interrupt-Tiny13.asm ; PORTB,PB1 = LEDgn (Output) ; PORTB,PB2 = LEDrt (Output) ; PINB,PB3 = sw1 (Input) ; PINB,PB4 = sw2 (Input) ; AVR: Tiny13 .INCLUDE "tn13def.inc" ; Deklaration für Tiny13 .EQU takt = 1200000 ; Systemtakt 1,2 MHz .EQU LEDgn = PORTB,PB1 .EQU LEDrt = PORTB,PB2 .DEF akku = r16 ; r16 in akku benannt #define sw1 PINB,PB3 #define sw2 PINB,PB4 rjmp reset ; Reseteinsprung .ORG OVF0addr ; Interrupt-Vektor rjmp TIM0_OVF ; Sprung zur ISR reset: ldi akku,LOW (RAMEND) ; Stapel anlegen out SPL,akku ldi akku,0x06 ; Bitmuster 0000 0110 out DDRB,akku ; Datenricht. PB1/2=Output ; PB0 und PB3 bis PB7=Input ldi akku,0b11111001 out PORTB,akku ; PULLUP ; Timer0 initialisieren: ldi akku,1<<CS02|1<<CS00 ; Prescale = 1024 (Beispiel) out TCCR0B,akku ldi akku,1<<TOIE0 ; Timer Overflow Interrupt einrichten out TIMSK0,akku sei ; Timer frei loop: nop ;noch steckt im .EQU der Wurm drin rjmp loop ;Interrupt-ISR TIM0_OVF: push r2 ;Kopie r2 auf den Stack, danach SP-1 in r2,SREG ;Inhalt vom Statusregister in r2 laden dec r17 ;ISR Abarbeitung (hier dec r17) out SREG,r2 ;Inhalt von r2 ins SREG laden pop r2 ;SP+1, danach vom Stack in r2 laden reti .EXIT hab ich etwa die Assembler-Direktive .EQU falsch interpretiert? Wenn ich die beiden entferne (.EQU LEDgn und LEDrt) ist der Fehler verschwunden. Bevor ich jetzt weiter mache, muß das erst raus. Grüße Rolf
Hi .equ ist keine Textersetzung sondern eine Wertzuweisung. Also .equ Konstante = Wert Also z.B. .equ LEDPort = PortB oder .equ LEDgn = PB1 funktionieren. Deine Kombination nicht. Ersetze einfach das .equ durch #define. MfG Spess
Rolf Hegewald schrieb: > Hallo Spess, Hannes Lux u. Karl Heinz, > ich bin dabei, ein mit Bascom erstelltes Programm im Jahr 2011 > auf Assembler umzusetzen. >... Ich bin zwar selber noch Anfänger und gehöre auch nicht zu Deinen Erlauchten, aber ich freue mich das sich jemand beginnt für Assembler zu interessieren. Ich sehe im wesentlichen den Geschwindigkeitsvorteil in dieser Sprache, sowie das besesse Verständnis für die Programmierung der Mikrocontroller, deshalb möchte ich Dich auf etwas hinweisen, was wir als Anfänger irgendwie als Standard hinnehmen, also ein muß. Dies ist jedoch eine Abwägungssache. Wie halt das Meiste im Leben. Ich meine jetzt konkret diese PUSH und POP Befehle. Jeder braucht 2 Taktzyklen, die man sich in dem unteren Programmschnipsel sparen kann, wenn man für die Sicherung des Statusregisters ( SREG ) ein kostbares oberes ( ab r16 aufwärts ) opfert, das nur zur Sicherung des SREG dient, was man ja sowieso - ich möchte sagen - fast immer in einer Interrupt-Service-Routine ( ISR ) braucht.
1 | > |
2 | > ;Interrupt-ISR |
3 | > TIM0_OVF: push r2 ;Kopie r2 auf den Stack, danach SP-1 |
4 | > in r2,SREG ;Inhalt vom Statusregister in r2 laden |
5 | > dec r17 ;ISR Abarbeitung (hier dec r17) |
6 | > out SREG,r2 ;Inhalt von r2 ins SREG laden |
7 | > pop r2 ;SP+1, danach vom Stack in r2 laden |
8 | > reti |
9 | > .EXIT |
10 | > |
Bernd_Stein
Hi >Ich meine jetzt konkret diese PUSH und POP Befehle. Jeder braucht >2 Taktzyklen, die man sich in dem unteren Programmschnipsel sparen kann, >wenn man für die Sicherung des Statusregisters ( SREG ) ein kostbares >oberes ( ab r16 aufwärts ) opfert, das nur zur Sicherung des SREG dient, >was man ja sowieso - ich möchte sagen - fast immer in einer >Interrupt-Service-Routine ( ISR ) braucht. Da verstehe ich den Sinn nicht. Wenn man ein Register zum Sichern von SREG reserviert, dann im Bereich r0...r15 und nicht im oberen Bereich. Es sei denn, der AVR hat keine r0..r15. MfG Spess
spess53 schrieb: > > Da verstehe ich den Sinn nicht. Wenn man ein Register zum Sichern von > SREG reserviert, dann im Bereich r0...r15 und nicht im oberen Bereich. > Es sei denn, der AVR hat keine r0..r15. > > MfG Spess > Ja, ja so ist das, wenn man nicht Sattelfest ist. Der Grund liegt darin, das ich einfach gedacht habe das die Befehle IN und OUT nur auf r16 aufwärts zugreifen können. Was natürlich falsch ist. Entschuldigung für die Verwirrung die ich evtl. bei dem einen oder anderen angestiftet habe. Bin jetzt wohl damit durcheinander geraten, das diese Befehle nur die SF-Register bis 63 ansprechen können. Bernd_Stein
sch... jetzt fang ich nochmal an zu schreiben. war einfach ausgeloggt, und dann ist alles geschriebene hinüber. Also nochmal: habe es abgeändert wie folgt ; AVR: Tiny13 .INCLUDE "tn13def.inc" ; Deklaration für Tiny13 .EQU takt = 1200000 ; Systemtakt 1,2 MHz #define sw1 PINB,PB3 #define sw2 PINB,PB4 #define LEDgn PORTB,PB1 #define LEDrt PORTB,PB2 .DEF akku = r16 ; r16 in akku benannt und es funzt. Ich habe von Hannes Lux die Quelldatei "schranke.asm" studiert und meine 2 ISR gesehen zu haben. Das würde mich hier auch interessieren. a.) Zeiten von 10 Sec. aufzubauen b.) Abfrage der Tasten sw1 / sw2 Hannes hat mengenweise .EQU aufgebaut, da den Überblick zu haben ist nicht einfach. Aber eins nach den anderen. Grüße Rolf
Rolf Hegewald schrieb: > sch... jetzt fang ich nochmal an zu schreiben. > war einfach ausgeloggt, und dann ist alles geschriebene hinüber. Hast Du mal versucht, zurück zu blättern (Firefox)? Dann sollte das Editfenster wieder Deinen Text zeigen. Oder vor dem Abschicken eines längeren Textes markieren und Strg-C. Peter
Hallo Peter, hab ich mit meinen Internet-Explorer versucht, vergebens. Merkwürdig, muß mich auch bei anderen Foren sehr oft neu anmelden. Man sagte mir, das sei eine Einstellungssache am Browser. ach ja Spess, über diese Wertzuweisung wie z.B. .EQU konstante = 20 habe ich mir nochmal meine Gedanken gemacht. Hier wird also konstante der Dezimalwert 20 zugewiesen. Aber was ist denn bei .EQU LEDgn = PORTB ;so von Dir geschrieben PORTB ist doch ein Register und kein Wert, oder? Dezimal 20 = hex 0x20 binär 0b00100000 ist das richtig? Grüße Rolf
Hi >PORTB ist doch ein Register und kein Wert, oder? Nein. In deiner Include-Datei tn13def.inc steht: .equ PORTB =$18 Damit ist 'PORTB' ein Wert. >Dezimal 20 = hex 0x20 binär 0b00100000 ist das richtig? Nö. Dezimal 20 = 0x14 MfG Spess
Hallo Leute, und wieder mal läßt mich der Timer0 keine Ruhe! Habe mir aus dem Tutorial eine Abhandlung "Interrupt" ins Studio4 runter gezogen. War auf dem Mega8 gedacht, habe es auf dem Tiny13 zugeschnitten. ; Projekt-Name: Projekttiny13 Datum: 08.04.2012 ; Datei: Interrupt-Tiny13-01.asm ; PORTB,PB1 = LEDgn (an PB1 LEDgn) ; AVR: Tiny13 .INCLUDE "tn13def.inc" ; Deklaration für Tiny13 .EQU takt = 1200000 ; Systemtakt 1,2 MHz #define LEDgn PORTB,PB1 .DEF temp = r16 ; r16 in temp benannt .DEF leds = r17 ; r17 in leds benannt rjmp reset ; Reseteinsprung .ORG OVF0addr ; Interrupt-Vektor rjmp TIM0_OVF ; Sprung zur ISR reset: ldi temp,LOW (RAMEND) ; Stapel anlegen out SPL,temp ldi temp,0xFF out DDRB,temp ; Datenrichtung PortB = Output ; Timer0 initialisieren: ldi temp,1<<CS02|1<<CS00 ; Prescale = 1024 (Beispiel) out TCCR0B,temp ; Register TCCR0B ldi temp,1<<TOIE0 ; Timer Overflow Interrupt einrichten out TIMSK0,temp ; Register TIMSK0 sei ; Timer frei (im SREG-Register) ldi leds,0xFF ; lade R17 mit FF, aber wofür? loop: rjmp loop ; Schleife ;Interrupt-ISR TIM0_OVF: push r2 ; Kopie r2 auf den Stack, danach SP-1 in r2,SREG ; Inhalt vom Statusregister in r2 laden out PORTB,leds ; lade PORTB mit Inhalt von r17 com leds ; negiere Inhalt von r17 (auf Low gesetzt) out SREG,r2 ; Inhalt von r2 ins SREG laden pop r2 ; SP+1, danach vom Stack in r2 laden reti .EXIT Und dazu habe ich zwei Fragen: 1. Nach Einschalten blinkt die LED mit ca. 3 Hz Im Befehl ldi leds,0xFF habe ich den Wert auf 0x1F verkleinert, ergab keine Änderung...mh, ich dachte, dann nehme den Wert mal ganz weg, ergibt keine Änderung! Er hat doch dann für den Ablauf in der ISR gar keinen Einfluß, oder? Aber mit com leds (r17) werden die Bits negiert, also zu LOW gesetzt. Wie kommt dann die LED durch out PORTB,leds wieder zum leuchten. Die zweite Frage stelle ich später. Grüße Rolf
Hi >1. Nach Einschalten blinkt die LED mit ca. 3 Hz Im Befehl ldi leds,0xFF habe ich den Wert auf 0x1F verkleinert, ergab keine Änderung...mh, ich dachte, dann nehme den Wert mal ganz weg, ergibt keine Änderung! Na ja, Bei einer LED bemerkst du nichts. Bei mehreren LEDs am Port wäre ein Unterschied sichtbar. Mit der Frequenz hat das allerdings nichts zu tun. Die wird von deinem Timer bestimmt. >Aber mit com leds (r17) werden die Bits negiert, also zu LOW gesetzt. >Wie kommt dann die LED durch out PORTB,leds wieder zum leuchten. Negieren heisst nicht, das sie auf Null gesetzt werden, sondern, das aus einer 1 eine 0 und aus einer 0 eine 1 wird. Und wie ist die zweite Frage? MfG Spess
Hallo Spess, danke für Deine Antwort, hatte heute zu Ostern mit gar keiner Antwort gerechnet. Hier nochmal die beiden Befehle in der ISR out PORTB,leds ; lade PORTB mit Inhalt von r17 com leds ; negiere Inhalt von r17 (auf Low Im ersten Befehl "out PORTB,leds" ; =Register r17 steht PORTB/PB1 auf HIGH, sonst würde die LEDgn nicht leuchten. Die LED liegt an Vcc und wird über einen NPN-Transistor geschaltet. Im zweiten Befehl "com leds" wird PORTB/PB1 zu LOW gebracht, die LED muß dunkel sein. Tritt nun ein erneuter Overflow ein, leuchtet sie ja wieder... aber wodurch, wo ist PORTB/PB1 wieder zu HIGH gebracht worden? Das ist mir alles noch so unlogisch! ldi leds,0xFF ; lade R17 mit FF, aber wofür? durch ldi....... nicht, denn wenn ich es entferne, kommt ja keine Änderung. Ich vermute, daß ich hier einen logischen Denkfehler habe. Grüße Rolf
Hi Du hast nur eine LED an PB1. Also ist nur Bit1 vom Led interessant: Led = 0Bxxxxxx1x 1.Overflow out 0bxxxxxx1x -> Led leuchtet com 0bxxxxxx1x -> led = 0bxxxxxx0x 2.Overflow out 0bxxxxxx0x -> Led aus com 0bxxxxxx0x -> led = 0bxxxxxx1x 3.Overflow out 0bxxxxxx1x -> Led leuchtet com 0bxxxxxx1x -> led = 0bxxxxxx0x und so weiter >ldi leds,0xFF ; lade R17 mit FF, aber wofür? >durch ldi....... nicht, denn wenn ich es entferne, kommt ja keine >Änderung. Led ist das Register r17. Und das hat auch wenn du nichts hineinschreibst beim Einschalten einen (zufälligen) Wert. Ob das Bit1 beim Start 0 oder 1 hat auf das nachfolgend Blinken keinen Einfluss. MfG Spess
ja, nach zweimal Lesen blick ich jetzt durch! Meine errechnete Zeit von Overflow zum nächsten beträgt bei f=1,2 MHz und Prescale 1024 etwa 0,218 Sec. Jetzt die 2. Frage: Um die Blinkfrequenz zu verlangsamen schlägt das Tutorial zwei Möglichkeiten vor. Entweder Timer1 nutzen, oder ein Zählregister aufstellen. z.B. Register r18 mit 0x07 laden Decrementieren und auf Low abfagen. Hatte ich mir so gedacht: ldi r18,0x07 gehe: tst r18 breq ende dec r18 rjmp gehe ende: Nun bin ich mir unsicher, setze ich den Ablauf mit in der ISR hinein oder lasse ich es mit loop: Zählablauf rjmp loop Grüße Rolf
... ldi r18,0x07 tst r18 gehe: breq ende dec r18 rjmp gehe ende: das "tst r18" nur einmal nutzen, da das "dec" das zero flag sowieso setzten würde wenn r18 null wird?
Hallo noob, Danke für Dein Hinweis! Es hat mir keine Ruhe gelassen, jetzt sieht die ISR so aus ;Interrupt-ISR TIM0_OVF: push r2 in r2,SREG out PORTB,leds com leds ldi r18,0xFF tst r18 gehe: breq ende dec r18 rjmp gehe ende: out SREG,r2 pop r2 reti .EXIT aber es bringt nichts, die LED blinkt weiterhin mit ca. 3Hz wie vorher ohne Zählschleife. Wenn ein Durchlauf = 0,218 Sec. dauert, dann müßten es ja jetzt x 256 = 55,8 Secunden sein...Sch. Technik, bestimmt wieder ein Denkfehler von mir. Oder sollte ich die Zählschleife zwischen out / com setzen? Grüße Rolf
Hi >aber es bringt nichts, die LED blinkt weiterhin mit ca. 3Hz >wie vorher ohne Zählschleife. Damit veränderst du auch nur die Abarbeitungszeit der Interruptroutine.
1 | .... |
2 | ldi r18,0xFF |
3 | .... |
4 | |
5 | ;Interrupt-ISR |
6 | TIM0_OVF: push r2 |
7 | in r2,SREG |
8 | |
9 | dec r18 ; wenn <>0 |
10 | brne ende ; dann raus |
11 | |
12 | out PORTB,leds ; sonst Blinken |
13 | com leds ; und Delayzähler |
14 | ldi r18,0xFF ; neu setzen |
15 | |
16 | ende: out SREG,r2 |
17 | pop r2 |
18 | reti |
Allerdings solltest du den Prescaler kleiner machen oder r18 mit einem kleineren Wert laden. Sonst wird die Blinkperiode sehhhhhr lang. MfG Spess
Hallo Spess, es funzt! Sieht also nach Deinen Vorschlag so aus: ldi leds,0xFF ;egal wie, die LED bleibt erst dunkel ;aber das sind im Momment Kleinigkeiten. ldi r18,0b01111111 ;Binär behalte ich besser Übersicht. loop: rjmp loop ;Interrupt-ISR TIM0_OVF: push r2 in r2,SREG dec r18 ; wenn <>0 brne ende ; dann raus out PORTB,leds ; sonst Blinken com leds ; und Delayzähler ldi r18,0b01111111 ; neu setzen ende: out SREG,r2 pop r2 reti .EXIT Nach meinen Messungen sehen die Zeiten in etwa so aus: Inhalt in r18 0000 0111 (hex=07; dez.=7) ca. 2 Sec. 0000 1111 (hex=0F; dez.=15) ca. < 4 Sec. 0001 1111 (hex=1F; dez.=31) ca. < 8 Sec. 0011 1111 (hex=3F; dez.=63) ca. <16 Sec. 0111 1111 (hex=7F; dez.=127 ca. 27 Sec. Für mich war hier als Beispiel im Besonderen die Frage wichtig "Wie kann man in der ISR zwei Dinge realisieren"! Einmal eine Zeit ablaufen lassen und zum anderen etwas zu steuern. Für viele Frager ein Anstoß fürs Tutorial, denn erst hierdurch bin ich schlauer geworden. Für den Rest, den man noch nicht begriffen hat, helfen dann schon die Provis wie Spess, Hannes Lux oder K. H. Buchegger. Viele Grüße und ein Dankeschön Rolf
Rolf Hegewald schrieb: > TIM0_OVF: push r2 > in r2,SREG > > dec r18 ; wenn <>0 > brne ende ; dann raus > > out PORTB,leds ; sonst Blinken > com leds ; und Delayzähler > ldi r18,0b01111111 ; neu setzen > r18 wir hier als Zähler benutzt! Bei jedem ISR AUfruf wird er um 1 verringert, und wenn dann irgendwann 0 erreicht ist, werden die LED umgeschaltet und der Zähler kriegt wieder einen Startwert. Hier ist also eine Binärschreibweise für die Zahl in r18 nicht angebracht. Eine Dezimalschreibweise ist hier viel besser. Denn du sagst ja auch nicht: Ich lass r18 von 0b01111111 aus herunterzählen. Wieviele Wiederholungen sind des das? Da musst du im Kopf erst mal die Binärzahl in eine Dezimalzahl umwandeln um zur Erkentniss zu kommen: r18 wird 63 mal heruntergezählt. Dann schreibs doch gleich so hin! ldi, r18, 63 fertig. Du brauchst nichts umrechnen und jeder kann sofort sehen, wieviele Wiederholungen das sein werden. Ob man Hexadezimal-, Binär- oder Dezimalschreibweise bevorzugt hängt davon ab, was die Zahl bedeutet! In welchem Zusammenhang sie auftaucht und welches die natürlichste Schreibweise dafür ist. Bei Zahlen, die im Zusammenhang mit 'zählen' im weitesten Sinn auftauchen ist in der überwiegenden Mehrzahl der Fälle die dezimale Schreibweise die natürlichste. Denn: wir alle sind Dezimalzahlen von klein auf gewohnt und denken und rechnen mit ihnen. > Für mich war hier als Beispiel im Besonderen die Frage wichtig > "Wie kann man in der ISR zwei Dinge realisieren"! > Einmal eine Zeit ablaufen lassen und zum anderen etwas zu > steuern. Dann mach das doch. Du machst dann eben 2 Dinge hintereinander in der ISR. Manchmal hast du eben Zahlen in Registern, die du für beide Dinge gebrauchen kannst, aber das muss nicht so sein. Der Trick hier bei dir, besteht darin, dass du nur bei jeder n-ten Wiederholung in der ISR die LED umschaltest. Deine ISR kannst du dir wie den Sekundenzeiger einer Uhr vorstellen. Früher hast du bei jedem Ticken die LED umgeschaltet. Wenn du jetzt möchtest, das nur jede 7-te Uhrentick umgeschaltet wird, wie machst du das. Du zählst im Kopf die Anzahl der Ticker mit (oder machst dir eine Stricherlliste). Bei jedem Tick zählst du 1 runter bis 0, machst deine Aktion und fängst wieder von vorne zu zählen an. 6, 5, 4, 3, 2, 1, 0 - umschalten - 6, 5, 4, 3, 2, 1, 0 - umschalten - 6, ... Deine Uhr tickt nach wie vor jede Sekunde 1-mal. Aber die LED werden alle 7 Sekunden umgeschaltet, wie gewünscht. Und in deinem Programm übernimmt eben das Register r18 die Rolle dieser Stricherlliste. Viele Konzepte aus der realen Welt lassen sich überraschend gut auf die Programmierung anwenden. Wenn du mit Timer zu tun hast, dann ist oft die Analogie "Eine Uhr tickt alle 1 Sekunde, wie würde ich persönnlich mein Problem damit lösen" ein überraschend guter Leitfaden. Denn im Prinzip weißt du von vielen Problemen wie man sie löst. Du könntest das aus dem Stand heraus. Und in einem Programm ist das auch nicht anders. Die Register sind dein 'Notizzettel' auf dem du dir Notizen in Form von Zahlen machen kannst und mit denen du operieren kannst. Du musst nur immer herausfinden, wie DU dasselbe Problem mit den relevanten Zahlen und einem Notizblock lösen würdest. Vor noch gar nicht allzulanger Zeit war es so, dass es für jedes Problem einen eigenen Befehl gab. Aber das ändert sich jetzt langsam. Du kennst jetzt die wichtigsten Befehle. Jetzt beginnt die Phase, in der du mit Kombinationen von Befehlen Ideen ausdrückst. So wie ein Maler seine Pinsel, Farben, Techniken, Leinwände, deren Vor und Nachzüge kennen gelernt hat, so beginnst du jetzt immer mehr, dein Basiswissen einzusetzen um mit Kombinationen davon bestimmte Dinge zu erreichen.
an Karl Heinz meinen Dank, habe es drei Mal gelesen. Nun habe ich mich durchgerungen und bei Reichelt den ATtiny 25 bestellt. Aus dem Datenblatt "Register Summary" habe ich das vom Tiny13 und 25 ausgedruckt. Identisch sind die Register mit denen ich schon gearbeitet habe: SREG SPL TCCR0B TCNT0 PORTB DDRB PINB hinzu gekommen ist SPH jetzt müßte ich das so aufstellen .INCLUDE "tn25def.inc" .EQU takt = 1200000 rjmp start .ORG OVF0addr ;bleibt das so? rjmp TIM0_OVF ;bleibt das so? (war die vom Tiny13) start: ldi r16,LOW (RAMEND) out SPL,r16 ldi r16,HIGH (RAMEND) out SPH,r16 geändert hat sich Register TIMSK0 in TIMSK der Tiny13 hat einen Speicher von 1KByte, das wären 1024 Byte. Was sich darin verbirgt ist mir immer noch nicht ganz klar. Soviel weiß ich: 32 Arbeitsregister r0-r32 von Speicher 00-1F=dez.0-31 (32 Byte) 64 SFR Register von Speicher 20-5F=dez.32-95 (64 Byte) 64 x 8Bit SRam von Speicher 60-9F=dez.96-159 (64 Byte) der Tiny 25 hat 2KByte, RAM=128 Byte, EEPROM=128 Byte SRAM weiß ich nicht! Bedeutet das, die Angabe 2K ist sein Gesamtspeicher, in dem jetzt alle Speicherarten drin stecken, also Ram, SRAM, EEPROM Grüße Rolf
Hi >hinzu gekommen ist SPH ist eigentlich nur für den ATTiny85 interessant, da dort der Stackpointer nicht mehr in ein Byte passt. Beim ATTiny25 brauchst du übrigens den Stackpointer nicht mehr initialisieren. Der wird nach einem Reset automatisch auf RAMEND gesetzt. ->Datenblatt S.11: 4.6.1 SPH and SPL — Stack Pointer Register >der Tiny 25 hat 2KByte, RAM=128 Byte, EEPROM=128 Byte >SRAM weiß ich nicht! Der interne RAM der AVRs ist generell S(tatic)RAM. >Bedeutet das, die Angabe 2K ist sein Gesamtspeicher, in dem jetzt >alle Speicherarten drin stecken, also Ram, SRAM, EEPROM Nein. Das ist nur der Flash. MfG Spess
Hallo Spess, dann habe ich in meinen Angaben doch Quatsch geschrieben! Nämlich: 32 Arbeitsregister r0-r32 von Speicher 00-1F=dez.0-31 (32 Byte) 64 SFR Register von Speicher 20-5F=dez.32-95 (64 Byte) was schließt sich denn ab Speicher 60 an wenn er einen Speicher von 1KByte hat und es das SRAM ist, dann stimmt doch das nachfolgende nicht, oder 64 x 8Bit SRam von Speicher 60-9F=dez.96-159 (64 Byte) in welchen Bereich steckt denn nun das EEPROM? Im SRAM gehen doch die Daten nicht verloren. Fragen über Fragen!
Sorry, ich hatte den Anfang des Threads verpasst, habe ihn erst jetzt gefunden... Rolf Hegewald schrieb: > in welchen Bereich steckt denn nun das EEPROM? Das EEPROM wird nicht in den Adressbereich des RAMs gemappt, es hat eine eigene Adressierung. Die Adresse wird nach eearh:eearl geschrieben, die Daten in eedr geschrieben bzw daraus gelesen. Der Schreib- oder Lesebefehl muss durch Setzen der entsprechenden Bits in eecr ausgelöst werden. > Im SRAM gehen doch die Daten nicht verloren. Doch, SRAM ist flüchtig. Die Daten gehen bei Ausschalten der Versorgungsspannung verloren. Nur Flash (Programmspeicher) und EEPROM (Daten- bzw. Parameterspeicher) sind nichtflüchtig, behalten also auch ohne Versorgungsspannung ihren Inhalt. ...
Hallo Hannes, danke für Deine Antwort. Habe soeben den ersten Tiny 25 zum laufen gebracht. In der ISR sind einmal ein Zeitablauf und EIN/AUS einer Led enthalten. Sieht alles so aus: ; Projekt-Name: Projekttiny25 Datum: 15.04.2012 ; Datei: Interrupt-Tiny25-00.asm ; PORTB,PB1 = LEDgn (an PB1 LEDgn) ; AVR: ATTINY13-20PU (DIP) .INCLUDE "tn25def.inc" ; Deklaration für Tiny25 .EQU takt = 1200000 ; Systemtakt 1,2 MHz #define LEDgn PORTB,PB1 .DEF temp = r16 ; r16 in temp benannt .DEF leds = r17 ; r17 in leds benannt rjmp reset ; Reseteinsprung .ORG OVF0addr ; Interrupt-Vektor rjmp TIM0_OVF ; Sprung zur ISR reset: ldi temp,LOW (RAMEND) ; Stapel anlegen out SPL,temp ldi temp,0xFF out DDRB,temp ; Datenrichtung PortB = Output ; Timer0 initialisieren: ldi temp,1<<CS02|1<<CS00 ; Prescale = 1024 (Beispiel) out TCCR0B,temp ; Register TCCR0B ldi temp,1<<TOIE0 ; Timer Overflow Interrupt einrichten out TIMSK,temp ; Register TIMSK0 sei ; Timer frei (im SREG-Register) ldi leds,0xFF ldi r18,7 loop: rjmp loop ;Interrupt-ISR TIM0_OVF: push r2 in r2,SREG dec r18 ; wenn <>0 brne ende ; dann raus out PORTB,leds ; sonst Blinken com leds ; und Delayzähler ldi r18,7 ; neu setzen ende: out SREG,r2 pop r2 reti .EXIT Das ist für den Tiny13 32 Arbeitsregister r0-r32 von Speicher 00-1F=dez.0-31 (32 Byte) 64 SFR Register von Speicher 20-5F=dez.32-95 (64 Byte) was schließt sich denn ab Speicher 60 an hoffentlich blicke ich da mal richtig durch, im Tutorial muß ich nochmal lesen. Grüße Rolf
Hallo Leute, ich habe wieder mal mit einem neuen Tiny25 geübt, hier die .asm
1 | ; Projekt-Name: Projekttiny25 Datum: 27.04.2012 |
2 | |
3 | ; Datei: Interrupt-Tiny25-01.asm |
4 | |
5 | ; PORTB,PB0 = LEDrt / PB1 = LEDgn / PB2 = LEDgl (mit #define) |
6 | |
7 | ; PINB,PB3 = sw1 (mit #define) |
8 | ; PINB,PB4 = sw2 (mit #define) |
9 | |
10 | ; AVR: ATTINY25-20PU (DIP) |
11 | |
12 | ; Ablauf: nach sw1 langsames, sw2 schnelles nacheinander Leuchten der Leds. |
13 | |
14 | .INCLUDE "tn25def.inc" ; Deklaration für Tiny25 |
15 | .EQU takt = 1200000 ; Systemtakt 1,2 MHz |
16 | |
17 | ;Definition von Arbeitsregistern |
18 | .def akku=r16 |
19 | .def temp1=r17 |
20 | .def temp2=r18 |
21 | |
22 | ;Definition von PORTB und PINB (SFR-Register) |
23 | #define LEDrt PORTB,PB0 |
24 | #define LEDgn PORTB,PB1 |
25 | #define LEDgl PORTB,PB2 |
26 | |
27 | #define sw1 PINB,PB3 |
28 | #define sw2 PINB,PB4 |
29 | |
30 | |
31 | rjmp reset ; Reseteinsprung |
32 | .ORG OVF0addr ; Interrupt-Vektor |
33 | rjmp TIM0_OVF ; Sprung zur ISR |
34 | |
35 | |
36 | reset: ldi akku,LOW (RAMEND) ; Stapel anlegen |
37 | out SPL,akku |
38 | |
39 | ldi akku,0b00000111 ; PB0-PB2=Outp. |
40 | out DDRB,akku ; Datenrichtungsregister |
41 | ldi akku,0b00011000 ; an PB3 und PB4=PULL UP |
42 | out PORTB,akku |
43 | ;Achtung: cbi bzw. sbi zum schalten der Ports verwenden |
44 | |
45 | ; Timer0 initialisieren: |
46 | ldi akku,1<<CS02|1<<CS00 ; Prescale = 1024 |
47 | out TCCR0B,akku ; Register TCCR0B |
48 | ldi akku,1<<TOIE0 ; Timer Overflow Interrupt einrichten |
49 | out TIMSK,akku ; Register TIMSK (Tiny13=TIMSK0) |
50 | sei ; Timer frei (im SREG-Register) |
51 | |
52 | ; Alle LEDs = AUS |
53 | cbi LEDrt |
54 | cbi LEDgn |
55 | cbi LEDgl |
56 | |
57 | loop: sbic sw1 ; Abfrage PINB,PB3 |
58 | rjmp gehesw2 ; Sprung, wenn sw1=1 |
59 | rjmp langsam |
60 | |
61 | gehesw2: sbic sw2 ; Abfrage PINB,PB4 |
62 | rjmp gehesw1 |
63 | rjmp schnell |
64 | gehesw1: rjmp loop |
65 | |
66 | langsam: sbi LEDrt |
67 | rcall zeit1 ; Pausenzeit ca. 1 Sec. |
68 | sbi LEDgn |
69 | rcall zeit1 |
70 | sbi LEDgl |
71 | |
72 | rcall zeit1 |
73 | cbi LEDrt |
74 | rcall zeit1 |
75 | cbi LEDgn |
76 | rcall zeit1 |
77 | cbi LEDgl |
78 | rcall zeit1 |
79 | rjmp langsam |
80 | |
81 | schnell: sbi LEDrt |
82 | rcall zeit3 ; Pausenzeit ca. 3 Sec. |
83 | sbi LEDgn |
84 | rcall zeit3 |
85 | sbi LEDgl |
86 | |
87 | rcall zeit3 |
88 | cbi LEDrt |
89 | rcall zeit3 |
90 | cbi LEDgn |
91 | rcall zeit3 |
92 | cbi LEDgl |
93 | rcall zeit3 |
94 | rjmp schnell |
95 | |
96 | zeit1: ldi temp1,0x01 ; Zeit ca. 1 Sec. |
97 | pause1: tst temp1 |
98 | brne pause1 ; springe nach pause1: wenn HIGH |
99 | ret |
100 | |
101 | zeit3: ldi temp2,0x05 ; Zeit ca. 3 Sec. |
102 | pause3: tst temp2 |
103 | brne pause3 ; springe nach pause3: wenn HIGH |
104 | ret |
105 | |
106 | ;Interrupt-ISR |
107 | TIM0_OVF: push r2 |
108 | in r2,SREG |
109 | dec temp1 |
110 | dec temp2 |
111 | out SREG,r2 |
112 | pop r2 |
113 | reti |
114 | .EXIT |
Ich wollte aus ; Alle LEDs = AUS
1 | cbi LEDrt |
2 | cbi LEDgn |
3 | cbi LEDgl |
1 | cbi LEDrt|LEDgn|LEDgl |
machen, aber dann sagte der Compiler Error. Ich habe bewußt zwei Arbeitsregister (r17 und r18) in die ISR geschoben, um zu sehen ob das funktioniert und das mit dem Interrupt besser begreifen zu können. Aber dann muß doch bei jedem Durchlauf erst r17 und danach r18 dekrementiert werden, oder? Es macht richtig Freude, mit den Befehlen wie "sbic oder brne" zu arbeiten. Wenn ich an die Bascom-Zeit zurück denke, was bin ich oft an dem "IF" verzweifelt. Grüße Rolf
Rolf Hegewald schrieb: > Ich habe bewußt zwei Arbeitsregister (r17 und r18) in die > ISR geschoben, um zu sehen ob das funktioniert und das mit dem > Interrupt besser begreifen zu können. > Aber dann muß doch bei jedem Durchlauf erst r17 und danach r18 > dekrementiert werden, oder? Ja, klar. Dein µC arbeitet einen Befehl nach dem anderen ab. Aber macht ja nichts. Am Ende der ISR ist der gewünschte Effekt eingetreten: beide Register, r17 und r18 sind dekrementiert. Und da die ISR von nichts anderem unterbrochen wird, sieht es in den Hauptschleifen so aus, als ob beide Register gemeinsam ihren Wert ändern. Die Hauptschleife kann nicht feststellen, welches der beiden Register zuerst dekrementiert wurde. Zu irgendeinem Zeitpunkt wird sie durch den Interrupt unterbrochen und wenn dessen Bearbeitung fertig ist, haben beide Register ihren Wert geändert.
Hi >Ich wollte aus ; Alle LEDs = AUS .... > cbi LEDrt|LEDgn|LEDgl >machen, aber dann sagte der Compiler Error. Kein Wunder. Setze mal deine #defines für LEDrt,LEDgn und LEDgl dort ein. MfG Spess
mh...versteh ich noch nicht. Ich habe diese doch zu Beginn deklariert, und nun soll ich es nochmal machen? Grüße Rolf
Hi
>mh...versteh ich noch nicht.
Aus cbi LEDrt|LEDgn|LEDgl
macht der Preprocessor
cbi PORTB,PB0 | PORTB,PB1 | PORTB,PB2
Und das versteht der Assembler nicht und meckert. Zu Recht.
Mach doch einfach ein Makro draus:
.macro LED_Off
cbi LEDrt
cbi LEDgn
cbi LEDgl
.endmacro
Im Programm schreibst du dann einfach
LED_Off
und fertig.
MfG Spess
Hallo Leute, einen Ortungspieper habe ich vom Pic auf Atmel umgesetzt. Er arbeitet je nach Stellung der 3 DIP-Schalter in den Zeiten 20 30 40 Minuten...dann schreit er im Intervall los. In jedem Kornfeld ist das Flugmodell auszumachen. Die Quelldatei habe ich mal nur auf 20 Minuten zusammen gerückt. ; Datei: zeitmess02.asm ;Datum: 04.05.2012 ; PORTB,Pb0: Ausgang (Pieper) ; PINB,Pb3-Pb4: Eingang (test=b3/sw1=b4) ; Register r17 mit veränderbaren Inhalt ; Register r18 mit festen Wert = 255 ; r17 = 21 = gemessen 1176 Sec. (ca. 20Min.) ; r17 = 32 = gemessen 1789 Sec. (ca. 30Min.) ; r17 = 43 = gemessen 2420 Sec. (ca. 40Min.) ;AVR: Tiny 13 .INCLUDE "tn13def.inc" ;Deklarationen für Tiny13 .EQU takt = 1200000 ;Systemtakt 1,2 MHz .DEF akku = r16 ;r16 in akku benannt #define test PINB,PB3 #define sw1 PINB,PB4 rjmp reset ;Reset-Einsprung .ORG OVF0addr ;Interupt-Vektoren rjmp TIM0_OVF ;Sprung zur ISR reset: ldi akku,LOW(RAMEND) out SPL,akku ldi akku,0b00000001;Bitmuster 0000 0001 out DDRB,akku ;PORTB,PB0 ist Ausgang ldi akku,0b00011110 ;PB1-PB4 = PULLUP out PORTB,akku ; Timer0 initial. ldi akku,1<<CS02|1<<CS00 out TCCR0B,akku ldi akku,1<<TOIE0 out TIMSK0,akku sei ; alle 0,22 Sec. Interrupt Overflow loop: ; Abfrage von test und sw1 auf LOW geh: sbic test ;PINB,PB3 = Taste rjmp gehsw1 ;Sprung nach gehsw1 rjmp piepen ;****************************** ; Zeitvorgabe als Beispiel für 1200 Sec. = 20 Min. gehsw1: sbic sw1 ; PINB,PB4 = DIP-Schalter1 rjmp geh ; Sprung nach geh, wenn sw1=1 ldi r18,255 ; dezimal = 255 sprung2: rcall variable ; nach r17= dezimal 22 dec r18 ; r18 - 1 tst r18 brne sprung2 ; Sprung, wenn r18=1 rjmp piepen ; Sprung, wenn r18=0 ;******************************* piepen: sbi PORTB,PB0 ; Piepen = EIN rcall zeit2 ; Zeit ca. 2 Sec cbi PORTB,PB0 ; Piepen = AUS rcall zeit3 ; Zeit ca. 3 Sec rjmp piepen rjmp loop ; Schleife ;******************************* ;0,22x9 = 1,98 Sec. zeit2: ldi r17,9 ; dezimal = 9 pause2: tst r17 ; teste r17 auf Null brne pause2 ; Sprung, wenn r17=1 ret ;0,22x15 = 3,3 Sec. zeit3: ldi r17,15 ; dezimal = 15 pause3: tst r17 ; teste r17 auf Null brne pause3 ; Sprung, wenn r17=1 ret ;******************************* variable: ldi r17,22 ; dezimal = 22 fest: tst r17 ; teste r17 auf Null brne fest ; Sprung, wenn r17=1 ret ;Interrupt-ISR TIM0_OVF: push r2 in r2,SREG dec r17 out SREG,r2 pop r2 reti .EXIT so, ich mußte eine Menge formatieren. Obwohl ich in Tools Optionen Edit auf Tab=1 und den Haken gesetzt hatte..versteh ich nicht. An den ganzen Timer0 Ablauf begreif ich eins immer noch nicht. Ich habe die Register R17 u. R18 am arbeiten. R18 hat den festen Wert von 255, R17 für 20 Minuten = 22 Dadurch, daß ich Prescale auf 1024 gesetzt habe, komme ich auf ca. 0,22 Sec. = 1Tick Mit einem Zeitmesser kam ich auf genau 1176 Sec. Stimmt ja auch alles, wenn man Toleranzen mit einbezieht. Aber! Ich gehe mal von aus und aktiviere vor Ubatt sw1. Nun stecke ich die Versorgung an...der Timer läuft los und die Hauptroutiene, die in Geschwindigkeit ankommt wo r18 auf 255 geladen wird...dann weiter sprung2: wo über rcall variable r17 auf 22 geladen wird. kommt zurück nach r18-1 und bald ist 255 zu Null angekommen. Das alles läuft mit einer Windeseile ab, da denkt der Timer doch noch garnicht daran, das Ganze anhalten zu wollen, und R17 um -1 zu verringern. Meiner Meinung steckt doch hier gar kein syncroner Ablauf drin R17 und R18 laufen wild durcheinander, oder? Das ich trotzdem auf fast genau 20 Min. komme wundert mich! Grüße Rolf
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.