Hallo zusammen, ich versuche mich gerade, in das Thema "Timer" einzuarbeiten. Dazu nutze ich das das AVR Tutorial. Als Controller nutze ich einen Tiny2313 und habe das Programm in Assembler geschrieben. Ich habe soweit alles versucht, an den Tiny2313 anzupassen. Aber leider ohne Erfolg... So wie ich es jetzt habe, leuchten bei mir die LEDs dauerhaft. Kleine Info zur Hardware: Ich nutze das STK 500. Die Frequenz habe ich wie im Programmbeispiel im Tutorial auf 4 MHz eingestellt. Vielleicht kann mal jemand einen Blick darüber werfer, warum das nicht funktioniert. Bin für jede Hilfe dankbar ! :) Möchte dann gerne mit dem Programm ein bißchen das Thema Timer kennen lernen und evtl. mal die Signale eines RC Empfänger auswerten. Daher der Name PPM-Test. Viele Grüße Sven
So, das "Problem" hat sich gelöst... und ich habe wieder einen Teil verstanden. Ich hatte den Vorverteiler auf 1 stehen. Also viel zu schnell. Da kommt das Auge nicht mit. Aus diesem Fehler habe ich auf jeden Fall was gelernt. ;)
Hallo Sven, ich kämpfe auch schon lange mit den Timer0 für Tiny2313. Leider gibt mein Buch nur Hinweise zum Mega8. Hier mal mein Quelltext:
1 | ; Datei: kran04.asm |
2 | |
3 | ; PORTB: Ausgabe |
4 | ; PortD: Eingänge |
5 | ;Datum: 05.12.2011 |
6 | |
7 | ;AVR: Tiny 2313 |
8 | |
9 | .INCLUDE "tn2313def.inc" ; Deklarationen für Tiny2313 |
10 | .EQU takt = 1000000 ; Systemtakt 1 MHz |
11 | .DEF akku = r16 ; Arbeitsregister r16 in akku benannt |
12 | .CSEG ;Programm - Flash |
13 | rjmp start |
14 | .ORG OVF0addr ;Timer0 Überlauf-Einsprung |
15 | rjmp timer |
16 | .ORG $13 |
17 | |
18 | ;Vorbereitung: Stapel anlegen, PortB=Out, PortD=Inp. |
19 | |
20 | start: ldi akku,LOW (RAMEND) |
21 | out SPL,akku |
22 | ldi akku,$ff ; Bitmuster 1111 1111 |
23 | out DDRB,akku ; Port B ist Output |
24 | ldi akku,$00 ; Bitmuster 0000 0000 |
25 | out DDRD,akku ; Port D ist Input |
26 | |
27 | ;Timer0 und Interrupt voreinstellen |
28 | ldi akku,0b00000101 ;Prescale = 1024 |
29 | out TCCR0,akku ;akku in Steuerreg. TCCR0 |
30 | in akku,TIMSK |
31 | ori akku,1 << TOIE0 |
32 | out TIMSK,akku |
33 | sei |
34 | |
35 | ;Arbeitsbeginn |
36 | |
37 | ldi akku,0b00000111 ; Bitmuster 0000 0111 |
38 | out PORTB,akku ; Pb0 - Pb2 = High |
39 | |
40 | |
41 | timer: ldi r16,100 |
42 | warte: dec r16 |
43 | brne warte |
44 | ldi r16,0b00000001 |
45 | out PORTB,r16 |
46 | reti |
Irgendwas muß mit den Vorbereitungen zum 2313 nicht stimmen. 3 LED am Port (B0 bis B2) leuchten dauerhaft. Was mache ich nur verkehrt! Worin erkennt das Interrupt, daß es nach dem Timerdurchlauf von 256 nach timer: springen soll. Bei Bascom gab es Config Timer0 = Timer,Prescale = 1024 On Timer0 timer Enable Timer0 Grüße Rolf
Hi >Was mache ich nur verkehrt! > .DEF akku = r16 ; Arbeitsregister r16 in akku benannt >timer: ldi r16,100 Entweder du benennst r16 mit akku, dann hat r16 in deinem Programm nichts zu suchen. Oder du bleibst bei r16. >;Arbeitsbeginn > ldi akku,0b00000111 ; Bitmuster 0000 0111 > out PORTB,akku ; Pb0 - Pb2 = High >timer: ldi r16,100 >.... Rate mal was dein ATTiny nach dem 'out PortB,akku' macht. Außerdem: -Kein SREG im Interrupt gesichert -Warten im Interrupt MfG Spess
>> ldi akku,0b00000111 ; Bitmuster 0000 0111 >> out PORTB,akku ; Pb0 - Pb2 = High > >>timer: ldi r16,100 >>.... > > Rate mal was dein ATTiny nach dem 'out PortB,akku' macht. @Rolf Ich denke der Hinweis war etwas zu subtil, vor allen Dingen wenn man ihn im Zusammenhang mit dem vorhergehenden Hinweis (Akku/R16) sieht. Daher etwas konkreter: Wo ist deine Hauptschleife? JEDES Programm braucht eine Hauptschleife, in der der Programmfluss verbleibt, solange der µC unter Strom steht! Es ist das, was in BASCOM das ... do ... Programmlogik loop war.
Hallo Leute, erst mal meinen Dank für Eure Infos! Ich habe gelesen und nochmals gelesen über Timer0 vom 2313, und anschließendes Interrupt. Das Register TCCR0 hab ich voll im Griff..eingestellt auf Prescale 1024. Das Zählregister TCNT0 auch überschaubar..wird inkrementiert bei Hoch- laufen, das macht es von alleine..also nicht wichtig. Das Überlaufregister TIFR..Bit0=TOVO wird gesetzt bei Überlauf. Das Register TIMSK muß Bit0 = TOIE0 gesetzt werden. Dieses hat außer I=sei höchste Priorität. Wie aus den Bild zu sehen, habe ich alles korrekt vorgegeben. (hoffentlich gut erkennbar) 3 Leds habe ich zuvor an PORTB/Pin0 - 2 dunkel gesetzt. Und es tut sich nichts, sie bleiben dunkel; über die ISR "timer" müßten sie alle 3 zum leuchten kommen, oder? An der Hardware kann es nicht liegen, denn sie lassen sich ohne Timer problemlos steuern. Jetzt sind die Experten gefragt! Grüße Rolf Im Buch steht: TOVO=1 (Überlauf)und TOIE0=1 und I=1 (sei)wird der Timer0 Interrupt ausgelöst.
Bitte Programmtext immer als Text und nicht als Bild. Unterschied: Aus einem Text kann ich mir mit Cut&Paste Teile ausschneiden, auf die ich Antworten möchte. Bei einem Bild kann ich das nicht. Weiterer Unterschied: Bei einem Text hängst DU einfach dein Programmfile als Attachment an, bei einem Bild hast du mehr Arbeit. Du hast 8 LED am Port B hängen? Dann ist es immer eine gute Idee, wenn du nicht alle 8 entweder auf 0 oder auf 1 stellst, sondern erst mal zb abwechselnd auf 0 und 1 ldi led,0b10101010 auf die Art brennen unabhängig davon, ob deine LED jetzt alle nach Masse oder alle nach Vcc verschaltet sind, immer auf jeden Fall 4 LED
Hi Nimm bitte deine ASM-Datei als Anhang. >Und es tut sich nichts, sie bleiben dunkel; über die ISR "timer" >müßten sie alle 3 zum leuchten kommen, oder? Kommt darauf an, wie die Leds angeschlossen sind. Der erste Overflow kommt nach etwa einer viertel Sekunde. Danach passiert nichts mehr. >Das Register TIMSK muß Bit0 = TOIE0 gesetzt werden. In meinem Datenblatt ist TOIE0 Bit1. Deshalb ist ldi akku,0b00000001 auch Unsinn. Mit ldi akku,1<<TOIE0 passiert das nicht. MfG Spess
> Jetzt sind die Experten gefragt!
Solche Dinge lassen sich aber auch noch im Simulator wunderbar testen.
Dort kann man dann auch in der Registerübersicht wunderbar sehen, welche
Bits man wirklich gesetzt hat und wie der Timer hochzählt.
Hinweis: Für den Simulator den Prescaler auf 1 setzen, sonst tippt man
sich die Fingerkuppen wund.
> ldi akku,0b00000111 ; Bitmuster 0000 0111 > out PORTB,akku ; Pb0 - Pb2 = High Das macht er und dann macht er hier weiter (ldi r16,100) und schaltet Sie wieder ein paar 100µS später wieder aus > >timer: ldi r16,100 >warte: dec r16 > brne warte > ldi r16,0b00000001 > out PORTB,r16 > reti mach mal ne Endlosschleife dazwischen damit er nicht in den Handler reinläuft (loop: rjmp loop): ldi akku,0b00000111 ; Bitmuster 0000 0111 out PORTB,akku ; Pb0 - Pb2 = High loop: rjmp loop timer: ldi r16,100 warte: dec r16 brne warte ldi r16,0b00000001 out PORTB,r16 reti
Hallo Spess, Erfolg....jetzt leuchten die 3 Leds an Pb0 bis PB2 nach Änderung wie in Deinem Vorschlag. ;Timer0 und Interrupt voreinstellen ldi akku, 0b00000101 ;Prescale = 1024 out TCCR0, akku ;akku in Steuerreg. TCCR0 ldi akku,(1<<TOIE0) ; Register TIMSK (Bit0=1) out TIMSK, akku ; Interrupt frei gegeben sei ; I=sei (Inter. frei) evtl. muß ich bei Prescale auch eine Änderung durchführen, denn das macht mich dann mit akku, xxxxxx auch stutzig! Wie soll ich das mit 0101 vorgeben =1024 Die Leds hängen an Plus über NPN gesteuert, d.h. High=LED Pin=1 Allen Anderen antworte ich morgen! grüße Rolf noch was: muß die Anweisung 1<<TOIE0 in Klammern?
Hi >evtl. muß ich bei Prescale auch eine Änderung durchführen, >denn das macht mich dann mit akku, xxxxxx auch stutzig! >Wie soll ich das mit 0101 vorgeben =1024 Das Bitmuster stimmt dort schon. Allerdings ist auch hier ein ldi r16, 1<<CS2|1<<CS0 informativer. >noch was: muß die Anweisung 1<<TOIE0 in Klammern? Nicht unbedingt. Aber stören tut es auch auch nicht. MfG Spess
Nur mal so als Anmerkung: spess53 schrieb: > ldi r16, 1<<CS2|1<<CS0 Das was Spess hier schreibt (Bitmanipulation) steht hier http://www.mikrocontroller.net/articles/Bitmanipulation sehr gut beschrieben. Welche Bits sich genau hinter CS2, CS0 oder auch TOIE0 verbergen findest du in der "tn2313def.inc" beschrieben. Gruß Steffen
Hi >Nur mal so als Anmerkung: >.... Das Problem ist das die meisten ,die hier mit Assemblerproblemen auftauchen, blutige Anfänger sind. Da liegt das Interesse erst mal darin, ein meist recht begrenztes, Ziel irgendwie zu erreichen. Die Form ist recht egal. An Lesbarkeit, Wartbarkeit oder gar Wiederverwendbarkeit des Codes wird kein Gedanke verschwendet, zumal die Mittel dazu (AVR-Assembler->Directives/Expressions oder AVR-Assembler->Preprocessor und anderes) weitestgehend unbekannt sind. MfG Spess
Hallo Spess und Seffen, danke für Eure Antwort noch zu später Stunde. Frage: was ist das für ein Längsstrich zwischen 1<<CS2 und 1<<CS0, kann sowas auf dem Laptop nicht finden..einen / ja! Zu Karl Heinz: ok, Quelldatei als Text und nicht Bild. 3 Leds liegen gegen Plus über 3 NPN Trans. an PB0-PB2 Der erste Durchbruch ist geschafft, nun geht es ins Eingemachte. Grüße Rolf
Hi >Frage: was ist das für ein Längsstrich zwischen 1<<CS2 und 1<<CS0, >kann sowas auf dem Laptop nicht finden..einen / ja! Sollte auch auf deinem Laptop mit AltGR + <>-Taste (links neben Y) erreichbar sein. MfG Spess
Rolf Hegewald schrieb: > Frage: was ist das für ein Längsstrich zwischen 1<<CS2 und 1<<CS0, Der befindet sich normalerweise (deutsche Tastatur) auf der Taste mit < und >. Erreichbar über "Alt Gr" zusammen mit <. Wird in der Regel durch einen unterbrochenen senkrechten Strich dargestellt. Volkmar
|| ok, hat geklappt! Nun steh ich vor einem Wahnsinns-Projekt, das ich in Hamburg im Miniatur-Wunderland (Modelleisenbahn) gesehen habe und im Jahr 2011 umgesetzt. Es handelt sich um einen Contenerkran der Fa. Brawa mit 2 Motoren. 1. Motor AUF/AB 2. Motor LINKS/RECHTS Das alles läuft mit einem PIC in Pic-Assembler. Mein Wunsch war es, mit Atmel, aber nicht mit Bascom umzusetzen, sondern wieder Assembler. Die Motoren zu steuern, ist nicht das Problem, dagegen Pausenzeiten in verschiedenen Zeitabständen schon. Mit den Pic habe ich 3 Register geladen und inkrementiert, sehr auf- wendig. Also habe ich mich mit den Timer0 angetan. Das Blockschema sieht so aus: 1. Motor AUF=EIN 2. Pause1 ;ca. 5 Sec. 3. Motor AUF=AUS 4. Pause1 5. Motor LINKS=EIN 6. Pause2 ;ca. 20 Sec. 7. Motor LINKS=AUS 8. Pause1 9. Motor AB=EIN 10. Abfrage über Lichtschranke usw. dann geht es wieder aufwärts, rechts und ab. Es kommen also zwei Zeiten in Betracht. Eine mit 5 Sec. die andere mit 20 Sec. Nun habe ich schon in der ISR herumgefummelt...aber! ;Timer0 und Interrupt voreinstellen ldi akku, 0b00000101 ;Prescale = 1024 out TCCR0, akku ;akku in Steuerreg. TCCR0 ldi akku,(1<<TOIE0) ; Register TIMSK (Bit0=1) out TIMSK, akku ; Interrupt frei gegeben sei ; I=sei (Inter. frei) ;Arbeitsbeginn loop: rjmp loop timer: ldi leds,0b00000001 out PORTB,leds ;Register r17 ldi akku,0b00000111 dec akku brne gehe ;Sprung, wenn akku nicht Null ldi leds,0b00000100 out PORTB,leds ldi akku,0b00000111 dec akku brne gehe gehe: reti Was meint Ihr, soll ich bei der alten Register-Methode bleiben, oder mich durchkämpfen. Grüße Rolf
Rolf Hegewald schrieb: > Was meint Ihr, soll ich bei der alten Register-Methode bleiben, > oder mich durchkämpfen. > Auf jeden Fall: Timer Timer sind deine Arbeitspferde. Ohne sie sind komplexere Programme nicht sinnvoll machbar. > Nun habe ich schon in der ISR herumgefummelt...aber! Aber was? > > ;Timer0 und Interrupt voreinstellen > ldi akku, 0b00000101 ;Prescale = 1024 > out TCCR0, akku ;akku in Steuerreg. TCCR0 > ldi akku,(1<<TOIE0) ; Register TIMSK (Bit0=1) > out TIMSK, akku ; Interrupt frei gegeben > sei ; I=sei (Inter. frei) > > ;Arbeitsbeginn > > loop: rjmp loop > > > timer: ldi leds,0b00000001 > out PORTB,leds ;Register r17 > ldi akku,0b00000111 > dec akku was machst du da? Wenn du vorher 7 in den Akku lädst (warum schreibst du dann nicht auch einfach ldi akku, 7 ist doch viel einfacher zu lesen. Ob dezimal oder hexadezimal oder binäre Schreibweise benutzt wird, hängt davon ab, wofür die Zahl steht. Man wählt immer die Schreibweise, die in der gegebenen Situation die natürlichste ist. Du willst etwas zählen, also wird dezimal die natürliche Schreibweise sein, denn du denkst dezimal) und diese 7 dann um 1 runterzählst, dann steht 6 im akku. Immer. Denn bei jedem Aufruf der Timer-ISR lädst du ja wieder 7 in den Akku. > brne gehe ;Sprung, wenn akku nicht Null das kann daher nie 0 sein > ldi leds,0b00000100 > out PORTB,leds > ldi akku,0b00000111 > dec akku > brne gehe > gehe: reti Du hast das Prinzip noch nicht verstanden. In der ISR realisierst du die Dinge, die nach einer gewissen Zeiteinheit(!) getan werden müssen. Das AUfsetzen bzw. Einstellen der Umgebung machst du ausserhalb. Die ISR ist wie das Ticken einer Uhr und bei jedem Tick siehst du nach bzw. bestimmst du, was genau jetzt, zu diesem Zeitpunkt, bei diesem Tick der Uhr, getan werden muss. Du denkst noch in Warteschleifen! Und genau das ist der falsche Ansatz. Du musst in zeitlichen Ereignissen denken. Tick ... 1 Sekunde vergangen, was gibt es jetzt zu tun? Tick ... wieder 1 Sekunde vergangen, ist jetzt etwas zu tun? Tick ... die nächste Sekunde ist abgelaufen, ich könnte mal den Motor einschalten Tick ... 1 Sekunde aufs Konto gutschreiben, ansonsten gibt es nichts Tick ... noch eine Sekunde. Heissa, ich wollte doch nach 2 Sekunden den Motor wieder ausschalten! Vor 2 Ticks hab ich ihn ein- geschaltet, also ist jetzt der Zeitpunkt, ihn auszuschalten Tick ... .... Grundsätzlich wirst du Ticks zählen müssen, weil du ja längere Zeiten als 1 Sekunde brauchst. Nehmen wir mal an, dass der Tick jede Sekunde kommt (du also genau alle 1 Sekunde einen Aufruf der ISR hast). Was musst du tun? du zählst 1 zu deiner Anzahl an Ticks dazu, weil du ja längere Zeiteinheiten als 1 Sekunde haben willst. Wenn du 20 derartige Ticks abzählst, dann sind 20 Sekunden vergangen, wenn du bei 20 angelangt bist (du kannst natürlich auch von 20 runterzählen und wenn du bei 0 bist, sind 20 Sekunden vergangen. Kommt aufs gleiche raus. Runterzählen ist meist einfacher) Solange du deine Sekunden nicht erreicht hast, gibt es nichts zu tun -> verlassen der ISR Sind die Sekunden erreicht, dann musst du zb etwas schalten zb LED ein oder LED aus. Dazu wirst du irgendeinen Mechanismus brauchen, der dir sagt ob jetzt ein oder ausgeschaltet werden soll. Du kannst zb das Portregister befragen ob zur Zeit eingeschaltet ist und dann daraus deine Schlüsse ziehen. Wie auch immer, auf jeden Fall muss dann deine Tickzählerei wieder von vorne beginnen. D.h. du setzt den Tickzähler wieder zurück (auf 0 wenn du ihn erhöhst, auf zb 20 wenn du mit der Methode runterzählen arbeitest) Und eines solltest du auf jeden Fall machen: In der ISR wird auf jeden Fall das Status-Register SREG gesichert! Das ist lebenswichtig, weil du nie vorhersehen kannst, welche andere Anweisungssequenz in der Hauptschleife durch die ISR unterbrochen wird. Zur Zeit ist deine Hauptschleife noch leer loop: rjmp loop aber das wird nicht immer so bleiben!
Rolf Hegewald schrieb: > Was meint Ihr, soll ich bei der alten Register-Methode bleiben, > oder mich durchkämpfen. Es ist einfacher als Du jetzt denkst... Lies Dich mal hier durch: http://www.hanneslux.de/avr/index.html Ist zwar alles schon etwas älter, hilft Dir aber sicherlich beim Verstehen. Ohne Timer komme ich eigentlich gar nicht zurecht... ...
Hallo, meinen Dank besonders an Karl Heinz für seine vielen aufklärenden Worte. Wenn ich das mit dem Tick richtig verstanden habe, würde bei mir eine Zeit von: (ich gehe mal von 1MHz Systemtakt aus) 1 ys x 1024 = 1,024 ms x 256 = 262,144 ms etwa 0,26 Sec. Auf die Genauigkeit kommt es jetzt nicht drauf an, nur vom Prinziep. Würde ich ein Register in der ISR auf $0F setzen und zu Null runter zählen, hätte ich ein Ergebnis von 0,26 x 15 = 3,9 Sec. Was habe ich nun in der Zwischenzeit gemacht..also wieder gelesen! Und dazu ist mir das von Hannes eine große Hilfe gewesen. D.h. ich muß den Tick EIN und Ausschalten können, bzw. eine loop Arbeitsschleife aufbauen. Das Ganze sieht jetzt so aus: .INCLUDE "tn2313def.inc" ; Deklarationen für Tiny2313 .EQU takt = 1000000 ; Systemtakt 1 MHz .EQU laufein = 1<<CS02|1<<CS00 .EQU laufaus = 0<<CS02|0<<CS00 .DEF flashein = r7 .DEF flashaus = r8 .DEF akku = r16 ; Arbeitsregister r16 in akku benannt .DEF warte4 = r17 ; für Pausenzeit ca. 4 Sec. .DEF warte15 = r18 ;für Pausenzeit ca. 15 Sec. .ORG 0x0000 rjmp start ;Sprung zu Vorbereitung .ORG OVF0addr ;Timer0 Überlauf-Einsprung rjmp timer ;Sprung zur ISR start: hier werden nur PortB als Ausg. gesetzt. Timer 0 voreinstellen ;Timer0 und Interrupt voreinstellen ldi akku,(1<<TOIE0) ; Register TIMSK (Bit0=1) out timsk,akku ; Interrupt frei gegeben sei ; I=sei (Inter. frei) ;Timer0 EIN-AUSschalten: ldi akku,laufein ;Bitm. 0101=1024 out flashein,akku ;in r7 Inhalt von akku ldi akku,laufaus ;Bitm. 0000=Timer Stopp out flashaus,akku ;in r8 Inhalt von akku ; out TCCR0,flashein = Timer EIN / out TCCR0,flashaus = Timer AUS Jetzt beginnt der eigentliche Arbeitsbeginn: loop: rcall pause4 ;Pause 4 Sec. rcall ein ;Motor linksauf-EIN rcall pause4 ;Pause 4 Sec. rcall halt ;Motor linksauf-HALT rjmp loop hier die Unterpr. pause4: warte4 $0F ;Bitmuster 0b00001111 in r17 out TCCR0,flashein ;Timer = EIN ende4: out TCCR0,flashaus ;Timer = HALT ret ein: ldi akku,$02 ; r16 = 02 out PORTB,akku ret halt: ldi akku,$00 out PORTB,akku ret und zum Schluß die ISR (und hier bin ich mir mit den brne noch etwas unsicher) timer: dec warte4 brne laufe laufe: rjmp ende4 reti .EXIT mit der Sreg muß ich mich noch antun. Ganz schön komplex..das Ganze, aber da blickt Ihr doch durch, oder? Aber ich komme aus einem Fehler nicht raus, der so aussieht. D:\Tiny2313\krantest2.asm(64): error: syntax error, unexpected INTEGER, expecting ':' Also wie gesagt, es läuft noch nicht! Grüße erst mal Rolf
Hi >Ganz schön komplex..das Ganze Ich habe Assemblerprogramme, die sind 200x größer. Da fängt es langsam an komplex zu werden. >aber da blickt Ihr doch durch, oder? Du must durchblicken. Fangen wir mal an: -Kein Stack initialisiert -Kein SREG gesichert -Sprung aus der Interruptroutine > dec warte4 > brne laufe >laufe: rjmp ende4 Unsinn. Egal ob Null oder nicht kommt das Programm zu 'laufe'. > warte4 $0F ;Bitmuster 0b00001111 in r17 Was soll das sein? >out flashein,akku ;in r7 Inhalt von akku heißt: out r7,r16 und das ist falsch. Richtig mov r7,r16 Das ist das, was ich auf die Schnelle gefunden habe. Aber da sind mit Sicherheit noch andere Eier vesteckt. MfG Spess
Rolf Hegewald schrieb: > D.h. ich muß den Tick EIN und Ausschalten können, bzw. eine loop > Arbeitsschleife aufbauen. Damit wirst Du nicht viel weiter kommen. Schau Dir mal meine Feuerwerks-Zünduhr an, da werden zu bestimmten Terminen bestimmte Aktionen ausgeführt: http://www.hanneslux.de/avr/zuenduhr/index.html http://www.hanneslux.de/avr/zuenduhr/ZndUhr01.asm Nur mit Zeit gesteuert wird Dein Kran sich aber verhedern, da würde ich auch noch mit Endschaltern (Lichtschranken) arbeiten, die signalisieren, dass eine bestimmte Position erreicht ist. Dann würde ich mir ein "Datensatzformat" ausdenken, z.B. 2 Bytes für die Verzögerung bis zum nächsten Schritt, 1 Byte für das Bitmuster, was zu tun ist, 1 Byte für das Bitmuster, welcher Endschalter die Sache vorzeitig beendet. Diese Datensätze kommen dann ins EEPROM des AVRs und können jederzeit nach Bedarf berändert werden, ohne das Programm (im Flash) verändern zu müssen. Mit einem (frei durchlaufenden ) Timer generiert man nun einen Basistakt von z.B. 10ms. In diesem findet erstmal die Entprellung der Endschaltereingänge statt, sowie auch das Herunterzählen der gerade laufenden Zeitverzögerung. Wird die laufende Verzögerung 0, dann wird ein Merker (Flag, Semaphore, Bitvariable,...) gesetzt, der dem Hauptprogramm mitteilt, dass der laufende Arbeitsgang zu Ende ist. Das Hauptprogramm prüft nun dieses "FertigMaisTeer-Flag" und macht Folgendes, falls es gesetzt war: FertigMaisTeer-Flag löschen (Jobauftrag entwerten, Job ist ja in Arbeit) Nächsten Datensatz aus EEP holen, Wartezeit-Zähler auf neuen Startwert setzen Ausgangs-Bitmuster ausgeben (also Schalthandlung ausführen) Eingangs-Bitmaske aktualisieren (welcher Eingang darf Abbruch auslösen) Endschalter-Flags löschen (alte Auslösungen entwerten) Weiterhin prüft die Hauptschleife die Endschalter-Flags und setzt bei Betätigung einfach mal den FertigMaisTeer-Merker, um den Arbeitstakt vorzeitig zu beenden. Vereinbart man, dass 0xFFFF (leeres EEPROM) als Verzögerungszeit ungültig ist und stattdessen als Rücksetzen des Arbeitstaktzählers auf den Anfang interpretiert wird, so kann man das Bewegungsprogramm als endlosen Ring ausführen. Baut man noch Routinen zum Update des Bewegungsprogramms per RS232 ein, dann kan das Bewegungsprogramm jederzeit von einem PC (auch über USB-RS232-Wandler) ersetzt werden, mindestens hunderttausend mal. Schreibt man sich für den PC noch ein Programm (GUI?) zum Editieren des Bewegungsprogramms und Verwalten eines Archives mit Bewegungsprogrammen sowie den Routinen zum Senden eines Bewegungsprogramms an den AVR der Kransteuerung, dann kann man den Kran recht flexibel zappeln lassen. Baut man in die Kommunikation zwischen PC und AVR neben den Kommandos zum EEP-Update noch ein paar Kommandos zur Direktsteuerung ein, dann kann man das Ding auch mal per Mausklick steuern. Ist mE kreativer, als nur ein Detail vom MiWuLa kopieren zu wollen. So, nun mach' was Du willst, aber mach' was (oder auch nicht...) ...
Hi Noch etwas: Der Timer0 besitzt TCCR0A und TCCR0B, aber kein TCCR0. Der Assembler akzeptiert TCCR0 nur weil er diese Bezeichnung nach TCC0B umleitet. Nimm bitte die richtigen Registerbezeichnungen. MfG Spess
spess53 schrieb: > was ich auf die Schnelle gefunden habe. Ich habe garnicht erst gesucht, da ich das Konzept für suboptimal halte. ...
Hi
>Ich habe garnicht erst gesucht, da ich das Konzept für suboptimal halte.
Nicht nur du.
MfG Spess
Ich seh das wie ihr. Und ich bin mir ziemlich sicher, dass die Jungs im MiWuLa da Endschalter (zb in Form von Gabellichtschranken) zur Fahrkontrolle eingebaut haben. Die können es sich doch gar nicht leisten, dass sich der Kran jeden 2.ten Tag verheddert. Das Zeug muss laufen! Ich bin eigentlich nur deswegen auf den Timer aufgesprungen, weil Timer nun mal ein wichtiges Arbeitsmittel sind. So wie der 2.te Gang beim Auto :-)
*kopfkratz* schrieb: > Ich würde den 1. bevorzugen... Ich auch, aber Kalle fährt sicherlich keinen Kleinwagen... ;-))) ...
mh...nun steh ich da! erst mal zu spess: sicher habe ich den Stack initial. Hab es hier weggelassen. Das mit TCCR0B und mov r7,r16 zieh ich mir nochmal rein. Ich denke, wenn ich zu Beginn r16 in akku benenne, soll ich dann nicht später mit r16 weiter machen. Am Anfang stehen die .DEFxxx Bezeichnungen. Nochmals zu diesen Kran: In AUF Rechts Linksbetrieb sind Endlagenschalter eingebaut, aber um die brauch ich mich garnicht zu kümmern. Der Motor wird autom. ab- geschaltet. Egal ob 4 oder 5 Sec. die Zeit muß nur so lang sein, daß die Endlage auch erreicht wird. Die Abwärtsfahrt zum Contener habe ich mit einem Readkontakt gelöst. Aber soweit bin ich noch lange nicht. Vergessen wir doch mal das Thema "Kran" und nehmen eine einzige LED an PortB,1 gegen Plus über NPN kleines Quellprogramm: loop: pause4 (ca. 4 Sec.) PB1 = EIN pause4 PB1 = AUS rjmp loop Ich muß doch den Timer0 EIN bzw. AUSschalten, oder sollte ich das mit sei machen? Nun lasst mich doch nicht so zappeln, es fehlt nur noch ein Tick bei mir, dann kommt der Durchbruch. Meine ISR timer: dec warte4 brne rjmp ende4 reti Darf ich den rjmp ende4 innerhalb der ISR machen oder nicht Bin gespannt, ob ich es schaffe, die eine LED zum blinken zu bringen. Grüße Rolf
Rolf Hegewald schrieb: > Darf ich den rjmp ende4 innerhalb der ISR machen oder nicht Nein, darfst Du nicht. > ende4: out TCCR0,flashaus > ret Das ret würde zwar auch aus der ISR zurückkehren, aber nur reti setzt das I-Flag in SREG wieder und erlaubt wieder Interrupts. Besorg' Dir erst mal das Instruction Set Pdf von Atmel. Rolf Hegewald schrieb: > Nun lasst mich doch nicht so zappeln, es fehlt nur noch ein Tick > bei mir, dann kommt der Durchbruch. Sagte der Blinddarm :D
Rolf Hegewald schrieb: > In AUF Rechts Linksbetrieb sind Endlagenschalter eingebaut, aber um > die brauch ich mich garnicht zu kümmern. Der Motor wird autom. ab- > geschaltet. Egal ob 4 oder 5 Sec. die Zeit muß nur so lang sein, > daß die Endlage auch erreicht wird. Ist zwar jetzt egal, aber für die Zukunft: Für sowas nimmt man der Einfachheit halber gleich die Endlagenschalter her. Ist doch viel einfacher. > Ich muß doch den Timer0 EIN bzw. AUSschalten, oder sollte ich das mit > sei machen? Der Timer läuft STÄNDIG Den stellst du am ANfang ein, dann kommt irgendwann der sei (wodurch die Timer ISR ab sofort dann regelmässig aufgerufen wird) und dann gehts im Hauptprogramm in die Hauptschleife hinein. > Meine ISR > timer: > dec warte4 Lies es mir von den Lippen ab: In einer ISR wird nicht gewartet! Der Programmaufbau ist so
1 | rjmp start |
2 | |
3 | Interrupt Vektoren |
4 | |
5 | start: |
6 | Stack Initialisieren |
7 | |
8 | Timer initialisieren |
9 | |
10 | Zustand des Krans sei gleich "fahre nach links" |
11 | Wartezeit für diesen Zustand sei 4 Sekunden |
12 | |
13 | sei |
14 | |
15 | loop: rjmp loop |
16 | |
17 | |
18 | Timer ISR: |
19 | SREG sichern |
20 | |
21 | Wartezeit um 1 runtzählen |
22 | ist die Wartezeit 0? |
23 | Nein -> zum Ende der ISR |
24 | |
25 | ; die Zeit für die Bewegung ist abgelaufen, wie gehts weiter |
26 | erst mal Motor aus |
27 | |
28 | welches ist der 'Zustand' des Kranes? |
29 | |
30 | "fahre nach links" |
31 | Neuer Zustand ist "fahre nach unten links" |
32 | Wartezeit sei 10 Sekunden |
33 | entsprechenden Motor ein |
34 | -> zum Ende der ISR |
35 | |
36 | "fahre nach unten links" |
37 | Neuer Zustand ist "fahre nach oben links" |
38 | Wartezeit sei 10 Sekunden |
39 | entsprechender Motor ein |
40 | -> zum Ende der ISR |
41 | |
42 | "fahre nach oben links" |
43 | Neuer Zustand ist "fahre nach rechts" |
44 | Wartezeit sei 4 Sekunden |
45 | entsprechender Motor ein |
46 | -> zum Ende der ISR |
47 | |
48 | "fahre nach rechts" |
49 | Neuer Zustand ist "fahre nach rechts unten" |
50 | Wartezeit sei 10 Sekunden |
51 | entsprechender Motor ein |
52 | -> zum Ende der ISR |
53 | |
54 | "fahre nach rechts unten" |
55 | Neuer Zustand ist "fahre nach rechts oben" |
56 | Wartezeit sei 10 Sekunden |
57 | entsprechender Motor ein |
58 | -> zum Ende der ISR |
59 | |
60 | "fahre nach rechts oben" |
61 | Neuer Zustand ist "fahre nach links" |
62 | Wartezeit sei 4 Sekunden |
63 | entsprechender Motor ein |
64 | -> zum Ende der ISR |
65 | |
66 | Ende der ISR: |
67 | SREG wieder herstellen |
68 | reti |
> Bin gespannt, ob ich es schaffe, die eine LED zum blinken zu bringen. Einfach ein Register in der ISR um 1 runterzählen. Wenn es danach nicht 0 ist, wird die ISR wieder verlassen. Ist es 0, dann schaltest du die LED um und belegst das Register wieder mit einem Zählwert vor, von dem aus runtergezählt wird. Wie gross dieser Zählwert ist, hängt davon ab wie schnell die LED blinken soll und wie oft die ISR aufgerufen wird. Das wiederrum hängt davon ab, wie schnell der Timer zählt und das wiederrum hängt von der Taktfrequenz und dem Vorteiler ab.
Hi >Ich denke, wenn ich zu Beginn r16 in akku benenne, soll ich dann >nicht später mit r16 weiter machen. >Am Anfang stehen die .DEFxxx Bezeichnungen. Richtig. Das sollte dir auch nur zeigen, was du machst. Wenn man einen Port den Namen 'flashaus' verpasst ist 'out flashaus,akku' richtig. Bei einem Register aber nicht. Persönlich bin ich Gegner von diesem .def-Gedödel. Das mag bei solchen Spielzeugprogrammen ganz nett sein. Bei größeren Programmen kann man einem Register nicht nur eine Funktion zuweisen. Und wenn man Librarys für Displays, Sensoren, Schnittstellen usw. schreibt müssen die mit verschiedenen Programmen konfliktlos zusammenarbeiten. Und da ist nun mal der Registername der kleinste gemeinsame Nenner. MfG Spess
Hallo an Alle, ich habe sofort alles von Karl Heinz ausgedruckt und das Pferd ganz Neu aufgesattelt. Ihr habt Recht, das Ding war suboptimal. Habe also von Anfang Neu aufgebaut und viele Anregungen von Euch zu Herzen genommen. Z.B. den .defxxx Düttelkram weggelassen und stur mit r16 losgearbeitet. Mich um das SREG Register gekümmert und die Sache läuft schon mal. Das Thema "Kran" wird ersetzt durch 3 LEDs an PB0-PB2. Hier also das Neue: ; PORTB: Ausgabe ; PortD: Eingänge ;Datum: 10.12.2011 ;AVR: Tiny 2313 .INCLUDE "tn2313def.inc" ; Deklarationen für Tiny2313 .EQU takt = 1000000 ; Systemtakt 1 MHz ; r16=Arbeitsregister rjmp start .ORG OVF0addr ;Interrupt Vektoren rjmp timer ;Sprung zur ISR ;Stack initialisieren, PortB=Outp., PortD=Inp. start: ldi r16,LOW (RAMEND) out SPL,r16 ldi r16,$ff ; Bitmuster 1111 1111 out DDRB,r16 ; Port B ist Output ldi r16,$00 ; Bitmuster 0000 0000 out DDRD,r16 ; Port D ist Input ;Timer0 initialisieren ldi r16,1<<CS02|1<<CS00 ;Prescale = 1024 out TCCR0B,r16 ;r16 in Steuerreg. TCCR0 ldi r16,1<<TOIE0 ;r16< 1 = Interrupt-Freigabe out TIMSK,r16 ;TIMSK = Timer Interrupt sei ; I-Bit im Statusregister SREG ; 0 = Interrupt gesperrt ; 1 = " " freigegeben ;Arbeitsbeginn loop: ldi r16,2 out PORTB,r16 rjmp timer ;Sprung zur ISR rjmp loop ;Interrupt - ISR timer: push r16 ;Register retten in r16,SREG ;Statusregister ldi r16,1 out PORTB,r16 reti Wie schon gesagt,das läuft. Diese Versuche stecken nicht in den Quelltext wie oben! Nun wollte ich die ersten Gehversuche mit einem Register z.B. r17 in der ISR machen und dieses runter zählen, und da komme ich mit brne immer noch ins schleudern. 1.Schritt...im Arbeitsbereich loop: habe ich r17 mit 0F geladen. 2. " ....springe mit rjmp timer zur ISR gehe dec,r17 brne gehe reti aber so ist das doch nicht ok, ich möchte doch nur nach jedem Timer-Überlauf r17 = -1 zählen. Ich weiß noch nicht, wie ich exakt rauskomme, na ja..Ihr werdet darüber lächeln, aber ich nehms hin! Grüße Rolf
Hi >;Interrupt - ISR >timer: push r16 ;Register retten > in r16,SREG ;Statusregister > ldi r16,1 > out PORTB,r16 > reti Das Sichern von SREG macht nur Sinn wenn man es auch wieder rekonstruiert. Push und Pop funktionieren nur wenn es genau so viele Pushs wie Pops gibt. Und warum erfindest du einen eigenen Namen für den Interrupt. Nimm den aus dem Datenblatt. Da weiß jeder, was gemeint ist.
1 | TIMER0_OVF: push r16 ; Timer0 Overflow |
2 | in r16,SREG |
3 | push r16 |
4 | .... |
5 | pop r16 |
6 | out SREG,r16 |
7 | pop r16 |
8 | reti |
MfG Spess
Hi >Wie schon gesagt,das läuft. Nicht wirklich. >;Arbeitsbeginn >loop: ldi r16,2 > out PORTB,r16 > rjmp timer ;Sprung zur ISR > rjmp loop Wenn du einen Motor eine bestimmte Zeit in eine Richtung fahren lassen willst geht das einfach so:
1 | ldi r16,2 |
2 | out PORTB,r16 ; Motor einschalten |
3 | ldi r17,10 ; Zeit laden |
4 | loop: test r17 ; Zeit abgelaufen? |
5 | brne loop |
6 | ldi r16,0 |
7 | out PORTB,r16 ; Motor ausschalten |
8 | .... |
9 | |
10 | TIMER0_OVF: |
11 | push r16 ; Timer0 Overflow |
12 | in r16,SREG |
13 | push r16 |
14 | |
15 | dec r17 |
16 | |
17 | pop r16 |
18 | out SREG,r16 |
19 | pop r16 |
20 | reti |
MfG Spess
Hallo spess, aufatmen, Dein Vorschlag läuft! Muß alles erst mal verarbeiten. Z.B. test war der Befehl "tst" nach ca. 2 Sec. schaltet ein PORT,x nach PORT,y Ich komme der Sache immer näher, meinen Dank nochmals. Übrigens: Studio gab mir eine Warnung mit "1<<CS2|1<<CS0 Habe ich abgeändert in "1<<CS02|1<<CS00" alles war ok! Nochmals mein Dankeschön Rolf
Hi >Z.B. test war der Befehl "tst" Ja, das war ein Tippfehler. Noch was: Quelltext sollte keine Tabs enthalten. Sonst sieht es in jedem Editor anders aus. Am besten du stellst in den Editor-Options vom AVR-Studio Tabwith auf 1 und aktivierst 'Replace Tabs with Space'. MfG Spess
Hi Du willst bestimmt nicht für jede Motorfahrt einen eigenen Code schreiben. Im Anhang mal eine Minimalvariante wie so etwas mit wenig Code flexibel geht. Die Motoransteuerungen (pause, M1_right, M1_left ...) und die Zeiten sind meiner Phantasie entsprungen. Musst du also anpassen. In der Tabelle 'ablauf' muss einfach nur eingetragen werden, was wie lange gemacht werden soll. MfG Spess
Hi War die Debugversion: ldi r16,1<<CS00 ; 1<<CS02|1<<CS00 ;FOC0A,FOC0B,WGM02,CS02,CS01,CS00 in ldi r16,1<<CS02|1<<CS00 ;FOC0A,FOC0B,WGM02,CS02,CS01,CS00 ändern. MfG Spess
Hallo Spess und Karl Heinz, alles super geworden mit dem Quelltext für den Contener. 2 Eingänge an PortD liegen über Readkontakte gegen GND. Habe ich so gelöst: loop: nop read1: spic PIND,PD0 rjmp read1 Motor aufwärts EIN Dann auf 2 Unterprogramme (5 bzw. 20 Secunden) rcall zeit5 rcall zeit20 zeit5: pause5: tst r17,17 ;gemessen ca. 5 Sec. brne pause5 ret zeit20: pause20: tst r17,5C ;gemessen ca. 24 Sec. brne pause20 ret Nun muß ich noch die Hardware zusammen stricken und dann kommt der große Momment. Leider zeigt mein Buch nur den Timer1 für einen Mega8. So wie ich lese, ist das Gebiet umfangreicher als der Timer0. Für die übernächste Zeit werde ich sowas für einen Tiny13 brauchen, und zwar als Ortungspieper für einen 3m Segler. Aber ich glaube, der kleine Tiny hat nur Timer0. Also meinen Dank nochmals für Eure Hilfe und geduldige Ausdauer mit mir. Grüße Rolf
Hi
>Leider zeigt mein Buch nur den Timer1 für einen Mega8.
Vergiss das Buch und nimm das Datenblatt.
MfG Spess
mh...was wäre das schön, wenn ich Eure Englischkenntnisse hätte! Und mit über 70 Jahren fange ich nicht mehr damit an, zumal mir das Volkshochschul-Englisch nicht viel nützen wird.
Hallo an ALLE, habe heute nochmal den ganzen Thread durchgekaut, um viele Sachlagen zur Erinnerung zu rufen. Der Containerkran (jetzt will ich es aber mal richtig schreiben) läuft und läuft. Danke nochmals und 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.