Hallo! Ich möchte mit einem ATTiny13 Folgendes realisieren: Für eine Modellanlage sollen 4 Pins des ATTiny in einem jeweils anderen Abstand für 150ms angesteuert werden. Dabei soll Pin0 alle 30s, Pin1 jede Minute, Pin2 alle 3 Minuten und Pin3 zufällig alle 30s bis 5min angesprochen werden. Die Schaltung muss nicht sonderlich genau sein - es darf ruhig mehrere Sekunden abweichen. Arbeiten möchte ich mit dem AVR Studio 4 und WinAVR sowie meinem STK500. Macht es hier sinn mit dem Timer zu arbeiten? Ich weiß, dass es hier diverse Threads zum Thema "Timer" gibt, aber auch nach diesen und dem AVR GCC Tutorial hab ich die Thematik noch nicht 100%ig verstanden. Wie kann ich den Interrupt ohne externen Quartz (ungefähr) alle 30s auslösen lassen? Was würdet ihr empfehlen? Danke im Voraus!
> Macht es hier sinn mit dem Timer zu arbeiten?
Eindeutig ja
...
Peter I. wrote: > Dabei soll Pin0 alle 30s, Pin1 jede Minute, Pin2 alle 3 Minuten und Pin3 > zufällig alle 30s bis 5min angesprochen werden. Das mit dem Zufall kannst Du Dir abschminken. Du kannst Pseudozufall nehmen (rand). Im EEPROM kannst Du Dir den letzten Wert merken, damit sich nicht immer die gleiche Folge ergibt. Besser ist echter Zufall (Timerwert beim Drücken einer Taste). Damit hast Du 2 voneinander unabhängige Ereignisse (CPU-Taktfrequenz und Mensch). > Macht es hier sinn mit dem Timer zu arbeiten? Wie denn sonst? Peter
>Besser ist echter Zufall (Timerwert beim Drücken einer Taste). >Damit hast Du 2 voneinander unabhängige Ereignisse (CPU-Taktfrequenz und >Mensch). Und wenn man unbedingt will: Mit begrenztem Mehraufwand ist auch echter Zufall ohne Taste machbar, vorausgesetzt, geringe Generationsraten sind kein Problem. Das Prinzip: (1) Die Taste durch einen genügend "niedrigqualitativen" und genügend langsamen Rechteckoszillator ersetzen, (2) mit dem Signal den ICP-Interrupt eines schnellen Timers (z. B. T/C1 mit 16 Mhz) auslösen und (3) das LSB des ICP-Zählerstands als Zufallsbit verwenden. Den Rechteckgenerator kann man z. B. mit einem NE555, zwei Widerständen und einem Kondensator realisieren - dessen Output ist mit ausreichend Phasenrauschen behaftet. Ich habe das mal so gemacht und eine ganze Nacht lang 4 Zufalls-Bytewerte pro Sekunde erzeugt, die sich als makellos gleichverteilt erwiesen.
> den ICP-Interrupt Hat der Tiny13 nicht... > eines schnellen Timers (z. B. T/C1 mit 16 Mhz) Hat der Tiny13 nicht... Ein Stück "Antenne" am ADC und ständiges Aufaddieren des ADC-Wertes bringt aber auch schon etwas "Zufall"... ...
Mir geht es auch weniger um den Zufall als die Gestaltung des Programmablaufes ;) - wobei das mit der Antenne klingt sehr interessant! Wie mache ich das mit dem Timer am Besten? Gruß, Peter
> Wie mache ich das mit dem Timer am Besten?
Wie es am Besten geht, das weiß ich nicht...
Ich würde so herangehen:
- Den Kleinsten gemeinsamen Nenner suchen, das wäre die Impulsdauer
von 150 ms, diese als Zeitraster akzeptieren.
- Für jede Spur den Zählumfang als Konstante ermitteln und deklarieren.
Also wieviele "Interrupts" Deine verschiedenen Intervalle dauern.
Bei 30 Sekunden wäre das z.B. 200.
- Für jede "Spur" eine Zählvariable anlegen, die die Interrupts zählt.
Es werden wohl 16-Bit-Variablen werden, die unsigned interpretiert
werden.
- Die Zählvariablen auf ihre Startwerte (Zählumfang) setzen.
- Den ADC auf den offenen ADC-Eingang schalten (ADMUX) und leicht
übertaktet (Vorteiler 1 zu 4) im Free-Run-Mode einschalten (ADCSR).
- Timers so einstellen, dass er alle 150 ms einen Compare-Interrupt
auslöst. Interrupt für Timer einschalten, Interrupt global freigeben.
- In dieser ISR erstmal alle Ausgänge ausschalten, denn es könnte ja
einer eingeschaltet gewesen sein. Dann für jede "Spur" die zugehörige
Zählvariable herunterzählen, beim Erreichen von 0 den zugehörigen
Ausgang einschalten und die Zählvariable wieder auf Startwert setzen.
Für die Zufalls-Spur das momentan kumulierte ADC-Ergebnis duch
Bitschieben mit 8 multiplizieren (natürlich 16 bittig) was 0 bis 2040
ergeben kann, also 0 bis 306 Sekunden und 200 (für den Mindestwert
von 30 Sekunden) aufaddieren. Das sind zwar dann max 5:36 Minuten,
erspart aber Rechnerei.
- In der Mainloop ADC im Polling auslesen, nur die unteren 3 Bit stehen
lassen (ANDI) und auf eine 8-Bit-Variable aufaddieren. Dann auf die
nächste Messung warten (Busywait).
...
Vielen Dank für Deine Antwort - das werde ich einmal genauso probieren. Das einzige, wo es (bisher) bei mir hapert: Wie bekomme ich das mit der Impulsdauer von 150ms hin? Generell bin ich noch nicht wirklich sicher, wie ich den ATTiny und seinen Timer takten, und dann einen zeitgesteuerten Interrupt - wie hier die 150ms - einrichten kann. Wie genau gehe ich da vor?
> Wie bekomme ich das mit der > Impulsdauer von 150ms hin? Der Tiny13 läuft mit einem Takt von 9,6 MHz und aktiviertem Taktvorteiler 1 zu 8, das ergibt 1,2 MHz Controllertakt (siehe Datenblatt). Das lässt sich zwar verändern, ist aber die Grundeinstellung bei Auslieferung und ist für Deinen Zweck völlig ausreichend. Es gibt also erstmal keinen Grund, das zu ändern. Nun musst Du Dir ausrechnen, wieviele Takte der Controller machen muss, damit 150 ms vergehen. Dazu reicht die Rechenkunst der Unterstufe, also erstmal alles auf eine Einheit bringen (Megahertz in Mikrosekunden umrechnen, Millisekunden in Mikrosekunden umrechnen), dann eine einfache Division. Du erhältst nun eine Zahl, die für den Zählumfang des Timers (8 Bit) zu groß ist. Daran hat der Hersteller aber bereits gedacht und hat Dir deswegen einen Vorteiler für den Timer eingebaut, mit dessen Hilfe man nur jeden x-ten Takt des Controllers zählen lassen kann. Einzelheiten verrät Dir das Datenblatt des Controllers im Abschnitt Registerbeschreibung im Kapitel Timer. > Generell bin ich noch nicht wirklich sicher, > wie ich den ATTiny und seinen Timer takten, und dann einen > zeitgesteuerten Interrupt - wie hier die 150ms - einrichten kann. Wie > genau gehe ich da vor? - Datenblatt lesen - Tutorial lesen und verstehen - Codes anderer Leute lesen, analysieren und verstehen, dann eigene Meinung bilden und selbst machen. - Und wenn Dir systematisches Arbeiten nicht liegt, dann ist vielleicht Versuch und Irrtum eine Möglichkeit, Unklarheiten zu beseitigen. Sorry, ist nicht böse gemeint, aber was schnell zusammengefragt wurde, ist auch schnell wieder vergessen. Es gibt Dinge, die muss man sich selbst erarbeiten, sonst versteht man sie nicht wirklich und eiert ewig herum... ...
Ich denke, dass Du damit auf jeden Fall Recht hast. Zu meinem Verständis: Ich habe die Taktfrequenz auf 1,2MHz gelassen, wie Du gesagt hast. Den Prescaler des Timers habe ich auf 1/1024 eingestellt. Das heißt für mich, das der Timerinterrupt 1171875 mal pro ms hochzählt, oder? (1,2MHz / 1024 Prescaler, * 1000000 ergibt Auslöser pro Sekunde (Hz) * 1000 ergibt Wert ins ms) Nun muss ich ja einen "geraden" Wert hinbekommen, um die 150ms abzubilden. Was passiert, wenn ich das Timerregister mit einem negativen Wert initialisiere? Wird dann der Overflowinterrupt trotzdem bei +255, oder bereits bei 0 ausgelöst? (Diese Methode habe ich in einem Beispiel gefunden). Vielen Dank für die Hilfe!
Also der Timer zählt bei 1,2MHz / 1024 1.175,875 Mal pro Sekunde. Das wären dann 1,175875 Mal pro ms. Du musst durch 1000 und nicht mal 1000 rechnen.. Anderenfalls wäre es im Umkehrschluss dann ja eine Frequenz von 1,2GHz ... Die 150ms bekommst du leider nicht genau hin. Mit den gewählten Vorteilern und Frequenzen bekommst du bei einem Overflow-Wert von 8 eine Länge von 146ms hin.. Du hast mehrere verschieden Modi mit denen der Timer läuft. Entweder man lässt ihn bis zu einem bestimmten Wert zählen. Bei erreichen wird ein Interrupt ausgelöst. Oder man gibt einen Startwert vor und der Timer zählt bis zum Overflow, was wieder in einem Interrupt endet..
Ich habe jetzt etwas weiter herumgepielt und den folgenden Code fabriziert, der leider nicht funktioniert: http://nopaste.info/6858c6696b.html Eigentlich sollte die LED alle 3 Sekunden kurz aufblinken. Was mache ich falsch?
Systemfrequenz = 1200000 Hz ==> Timer-Tickfrequenz = 1200000 Hz / 1024 = 1172.875 Hz ==> Timer-Überlauf-Frequenz = 1172.875 Hz / 256 = 4.577 Hz ==> Aufruffrequenz der Zeile "intTmr++;" = 4.577 Hz ==> Aufruffrequenz der Zeile "intTmr = 0;" = 4.577 Hz / 4596 = 9.96 * 10^-4 Hz Jetzt teilst Du noch weiter runter. Warte ein paar Stunden, irgendwann wird die LED aufleuchten. >Was mache ich falsch? Du probierst aufs Geradewohl, ohne den Timer verstanden zu haben.
Jetzt habe ich es endlich verstanden - vielen Dank!!!
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.