Hallo, wenn man den Timer mit einem Startwert verwenden möchte, muss man ja mit inline asm das Timer-Register laden, einen gewissen Wert hinzuaddieren (Startwert+Verstrichene Zyklen zwischen Laden und Schreiben des Timers; deshalb auch ASM, da ist die Anzahl an Zyklen bekannt). Wenn nun aber der Timer von einem Benutzerdefinierten Wert hochzählen soll (im C eingegeben oder gar berechnet), wie kann ich das dann machen, dass der ASM weiß, mit was er addieren soll? Sprich: Ist es sinnvoll ein Register (bekannt) als Variable definieren und auf dieses Register via asm zuzugreifen? Wie geht das (in C)? Oder ist es sinnvoller ein normaler Speicherbereich im RAM zu verwenden, damit das Register für den GCC nicht dauerhaft "belegt" ist? Wie gebe ich dann dem asm die Adresse? Wird ja schließlich zur Compile-Zeit festgelegt. MfG Christian
> deshalb auch ASM, da ist die Anzahl an Zyklen bekannt
Wenn jeder Zyklus wichtig ist, bleibt dir nichts
anderes übrig als auf Assembler zu gehen. Die meisten
C-Compiler haben einen inline-Assembler. Da kann man
dann Assembler Instruktionen in den C-Quellcode einbetten.
Meist ist das aber nicht notwendig.
Es geht um eine saubere Zeitbasis. Deshalb komme ich um inline asm nicht herum. Das ist klar! Mein Problem: Wie kann ich einen Wert zwischen C und inline asm austauschen? Sprich: Wie kann ich dem inline asm eine Konstante z.B. aus dem SPI oder ähnliches übergeben? Wie kann ich also ein Register in C ansprechen? Wie kann ich es wieder freigeben, damit C es wieder verwendet? MfG Christian
> Es geht um eine saubere Zeitbasis. Dann nimm bitte nichts, wo du von der Code-Laufzeit abhängig bist. Die Timer der aktuellen AVRs haben hier genug Möglichkeiten, dass man das nicht mehr braucht (Stichwort: CTC mode, clear timer on compare match).
Das hat aber einen deutlichen Nachteil: Ich bekomme nicht die Genauigkeit, die ich will: ICh will eine Quarz-Uhr bauen (hab es schon getan) und nun weiß ich, dass normale Quarze nur eine Genauigkeit von einigen 10-25 ppm haben. Mal von einer Quarzfrequenz von 2^22 Hz=4,194304 MHz aufgegangen, bedeutet das, dass das Quarz in der Sekunde um bis zu 105 Takte von der Nennzahl 4194304 abweicht (natürlich ist der Fehler konstant). Nun möchte ich nach einiger Zeit der Uhr eine 2. Zeit einprogrammieren, dei als Synchronisation fungiert: Er weiß, wieviel Takte in der Zwischenzeit vergangen sind und jetzt weiß er noch vieviele es sein müssten (der Benutzer kann ja etwa bis auf eine halbe Sec. genau eingeben; da dürfte ein Monat Sync-Zeit schon ganz gut sein). Jetzt kann er einen Korrekturfaktor errechnen. Wenn ich aber hingehe und ihn diesen Korrekturfaktor via CTC einrechnen lasse (prinzipiell ja möglich), erhalte ich 2 Probleme: 1.) Ich kann die Uhr nur schneller machen (Take übergehen); langsamer machen kann ich nicht, da ich den Timer nicht erweitern kann. (Planungsfehler, ok, aber damit muss ich nun leben) 2.) Die Genauigkeit ist miserabel. Egal, ob ich einen Presacler einsetze oder ihn ohne Prescaler laufen lasse und anschließend manuell eine Variable hochzähle die als "Postscaler" dient (mein Favorit, da ich den Prescalor 1 für den anderen Timer brauche ;-)) in jedem Fall kann ich nur um ganze Schritte im Timer korrigieren. Das bedeutet, dass der 16-Bit Timer noch mit einem 6-Bit Pre/Post-Scalor ausgestattet werden müssen. Damit wird aber eine Änderung von einem Takt am Ende zu einer konkreten Änderung von 64 Takten. Damit könnte ich allenfalls die Fehler einigermaßen in's Lot bringen; richtig weg bekomme ich die damit nicht. Ich sehe da einen besseren Weg: Mit dem regelmäßigen Timer Overflow wird eine Subroutine ausgeführt, die die Korrektur folgendermaßen vornimmt: Ich gehe davon aus, dass bereits Korrektur-Daten vorliegen, die via C aus dem EEPROM geholt werden. Nun wird bei jedem Overflow der Timer (inline asm!!!!!!) in ein Register geholt, mit einem fixen Wert (Korrektur für asm-Befehle) und dem Korrekturwert (ggf. subtrahieren) addiert. Nun wird zurückgeschrieben. Soweit hätte ich die selbe Auflösung wie bei CTC, nur könnte ich, da der Timer schon weitergelaufen ist, auch noch Takte "anhängen. Das gleiche wird nun aber auch bei jeder vollen Sekunde separaat gemacht. Damit kann ich nun eine Sekunde mit nur einem Takt Fehler als Basis erzeugen! Wende ich die Methode noch auf die Minuten an, dürfte es nicht mehr merklich von der Sollzeit abweichen (da kommt die Umstellung Sommer-/Winterzeit vorher ;-)). Ich kann es auch noch für Stunden durchziehen, dann ist das Ding "doch recht genau". Und jetz nicht sagen: Wie willst du die Korrektur-Daten so genau eingeben? Ganz einfach: Der Controller zählt die Tage mit. So kann er sich selbst im Laufe der Zeit synchronisieren, wenn der Benutzer ihm regelmäßig die neue Zeit einstellt. (bei Sommer-/Witerzeit muss die Sync-Funktion natürlich deaktiviert sein). So, jetzt hoff ich ihr wisst, warum ich mit asm auf Werte aus C zugreifen möchte und das nicht unbedingt über CTC lösen kann. Trotzdem danke für die Idee. Christian
Du musst dir eigentlich nur ausrechnen, aller wie vielen Sekunden du den Zielwert vom CTC einmalig entweder um 1 größer oder um 1 kleiner machen musst. Nach diesem einen Zyklus schaltest du wieder auf den Standardwert zurück. Zum Umschalten des OCRs hast du dann einen vollen CTC-Umlauf Zeit, das dürfte ja unkritisch genug sein, oder?
Nein, da ich die Zeit nicht dehen kann. Ich hab das Quarz so gewählt, dass ich mit einem 22-Bit-Teiler gerade auf 1 Sekunde komme. Ich kann den CTC also entweder auf 2^16-1 (MAX) oder MAX-1 legen. MAX+1 wäre aber nötig, um zu dehnen. Zudem sehe ich keine Probleme das Ding mit ASM zu machen; entweder inline oder externe Funktion. Find ich persönlich die bessere Möglichkeit, insbesondere, da hier die Genauigkeit im Endeffekt höher sein wird: Selbst wenn ich jeden Timer-Overflow eine neue Schranke TOP festlegen würde, wäre das noch deutlich ungenauer. Ich weiß nur nicht, wie ich a) Eine Variable in GCC und in ASM verwende? b) Eine ASM-Funktion von C aus aufrufe? c) ob ich eine ASM-Datei ganz normal einbinden kann (#include "Datei.S)? MfG Christian
> Nein, da ich die Zeit nicht dehen kann. Ich hab das Quarz so > gewählt, dass ich mit einem 22-Bit-Teiler gerade auf 1 Sekunde > komme. Ich kann den CTC also entweder auf 2^16-1 (MAX) oder MAX-1 > legen. MAX+1 wäre aber nötig, um zu dehnen. Nun, erstens hättest du wohl mit meinem Vorschlag genauso gut einen 08/15 4,000-MHz-Quarz nehmen können, zweitens kannst du ja statt dem 1:64-Vorteiler einen 1:256-Vorteiler nehmen, dann ist der OCR-Wert bei MAX/4. > Zudem sehe ich keine Probleme das Ding mit ASM zu machen; entweder > inline oder externe Funktion. Find ich persönlich die bessere > Möglichkeit, insbesondere, da hier die Genauigkeit im Endeffekt > höher sein wird: Nur, wenn du keinerlei andere Interruptquelle hast. Ansonsten hast du ein Jitter. > Ich weiß nur nicht, wie ich > a) Eine Variable in GCC und in ASM verwende? Eine externe? Die kennt einfach der Linker, du kannst das Symbol also im Assembler direkt benutzen. Wenn du kommentieren willst, dass der Linker das kennt, kannst du ja noch .extern SYMBOL schreiben, aber das ist praktisch eine Null-Operation: sowie du SYMBOL benutzt und der Assembler sonst keine Anweisung hat, woher er das nehmen soll, wird es automatisch `undefined extern'. > b) Eine ASM-Funktion von C aus aufrufe? Genauso, wie du eine C-Funktion von C aus aufrufst. Wenn du Parameter übergeben willst, musst du dich an das ABI halten. Steht in der avr-libc-FAQ. > c) ob ich eine ASM-Datei ganz normal einbinden kann (#include > "Datei.S)? Natürlich nicht: #include zieht die entsprechende Datei ja 1:1 in die `current compilation unit' rein, d. h. der C-Compiler würde dann deinen Assemblercode sehen. Findet er sicher nicht so toll. Du musst sie separat assemblieren. Vielleicht fängst du ja erst einmal mit der avr-libc-Doku selbst an? Da steht schon einiges dazu drin... OK, mixed C and assembly gibt's erst in der nächsten Version, kannst du dir aber im CVS schon mal ansehen: http://cvs.savannah.nongnu.org/viewcvs/avr-libc/doc/examples/asmdemo/?root=avr-libc
Wie bekomme ich den "Mist" (sorry, ich hasse cvs, da ich nie verstehe, wie das funkt.)? Ich kanns entweder manuell runterladen oder irgend einen fertigen Befehl eintippen. Wie ich das sonst bekomme weiß icht nicht. MfG Christian
Ja, wie du schon schreibst: entweder manuell runterladen (dafür habe ich dir ja die ViewCVS-Links gegeben, die drei oder vier Dateien sollten ja einigermaßen schnell gehen), oder mit einem cvs checkout -- wie das geht, steht cut&paste-fähig hier: https://savannah.nongnu.org/cvs/?group=avr-libc > (sorry, ich hasse cvs, da ich nie verstehe, > wie das funkt.) Da frage ich mich nur, wie du deine Versionsverwaltung organisierst... CVS ist sicher nicht der Stein der Weisen, aber ganz ohne eine Versionsverwaltung möchte ich auch meine privaten Projekte nicht betreiben.
Hier wird aber, wenn ich das richtig interpretiere (nur kurz drübergegagen), die .S-Datei auch an den avr-gcc übergeben, oder? Mit welchem genauen Befehl (kenne mich in der Makefile noch nicht wirklich aus ;-))? Wie wird dann dem Compiler beim Hauptprogramm eine Funktion in der .S-Datei zugänglich gemacht? Unter welchem Namen ist eine solche Funktion dann zu finden? MfG Christian
@Christian Die Lösung für dein Problem mit genaue Sekunde: http://www.mikrocontroller.net/articles/AVR_-_Die_genaue_Sekunde_/_RTC
@Christian "Zudem sehe ich keine Probleme das Ding mit ASM zu machen; entweder inline oder externe Funktion. Find ich persönlich die bessere Möglichkeit, insbesondere, da hier die Genauigkeit im Endeffekt höher sein wird: Selbst wenn ich jeden Timer-Overflow eine neue Schranke TOP festlegen würde, wäre das noch deutlich ungenauer." Das ist Quatsch mit Soße. Die Genauigkeit ist exakt die gleiche, ob Du nun den Timer direkt änderst oder den Comparewert. Der einzige Unterschied liegt darin, daß Du Dir mit der Änderung des Comparewertes bis zum nächsten Interrupt Zeit lassen kannst. Schau Dir mal den Link von Branko an. Peter
[color=indigo]Ïðîäàþ íîóòáóê Dell Latitude D600 - Pentium-M 1,4Ghz[/color] [b]http://www.kanal-service.ru[/b] [b]Îòêà÷êà æèäêèõ ñðåä[/b] [b]Îêàçàíèå óñëóã ïî ïðîìûâêå, ïðî÷èñòêå, óäàëåíèþ çàñîðîâ[/b] [b]Ãèäðîäèíàìè÷åñêàÿ ïðî÷èñòêà çàñîðîâ.[/b] [b]Ìåõàíè÷åñêàÿ ïðî÷èñòêà êàíàëèçàöèîííûõ òðóá[/b] [b]Ðó÷íàÿ ïðî÷èñòêà êàíàëèçàöèîííûõ òðóá[/b] [b]Ïðî÷èñòêà è îáñëóæèâàíèå èíæåíåðíûõ ñåòåé[/b] [b]Îòêà÷êà æèäêèõ ñðåä, òðàíñïîðòèðîâêà è óòèëèçàöèÿ îòõîäîâ ïîñëå ïðî÷èñòêè[/b] [b]ÒÅËÅÈÍÑÏÅÊÖÈß â êàíàëèçàöèîííûõ ñåòÿõ[/b] [b]Ïðîêëàäêà, ðåìîíò è ïåðåêëàäêà èíæåíåðíûõ ñåòåé[/b] Êîíòàêò: (812)+7(812)380-4140 http://www.kanal-service.ru
Hmm, wo sind eigentlich die "Artikel melden"-Links hingekommen?
Rolf Magnus wrote:
> Hmm, wo sind eigentlich die "Artikel melden"-Links hingekommen?
Stimmt... jetzt, da du es erwähnst, fällt es mir auch auf...
Добрый день Вы ищете РАБОТУ? У Вас есть свой САЙТ Вы хотите его РАСКРУТИТЬ? Мечтаете о СОБСТВЕННОМ перспективном БИЗНЕСЕ? Мы НАУЧИМ как ЗАРАБОТАТЬ и получать СТАБИЛЬНУЮ ПРИБЫЛЬ! Ждем Вас на WWW.BYOPT.NET вопросы сюда: byopt.net@list.ru Будем рады оказаться вам полезными
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.