Volt und Milivolt mit dem Ardurino Uno R3 ermitteln und weiter verarbeiten

Hallo in die Gemeinschaft, Ich bin der NEUE.
Ja, ganz neu im Feld der Mikrocontroller, jedoch etwas erfahren im Bereich der Elektronik.
Bin Lizenzierter Funkamateur und der Zufall brachte mir den Arduino Uno R3 ins Haus. Das weckt natürlich Begehrlichkeiten damit herum zuspielen. Vom Programmieren an sich habe ich nur wenig Kenntnisse, eben was man so für die Bash benötigt aber auch nichts was in die Tiefe geht.

Ich finde es eine Gute Idee mit dem Uno ein Voltmeter aufzubauen um so Zwei Spannungen gleichzeitig auf einem Display 20 x 4 auszugeben.
Allerdings wäre es hilfreich die 2.Anzeige als Millivoltmeter auszulegen.
Also um meinen Wunsch zu verdeutlichen:

U_0=5V max
############## Bargraph_0
############## Bargraph_1
U_1=0.099 max

Ich habe ein wenig Code dazu im Netz gefunden, welchen ich nach meinem Gutdünken abgeändert habe und nun möchte ich diesen erweitern, so das sich das obere Bild ergeben kann.

Hier der Code:

[code]
#include <LiquidCrystal.h>

#include <LcdBarGraph.h>

const int rs = 7, en = 8, d4 = 9, d5 = 10, d6 = 11, d7 = 12;

LiquidCrystal lcd(rs, en, d4, d5, d6, d7);


byte lcdNumCols = 20;               //Anzahl der Zeichen_Blöcke
byte lcdLine = 4;                   //Anzahl der Reihen die 20 Blöcke enthalten
byte sensorPin_0 = A0;              //Pin der Spannung liefert

                                    
LcdBarGraph lbg(&lcd, 20, 0, 1);    //erzeugt die Bar 20 Zeichen lang (100 Teile) Stelle 0 Zeile 1

        
void setup(){
                                    
  lcd.begin(20,4);                
  lcd.clear();                    //löscht alle Zeichen
  lcd.setCursor (6,0);            //Setzt die Position des folgenden Text
  lcd.print("------");            //TEXT
  lcd.setCursor (2,2);            //Setzt die Position des folgenden Text
  lcd.print("Voltage Bargraph"); //TEXT
   
                                  
  delay(5000);                    // Anzeigendauer Text oben
  lcd.clear();                    // Vermeidet Artefakte in der folgenden Anzeige
}

void loop()
{
  //  Voltmeter an pin A0         // Min V=0.00 Max V=5,1 Z-Diode nach Masse

  int inpuValue = analogRead(A0);                 // lese pin A0
                                          
  lbg.drawValue( inpuValue, 1024);                // Zeichnet den Bargraph mit <LcdBarGraph>
                                                
  float voltage0 = inpuValue * (5.0 / 1023.0);   // setzt die auflösung auf 10bit
  lcd.setCursor (0,0);                           //
  lcd.print("Volt:");                            //
  lcd.setCursor (8,0);                           // Siehe oben beim 
  lcd.print(voltage0);                           //
  lcd.setCursor (12,0);                          //
  lcd.print("V");                                //
 
  delay(100);
}



[/code]

Habe ich die Anweisungen alle richtig zusammengesucht?
Das Angeschlossene Display ist schon Antik, ist ein Truly aus 1998.

Ich bedanke mich schon im voraus für eure Antworten

Wenn Du für U_1 eine wenigstens geringe Auflösung haben willst, musst Du mit der Referenzspannung von 1,1V arbeiten (1,1V --> 1023 Einheiten). Wenn Dir das zu grob ist, wird das direkte Messen dieser Spannung nichts.
Die 5V musst Du dann über einen Spannungsteiler auf 1,1V runter teilen.

Gruß Tommy

Diese Rechnung ist falsch, aus mehreren Gründen:

  1. 10 Bit sind 1024 und nicht 1023 Stufen
  2. Die 5V sind eher 4,7V
  3. Für absolute Messungen verwendet man die interne Referenz, und nicht Vcc.

Zum Ausgleich der Toleranz Abweichung der internen Referenz kann man sehr schön die 2 Punkt Kalibrierung zum Einsatz bringen. (Geradengleichung)

Den Spannungsteiler sollte man getrennt vom 1000 mV Messbereich kalibrieren.
Und wenn sowieso ein Spannungsteiler gebaut wird, warum nicht einen für 10V max?

Hallo,

schau mal hier
https://www.arduino.cc/reference/de/language/functions/analog-io/analogreference/

Heinz

Die Spannung die von der USB-Schnittstelle kommt ist wenig konstant bzw sicher.
Die Spannung kann zwischen erfahrungsgemäß 5,1 und 4,6 V sein. Darum muß die Referenzspannung 5,0V gemessen werden und dementsprechend in den Sketch eingetragen werden. Dies verhindert aber nicht daß diese Spannung an einem anderen PC, Netzteil oder USB-Buchse verschieden sein könnteund damit die Messung falsch ist.

Abhilfe könnte wie bereits vorgeschlagen die interne Referenzspannung der Controller sein.
Der ATmega168, - 328 hat eine interne 1,1V Referenz
der ATmega1280 - 2560 hat 1,1 und 2,56V
der ATmega32U4 hat 2,56V
Andere Controller weiß ich nicht auswendig.
Diese Spannungen sind nicht ganz genau (10%) aber langzeitstabiel. Für eine genaue Spannugsmessung sollte diese am AREF Pin gemessen und in den Sketch eingetragen werden.
Alternativ kann an AREF-Pin eine Referenzspannung eingespeist werden. Dazu muß im Sketch die Referenzspannungsquelle auf EXTERN gestellt werden und eine Referenzspannungsquelle angeschlossen werden.
Die Referenzspannung sollte nicht unter 1V betragen.

Grüße Uwe

Herzlichen Dank an die Autoren für die detaillierten Hinweise. Die Bandbreite der angesprochenen Themen zeigt, was ich nicht beschrieben habe.
Es fällt mir immer schwerer meine Analogen Messgeräte abzulesen. Eine Anzeige zu haben die ich auf doppelte Armlänge auch ohne Brille erkennen kann, wäre die Lösung.

Im Detail geht es darum die Spannungen darzustellen, welche ein Richtkoppler zur Verfügung stellt.
Mit Hilfe so einer Vorrichtung werden auf zwei Drehspurinstrumenten die Vorlaufende und die Reflektierte Sendeleistung, gleichzeitig auf einem gemeinsamen Zifferblatt dargestellt. Das nennt sich Kreuzzeiger. Mit diesem Begriff kann sich der Interessierte bei Google informieren.

Also auf die Genauigkeit des Messwertes kommt es nicht so an. Auf das Verhältnis von U_0 zu U_1 dagegen schon. Die Bedingung " U_0 max = U_1 im Bereich von +- 5 mV" würde was brauchbares auf dem Display darstellen.

Aber bevor ich mich in unverständlicher Schreiberei verliere.

Hätte nicht jemand einen Link zu einem sehr sehr simpelen Audio µV Meter? Dessen Code meinen Anforderungen in etwa ähnlich wäre? So könnte ich eben mal anklemmen und ausprobieren wie sich der Testaufbau unter realen Bedingungen verhalten würde.

Danke im voraus .

Als wenn ein Kreuzzeiger Instrument hier keinem bekannt wäre....
Aber für blöd erklären ist immer einfacher, als vorher schon damit rauszurücken, was du erreichen willst.
z.B. ein Stehwellenmessgerät bauen.
Zwecks Antennenanpassung?

Tipp:
Es gibt durchaus Arduinos mit differenziellen ADCs und einstellbarem Gain.
z.B. der Mega

Da Du Wechselspannung messen willst mußt Du diese zuerst gleichrichten. Danach kannst Du die Spannung verstärken. Beides kannst Du mittels Operationsverstärker machen.

Andererseits gibt es AD/Wandler als ICs. Man kann einen AD-Wandler mit mehr Auflösung nehmen und diesen an den Arduino anschließen.

Grüße Uwe

Nun ich habe gesucht und doch noch ein brauchbares Beispiel gefunden, das meinen Bedarf decken kann.
Jedoch ist schon in der Uhrschrift ein Fehler enthalten.
Der Lautet so:
warning: comparison between signed and unsigned integer expressions [-Wsign-compare] if(millis() < lastT)

Auf was deutet diese Meldung den hin? Die IDE bricht den Vorgang jedoch nicht ab und das Programm scheint fehlerfrei zu laufen.
Ich hatte zuerst den Verdacht, da ich das Display von 16x2 auf 20x4 abgeändert habe, wäre der Auslöser gewesen. Dabei habe ich wohl nicht so viel falsch gemacht.

Der Urheber stellt diesen Sketch nicht Ausdrücklich der Allgemeinheit zur Verfügung, daher füge ich den YouTube-Link hier ein. Die Quelle ist dort verlinkt.

Ich wage es zunächst nicht diesen Sketch hier so einfach zu Posten.

Danke für Eure Mühe und Aufmerksamkeit

? was du meinen ?
Warnung: Vergleich zwischen vorzeichenbehafteten und vorzeichenlosen Integer-Ausdrücken [-Wsign-compare]
Sogar die Zeile und Datei wird dir zur Meldung geliefert....

Was millis() liefert, kann ich nachsehen, wenn ich's nicht weiß. Offensichtlich ist dein geheimes lastT Mist.
Das ganze ist auch nur eine Warnung, die erst weh tut, wenn lastT negativ wird.

Eine Warnung ist eine Warnung, kein Fehler. Aus einer warnung könnte aber ein Fehler werden.

Der Compiler/Linker gibt Warnungen und Fehler aus bei Fehlern wird die Kompilierung abgebrochen. Bei Warnungen wird kompiliert.

Grüße Uwe

Hallo in die Runde.

Ich hatte nun die Gelegenheit den Code und den UNO auf seine HF-festigkeit zu testen. So in meiner offenen Bauweise scheint sich das alles in Grenzen zu halten. Ebenso hatte ich die Befürchtung, das ich das unvermeidliche Rauschen am "Reflecktet" Sensor in Engen Grenzen halten lässt. 0 Volt feststellen ist ja immer so eine Sache, wenn HF im Spiel ist. Ich meine Festgestellt zu haben, das es nicht schädlich ist, die nicht benötigten Analogen Eingänge mit 500K auf Masse zu legen. So können diese kaum noch Unfug anstellen. Definiertes Potenzial. Das Tiefpass-Filter direkt an A4 A5 mit 200µH und 0,01µF stellt eine hinreichende Dämpfung der HF bereit.
Scheint bis jetzt hinreichend "Weich" zu laufen.

Allerdings ist es mir nicht möglich die folgenden Code Zeilen zu entschlüsseln.

  1. lcd.write(row ? 'F' : 'R');
    Was ist der Sinn und der Zweck?

  2. int anL = map(sqrt(analogRead(IN_LEFT)*19), 0, 128, 0, 100);
    Ebenso hier, benötige ich ein etwas Nachhilfe.

Den Sketch so weit ich den Selben verstanden habe, ist nur unvollständig kommentiert.
Für mich und jeden Anderen, wäre es wohl sehr hilfreich wenn die Funktionen genauer beschrieben werden könnten.

Ich bitte hiermit darum den Code zu überprüfen und dabei den einen oder anderen Kommentar zu ergänzen.

Die Vorangegangene Warnmeldung konnte ich durch ändern von
long lastT = 0; in unsigned long lastT = 0;
Beheben.

Besten Dank im Voraus

[code]
#include <LiquidCrystal.h>
 
#define IN_LEFT    A4  // analog input for left channel
#define IN_RIGHT   A5  // analog input for right channel
 
#define T_REFRESH    25                   // msec bar refresh rate
#define T_PEAKHOLD   (50 * T_REFRESH)     // msec peak hold time before return
 
LiquidCrystal lcd(7,    // RS
                  8,    // E
                  9,    // DB4
                  10,   // DB5
                  11,   // DB6
                  12    // DB7
                  );
 
byte  fill[6] = {0x20, 0x00, 0x01, 0x02, 0x03, 0xFF};       // character used to fill (0=empty  5=full)
byte  peak[7] = {0x20, 0x00, 0x04, 0x05, 0x06, 0x07, 0x20}; // character used to peak indicator
byte block[8][8]=
{
  {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, // define character for fill the bar
  {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},
  {0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C},
  {0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E},
 
  {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}, // define character for peak level
  {0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04},
  {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02},
  {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
};
 
int lmax[2];    // level max memory
int dly[2];     // delay & speed for peak return

unsigned long lastT = 0;
 
void  bar(int row, int lev) {
 
    lcd.setCursor(0, row);
//   lcd.write(row ? 'F' : 'R');
 
    for(int i = 1; i < 20; i++) {
        int f = constrain(lev-i*5, 0, 5);
        int p = constrain(lmax[row]-i*5, 0, 6);
        if(f)
            lcd.write(fill[f]);
        else
            lcd.write(peak[p]);
    }
 
    if(lev > lmax[row]) {
        lmax[row] = lev;
        dly[row]  = -(T_PEAKHOLD) / T_REFRESH;      // Starting delay value. Negative=peak don’t move
    }
    else {
        if(dly[row] > 0)
            lmax[row] -= dly[row];
 
        if(lmax[row] < 0)
            lmax[row] = 0;
        else
            dly[row]++;
    }
}
 
void  setup() {
 
    byte fillbar[8] = {
    B00000,
    B01000,
    B01100,
    B01010,
    B01001,
    B01010,
    B01100,
    B01000
    };
 
    byte mark[8] = {
    B00000,
    B01010,
    B10001,
    B10101,
    B10001,
    B01010,
    B00000,
    B00000
    };

 
    lcd.begin(20, 4);           //Vorspann beginnt
 
    lcd.createChar(0, fillbar);
    lcd.createChar(1, mark);
 
    lcd.setCursor(2, 3);
    lcd.print("RF PEAK & LEVEL");
    
 
    for(int i = 0; i < 20; i++) {
        lcd.setCursor(i, 1);
        lcd.write((byte)0);
 
        delay(150);
    }                           //Vorspann beendet
 
    lcd.clear();

    lcd.setCursor(0, 0);
    lcd.write("Power  =");    //Nur Text in 0

    lcd.setCursor(0, 3);
    lcd.write("Revers =");    //Nur Text in 3
 
    for(int j = 0; j < 8; j++)
        lcd.createChar(j, block[j]);
        
}
 
void  loop() {
 
    if(millis() < lastT)
        return;
 
    lastT += T_REFRESH;
    
                                  // sqrt to have non linear scale (better was log)
    int anL = map(sqrt(analogRead(IN_LEFT)*19), 0, 128, 0, 100);
    int anR = map(sqrt(analogRead(IN_RIGHT)*19), 0, 128, 0, 100);
     
    bar(1, anL);
    bar(2, anR);
}
[/code]

Das ist der "ternäre Operator".
Die Erklärung dazu findet sich in jedem C und C++ Grundlagenbuch.
Auch Google kennt den Begriff.

Das überlebt den Überlauf nicht schadlos.

Hi @combie , Ich bedanke mich höflich für Deine Unterstützung.

Ich habe so erkannt das ich wohl sehr analog denke. Ob ich den "ternäre Operator" verstanden habe?
Wohl eher nicht.
Und im weiteren scheint sich der Controller in gewissen Zeitabständen zu verrechnen. Das in deinem Link herausstellt. Auf den Rest der Diskussion gehe ich so nicht weiter ein.

Aber so ein Arduino weckt ja bekanntlich Begehrlichkeiten.
Es ist ja schon mal sehr hilfreich eine viel genauere Anzeige zu haben. Stelle mich aber auch vor, das der Controller die Abstimmung meines L-Tuners ganz allein vornehmen könnte.

Man sollte meinen das das Netz voll von Beispielen ist, auf welche weise solche Steller Automaten in Software zu Bewerkstelligen wären. NIX ist !

Ist Dir eine Quelle bekannt, in Welcher solche Aufgaben Diskutiert werden?

Einige Fachbegriffe, in dieser Hinsicht, würden mir schon helfen Zielorientierte Fragen zu stellen.

Besten Dank im voraus

Das ist sicherlich möglich.
Wenn du deine "Stellglieder" mit einem Antrieb versiehst.
Oder (Koax)Relais verwendest.

Und nein, ich wüsste nicht, dass das schon mal jemand gemacht hat.
Aber das heißt ja auch Programmieren!
Was noch nicht gibt, wird gebaut.

Du möchtest also irgendeine Sorte von Optimum finden..
Richtig?

Ha hilfts nix, da wirst du irgendeine Form einer Bewertungsfunktion bauen müssen.
Automatisch an deinen Stellgliedern rum drehen dürfen, und immer schauen, welche Stellung besser ist.
Schlussendlich:
Du wirst dein Intelligenz/Verhalten/Wissen formalisieren dürfen und dieses dann in C++ gießen.

Von Start, bis Optimum gefunden, hat es Ähnlichkeiten mit einem Regler.
z.B ähnlich mit "PID Regler"

Für das Grundgerüst bieten sich "Endliche Automaten" oder "Schrittketten" an