Zwei Potis an Arduino Due: Fehler in der Ausgabe der Werte

Hallo,

ich möchte gern an zwei nebeneinanderliegenden Analog Pins jeweils einen Poti anschließen. Zum Testen habe ich den Code für beide Pins vorbereitet, aber in Ermangelung des zweiten Potis nur mit einem getestet. Der Test-Poti ist mit den äußeren Anschlüssen mit 3,3V und GND Pin verbunden. Das Kabel vom Mittelausgang des Potis habe ich dann zwischen den Analogpins umgesteckt.

Beim Drehen des Potis an Pin A4 sollten eigentlich MIDI-Daten für Kanal 4 übertragen werden, an Pin A5 für Kanal 5. Die Beobachtung ist nun, dass beim Drehen des Potis an einem der Kanäle, immer für beide Kanäle ein Wert ausgegeben wird. Der Unterschied ist lediglich der, dass beim angesteckten Pin (z.B. A4) die Werte zwischen 0 und 127 pendeln, am Nachbar-Pin A5 etwas "enger, d.h. zwischen 7 und 124. Steckt man auf A5 um zeigt sich das gleiche Verhalten, nur andersherum.

Ich habe nun einige Zeit herumprobiert, jedoch keine Lösung gefunden. Nun hoffe ich auf euch :slight_smile:

#include "MIDIUSB.h"

int LastPotOW = 1;
int LastPotSW = 1;

int PotT = 20;

int CCchanOW = 4;
int CCchanSW = 5;

int controller = 11; //Controller Nummer, 11=Expression Pedal


void controlChange(byte channel, byte control, byte value) {
  midiEventPacket_t event = {0x0B, 0xB0 | channel, control, value};
  MidiUSB.sendMIDI(event);
}


void setup() {
  pinMode(A4, INPUT);
  pinMode(A5, INPUT);
}

void loop() {
  int CurOW = analogRead(4);
  int MapOW = map(CurOW, 0, 1023, 0, 127);
  int CurSW = analogRead(5);
  int MapSW = map(CurSW, 0, 1023, 0, 127);

  if (abs(CurOW - LastPotOW) >= PotT) {
    controlChange(CCchanOW, controller, MapOW); // Set the value of controller 10 on channel 0 to 65
    LastPotOW = CurOW;
  }
  
  if (abs(CurSW - LastPotSW) >= PotT) {
    controlChange(CCchanSW, controller, MapSW); // Set the value of controller 10 on channel 0 to 65
    LastPotSW = CurSW;
  }
}

hairlessmidi

Du solltest den unbenutzten Anschluss mit einem Widerstand von ~10 Kiloohom auf Masse legen, damit er nicht schwebt. Offen wird er immer irgend welchen Unsinn anzeigen.

Danke für die schnelle Hilfe! Der Widerstand hat die gesuchte Abhilfe gebracht. Wieder ein Stück schlauer geworden.

Der Controller auf dem Due hat eigentlich nur einen AD-Wandler Die vielen analogen Eingänge werden durch einen Multiplexer realisiert der die Eingänge nacheinander an den ADC verbindet. Der ADC hat eine Sample and Holt Schaltung der die zumessende Spannung für die Dauer der Wandlung konstant hält. Ist nun ein analoges Eingangspin nicht beschaltet so verbleibt die zuletzt gemessene Spannung in der S&H Schaltung und wird ein zweites mal gemessen.
Aus diesem Grund mißt Du zweimal fast die geliD Wandlerobwohl der Multiplexer 2 verschiedene Eingangspins an den AD-Wandler anschließt.

Ein ähnliches Phänomen hast Du wenn der Innenwiderstand der analogen Spannung zu groß ist. Dies ist zB der Fall wenn Du zB einen 1MOhm- Potentiometer als Spannungsteiler nehemn würdest. Die analoge Spannungsquelle (poty) kann nicht genug Strom liefern damit die Sample and Hold Schaltung den internen Kondensator ganz umlädt. Man erreicht nicht die Messspannung sondern nur etwas zwischen der letzten Messung und der jetzigen. Abhilfe schafft eine niederohmige Spannungsquelle für die zu messende Spannung. Wenn die Spannung sich nur langsam ändert kann ein 0,1µF Kondensator zwischen Analogpin und Masse den Strom leifern der für die Konvertierung notwendig ist. Ansonsten hilft nur ein Impedanzwandler zB mit einem Operationsverstärker aufgebaut.

Grüße Uwe

Hallo @uwefed

danke für die ausführliche Erklärung! Jetzt verstehe ich das nocheinmal besser. Dein zweiter Absatz klingt fast so, als würdest du mein Projekt besser kennen als ich. Ich habe daraufhin gerade noch einmal die Widerstände gemessen. Denn im Laboraufbau habe ich ein 10 kO Poti benutzt. In der geplanten Anwendung (ein Schweller-Tritt einer MIDI-Orgel) wollte ich eine vorhandene Schaltung nutzen und nur an den Arduino anklemmen. Der unterschiedliche Widerstand wird hier durch eine Fotozelle und ein Leuchtmittel erzeugt. Je nach Stellung des Tritts wird mehr oder weniger Licht auf die Fotozelle durchgelassen.

Momentan ist dort eine 12V Glühbirne mit 0,1A verbaut. Wenn die an ist, bewegt sich der Widerstand zwischen ca. 1,5 Kilo Ohm und 2,5 Mega Ohm. Das wäre ja, wenn ich dich richtig verstanden habe, genau das von dir beschriebene Problemszenario. Wenn es auf der Fotozelle hell genug wird, sinkt der Widerstand zumindest laut Multimeter auf 0 Ohm.

Die Frage ist nun, ob es ggf. ausreicht, ein ausreichend helles (LED-) Leuchtmittel einzusetzen, das auch separat und nicht durch den Arduino mit Spannung versorgt wird. Das könnte den Widerstand ggf. genug absenken. Was wäre denn der maximale Widerstand, mit dem ein Arduino Due mit 3,3V umgehen kann?

Alternativ eine Frage zu deiner Kondensator-Abhilfe bzw. ich hoffe ich habe den Aufbau richtig verstanden. Ich würde einmal die Fotozelle, die nur zwei Anschlüsse hat, auf 3,3V und Analog-Pin klemmen. Entweder kommen dann am Pin bis zu 3,3V oder gar nichts an. Und zusätzlich dazu würde ich Analog-Pin und GND mit einem 0,1µF Kondensator "überbrücken"?

Mache einen Testaufbau.
Spiele den Code rauf:

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

void loop()
{
  Serial.println(analogRead(A0));
  delay(50);
}

Dann verbinde kurz A0 mit +3,3V.
Warte, bis auf dem seriellen Monitor 0 ausgegeben wird.

Könnte etwas länger dauern...

@combie
Glaub mir, ich möchte wirklich nicht, dass du in Bezug auf meine Anfragen unsinnige Anstrengungen zeigen musst. Dir steht es frei, diese einfach zu ignorieren.

Hier wird teilweise für Anfragen ein gewaltiges Fachwissen vorausgesetzt. Hätte ich das in dem Maße, würde ich ja nicht fragen müssen.

Danke trotzdem für alle Antworten! Auch den Test werde ich machen, gute Idee.

Meines erachtens nicht.

Grüße Uwe

Ich danke dir für die Aufmerksamkeit welche du mir dann doch noch zukommen lässt.

Das ist auch vollkommen logisch!
Denn auf Grund meiner hoch entwickelten präkognitiven Fähigkeiten, weiß ich schon lange bevor ich antworte, dass (und von wem) ich ignoriert werden werde.

Auch hier meinen Dank!
Ohne deine doch sehr klare und logische Ansage, wäre ich wohl nie auf die Idee gekommen, dass ich Fragen auch ignorieren darf.

Solange du Ansagen wie "Datenblatt" ignorierst/überliest wird sich an dem Zustand auch schwerlich was ändern.

Offensichtlich betrachtest du das Forum als eine Art DokuVorleseService.
Ich nicht.

image

Ich würde die Schaltung so lassen wie es ist und einen Operationsverstärker nehmen. Schaltung Impedanzwandler.

Als Operationsverstärker braucht es einen RAIL to RAIL Typ. zB LMV358 (2 fach)

Grüße Uwe

Hallo zusammen,

nach Euren Antworten war ich etwas pessimistisch, dass sich das Problem schnell lösen lässt. Ich habe nun einfach einen Test gemacht, Schaltung wie im Funduino-Tutorial. Als Widerstand zwischen Fotowiderstand und GND habe ich einen 10 kOhm verwendet. Und dann habe ich es einfach probiert, wie von my_xy_project vorgeschlagen (gut, er hatte es mit dem Serial Monitor vorgeschlagen...).

Die Beobachtung war überraschend gut, fast sogar sehr gut. Die Reaktion war sehr schnell, d.h. unmittelbar. Keine Verzögerungen. Die Max/Min Werte, die aus den 1024 möglichen Werten am Analogpin gemappt werden, sind 0 und 127. Im momentanen Setting ohne Änderung sind erkannte Werte zwischen 1 und 108 möglich. Bei 108 fällt das maximale Licht der Funzel-Glühbirne auf den Fotowiderstand. Hält man dann eine zusätzliche Lichtquelle in Richtung Fotowiderstand, sinkt dieser noch mehr ab und es kommen Werte um 121/123.

Meine Schlussfolgerung wäre nun: ich ersetze die E10 Glühbirnen durch E10 LED Leuchtmittel, die etwas heller leuchten. Spannungsversorgung derer wäre extern, also nicht über Arduino. Dann müsste ich ohne weitere Änderung der Hardware inkl. Verkabelung (fast) die komplette Bandbreite zwischen 0 und 127 ausschöpfen können.

Danke für Eure Hilfe!

Warum willst Du das?
Und warum willst Du das durch ein helleres Leuchtmittel machen lassen?
Wenn Dir bekannt ist, das Du nicht auf 127 kommst, dann kannst Du auch das mapping ändern.
Möglich wäre als obere Grenze 140 anstatt 127 zu definieren. Dann bliebe die Funzel erhalten, und in einem weiteren Schritt könntest Du testen, ob x>127 und dann auf x=127 setzen, um z.B. eine hellere Quelle zu ermöglichen.

Ja, das habe ich im Nachgang dann auch gedacht. Wobei die 127 eine fixe Obergrenze sind, kommt aus dem MIDI-Protokoll. Daher wäre gut, auf der Seite des Mappings 0 bis 127 ausschöpfen zu können.

Aber vermutlich käme ich ans selbe Ziel, wenn ich den Bereich "0 bis 1023" anders auf die "0 bis 127" mappe, z.B. nur 0 bis 850 oder 870. Das teste ich in den nächsten Tagen mal aus. Bzw. ich müsste mir über Serial Monitor ja ausgeben lassen können, was der Maximalwert am Analogpin ist. Das wäre dann mein Maximalwert fürs Mapping.

Das geht zwar, macht aber keinen SInn.
Was passiert, wenn Du durch irgendeinen Zufall über die selbst gesteckte Grenze drüberwegschiesst?

Probiere es aus!



void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println(F("\r\nStart...\r\n"));
  uint16_t myValue = 900;
  uint8_t mapValue = map(myValue, 0, 870, 0, 127);
  Serial.println(mapValue);
}

void loop() {
  // put your main code here, to run repeatedly:

}

Was hindert Dich daran:

zu ändern in

  uint16_t CurOW = analogRead(4);
  uint8_t MapOW = map(CurOW, 0, 1023, 0, 140);
  if (MapOW>127) MapOW=127;

PS: Das analogRead(4);solltest Du ändern und den Pins Namen geben. Diese als const deklarieren und genauso verwenden. Freut sich der Compiler, der Leser und Du Dich später auch, wenn Du nur an einer Stelle die Pin-Nummer ändern und nicht stundenlang durch den Code scrollen musst.

Natürlich hindert mich nichts daran, ich möchte es nur gern verstehen.

Ich habe es genauso ausprobiert. Ergebnis war 131, d.h. 0 bis 127 wurde auf 0 bis 870 gemappt und bei Überschreiten der 870 wurde (vermutlich im selben Verhältnis) auf 127 drauf addiert bis 131. Den Wert kann man dann, wie du schon geschrieben hast, auf 127 deckeln und fertig.

Deinen Mapping-Ansatz (0 bis 140) habe ich genauso getestet und das ist vom Ergebnis her vergleichbar, sprich man kann auf gemappte Werte von 0 bis 127 kommen.

Hier mal das Ergebnis einkopiert. Beim ersten Test-Set habe ich "dein" Mapping verwendet, beim zweiten "meins" und jeweils die Überschreitung der vorgesehenen MIDI-Werte provoziert.

12:49:01.641 -> 
12:49:01.641 -> Start...
12:49:01.641 -> 
12:49:01.641 -> 1023
12:49:01.641 -> 140
12:49:01.641 -> 127
12:49:38.215 -> 
12:49:38.215 -> Start...
12:49:38.215 -> 
12:49:38.215 -> 900
12:49:38.215 -> 131
12:49:38.215 -> 127

Das war der Versuchs-Code, die Werte im Mapping jeweils angepasst.

  Serial.begin(115200);
  Serial.println(F("\r\nStart...\r\n"));
  uint16_t myValue = 900;
  uint8_t mapValue = map(myValue, 0, 870, 0, 127);
  Serial.println(myValue);
  Serial.println(mapValue);
  if (mapValue>127) mapValue=127;
  Serial.println(mapValue);

Worin besteht denn der Vorteil der Beibehaltung von "0...1023", wenn man bei beiden Ansätzen die Obergrenze des gemappten Wertes setzen und somit innerhalb des Zielkorridors von MIDI bleiben kann?

Danke übrigens für den Benennungs-Tip! Leuchtet ein...

Warum willst Du etwas künstlich durch Software begrenzen, was bereits durch die Hardware begrenzt ist?
Das im obigem Code einfach proportional weiter gemappt wurde ist Zufall.

Das soetwas auch schief gehen kann, zeigt Dir vielleicht das folgende Beispiel.


void setup() {
  Serial.begin(115200);
  Serial.println(F("\r\nStart...\r\n"));

  for (byte b = 0; b < 50; b += 5)
  {
    int16_t mapValue = 880 + b;
    int8_t myValue = map(mapValue, 0, 885, 0, 127);
    Serial.print(F("Übergabewert: "));
    Serial.print(mapValue);
    Serial.print(F(" Ausgabewert: "));
    Serial.println(myValue);
  }
}

void loop() {
  // put your main code here, to run repeatedly:

}

Die Ausgangslage ist der durch die Hardware begrenzte Wert. Dem ist mit dem Map ein Äquivalent gegenüber zustellen.
Wenn Du bei einem Eingangswert von 890 einen Ausgangswert von 127 hast, kannst Du nicht darauf vertrauen, das 890 die Obergrenze ist, sondern das, was Dir die Hardware vorgibt.
Das Du auch nicht darauf vertrauen kannst, das nach map das prportional heraus kommt, habe ich hoffentlich gezeigt.

Bedenke: Heute weisst Du noch, was Du da evtl. vor hast.
Das soll aber auch noch nach langer Zeit, ohne das Du an den Code denkst, so sein.

Wenn Du auf Deinen 890 zu 127 bestehst, dann mach das anders rum und beschneide den Eingangswert, sodas die Ausgabe nicht überlaufen kann.

constexpr uint8_t analogPin = 4;
void setup() {
  Serial.begin(115200);
  Serial.println(F("\r\nStart...\r\n"));

  int16_t mapValue = analogRead(analogPin);
  if (mapValue > 890) mapValue = 890;
  int8_t myValue = map(mapValue, 0, 890, 0, 127);
  Serial.print(F("Übergabewert: "));
  Serial.print(mapValue);
  Serial.print(F(" Ausgabewert: "));
  Serial.println(myValue);
}


void loop() {
  // put your main code here, to run repeatedly:

}

constrain()
Natürlich nach dem map(), und nicht davor.

Ok, verstanden und so in meinen Code eingebaut. Vielen Dank!

Natürlich vor dem map() und nicht danach.

Natürlich je nach dem, was man machen will.
Wenn man (wie viele andere auch) denkt, in map wäre schon ein constrain drin, kann man es gerne danach, mit den Grenzen des map-Ausgangs machen.
Wenn man den Eingang zum map begrenzen will, macht man es natürlich vorher.

Im übrigen ist die normale Umrechnung von 0 .. 1023 auf 0 .. 127
eine Division durch 8. (oder >> 3)