Hallo, ich bin gerade dabei mal ein altes Problem wieder zu lösen. Will ein 12VDC-Motor mit PWM ansteuern, sozusagen schneller,langsamer. Dann auch noch Links und Rechtslauf. Dafür hab ich mir den ATTiny2313 DIP20 rausgesucht. Frage mich ob der uC der richtige Ansatz ist. Meine Sorge ist, der benutzt nur einen 10Bit Prescaler für Timer1 und Timer0. Ob man damit Tastenentprellung und PWM realisieren kann? Ich will da vier taster(4 Pins) anschliesen ein LCD(6Pins) und naja dann der Standart(reset,xtal...). Nun sind ja vier Taster nicht die Welt.Und um alles zu organisieren darüber, wollte ich eine Menüsteuerung dafür entwickeln. Funktionen wie: Start, Stop, Links-, Rechtslauf,schneller, langsamer, Demoprogramm Nun habe ich zwar so die Grundzüge von Assembler, Speicherorganisation, Pointern, ... verstanden. Aber mir fehlt einfach dass verständnis dass nun zu programmieren. wie muss ich die Auswertung vornehmen für eine Taste, damit dem Programm klar ist das sie mehrere Bedeutungen hat. Mach man das mit einem Register? und dann jedes Bit auswerden und sprungmarken organisieren? Mir fehlt einfach der Ansatz. Wenn mir jemand helfen könnte, wäre ich sehr dankbar. daniel
Hat sich geklärt :) mir ist die Idee gekommen, nach einer Entprell funktion die ich hier im Forum gefunden habe werde ich es mit einem cp- Befehl durch die Funktionen springen :) und mich so durch mein Menü hangeln. Falls wer noch eine bessere Lösung hat :) ich bin für Tipps immer lernbereit :) daniel
Nunja, "Menü" bedeutet ja, dass du einen Dialog mit dem Controller führst, also ein Ausgabegerät (LCD) angeschlossen hast, das dir die "Menüangebote" anbietet. Beim Abarbeiten der "Tastendruck-Flags" (keypress) der Entprellroutine könnte auch der Befehl "sbrc" bzw. "sbrs" in Kombination mit einem "rjmp" oder "rcall" hilfreich sein. Einige Beispiele für interaktive Menüs auf AVR in ASM kannst du hier finden: http://www.hanneslux.de/avr/stopuhr/index.html http://www.hanneslux.de/avr/zuenduhr/index.html ...
Was bedeutet rcall eigentlich genau? rjmp kann ich mir ja vorstellen, aber ein call geht doch immer an eine bestimmte routine :-?
Hi, vielen Dank super für die schnelle Antwort. rcall bedeutet relative call, vermute ich zumindest. Zumindest hab ich das so beim Rabbit kennengelernt, soll angeblich ein byte sparen da der befehl nur um 122 vorwärts und um 126 rückwärts springen kann. Ja es soll ein LCD angeschlossen werden, denke da an das im Tutorial vorgestellte 20x2 Zeiler LCD mit dem Controller HD44780. Wenn jemand ne günstigere Lösung hat, lass mich gern beraten. So wie ich erfahren habe geht ja das meiste Geld ins Display ;). Ich habe dass so ausprobiert main: BREQ r24,r23 ;wenn gleich dann mache das nächste rcall Sprungmarke ;soll springen rjmp main ;IRQ gesteuerte endlosschleife und was macht der gute ?! der macht nicht den Sprung obwohls gleich ist :( der macht auch nicht den rjmp, der geht weiter und da bei mir als letzes ein sprung zur init kam, machte er den Sprung. Verstanden hab ich es nicht, warum das so ist. Aber die Idee ist doch erstmal korrekt oder? Bei sbrs kann ich nur ein Bit prüfen nicht die ganze Summe und vergleichen. Durch eine Entprellfunktion ( ;) hier aus dem Forum) gibts ein Register (Status von 4 Tasten) wo auch ein gleichzeitiges drücken mehrerer Tasten vorkommen kann und das wollte ich als ungültig erachten. Vielen Dank für die Links, das sieht interresant aus. Aber noch eine Frage mal am Rande verlegen , was hat das eigentlich mit diesen Makros auf sich? sind das eine Art unterprogramme oder wie kann man sie verstehen? daniel
>>>> NACHTRAG <<<<<<
Sorry, ich hatte nicht BREQ benutzt sondern CPSE.
Da stand irgendwo CPSE r24,r25 ; Vergleiche r24,r25 springe wenn
gleich
habs dann so geschrieben
main:
CPSE r24,r25
rcall Sprungmarke
rjmp main
Wie gesagt ging aber nicht :(, aber ich werd es mal mit BREQ
Sprungmarke probieren, natürlich muss dann aber ein CP r24,r25 davor
:)
Noch eine Frage zu diesem hier
txt_10: .db "10ms",0,0
was bedeuten die ,0,0 dahinter?
daniel
> txt_10: .db "10ms",0,0 > was bedeuten die ,0,0 dahinter? Die erste 0 ist die Ende-Kennung für die Stringausgabe-Routine, die zweite 0 ist erforderlich, damit die Anzahl der Bytes pro .db-Zeile geradzahlig wird, da der Flash word (Doppelbyte)-adressiert wird. Du bemängelst, dass sbrc/sbrs nur ein Bit prüft. Das ist ja gerade der Vorteil. Die PeDa-Entprellroutine (die im Timer-Interrupt läuft und bis zu 8 Tasten an einem Port gleichzeitig entprellt) stellt neben dem Tastenstatus (keystate, bei mir tas) auch die Tastenflags (keypress, bei mir tfl) zur Verfügung, in dem jedes Bit für eine andere Taste steht. Um nun auf die Tastendrücke zu reagieren, können die einzelnen Bits geprüft und danach verzweigt werden. Dass mehrere gleichzeitig gedrückte Tasten auch erkannt werden, ist kein Mangel, sondern ein echter Vorteil. Somit sind z.B. Shift-Tasten möglich, die nicht separat ausgewertet werden (das Bit in keypress/tfl einfach nicht auswerten), sondern deren Status (Bit in keystate/tas) beim Auswerten der anderen Tasten nebenbei zur Fallunterscheidung mit herangezogen wird. So kann eine Taste mehrere Funktionen bekommen, abhängig vom Zustand einer Shift-Taste. Durch eine kleine Erweiterung der Tastenentprellroutine kann man auch auf das Loslassen der Tasten triggern und sogar auf unterschiedlich lang gedrückte Tasten unterschiedlich reagieren. Dann braucht die Routine aber einige Variablen mehr, weshalb ich dann die Variablen nicht mehr in Registern halte sondern im SRAM. > Was bedeutet rcall eigentlich genau? rcall ist der Aufruf eines Unterprogramms, welches mit ret beendet wird, worauf das Programm direkt hinter dem rcall fortgeführt wird. Informationen zu den Befehlen findest du übrigens im "AVR instruction set", das jedem AVR-Studio als PDF beiliegt und in der Onlinehilfe zum AVR-Studio (Cursor auf fraglichen Befehl, F1-Taste...). ...
Hi Daniel und Feak5 RCALL heißt Relative Call, soweit völlig korrekt. Daniels Beschreibung ist auch richtig. Ein Unterschied gibts aber: Beim AVR ist es so, dass er +/- 127 Schritte springen kann. Unterschied zwischen RCALL und RJMP: Wenn du RCALL benutzt, dann wird die aktuelle Adresse des Befehlszeigers auf dem Stack gesichert und an das angegebene Label gesprungen. Wenn der Controller jetzt auf ein 'RET' stößt, holt er die Adresse wieder vom Stack und springt an die Stelle zurück, von wo RCALL ausgeführt wurde. Eine typische Anwendung hierfür ist ein Funktionsaufruf. Also ein Unterprogramm, wo reingesprungen wird (RCALL), was gemacht wird und anschließend wieder zurückgesprungen wird (RET). Der Unterschied zu RJMP ist nun folgender: RJMP speichert keine Adresse auf dem Stack. RJMP springt einfach nur an das angegebene Label. Benutzt man hier (fälschlicherweise) ein 'RET', so wird der Controller an eine zufällige Adresse springen, da zuvor noch keine validen Daten auf den Stack gelegt wurden. Man kann sagen, RCALL ist "bidirektional" und RJMP ist "unidirektional". Wenn man mit RJMP/RCALL weiter als 127 Bytes springen will, so muss man die 2 Byte langen Equivalente "JMP" und "CALL" verwenden. >> BREQ r24,r23 ;wenn gleich dann mache das nächste Genau, das funktioniert nicht, wie du schon sagtest. Wenn du statt BREQ aber CPSE nimmst, sollte das ganze eigentlich funktionieren Grübel. Der Fehler muss woanders liegen. Makros sind keine "Funktionen" oder ähnliches. Sie sind einfach nur Definitionen. Der Precompiler (Also der Compiler, der vor dem eigentlichen Compiler durchläuft) sucht das gesamte Programm nach zuvor definierten Makros ab. Stößt er auf ein Makro, dann ersetzt er diesen Makronamen durch den Inhalt des Makros. Man kann sagen, dass ein Makro einfach nur ein Synonym ist. Also einfach ein "Suchen und Ersetzen" durch den Precompiler. (Wobei es auch kompliziertere, verschachtelte, Makros gibt.. Aber das ist mir zu wurstelig). Wenn dann alles ersetzt ist, wird das Programm kompiliert. Die Nullen hinter dem Text schließen den Text ab. Das findet man besonders bei C-Programmierung und Assemblerprogrammierung wieder. Es wird benutzt, um zu bestimmen, wo der Text zuende ist. Stößt also irgndeine Funktion auf eine 0 in dem String, so wird der String als zuende erkannt. (Nicht verwechseln mit dem Zeichen '0'. Es ist die "binäre Null"). Warum Hannes da zwei Nullen hingeschrieben hat, kann ich mir nicht erklären. Ich könnte mir aber vorstellen, dass es daran liegt, dass der Flash-Speicher (Wo er die Daten da ablegt) Doppel-byte orientiert ist. Er speichert aber diese 0 (wegen ".db" (= data BYTE)) als ein Byte ab. Um aber jetzt ein Doppelwort vollzukriegen, darf es keine ungrade Anzahl an Bytes hinter einem .db geben. Und als "Ausgleich" hat er dann noch eine Null dahintergehangen. (Ist so gesehen natürlich "toter" Speicherbereich, aber 1. Hat man ja genug und 2. Gehts auch nicht, oder nur mit Umständen anders).
Sorry, ich meinte "Freak5" :-) Für andere Tippfehler schau ich meinen Post jetzt nicht mehr nach. Ich geh nun schlafen.
> Verdammt Hannes!
Haste Töne? Jetzt werde ich auch noch verdammt... ;-)
Simon, ich bin ganz bewusst nicht so ins Detail gegangen, um zu
erreichen, dass Freak5 (ein langjähriger Forumbenutzer) mal die Nase in
die auf seinem Rechner vorhandenen Informationsquellen steckt.
...
Ich programmiere auch schon lange die AVRs die Aussage oben, dass man rjmp und rcall verwenden soll, hat in mir nur die Frage hervorgerufen, was daran so besonders ist, dass genau das in diesem speziellen Fall genutzt werden muss. Ich benutze, wenn nichts optimiert werden muss immer call und jmp. Diese Aussage "Wenn man mit RJMP/RCALL weiter als 127 Bytes springen will, so muss man die 2 Byte langen Equivalente "JMP" und "CALL" verwenden." hat eigentlich schon alles beantwortet. Dass RJMP und RCALL relative Jump und relative CALL bedeutet, wusste ich auch, da ich schließlich auch im Besitz des Instruction Set Datenblattes bin. Nur da steht nicht die Größe des Befehls drin. OK, HanneS hat auch recht, dass ich mir mal die Aufrufe wie ICall, EICaLL usw. ansehen sollte.
> Ich benutze, wenn nichts optimiert werden muss > immer call und jmp. Hast du denn schon mal versucht, einen Tiy15 oder Mega8 mit call und jmp zu programmieren? Oder schießt du immer mit Kanonen auf Spatzen? Ich meine damit, oder ignorierst du die kleineren AVRs, die viele Aufgaben sehr gut erledigen können. Es muss nicht immer der Mega16 oder größer sein... ...
@Hannes: Naja, ich habe jetzt schon seit einem Jahr nicht mehr programmiert, da ich mir einen Programmer gelötet habe, der aufgrund eines Krümelchens Lötzinn zwischen dem Sockel und GND meine AVRs gekillt hat(ich will in 2 Wochen wieder mit dem Programmieren anfangen), aber vorher habe ich das immer so gemacht, dass ich mir ganz schnell einen Sockel auf eine Lochrasterplatine gelötet habe und dann die Schaltung darüber aufgebaut habe(ich habe kein Breadboard). Da die Sockel günstig sind und man die AVRs schnell tauschen kann, habe ich dann immer einen AVR für X Schaltungen verwendet. Dumm ist nur, wenn man den Code verliert, aber bis jetzt habe ich so wie so nur Testschaltungen gemacht. (OK, einen AVR 32 benutze ich als Oszillator. Mit den letzten 3 Pins, die den Kurzschluss überlebt haben, ist der auch nicht mehr zu viel zu gebrauchen.) Wenn ich einen AVR in eine Schaltung bauen würde, wo ich weiß, dass er da auch für immer stecken bleibne soll, würde ich mir ein paar Gedanken machen, ob ich nicht einen Tiny nehmen kann, wenn ich nicht x Erweiterungen im Kopf habe, die vielleicht einen ATmega128 voraussetzen. Bis jetzt habe ich ja so wie so nur aus Spaß programmiert um private Probleme zu lösen. In der Schule wird man höchstens für einen Spinner gehalten( Ich glaube, dass die meinsten Lehrer sowas nicht zum Bereich des Machbaren zählen ).
Hallo, Vielen Dank für die Superschnellen Antworten. Bin gerade dabei mich durch das Datenblatt zu kämpfen. ;) Stück für Stück gehts voran. :) Ich hab noch eine Frage zu den Tasten, man kann maximal nur 2 tasten Interrput fähig machen, INT0 und INT1 oder? müssen die anderen dann gepollt werden? Vielen dank, ich denke die Auswertung wird nicht mehr meine Sorge sein, viel mehr die Gestaltung und Strukturierung und dann die Ausgabe dessen. Aber dazu kann ich mich durch die Beispiele arbeiten :) daniel
> man kann maximal nur 2 tasten > Interrput fähig machen, INT0 und INT1 oder? Das Einlesen der Tasten über diese Interrupts ist die schlechteste Art, Tasten einzulesen. Das gibt nur Ärger. Nimm stattdessen einen Timer-Interrupt und benutze die Entprellroutine von Peter Dannegger, dann bist du alle Sorgen los. Beispiele, wie das geht, habe ich weiter oben http://www.mikrocontroller.net/forum/read-1-375525.html#375614 bereits verlinkt. Weitere Informationen dazu findest du in der Artikelsammlung (nach "entprellung" suchen) und in der Codesammlung (nach "bulletproof" suchen). ...
Hallo, ohh wusste ich nicht, beim Rabbit hatte ich es immer so gemacht. ja diesen Routine von PD hab ich mir schon erlaubt zu verwenden ;). Ich brauch den Timer0 aber für mein PWM signal, hab es auf Phase Correct ( Zählt rauf und wieder runter)eingestellt, mit dem Compare Match A, kann ich da noch ein Compare Match B verwenden für die Entprellroutine. Aber man braucht doch den Interrupt um den guten uC wieder zu wecken wenn man ihn schlafen geschickt hat? da müsste ich doch meinen Start- Taster dranhängen. daniel
Das Wecken aus dem Tiefschlaf funktioniert nur mit dem Level-Interrupt. Das ist der einzige sinnvolle Grund, Taster an einen externen Interrupt zu schalten. Die Entprellung würde ich aber trotzdem per PeDa-Entprellung im 10..20ms-Abstand machen. Hat der Tiny2313 nicht 2 Timer? (Sorry, ist nicht mein Favorit) Ist es evtl. möglich, zusätzlich zur Hardware-PWM-Erzeugung einen Interrupt auszulösen und darin einen Softwaretimer für die Entprellung hochzuzählen? Die eigentliche Entprellung (und das Rücksetzen des Softwaretimers) kann ja die Mainloop übernehmen. In einem größeren Projekt habe ich 5 Bytes zu entprellen und noch auf kurzen oder langen Tastendruck zu unterscheiden, da läuft die Entprellung auch in der Mainloop, allerdings von einem Timer per Flag synchronisiert.Aufgrund der Menge der Variablen werden diese dann natürlich im SRAM gehalten. Es gibt also immer einen Weg... ...
Vergessen: Ein Beispiel, wie der AVR (Tiny15) per Level-Interrupt aus dem Tiefschlaf geweckt wird, die Tastenentprellung aber per PeDa-Routine erfolgt, findest du hier: http://www.hanneslux.de/avr/divers/melody/melody04.html Da wird übrigens auch noch der ADC-Interrupt als Timer missbraucht... ...
Hi, Vielen Dank, ich werde es mir Anschauen, nur hab ich heute leiderns keine Zeit :(. Es stehen die Prüfungen an :( Aber naja so ganz zum lernen komm ich auch nicht ;). Ich hab mir da noch Gedanken gemacht, appropo ADC: der Tiny2313 hat gar keinen ADC. ich wollte aber die Drehzahl des Motors mittels eines Strom-Spannungswandlers messen und dann die Spannung in die Drehzahl umwandeln,mittels Tabelle oder direkt berechnen. da brauch ich doch ein ADC? deswegen denke ich werde ich umsteigen auf den ATtiny26L der hat einen, nur leiderns hat er keinen direkten PWM Ausgang mehr :(. Oder täusche ich mich und der hat beides. Zumindest im Datenblatt konnte ich keinen besagten Pin finden :(. Vielleicht sollte ich doch ganz umsteigen auf einen ATmega8? daniel
Ohne jetzt ins Datenblatt zu schaun sagt mir meine Erinnerung, dass der Tiny26 zwei PWM-Kanäle hat, die auf 4 PWM-Ausgänge (zwei davon invertiert) geführt sind. Es wird sich lohnen, das Datenblatt mal zu befragen... ;-) ...
Hi, ja du hast recht, der Tiny26L hat sowohl 4PWM Ausgänge,sowie 10 ADC eingänge. Schlecht wird nur das ich meine Tasten zum Beispiel nicht alle auf einen Port legen kann, denn ich muss mich entscheiden wer 4 Eingänge hintereinander bekommt, denn XTAL1,XTAL2,Reset sind auch schon wieder 3 Pins weg. Und 4 hinereinanderfolgende nehme ich für das Display. Es dürfte kein Problem sein Tasten von mehreren Ports abzufragen, oder? Wie sind deine Menüs eigentlich aufgebaut, von der Steuerung betrachtet? Du hast ein steuermenü das den Pointer festlegt, welcher dann in ein Menue springt und dort die Aufgaben für das Menue abarbeitet. Speicherst du in einem Register oder Flag, in welchen Menü sich die Steuerung gerade befindet? Noch eins ist mir nicht ganz klar. Mit welchen Sprungmarken du im Hauptprgramm dann angibst, was zum jeweiligen Menue dann textmässig auf dem LCD erscheint? Vielen Dank für die kurzen Infos bereits. Das hat mir schon sehr geholfen und auch die ASM-Files daniel
> Du hast ein steuermenü das den Pointer festlegt, welcher dann in ein Menue springt und dort die Aufgaben für das Menue abarbeitet. Speicherst du in einem Register oder Flag, in welchen Menü sich die Steuerung gerade befindet? < Es gibt die Variable namens "mp" (Menüpunkt), die als Zeiger auf die Menüroutine (über ijmp) genutzt wird, aber auch als Zeiger auf den Menütext. Diese Variable (Register) repräsentiert immer den momentanen Status der Menüsteuerung. > Noch eins ist mir nicht ganz klar. Mit welchen Sprungmarken du im Hauptprgramm dann angibst, was zum jeweiligen Menue dann textmässig auf dem LCD erscheint? < Jeder Menüpunkt-Job wird mit "rjmp tastaus" verlassen, die Routine "tastaus" löscht alle Tastenflags (was die Menü-Job-Routinen schlanker macht) und gibt die beiden Menütexte (obere und untere Zeile des Displays) aus und fällt dann in die Mainloop. Schau dir mal dort den Aufruf des Macros und in der Print-Include das Macro und die Ausgaberoutine für indizierte Texte an, dann wird dir das klar. Da wird nämlich auch die Variable "mp" zur Auswahl des Textes genutzt, kurz vor den Texten (am Ende des Quelltextes) stehen dann die Tabellen (Listen) mit den Zeigern auf die Texte, ist der Zeiger erstmal positioniert, erfolgt die Textausgabe wie eine gewöhnliche Ausgabe eines 0-terminierten Strings. Diese Form der indizierten Ausgabe ist recht effizient, was Codegröße und auch Prozessorbelastung betrifft, sie eignet sich auch gut zur Ausgabe von Wochentagsnamen, Monatsnamen usw.. Ob es noch effizienter geht, kann ich nicht sagen, die Routine wurde nicht "gefunden" sondern selbst erdacht. Meinen Ansprüchen genügt sie aber (noch). ...
Gibt eigentlich ein "übliches" Programmierschema, welches Menüsteuerungen etwas abstrahiert? Mir schwebt eine Art Adjaszenzmatrix (Verbindung der Menüs) mit fest hinterlegten Bildschirminhalten vor. Bisher programmiere ich das immer unelegant á la "Wenn ich im Menü A bin und es wird der Knopf 1 gedrückt, springe ins Menü B" usw. Das geht bis zu einem gewissen Grad, wird dann aber unübersichtlich, besonders wenn auch Rück- oder Übersprünge möglich sein sollen. Frank
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.