mikrocontroller.net

Forum: Projekte & Code ADC readout routine


Autor: Michael H. (overthere)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

bei einem ADC möchte man oft mehere Werte auslesen, und sich nicht groß 
darum kümmern, die ADMUX-Channel zu wechseln.
Auch ist es zu einer Unart geworden auf ADC Werte zu warten.

Diese Routine löst das Problem: Es werden kontinuierlich alle aktiven 
Channels ausgelesen, und es ist somit immer der aktuelle Wert da. Die 
Routine ist einfach zu benutzen und verbraucht sehr wenig RAM und Flash. 
Desshalb ist diese Routine bestens für Einsteiger geeignet, erfüllt aber 
(hoffentlich) auch die Geschwindigkeitsanforderungen der Profis.

Der Code im Anhang ist auf Englisch dokumentiert. Veröffentlich ist er 
unter der GPL.

Viel Spass beim Ausprobieren.

Autor: Michael H. (overthere)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
und die adc.h

Autor: Michael H. (overthere)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Update für die ADC Readout routine. Einen Bug beim Lesen entfernt. Der 
ausleser kam beim umsetzen vom ADMUX etwas durcheinander, sodass falsche 
Werte ausgegeben wurden.

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin,

/* Warnung: Versuche nicht _adc_current_pos durch eine lokale
   * Variable zu ersetzen. Das geht nicht, und hat mich zwei
   * Tage Fehlersuche gekostet! */

das Schlüsselwort static ist dir unbekannt ?

MfG

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

Bewertung
0 lesenswert
nicht lesenswert
Du gestattest ein paar Anmerkungen
ISR(SIG_ADC){
vermische nicht neue ISR Schreibweise mit den alten Namen der Interrupt 
Vektoren. Die neuen Namen der Interrupt Vektoren enden allesamt immer 
auf _vect

_adc_current_pos
Ob diese Variable aus dem Modul herausgeführt werden muss oder nicht, 
ist debatierbar. Defaultmässig würde ich sie im Modul verstecken mit dem 
Hintergedanken, dass es ausserhalb niemanden etwas angeht, welcher ADC 
jetzt gerade im Moment ausgelesen wird. Selbiges für das _adcdata Array. 
Da du sowieso schöne Zugriffsfunktionen hast, willst du eigentlich 
nicht, dass sich jeder dahergelaufene Code an diesen Variablen zu 
schaffen macht.

Variablennamen die mit _ beginnen sind ausschliesslich für den Compiler 
bzw. die Runtime-Library reserviert. Sinn der Sache ist es, dass es 
keine Namenskollisionen von selbstdefinierten Namen und Dingen aus der 
Runtime Library gibt. Man könnte jetzt argumentieren, dass dieselbe 
Strategie auch hier sinnvoll ist, aber so richtig koscher ist es 
trotzdem noch nicht. Machst du deine jetzigen Variablen modulglobal 
(also static auf File-Scope), dann stellt sich dieses Problem allerdings 
gar nicht mehr :-)

#define ADC_adcs 7
Halte dich bitte an die Konvention, dass Makros komplett in 
Grossbuchstaben geschrieben werden. Das ist zwar nur eine Konvention, 
allerdings ist es eine der wenigen, an die sich tatsächlich so gut wie 
alle C-Programmierer halten. Sinn der Sache ist es, dass man im Code den 
Unterschied zwischen
    k = max( i++, j++ );
und
    k = MAX( i++, j++ );
sofort erkennen kann. Zweiteres ist ein Makro, und daher muss man das 
Makro überprüfen, ob diese Operation nicht in die Hose gehen wird. 
Ersteres ist eine Funktion und daher brauche ich mir keine Gedanken 
machen. Die Argumente werde einmal ausgewertet und an die Funktion 
übergeben. Da kann es per Definition nicht passieren, dass i++ zweimal 
ausgewertet wird.
Auch ist bei
extern volatile unsigned int _adcdata[ADC_ADCS];
jedem sofort klar, das die Anzahl der _adcdata Einträge mittels eines 
Makros festgelegt wird und es daher irgendwo einen #define dafür gibt.
(_adcdata[_adc_current_pos]==ADC_DO_NOT_MEASURE
ADC_DO_NOT_MEASURE  (schau dir auch die Schreibweise an: measure, nicht 
messure) ist ein Makro, welches einen fixen Wert verkörpert. Mit der 
Schreibweise seh ich das, mit deiner ist nicht klar ob es sich da nicht 
etwa um eine Variable handelt, die ihren Wert auf dubiose Weise bekommt.

#define ADCSRA_CONFIG (1<<ADEN)+(1<<ADSC)+(1<<ADIE)+(1<<ADPS2)+(1<<ADPS1)+(0<<ADPS0)
Wozu gibt es dieses Makro, wenn es dann sowieso nicht benutzt wird?

void adc_remove(unsigned char channel) {
  unsigned char i=ADC_adcs; 
  while(i--){
    if(i==channel) continue;
    if(_adcdata[i]==ADC_do_not_messure){ 
      _adcdata[channel]=ADC_do_not_messure;
      return;
    }
  }
}
Sorry, aber diese Funktion verstehe ich einfach nicht. IMHO ist die 
völlig falsch: Ein Kanal wird nur dann aus der Messung ausgeschlossen, 
wenn es noch einen anderen Kanal gibt, der bereits aus der Messung 
ausgeschlossen war? Irgendwie ergibt das nicht viel Sinn (oder aber ich 
verstehe den Sinn nicht)

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.