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ä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.
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!
Von dieser Version werden nun auch die Mikrosekunden als µs und nicht als us ausgedruckt.
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).
Anbei die aktuelle Version mit dem vom vorigen Post und pthread_kill sowie pthread_exit um main korrekt zu terminieren.
Sorry, ich hatte vorhin aus dem falschen Verzeichnis upgeloadet; anbei nun die richtige Version.
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
Weil mir gerade eben aufgefallen ist, dass noch die Anzeige von "HOLD" fehlt, ist die nun in dieser Version eingebaut; da sollte nun nichts fehlen.
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 ;-)
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.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.