2560: Free Running A8 - A15

Servus,
ich will den free running mode nutzen für Pin14.
Vorher lief das mit analogread A14 problemlos, also kein technisches Problem.

Jetzt habe ich viel gesucht, Chat-GPT gibt auch schon auf.
Ich bekomme einfach keine richtigen Daten zwischen A8 und A15.
Ja da muss was umgeschaltet werden, erklärt mir Chat GPT nun den ganzen Tag aber davon klappt rein gar nichts.

Der Aufruf in der Loop ist zu langsam und ich brache ca 5kHz Samplerate.

Hat jemand so etwas zum laufen bekommen?

Vielleicht hier

einsteigen.

Hab ich gesehen und löst das Problem nicht mit A8 - A15.

uint16_t adcValue = 0; // Variable für den ADC-Wert

void setup() {
  Serial.begin(115200);

  // --------- ADC auf A14 (PK6) konfigurieren und messen ---------
  ADMUX = (1 << REFS0) | (14 & 0x0F); // AVcc Referenz, Kanal 14
  ADCSRB |= (1 << MUX5);              // MUX5 für Kanal > 7 setzen
  ADCSRA = (1 << ADEN) | (1 << ADPS2); // ADC aktivieren, Prescaler 16

  ADCSRA |= (1 << ADSC);              // Wandlung starten
  while (ADCSRA & (1 << ADSC));       // Warten bis fertig

  adcValue = ADC;                     // Ergebnis speichern
}

void loop() {
  // Nur die Ausgabe!
  float voltage = adcValue * (5.0 / 1023.0); // Umrechnung in Volt

  Serial.print("Spannung an A14: ");
  Serial.print(voltage, 3);
  Serial.println(" V");

  delay(500); 
}

Das ist zum testen, zeigt aber vollkommen falschen Wert an.
Mit analogread A14 stimmt es dann aber.

Um an den oberen Port zu kommen, muss MUX5 gesetzt sein. Siehe

Table 25.1

Hat hier jemand geschafft

1 Like

Hallo,

die Tabelle 26.4 wäre die passende.

Du möchtest Pin A14 als Eingang konfigurieren, welcher zufällig dem ADC14 entspricht.

Was willst du mit (14 & 0x0F) erreichen?
Schau dir die Bitfolge an.

Lese aus der Tabelle die benötigten MUX Bits für ADC14 heraus.
Die MUX Bits verstreuen sich auf das Register ADMUX und ADCSRB.

Für ADC14 benötigt man die MUX Bitfolge 10 01 10.
Also Bits 5, 2 und 1.
Das konfigurierst du und setzt ADCSRB hart auf 0 ohne verodern.

Desweiteren sollte man neue Werte erst abrufen wenn, wenn eine Messung fertig ist.
Auf das Flag kann man pollen oder die ISR verwenden.

Und das hier

float voltage = adcValue * (5.0 / 1023.0); // Umrechnung in Volt

bitte korrigieren in

float voltage = adcValue * (5.0 / 1024); // Umrechnung in Volt

noch etwas besser

const float voltage = 5.0 * adcValue / 1024; // Umrechnung in V
// oder
const unsigned long milliVolt = 5000UL * adcValue / 1024; // Umrechnung in mV

Wieviele Analoge Eingänge willst Du gleichzeitig mit 5kHz Samplerate lesen und welche Auflösung (volle 10 bit oder weniger)?

Grüße Uwe

Soweit ich weiß, habe ich das auch für hohe Pinnummern am Mega getestet:

Hallo,
vielen Dank für die Erklärung!
Da ich nicht weitergekommen bin sollte halt KI unterstützen.

Nun hat es geklappt!

Zeigst Du Deine Lösung?

Ja, bitte

Hier die einfache Lösung.
Für sich alleine geht das sehr gut!
ABER ich wollte damit eigentlich 2 Spannungen erfassen und die restlichen 6 sind nicht so kritisch.
Die 6 Unkritischen frage ich alle 500ms mit einem analogread ab indem ich den free run unterbreche und wieder starte.
Da funktioniert generell auch, allerdings sind die Werte der zwei schnellen Messungen unbrauchbar für mich, da es zu starken Ausreißern kommt.
Ich habe schon mit dem Verwerfen von Messungen versucht nach dem Umschalten der Kanäle. Bringt nichts.
Wie gesagt einzeln zum Testen super, im Code der sehr komplex ist scheint das nicht mehr stabil zu klappen.

So hier der Test für A14:

// Nur A14 (ADC 14) abfragen und ausgeben

const float ADC_REF = 5.0;
const int ADC_MAX = 1023;

volatile int a14Value = 0;

void setup() {
  Serial.begin(115200);

  // ADC auf A14 (ADC 14) initialisieren (Free Running, Interrupt)
  uint8_t adcChan = 14;
  ADMUX = (1 << REFS0) | (adcChan & 0x07);  // AVcc als Referenz, Kanal 14 (niedrige 3 Bit)
  if (adcChan >= 8) ADCSRB |= (1 << MUX5);
  else ADCSRB &= ~(1 << MUX5);

  // Prescaler 128, Free Running, Interrupt enable
  ADCSRA = (1 << ADEN) | (1 << ADIE) | (1 << ADATE) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
  ADCSRB &= ~(1 << ADTS2) & ~(1 << ADTS1) & ~(1 << ADTS0); // Free Running Mode
  ADCSRA |= (1 << ADSC); // Start ADC
  sei(); // Interrupts einschalten
}

ISR(ADC_vect) {
  a14Value = ADC; // Wert direkt übernehmen
}

void loop() {
  static unsigned long lastPrint = 0;

  if (millis() - lastPrint > 1) {
    lastPrint = millis();

    // Wert atomar kopieren
    int value;
    noInterrupts();
    value = a14Value;
    interrupts();

    float voltage = value * ADC_REF / ADC_MAX;

    Serial.println(value);

  }
}

Wie kommst du auf diese witzige Idee?

War der falsche Code, hab den richtigen eingefügt.

Ja und man kann auch höhere Geschwindigkeiten testen, klappt sogar sehr gut und es kommt immer auf die Anwendung an die man umsetzten möchte.
Und so kommt man auf witzige Ideen!

Das ist aber nett von dir!

Klar!
Natürlich kann man das Datenblatt ignorieren.

Siehe dazu deine eigene Aussage:

Welche natürlich geheim bleiben muss.
Genauso wie die Beschaltung und das versagende Programm.

Na hast was falsches gefrühstückt?
Ich kann dir hier gerne 14 Dateien zur main.ino posten insgesammt knapp 5k zeilen Code.
Den Du niemals verstehen wirst wenn Du nicht die Anwendung kennst und die dazugehörige Hardware bestehend aus einer Platine mit fast 700 Pins die nur ein Teil es komplexen selbst entwickelten Gerätes mit zusätlichen 7 Baugruppen sind.

BOA EY!
Krass oder?
Läuft ganz vorzüglich und ich wollte nur etwas zu einem einzigen Punkt wissen,
wie ich für zwei Werte die ich aus einem mir bekannten Grund schneller sampeln möchte.
Dazu brauchst DU weder den gesamten Code, noch wissen was ich mir hier bastel.
Hättest Du gefragt, hättest Du sogar eine Antwort bekommen.

So Thema geschlossen!
Lese hier nicht mehr mit :smiley:
Geh mal an die Luft, tut Dir gut!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.