Programm zum billigen DMM VC820/VC840

Gast #186254
Die Digitalmultimeter VC820/VC840 gibt es bei Conrad schon ab 49,95 EUR
komplett mit Batterie, Meßkabeln und seriellem Kabel, das sogar über
einen Optokopper vom DMM galvanisch getrennt ist.
Den mit google dazu gefundenen Treiber-Quellcode mußte ich
überarbeiten, damit er die meisten Übertragungsfehler rausfiltert,
Timeouts hat und nicht ewig wartet, auch für Langzeit-Messungen
verwendet werden kann und das Device nicht blockiert.
Diese Sachen sind im Treiber kommentiert (Anhang).

Man kann die Daten beispielsweise mit

./vc840 | tee data

in die Datei data schreiben und gleichzeitig auf der Konsole ausgeben.

Mit diesem Shell-Skript kann man die Daten auch sekündlich plotten:

#!/bin/sh
# gnuplot script, example usage: ./plotting.sh | gnuplot
# plot the data in "data" every second
echo set grid xtics ytics
while true; do
echo plot \"data\" with lines
sleep 1
done

Getestet habe ich es nur unter Linux, aber mit mimimalen Änderungen
sollte es unter jedem Posix-Kompatiblem Betriebssystem funktionieren.

Wegen den Posix-Threads muß man den Sorcecode mit der Option -lpthread
kompilieren. Ich benutze dafür diese allgemeine Funktion in der
.bashrc:

# Funktion zum Kompilieren. Bsp.: "c bsp" kompiliert bsp.c und
produziert bsp.
function c {
  gcc -Wall -I. -O3 -D_GNU_SOURCE -D__SMP__ -DLINUX -D_LARGEFILE_SOURCE
-D_FILE_OFFSET_BITS=64 -D_REENTRANT -lpthread -lrt -mcpu=i686
-fexpensive-optimizations -DCPU=686 -ffast-math -m486 -lm -lz -o $1
$1.c && prelink -fmRv ./$1 && strip $1
}
Angehängte Dateien:
Gast #186255
Angehängt die überarbeitete Version, in der der erste USB-RS232-Adapter
als Schnittstelle eingetragen ist (in der ersten Version ist es die
erste serielle Schnittstelle).

Der erste von zwei Checks, ob das Datenpaket unfragmentiert ist, war
nicht ganz korrekt. Jetzt erfolgt dieser Check durch Überprüfen der
Zeit, die zwischen dem Empfangen von Byte n-1 und Byte n (>0) vergeht.
select gibt diese Zeit ja immer mit aus.
Angehängte Dateien:
Gast #186256
Und weil mir aufgefallen ist, dass man die Pausen-Länge zwischen zwei
Datenpaketen (muß mindestens 100 ms sein) einfacher und mit weniger
Code überprüfen kann, ist anbei diese Version ;-)

Mit der Version habe ich es nicht geschafft durch Wackelkontakt oder
verschobene Lichtschranke oder Umschalten oder Ein-/Aus-Schalten
verfälschte Daten zu bekommen; die beschädigten Daten wurde alle
rausgefiltert!
Angehängte Dateien:
Gast #186258
Nachtrag: Bei Onboard-Ports gibt's das Problem, dass der Treiber im
Kernel die Daten-Pakete deutlich fragmentiert; da hilft dann nur
i_deadline auf 50000 erhöhen oder einen RS232-USB-Adapter an ein einen
USB2-Controller zu benutzen (oder ein USB1-Controller mit dem langen
timeout).
Und statt
fd = open (device, O_RDWR);
sollte
fd = open (device, O_RDWR | O_NDELAY);
besser sein (obwohl ich keinen Unterschied gemerkt habe).
Gast #186261
So, nachdem ich mal nachgesehen habe wie man eine serielle Schnittstelle
exklusiv öffnet, damit sich nicht mehrere Programme die Daten der
Schnittstelle gegenseitig wegnehmen oder die Schnittstelle
dekonfigurieren, wird die Schnittstelle nun mit überarbeitetem ioctl
geöffnet:

  // Set IO-Control-Parameter and check the device.
  if (-1 == ioctl (fd, TIOCEXCL, &modelines)) // Put the tty into
exclusive mode.
  {
    fprintf (stderr, "Error at ioctl TIOCEXCL on %s!\n", device);
    perror ("ioctl()");
    return (-1);
  }

Damit wird die Schnittstelle nur exklusiv geöffnet und der Versuch, das
Programm ein zweites mal zu starten scheitert:

> ./vc840
Using serial output to /dev/ttyUSB0, baudrate 2400
open failed: Device or resource busy
Angehängte Dateien:
Gast #186263
Gemäß Murphys Law hatte get_time noch einen selten sichtbaren Bug, weil
die Zeit in µs mit zwei getrennten Aufrufen bestimmt wurde.
In der angehängten Version ist dieser Bug mit nur einem Aufruf von
gettimeofday beseitigt und zudem werden im Fehlerfall die Daten und die
Zeit nach stderr ausgegeben.

Übrigens kann man mit
{ ./vc840 | tee data ; } 3>&2 2>&1 1>&3 | tee log.err
die Daten und Fehlermeldungen getrennt speichern und gleichzeitig beide
zusammen in derselben Konsole ausgeben ;-)
Angehängte Dateien:
Gast #186264
Gerade ist mir noch aufgefallen, daß die Variable zum Setzen der
Baudrate als int deklariert wurde und daß deshalb alle Zuweisungen, z.
B.

 bdflag = B2400;

eigentlich immer 0 zuweisen sollten, da es keine ints sind.
Anbei nun die korrigierte Version mit der korrekten Deklaration

 speed_t bdflag;

Merkwürdig, daß der gcc das trotz allen aktivierten Warnungen nicht
gemeldet hat und daß es trotzdem funktionierte.
Angehängte Dateien:

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 21 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.