mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Berechnung abbrechen


Autor: Luky (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Gast123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Bergie B. (bergie)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Luky (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Luky (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert



ISR(USART_RX_vect) { 
(...)

USART_transmit( HIGHER(ADCVal) );
USART_transmit( HIGH(ADCVal) );
USART_transmit( LOW(ADCVal) );

ADCVal = 0;

}

main

for (;;) {  // Loop forever

  if ( ADCVal == 0 ) { //neuer Zyklus: Initialisieren

    readFromLTC2485(0, 4); //ADC lesen
    ADCVal = ((uint32_t) (ucDataRead[0]&0x3F)<<24) + ((uint32_t) ucDataRead[1]<<16) + (ucDataRead[2]<<8) + ucDataRead[3];

(...)

  }
    //normal: mittle Werte

    readFromLTC2485(0, 4); //ADC lesen
    ADCVal = ( ADCVal + ( (uint32_t) (ucDataRead[0]&0x3F)<<24) + ((uint32_t) ucDataRead[1]<<16) + (ucDataRead[2]<<8) + ucDataRead[3] ) / 2 ;

(...)  

  } //forever  


Autor: Bergie B. (bergie)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 ?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Luky (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm
Da ist wohl mit den Postings was schief gelaufen.

Autor: Luky (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Luky (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.