Forum: Mikrocontroller und Digitale Elektronik AVR ATTiny13 und Zeitsteuerung - Vorschlag zur Realisierung


von Peter I. (extasic)


Lesenswert?

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!

von Hannes Lux (Gast)


Lesenswert?

> Macht es hier sinn mit dem Timer zu arbeiten?

Eindeutig ja

...

von Peter D. (peda)


Lesenswert?

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

von Gast (Gast)


Lesenswert?

>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.

von Hannes Lux (Gast)


Lesenswert?

> 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"...

...

von Peter (Gast)


Lesenswert?

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

von Hannes Lux (Gast)


Lesenswert?

> 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).

...

von Peter I. (extasic)


Lesenswert?

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?

von Hannes Lux (Gast)


Lesenswert?

> 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...

...

von Peter I. (extasic)


Lesenswert?

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!

von Daniel D. (bademeister)


Lesenswert?

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..

von Peter I. (extasic)


Lesenswert?

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?

von Gast (Gast)


Lesenswert?

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.

von Peter I. (extasic)


Lesenswert?

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
Noch kein Account? Hier anmelden.