Ein Mikrocontroller (Atmega168) soll ein paar Spannungen einlesen. Dazu
wird über einen längeren Zeitraum gemittelt.
Auf Nachfrage werden die Werte gesendet und ein neuer Zyklus gestartet.
Mein Problem ist, dass die Reaktionszeit auf die Sendeaufforderung sehr
kurz und konstant sein muss. Also bleibt mir -glaube ich- nichts anderes
übrig, als eine Interruptroutine für das Senden über USART zu verwenden.
Das Problem liegt nun darin, dass ich nach dem senden wieder von einem
definierten Zustand starten will.
Das Programm soll also nicht mit der Messung dort fortfahren, wo der
USART-Interrupt aufgetreten ist, sondern am Beginn der Messroutine.
Kann ich nach dem Interrupt ohne einen vollständigen Softwarereset
auszulösen (dann müsste ich zu viele Initialisierungen machen und das
dauert zu lange) an eine bestimmte Stelle springen?
Hi,
evtl. hilft es, in der ISR ein Flag oder Bit zu setzen in einer
Variablen, die in jedem Messdurchlauf abgefragt wird. Ist das "lieber
controller, starte mal bitte von vorn"-Flag gesetzt, erfolgt im
Hauptprogramm oder an einer anderen sinnvollen Stelle der Sprung zum
Anfang des Messablaufs.
Luky schrieb:
> Mein Problem ist, dass die Reaktionszeit auf die Sendeaufforderung sehr> kurz und konstant sein muss.
Wie kurz?
Wie konstant?
> Also bleibt mir -glaube ich- nichts anderes> übrig, als eine Interruptroutine für das Senden über USART zu verwenden.> Das Problem liegt nun darin, dass ich nach dem senden wieder von einem> definierten Zustand starten will.> Das Programm soll also nicht mit der Messung dort fortfahren, wo der> USART-Interrupt aufgetreten ist, sondern am Beginn der Messroutine.> Kann ich nach dem Interrupt ohne einen vollständigen Softwarereset> auszulösen (dann müsste ich zu viele Initialisierungen machen und das> dauert zu lange) an eine bestimmte Stelle springen?
Dein ganzes 'Konzept' klingt danach, als ob es verkorkst ist.
Vermutung ins Blaue: du verwendest _delay_ms und kommst jetzt in
Schwierigkeiten, weil du kein Timing garantieren kannst.
-> _delay_ms ist fast immer der falsche Weg um ein Timing zu erzeugen.
Der saubere, richtige Weg führt praktisch immer über einen Timer, der
einen Basistakt erzeugt.
hi!
Meiner erste Idee dazu wäre das du beim starten deiner Messung ein Flag
setzt. Dieses wird immer wieder abgefragt wärend der Messung. Sollte es
nicht mehr gesetzt sein könntest du die Messung beenden, alle Werte
verwerfen und eine neue Messung starten. Nun must du nur noch den Wert
des Flag im IE zurücksetzten.
Vieleicht hat ja noch jemand eine schönere Lösung.
LG
Nein, ich habe kein _delay_ms.
Ich messe ein paar Spannungen (auch mit externem, langsamen ADC) und
mittle diese über die (unbekannt lange) Messperiode.
Der Hauptcontroller fragt dann zu einem unbekannten Zeitpunkt die
Messcontroller ab. Diese müssen also schnell reagieren, damit ich
mehrere Slaves dranhängen und zuverlässig auf Timeouts prüfen kann. Die
Einsprungzeit in die Interruptroutine kann ich kompensieren, eine
Abfrage vor jeden Messbefehl wird aber etwas schwierig, vor allem da
diese nicht atomar sind und ich verhindern möchte, mitten in einem
Zyklus wieder zu beginnen.
Und immer mit cli und sei die Interrupts zu deaktivieren / aktivieren
baut teilweise ziemliche Verzögerungen ein.
Ich möchte also nach dem Sendevorgang die alten Messungen alle verwerfen
und sauber von neuem beginnen.
Luky schrieb:
> Nein, ich habe kein _delay_ms.
Dann: Code zeigen
> Ich messe ein paar Spannungen (auch mit externem, langsamen ADC) und> mittle diese über die (unbekannt lange) Messperiode.
OK.
> Der Hauptcontroller fragt dann zu einem unbekannten Zeitpunkt die> Messcontroller ab. Diese müssen also schnell reagieren, damit ich> mehrere Slaves dranhängen und zuverlässig auf Timeouts prüfen kann.
Was stellst du dir so als Zahlenwert für einen Timeout vor?
> Und immer mit cli und sei die Interrupts zu deaktivieren / aktivieren> baut teilweise ziemliche Verzögerungen ein.
Das ist mir noch nicht klar.
Code?
> Ich möchte also nach dem Sendevorgang die alten Messungen alle verwerfen> und sauber von neuem beginnen.
Klingt für mich nach:
Nach dem Senden werden die Summenvariablen, die du zum Berechnen des
Mittelwerts benutzt, auf 0 zurückgesetzt.
Also ich bin mit nicht sicher ob ich das richtig verstehe, aber ich
schreibe mal drauflos:
1) Du machst eine Messung.(Var: a)
2) Du Speicherwer den Wert (a) in 'X' ab.
3) Du machst eine Messung.(Var: a)
4) (a+X)/2 => X
5) 3 & 4 werden immer weiter wiederholt
nach 10 Messungen hat der:
- 10 Messwert 1/2 einfluss auf X
- 9 Messwert 1/4 einfluss auf X
- 8 Messwert 1/8 einfluss auf X
- 7 Messwert 1/16 einfluss auf X
- 6 Messwert 1/32 einfluss auf X
- 5 Messwert 1/64 einfluss auf X
- 4 Messwert 1/128 einfluss auf X
- 3 Messwert 1/265 einfluss auf X
- 2 Messwert 1/512 einfluss auf X
- 1 Messwert 1/512 einfluss auf X
ist das gewollt ? oder sehe ich das falsch ?
Luky schrieb:
> if ( ADCVal == 0 ) { //neuer Zyklus: Initialisieren>> readFromLTC2485(0, 4); //ADC lesen
Was macht readFromLTC2485?
Du hast von einem externen ADC gesprochen. Die werden doch normalerweise
so irgendwie angesprochen
Starte Wandlung
Warte aufs Fertigwerden
Lies Ergebnis aus
Das kann man auch oft umdrehen
if( Ergebnis schon fertig ) {
Lies Ergebnis und verarbeite
Starte Wandlung
}
man hat dann so vom Starten der Wandlung bis zum Holen des Ergebnisses
in der übergeordneten Endlosschleife alle Zeit der Welt, andere Dinge zu
erledigen.
Während der ADC buddelt, macht man andere Sachen und wenn die fertig
sind, wird der ADC befragt ob er schon fertig ist und das Ergebnis
geholt. Quasi in Multitasking auf 2 Chips. Der ADC fängt zu werkeln an,
ohne dass ihm zunächst wer auf die Finger schaut.
> gesprungen wurde nicht verwenden zu müssen und "einfach" an den beginn> der Endlosschleiefe zu springen und nicht dorthin, wo der Interrupt> unterbrochen hat.
Vergiss diese wilden Sprünge quer durch die Pampa gleich wieder.
Das bringt dich nicht weiter. Wenn überhaupt, dann bringt dich dieser
Gedankengang maximal nur in Schwierigkeiten.
Was ist mit der ADC Abfrage? Lässt sich die nach obigem Schema umbauen?
Luky schrieb:
> gesprungen wurde nicht verwenden zu müssen und "einfach" an den beginn> der Endlosschleiefe zu springen und nicht dorthin, wo der Interrupt> unterbrochen hat.
Vergiss diese wilden Sprünge quer durch die Pampa gleich wieder.
Das bringt dich nicht weiter. Wenn überhaupt, dann bringt dich dieser
Gedankengang maximal nur in Schwierigkeiten.
Was ist mit der ADC Abfrage? Lässt sich die nach obigem Schema umbauen?
Ja eigentlich wollte ich folgendes posten:
Momentan handelt es sich hier noch um einen simplen Filter, der soll
aber besser werden.
Ja. das ist schon richtig so.
Im Programm schalte ich danach noch den externen Multiplexer um und
messe 7 andere Spannungen, der Teil ist aber nicht hier im Code.
Die Frage ist, ob es eine Möglichkeit gibt die Deaktivierung der
Interrupts vor jeder Messung und der Abfrage ob in die Interruptroutine
gesprungen wurde nicht verwenden zu müssen und "einfach" an den beginn
der Endlosschleiefe zu springen und nicht dorthin, wo der Interrupt
unterbrochen hat.
Luky schrieb:
> Im Programm schalte ich danach noch den externen Multiplexer um und> messe 7 andere Spannungen, der Teil ist aber nicht hier im Code.
Hmm
> readFromLTC2485(0, 4); //ADC lesen
liest das 4 Spannungen vom ADC?
Kein Wunder dass du in Schwierigkeiten kommst.
Das liest 4 Bytes vom ADC und speichert sie in ucDataRead[0]..[3]
Funktioniert auch alles wunderbar.
Aber wenn ich am Anfang die Interrupts deaktiviere und sie am ende
wieder aktiviere gibt es halt zu viel Verzögerung und ich beginne in
einem undefinierten Zustand wieder mit dem neuen Messzyklus.
Mir würde die Idee mit dem "wilden Sprüngen" an genau eine Stelle
deshalb sehr gut gefallen...