Schlagwort-Archive: Matlab

LEGO Mindstorms EV3 mit Matlab und Simulink

Loading

Wer mit Matlab und Simulink arbeitet oder lernt und einen LEGO EV3 Brick samt Sensoren und Aktoren besitzt, kann diese Systeme miteinander verknüpfen. Rund um den EV3 Brick gibt es natürlich eine Community und etliche Plattformen, über die man mit dem Brick kommunizieren kann. Doch dazu später.

Der Lego EV3 Brick ist im Wesentlichen ein Einplatinencomputer der mit einem LC-Display und vier Input- sowie vier Output-Ports (Schnittstellen für Sensoren und Aktoren) ausgestattet ist. Als Datenschnittstellen gibt es einen USB Port als HOST und einen MiniUSB Port als Interface zum PC und den diversen Softwaretools.

Will man mit dem Brick wireless kommunizieren, so ist dies über WiFi, beziehungsweise über Bluetooth möglich. Allerdings ist die Hardware zur Funkübertragung nicht im Brick verbaut und muss als USB Dongle in den Host-Port gesteckt werden.

Folgende USB Wifi Sticks sind lt. Internetrecherche mit dem EV3 und der originalen Legofirmware ab 1.08 kompatibel: (Quelle: Internet)

  • tp-link WL0084E
  • EDIMAX EW-7811Un mit dem Chipsatz RTL8188CUS
  • LogiLink WL0084W auf der Vertriebsseite (Conrad) angeblich mit dem Chipsatz Railink RT5370 jedoch das Herstellerdatenblatt gibt den Chipsatz RTL8188EUS an.

Im Test hat sich gezeigt, dass lediglich Dongles mit dem Realtek RTL8188CUS Chip im embedded Linux des EV3 Driver mäßig implementiert sind. Der Nachfolger von Realtek der RTL8188EUS funktioniert hier nicht.  Und die meisten Hersteller von Wifi USB Dongles (Stand 2021) vertreiben ihre Sticks mit dem 8188EUS Chip, sei dies TPLink, Edimax, LogiLink und wie sie alle heißen. Erkennbar ist das bei manchen an der Typenbezeichnung V2, oder 7811UN V2 (bei Edimax) oder V.02, V.03 bei TPLink. Ist diese Kennzeichnung beim Stick oder dessen Verpackung dabei dann wird das nix. Zumindest nicht, wenn mit der originalen Legofirmware gearbeitet werden will.

Vergleich edimax 7811un und 7811un v2
edimax 7188un mit RTL8188CUS chip
edimax 7188un V2 mit RTL8188EUS chip

Nun weiter zum EV3 Brick:

Auf diesem Einplatinencomputer läuft ein auf Linux basierendes embedded Betriebssystem das auf einem internen Flash- Speicher abgelegt ist. Dieses Betriebssystem wird in Form einer Firmware von LEGO zur Verfügung gestellt und ist zur Zeit in der Version 1.10 verfügbar. Diese Firmware ist beinhaltet sämtliche Partitionen der Laufwerke und deren Inhalt und wird im Rahmen eines Updates in einem „.bin“ File verpackt in den Flash geladen. Mit den Softwaretools „binwalk“ ist es unter Linux möglich, die Struktur der Partitionen aus dem Firmware File wiederherzustellen, zu ändern und wieder als „.bin“ Firmware Image auf die Hardware hochzuladen.

Es gibt aber auch Custom Firmware und Betriebssysteme die per SD-Card gebootet werden können. Welche Treiber hier mitgeliefert werden ist auf den Seiten der entsprechenden Custom OS Hersteller nachzulesen.

Folgende Betriebssysteme habe ich für den EV3 auf die Schnelle gefunden:

  • ev3dev (https://www.ev3dev.org/)
  • leJOS (https://sourceforge.net/projects/lejos/files/lejos-EV3/)

Man kann den EV3 mit folgenden (und ich nenne hier auch nur die gängigen die auch mir eingefallen sind) Tools bzw. Programmiersprachen programmieren:

  • LEGO EV3 Originalsoftware
  • NI Labview bist Labview Fall2016 ? (Unterstützt bzw. EV3 Plugins implementiert)
  • Matlab und Simulink (Harware Supportpackage für EV3 notwendig) link
  • MicroPython EV3 link

Fakt ist jedoch: der in die originale Lego EV3 Firmware (1.08H , 1.09D) integrierte Treiber für WLAN-Sticks unterstützt nur den Chipsatz RTL8188CUS. Und den benötigt man, wenn man über SIMULINK im „Monitor und Tune“ Modus mit dem Brick arbeiten will. Denn interessanter Weise klappt das NUR über eine WiFi Verbindung und NICHT über einen direkten USB Link zwischen PC und EV3.

Es ist auch NUR mit der Firmware 1.08H möglich mit Simulink zu kommunizieren da hier TELNET und SSH als Kommunikationsprotokoll genutzt werden. Und nur in der 1.08H ist eine ungeschützte Verbindung der Weg zum Erfolg. Ab der Version 1.09D ist ein Login notwendig.

Da die Firmware Versionen mittlerweile schwer zu finden sind, stelle ich hier einen Link zum Download herein.

Download EV3 Firmware 1.08H
Download EV3 Firmware 1.09D

Was benötigt man nun, um über Simulink mit dem EV3 sprechen zu können ?

  • zunächst muß Matlab und Simulink installiert sein
  • dann muss man das Support Package EV3 für Matlab und EV3 für Simulink herunterladen und installieren
  • auf dem EV3 Brick solltedie originale Firmware 1.08H vorhanden sein. Ist dies nicht der Fall kann die Version über den Firmwaredownloader in der orginalen EV3 PC Software auf das Gerät übertragen werden.
  • im EV3 Brick muß ein USB Wifi Dongle mit dem „CUS“ Chipsatz stecken
  • der PC muß idealerweise im selben Netz hängen wie auch das Wifi-Funknetz mit dem sich der Brick verbindet. Ein DHCP Server muß die IP Adressen für die Funkgeräte verteilen
  • jetzt kann der Brick gestartet werden. Danach muß er mit dem WLAN Netz verbunden werden (es sollten WPA2 Passwörter ohne Sonderzeichen festgelegt sein, da der EV3 Brick diese nicht zur Verfügung stellt)
  • ist der EV3 mit dem Netz verbunden, dann ist unter dem Menu „Brick Info“ die aktuelle IP Adresse des Bricks und die Brick ID zu notieren. Diese Infos werden gleich im Simulink Setup benötigt
  • nun zu Simulink: dort ist im Menu „configuration Parameters“ unter „Hardware Implementation -> Hardware board“ Mindstorms EV3 zu wählen 
  • das Setup wird im selben Menu unter „Hardware board settings“ -> Target hardware resources -> Groups -> Host to Target Connection festgelegt. Hier ist „Ethernet“ als Connection Type einzustellen. Die vorher ermittele IP Adresse und ID des Brick sind hier auch einzugeben.Das war´s dann auch schon. Nun sollte es möglich sein eure Simulink Modelle mit der EV3 Hardware zu nutzen und auch die Tune Infos während der Simulation am PC zu sehen …

 

 

 

Diodenkennlinie mit Sourcemeter und Matlab aufnehmen

Loading

Dieses Mal gibt es hier keinen Bericht über die Restauration oder die Vorstellung eines alten Gerätes. Im Rahmen meiner beruflichen Tätigkeit muss ich immer wieder Messaufbauten realisieren und diese nach Möglichkeit automatisieren, um die Messzeiten zu minimieren. Auch die Datenauswertung und das Postprocessing möchte ich immer gerne automatisieren. Dafür gibt es sehr viele unterschiedliche Lösungsansätze. Der Grundansatz ist aber immer gleich. Ein, oder mehrere Messgeräte sind über eine Schnittstelle mit einem Rechner oder Controller verbunden. Auf dem Rechner oder Controller läuft eine Software, die das Messgerät steuert und die gemessenen Daten an den Rechner zurücksendet. Auf dem Rechner werden die Daten dann gespeichert, den Anforderungen entsprechend aufbereitet und ausgegeben.

Die Schnittstellen zwischen Rechner und Messtechnik können je nach Ausstattung des Messgerätes dabei RS232, GPIP, IEEE1394, USB oder LAN sein. Bei vielen Geräten wird der einfache SCPI-Befehlssatz im ASCII Code zum Befehle senden und empfangen über das entsprechende Protokoll der gewählten Schnittstelle verwendet. Die Software am Rechner oder Controller muss in der Lage sein die Hardware anzusprechen und schon kann eine Datenkommunikation hergestellt werden. Als Software oder Skriptsprache kann hier beispielsweise NI-LabVIEW, Matlab, C-Code, C++ Code, C#, Python, etc. verwendet werden. Und die Rechner- oder Controllerhardware kann ein Windows, Mac, oder LinuxPC sein, aber auch ein einfacher Arduino, RaspberryPi, oder ein programmierter Mikro-Controller, der eine der benötigten Schnittstelleninterfaces besitzt.

Bei meiner Arbeit wird das gerne mit Matworks Matlab gemacht (bzw. ich mache es gerne mit Matlab, weil ich Programme und Skripten lieber tippe als sie zu zeichnen 😀 ), einer skriptorientierten Software. Im konkreten Beispiel habe ich ein SOURCEMETER des Herstellers Keithley, das Keithley2400 über die RS232 Schnittstelle an einem WIN10 PC mit Matlab 2017b angesteuert. Das Sourcemeter hat die Aufgabe eine Diodenkennlinie aufzunehmen. Das Sourcemeter ist imstande einen Strom zu sourcen, also eine steuerbare Stromquelle zu sein und gleichzeitig den gesourcten Strom und die an den Klemmen anliegende Spannung zu messen. Umgekehrt wiederum kann es auch als steuerbare Spannungsquelle eingesetzt werden, die Spannung an den Klemmen und den Strom durch den DUT (Device Under Test) messen.  Und das geht in allen vier Quadranten, also Stromquelle oder -Senke, oder Spannungsquelle oder -Senke sein.

Genau das benötigte ich in diesem supereinfachen Beispiel um die Kennlinie eines PN-Überganges aufzunehmen und zwar vom Diffusionsbereich bis in den Durchlassbereich und natürlich auch wenn der PN-Übergang unter Photonenbeschuss steht 🙂

Die folgenden beiden Matlab-Skripten ermöglichen diese einfache Kennlinienaufnahme. Der Messaufbau selbst besteht lediglich aus einer, an die Klemmen des K2400 angeschlossenen Diode (in diesem Fall eine Photozelle). Dabei stellt das erste Skript eine gesteuerte Stromquelle dar und im zweiten Skript wird die Spannungsquelle durchgesteuert und jeweils die Daten aufgezeichnet und zum Schluss als Plot dargestellt.

 Matlab Code stromgetrieben:

% IV Logger PN Kennlinie
% 2.05.2019 ingmarsretro
% der supereasysimple-code
% drive current and measure voltage
% with sourcemter über RS232 

 serialObject = serial('COM4','BaudRate',19200, 'DataBits',8);   

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Sourcemeter 2400 setup                             %
    % serial config: 8N1, 19200, termchar CR+LF          %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
    fopen(serialObject)
    s.InputBufferSize = 6000;
    fprintf(serialObject,'*RST');
    
    mincurr = -15E-3;  % maximaler negativer strom (load an der Zelle) 
    maxcurr = 10E-4;   % maximaler positiver strom 
    step = 1E-5;       % schrittweite
    

    %%%%%%%%%%%%%%%%%%%%%%%%%%
    % Messgeraet einstellen  %
    %%%%%%%%%%%%%%%%%%%%%%%%%%
    % SOURCING ->  CURRENT
    %
    %fprintf(serialObject,':INIT:CONT OFF;:ABOR');
    fprintf(serialObject,':FORM:DATA ASCII');
    fprintf(serialObject,':SOUR:FUNC CURR');
    fprintf(serialObject,':SOUR:CURR:MODE FIX');
    fprintf(serialObject,':SOUR:CURR:RANG 10E-2'); % -> 000.000mA
    fprintf(serialObject,':SOUR:CURR:LEV 0.0'); % -> Starteinstellung 0 A
    
    % MEASUREMENT -> Spannung 
    fprintf(serialObject,':SENS:FUNC "VOLT:DC"');
    fprintf(serialObject,':SENS:VOLT:PROT 8');     % -> compliance 8V
    fprintf(serialObject,':SENS:VOLT:RANG 10E-1'); % -> 0.00000 V
    fprintf(serialObject,':TRIG:COUN 1');
    
    %fprintf(serialObject,':CONF:VOLT:DC');
    
    fprintf(serialObject,':OUTP ON');

        %% Messen und Daten abholen
    count = 1; 
    v(1)=0; i(1)=0;  %init der arrays 
   
       for curr = mincurr:step:maxcurr
           
          strom=num2str(curr);
          command = strcat(':SOUR:CURR:LEV ',{' '},strom);
          fprintf(serialObject,char(command));
         

          fprintf(serialObject,':READ?');
          data=fscanf(serialObject);  % gesamten buffer des device einlesen
          c = strsplit(data,',');          % gelesenen string nach ',' in zellen zerlegen
          i(count) = str2num(cell2mat(c(2)));                 % stromzelle 
          v(count) = str2num(cell2mat(c(1)));                 % spannungszelle
        

        count = count +1;
       end
   
    
    figure(1);
    plot(v,i);
    grid on; hold on;
    xlabel('voltage [V]'); ylabel('current [A]')
    title('IV - Kennlinie ');
    
    %% instrument in local mode schalten
    fprintf(serialObject,':OUTP OFF');
    fprintf(serialObject,'SYSTEM:LOCAL');
    fclose(serialObject);

 

Matlab Code spannungsgetrieben:

% IV Logger PN Kennlinie
% 3.05.2019 ingmarsretro
% der supereasysimple-code
% drive current and measure voltage
% wit sourcemter über RS232 

 serialObject = serial('COM4','BaudRate',19200, 'DataBits',8);   

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Sourcemeter 2400 setup                             %
    % serial config: 8N1, 19200, termchar CR+LF          %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
    fopen(serialObject)
    s.InputBufferSize = 6000;
    fprintf(serialObject,'*RST');
    
    minvolt = -1;      % maximale negative spannung  
    maxvolt = 0.5;       % maximale positive spannung
    
    %mincurr = -20E-3;  % maximaler negativer strom (load an der Zelle) 
    %maxcurr = 10E-4;   % maximaler positiver strom 
    
    step = 1E-2;       % schrittweite
    
    % 
    %%%%%%%%%%%%%%%%%%%%%%%%%%
    % Messgeraet einstellen  %
    %%%%%%%%%%%%%%%%%%%%%%%%%%
    % SOURCING ->  VOLTAGE
    %
    %fprintf(serialObject,':INIT:CONT OFF;:ABOR');
    fprintf(serialObject,':FORM:DATA ASCII');
    fprintf(serialObject,':SOUR:FUNC VOLT');
    fprintf(serialObject,':SOUR:VOLT:MODE FIX');
    fprintf(serialObject,':SOUR:VOLT:RANG 10E-0');    % -> 00.0000 V
    fprintf(serialObject,':SOUR:VOLT:LEV 0.0');       % -> Starteinstellung 0 V
    
    % MEASUREMENT -> CURRENT 
    fprintf(serialObject,':SENS:FUNC "CURR:DC"');
    fprintf(serialObject,':SENS:CURR:PROT 40E-3');     % -> compliance 10.0000 mA
    fprintf(serialObject,':SENS:CURR:RANG 10E-2');     % -> 0.00000 mA  (muss kleiner als complience sein)
    fprintf(serialObject,':TRIG:COUN 1');
    
    %fprintf(serialObject,':CONF:VOLT:DC');
    
    fprintf(serialObject,':OUTP ON');


        %% Messen und Daten abholen
    count = 1; 
    v(1)=0; i(1)=0;  %init der arrays 
   
       for volt = minvolt:step:maxvolt
           
          spannung=num2str(volt);
          command = strcat(':SOUR:VOLT:LEV ',{' '},spannung);
          fprintf(serialObject,char(command));
           


          fprintf(serialObject,':READ?');
          data=fscanf(serialObject);  % gesamten buffer des device einlesen
          c = strsplit(data,',');          % gelesenen string nach ',' in zellen zerlegen
          i(count) = str2num(cell2mat(c(2)));                 % stromzelle 
          v(count) = str2num(cell2mat(c(1)));                 % spannungszelle
        
        

        count = count +1;
       end
   
    
    figure(1);
    plot(v,i);
    grid on; hold on;
    xlabel('voltage [V]'); ylabel('current [A]')
    title('IV - Kennlinie ');
    
    %% instrument in local mode schalten
    fprintf(serialObject,':OUTP OFF');
    fprintf(serialObject,'SYSTEM:LOCAL');
    fclose(serialObject);

 

Das Ergebnis der beiden Skripten ist der folgende Kennlinienverlauf:

Kleines Bastelprojekt zur Sommerzeit

Loading

Solarmodul
Als Mini – Bastelprojekt zur Sommerzeit bezeichne ich folgende Bastelei. Ein kleines monokristallines Solarmodul mit der Bezeichnung „SM 6“ von einem bekannten, großen Elektronikdistributor der mit „C“ beginnt und mit „d“ endet, spielt in dem Projekt die Hauptrolle. Das Modul hat eine Nennleistung von 6Wp bei einem maximalen Strom von 320mA. Die Nennspannung liegt bei 17,3V. Die Leerlaufspannung beträgt 20,8V. Die Siliziumzellen sind in einer EVA (Ethylen-Vinyl-Acetat) Kunststoffplatte eingebettet und UV- und feuchtigkeitsbeständig. Das ganze Modul ist ca. 25cm x 25 cm groß. Es ist also ideal geeignet, um die Energie zum Betreiben von USB-Geräten bereitzustellen. Hierbei habe ich zum Beispiel an WIFI-IP-Cams gedacht. Auch das Laden von Smartphones oder Tablets sollte damit möglich sein.
Um das nun auch durchführen zu können, muss aus der Nennspannung der Photovoltaikzelle die Betriebsspannung des USB-Standards (5V) erzeugt werden. Das könnte man jetzt ganz einfach mit einem 7805er Regler machen und die Differenz dabei in Wärme umwandeln. Doch das ist die, so ziemlich ineffizienteste Möglichkeit, die Energie des Panels in ein Handy zu bekommen.
Zum einen ist der Innenwiderstand des Panels von der Lichtintensität abhängig, was einen großen Einfluss auf den Wirkungsgrad bei nicht angepassten Lastwiderständen hat. Zum anderen ist ein Längsregler ein Energievernichter, da die Differenz zwischen Eingangsspannung und geregelter Ausgangsspannung bei Stromfluß in Verlustleistung, also Wärme umgewandelt wird. Hier ist man mit einem Schaltwandler (Buck-Converter) besser bedient.
 
In einem einfachen Laboraufbau kann das Verhalten des Panels untersucht werden. Dazu wird die Leerlaufspannung des Panels bei unterschiedlicher Beleuchtungsstärke gemessen. Anschließend wird das Panel mit unterschiedlichen Widerstandswerten belastet und der Strom durch die Last, sowie die Spannung am Panel gemessen. Die Messwerte werden aufgezeichnet und der Ri (Innenwiderstand der Quelle) berechnet. Der nachfolgende Stromlaufplan zeigt den Messaufbau:
Messaufbau – Schaltung
Als Amperemeter dient ein Agilent- und als Voltmeter ein Keithley 2701 Tischmultimeter. Diese Messgeräte können beide über SCPI-Befehle gesteuert werden. Als Schnittstelle ist jeweils ein LAN-Port vorhanden. Das macht es einfach, über einen PC und ein geeignetes Skript, einen automatisierten Messablauf zu realisieren. Und da Matlab eine sehr bequeme Möglichkeit bietet, zu skripten, wird es auch gleich verwendet. Um in einem Labor messen zu können und in etwa dieselben Umgebungsbedingungen zu haben, wird anstelle der Sonne eine Tischlampe mit Halogenglühbirne verwendet. Die Helligkeit der Lampe wird einfach durch die Versorgung mit einem Labornetzgerät von 0-13V eingestellt. Natürlich kann auch das Labornetzgerät per Matlab gesteuert werden.
Messaufbau mit Lampe als „Sonne“

Die Lampe ist in einem Abstand von 25cm mittig über dem Panel platziert. Um ein Gefühl zu bekommen, welche Beleuchtungsstärke mit der Lampe erreicht wird, wird mit einem Luxmeter eine Referenzmessung gemacht. Das heißt, die Lampe fährt die Leistungsrampe von 0-13V durch und das Luxmeter misst die Beleuchtungsstärke im Abstand von 25cm unter der Lampe. Das Ganze wird in 0.5V Schritten aufgelöst. Daraus ergibt sich eine Kurve, die so aussieht:

Spannung an der Lampe ergibt Beleuchtungsstärke

Jetzt kann die Messung beginnen. Als Lastwiderstand werden manuell Widerstände an das Panel geschaltet und Strom und Spannung bei jeder Helligkeitsstufe gemessen. Es sind elf Lastwiderstandswerte die von 4.7 Ohm bis 220 Ohm reichen nacheinander angeschlossen. Eine Leerlaufmessung wird dann natürlich ohne Lastwiderstand gemacht. Folgender Graph zeigt den errechneten Innenwiderstand bei zwei Lasten des Panels über den Helligkeitsverlauf der Lampe in Lux und im weiteren Graph über die Spannung an der Lampe (für die bessere Skalierung). Den Innenwiderstand einer Quelle errechnet man aus der Leerlaufspannung der Quelle abzüglich der Spannung unter Last, dividiert durch den Strom. Mit der Differenz der Leerlauf und Lastspannung erhält man also den Spannungsabfall am Innenwiderstand. Da im Lastfall auch der Strom bekannt ist, braucht man nur mehr das Ohm´sche Gesetz anzuwenden, um den Widerstandswert zu erhalten…

Innenwiderstand vs. Beleuchtungsstärke
Innenwiderstand vs. Spannung an der Lampe

Da jetzt einige Klarheiten über das Verhalten der PV-Zelle beseitigt wurden, kann ich noch kurz über den Aufbau des Spannungswandlers berichten. Wie schon zuvor angekündigt, ist ein Schaltwandler der effizientere Weg, die Energie an den Verbraucher anzupassen. Hier kommt ein LM2596S zum Einsatz. Der LM 2596 ist ein „Simple Switcher Power Converter, der mit 150kHz schaltet und eine Last mit 3A versorgen kann.) Hier eine Übersicht der Funktionen:

  • 3.3-V, 5-V, 12-V, and Adjustable Output Versions
  • Adjustable Version Output Voltage Range: 1.2-V to 37-V ± 4% Maximum
    Over Line and Load Conditions
  • Available in TO-220 and TO-263 Packages
  • 3-A Output Load Current
  • Input Voltage Range Up to 40 V
  • Excellent Line and Load Regulation Specifications
  • 150-kHz Fixed-Frequency Internal Oscillator
  • TTL Shutdown Capability
  • Low Power Standby Mode, IQ, Typically 80μA
  • Uses Readily Available Standard Inductors
  • Thermal Shutdown and Current-Limit Protection

(Quelle: Datenblatt des Herstellers TEXAS Instrument)

Mit diesem Schaltwandler und noch ein paar wenigen anderen Komponenten lässt sich schnell eine Schaltung zusammenzimmern und mit dem Layout Tool „Eagle“ in eine Platine verwandeln. Diese Schaltung ist aber so einfach aufgebaut, dass sie lediglich mit den Vorzügen des LM2596 möglichst effizient arbeitet, aber kein Powertracking durchführt. Das heißt, die Last, die die Schaltung für die Solarzelle darstellt wird nicht an den Innenwiderstand der Solarzelle angepasst.

 

Schaltbild des DC-DC Converters

Aus dieser Schaltung wurde dann ein einfaches Layout erstellt, eine Platine geätzt und diese bestückt. Eine USB-Buchse am Ausgang ermöglicht das direkte Ansschließen von USB-Geräten. Um das Ganze auch ein wenig vernünftig aussehen zu lassen habe ich der Platine noch ein kleines Kunststoffgehäuse gespendet…

Messaufbau
Schaltbare Lastwiderstände
Layout am Computer
Folie zum Erstellen der Printplatte
Geätzte PCB
Bestückte PCB
Fertige Schaltung

Datenknoten mit Arduino

Loading

Leider sind die Abstände, in denen ich ein wenig Zeit finde, einen neuen Beitrag für den Blog zu schreiben, nicht kürzer geworden. Aber einen Beitrag pro Monat zu posten, halte ich ein… 🙂

Dieses Mal ist es kein Retro Bastelprojekt aus den heimischen Gefilden oder eine Restauration eines alten Gerätes, sondern wieder etwas zum Thema Arduino. Die Idee – es soll ein Sensor gebaut werden, der wie immer, eine physikalische Größe in ein elektrisches Signal umwandelt. Das ist jetzt nichts Besonderes und um welche Art von Sensor es sich handeln wird, werde ich vorerst noch nicht beschreiben. Aber es soll nicht ein Sensorboard geben, sondern viele. Und diese Sensorboard kurz „Sensoren“ sollen in einer zweidimensionalen Matrix miteinander vernetzt werden. Man kann sich das in etwa vorstellen wie ein Schachbrett, wobei jedes der Schachbrettfelder einen Sensor darstellt. Dieses Netzwerk an Sensoren – also Sensorknoten – soll dann über eine Übergabestelle mit einem Rechner verbunden sein und die Sensordaten des jeweiligen Feldes ausgeben. Es soll dann auch möglich sein, einzelne Felder aus dem Netzwerk zu entfernen ohne dass das verbleibende Netzwerk seine Funktion verliert.

Das ganze System soll möglichst einfach und günstig aufgebaut werden. Und so ist schnell ein Systemkonzept entstanden, in dem die Knoten über den I²C Bus kommunizieren und ihre Daten zu einem Master senden. Das folgende Diagramm soll das verdeutlichen.

Dieses Konzept, so dachte ich mir, lässt sich am einfachsten mit einem Atmega Microcontroller realisieren. Der hat genügend IO´s, einen I²C Bus und UART onboard, ebenso auch analoge Eingänge und benötigt wenig Bauteilperipherie, um ihn in einem eigenen Layout zum Leben zu erwecken. Und es gibt nichts schnelleres, so einen Testaufbau eines solchen Knotennetzwerks zu realisieren, als die gut bekannten Arduino Development Boards zu benutzen. Ich habe die günstigste Variante für einen Testaufbau gewählt -> den Chinanachbau vom Arduino Uno (Joy-IT UNO) mit dem Atmga328 im gesockelten DIL Gehäuse.

Joy-It Uno Boards

Im Bild sind zehn Stück dieser Microcontrollerboards zu sehen. Von denen soll einer als Bus-Master und neun Stück als Slaves eingesetzt werden. Jeder dieser Slaves hat natürlich eine eindeutige Bus-Adresse, die im System nur einmal vorkommt. Im Testaufbau wird diese Busadresse über den Programmcode fest vergeben, da ohnehin jeder Arduino einmal mit dem Rechner verbunden werden muss, um den Programm-Upload durchzuführen. Das soll natürlich später anders aussehen. Denn der Arduino wird auf den Atmega328 Chip, seinen Quarz und die paar Widerstände reduziert auf dem Sensorboard mit gelayoutet. Programmiert soll der Chip dann über die ISP Pins werden. Da bei vielen Boards natürlich nicht jedes Mal der Programmcode individuell angepasst wird und alle das gleiche Flashfile erhalten sollen, will ich die Sensoradresse mit einem 7Bit Dipschalter einstellen. Ein 4021 Cmos Static Shift Register soll die Bits nach dem Einschalten des Controllers auslesen und seriell in den Controller schieben. Der daraus resultierende Wert steht dann in einer Variablen als Busadresse zu Verfügung.

Jeder dieser Slaves mit seiner individuellen Busadresse wird nun vom Masterknoten der Reihe nach abgefragt, welchen Zustand er hat und ob er einen Ausgang schalten soll, oder nicht. Das bedeutet, der Knoten hat lediglich einen DO (Digitalen Ausgang) mit dem er beispielsweise eine LED aus- und einschalten kann und einen oder mehrere DI (Digitalen Eingang) der einen Zustand, zum Beispiel eines einfachen Schalters abfragt. Diese Funktionen werden in 2 Bits eines Bytes gespeichert. Ein weiteres Byte dient zur Übertragung der Busadresse. Es werden also zwei Bytes über den Bus geschickt. Das untenstehende Bild zeigt den Testaufbau mit den „UNO-Boards“

Alle Arduinos sind mit I²C Datenbus und Spannungsversorgung verbunden

Der Ablauf läuft wie folgt:

MASTER:
Der Masterknoten sendet nach der Reihe an alle Slave-Adressen eine Anfrage und einen Schaltbefehl (der kommt für alle Knoten von einem TEST-Taster Eingang am Master) für den LED-Ausgang des Knotens und sieht ob eine Antwort zurückkommt oder nicht. Wenn keine Antwort kommt, ist der Knoten nicht im Netz oder defekt. Kommt eine Antwort, so besteht diese aus der Adresse des Knotens und seinem Statusbyte. Diese Informationen werden über ein RS232 Terminal an den, am Master angeschlossenen Rechner übertragen. So kann dort beispielsweise über eine Visualisierung mittels (NI LabVIEW, oder Matlab o.ä.) der Schaltzustand jedes einzelnen Knotens am Bildschirm angezeigt werden. Mit einer Anpassung des Master Programmes ist es auch möglich, die LED-Ausgänge der Slaves über den Rechner zu schalten.

SLAVE:
Wenn der Masterknoten vom Slave Daten anfordert, so sendet der Slave zwei Bytes zurück. Wobei Byte0 wieder die Slave ID (also Busadresse ist) und Byte1 die Daten. Byte1 besteht eigentlich aus nur zwei Bit, die wie folgt kodiert sind (in dezimaler Darstellung):
 0 = LED aus | Sensor nicht ausgelöst
 1 = LED ein | Sensor nicht ausgelöst
 2 = LED aus | Sensor ausgelöst
 3 = LED ein | Sensor ausgelöst

Der Programmcode als Beispiel:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// I2C Slave Code
// 16.05.2018 
// ver 1.3
#include <Wire.h>
#define ADDRESS 2     // adresse des slave knotens
#define PAYLOAD_SIZE 2 // anzahl der bytes  die vom masterknoten zu erwarten sind
int LED=12;            // indicator led an pin D12
int SENSOR = 8;        // sensor input an pin D8
bool actionState=0;      // sensor zustand
int busstatus;  // statusvariable 
                       // 0 = LED aus | sensor nicht belegt
                       // 1 = LED ein | sensor nicht belegt
                       // 2 = LED aus | sensor belegt
                       // 3 = LED ein | sensor belegt
 
bool sensled=0;          // sensor LED
byte nodePayload[PAYLOAD_SIZE];

void setup()
{
  pinMode(LED, OUTPUT);         //sensorLED
  pinMode(SENSOR, INPUT);       //Sensor 
  Wire.begin(ADDRESS);          // Activate I2C network
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent); // auf master anforderung warten
                      //  // debug interface
                      //  Serial.begin(9600); 
}

// *********************************mainloop****************************************************
void loop()
{ 
  delay(5);
  
   if(sensled){digitalWrite(LED, HIGH);}
         else{digitalWrite(LED, LOW);}

  actionState = digitalRead(SENSOR);  //Sensoreingang abfragen        
   if((actionState==1)&&(sensled==1)) {busstatus=3;}
   else if ((actionState==0)&&(sensled==1)) {busstatus=1;}
   else if ((actionState==1)&&(sensled==0)) {busstatus=2;}
   else if ((actionState==0)&&(sensled==0)) {busstatus=0;}

                      //  Serial.println("######################");
                      //  Serial.print("busstatus neu setzen ");
                      //  Serial.println(busstatus);
                      //  Serial.print("sensled LED            ");
                      //  Serial.println(sensled);
                      //  Serial.print("actionState           ");
                      //  Serial.println(actionState);
                      //  Serial.println("######################");
  nodePayload[0] = ADDRESS;                  // Adresse in byte0 zurücksenden.  
  nodePayload[1] = busstatus;                //byte 1 ist die statusinfo der LED
}



// *********************************************************************************************
void requestEvent()
{ Wire.write(nodePayload,PAYLOAD_SIZE);  
  Serial.println("bytes status schreiben");
  Serial.println(nodePayload[0]);
  Serial.println(nodePayload[1]);
  delay(5);
}

// *********************************************************************************************
void receiveEvent(int bytes)  //einen wert vom I2C lesen
      
{
  
  busstatus = Wire.read(); //If the value received was true turn the led on, otherwise turn it off  
                              //  Serial.println("status empfangen");
                              //  Serial.println(busstatus);
  if((busstatus==1)||(busstatus==3)){sensled = 1;}
                                else{sensled = 0;}
                                              
}

 

Die Busadresse ist in diesem Slave-Code noch individuell einzugeben. In der nächsten Version ist dann der vorherbeschriebene „Serializer“ der parallelen Dip-Schaltervariante implementiert. Das folgende Codebeispiel ist von Masterknoten, der die Slaves ausliest und mittel Prüftaster ein LED Muster an die Sensor Slaves sendet:

 

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// I2C masterknoten 
// 16.05.2018 
// ver 1.2
// changes abfrage wenn kein knoten am bus dann 255 ausgeben
#include <Wire.h>

#define busbytes 2          // wievele byte vom I2C knoten zu erwarten sind
#define maxKNOTEN  10       // anzahl der zu scannenden slaves
#define startKNOTEN 2       // startadresse der slaves
#define DELAY 5             // einfach ein delay ....

int i; int j=0;
int buttonPin = 12;
int testbut = 0; int anim = 0;
int buttonState = 0;
int DATEN[busbytes];
int adresse; int busstatus;  
byte sensorbelegt; byte ledsensoron;

                       // 0 = LED aus | Sensor nicht belegt
                       // 1 = LED ein | Sensor nicht belegt
                       // 2 = LED aus | Sensor belegt
                       // 3 = LED ein | Sensor belegt

int leddat1[] = {1,1,1,1,0,1,1,1,1}; // -
int leddat2[] = {0,0,0,0,1,0,0,0,0}; // |

void setup()
{
  Serial.begin(9600);  
  Serial.println("MASTER-KNOTEN");
  Serial.print("Maximum Slaveknoten: ");
  Serial.println(maxKNOTEN);
  Serial.print("Datengroesse in byte: ");
  Serial.println(busbytes);
  Serial.println("***********************");
  
  Wire.begin();                 // Activate I2C link
  pinMode(buttonPin, INPUT);    // test-tastereingang festlegen
}


//#####################################################################################################
void loop()
    
{
  for (int Knotenadresse = startKNOTEN;         //alle knoten scannen
           Knotenadresse <= maxKNOTEN; 
           Knotenadresse++) 

        
    //################################################################################################       
    { 
     // testbut = 0;  
     anim = 0;   
    Wire.requestFrom(Knotenadresse, busbytes);        // daten vom jeweiligen knoten anfordern
                                                 
           DATEN[0]=255; DATEN[1]=255;   // wenn kein knoten dann auf 255 setzen    
          if(Wire.available() == busbytes) {                                    // wenn knoten und daten dann
            for (i = 0; i < busbytes; i++) DATEN[i] = Wire.read();          // daten holen (zuerst busID, dann daten)
           // for (j = 0; j < busbytes; j++) Serial.println(DATEN[j]);        // daten an rs232 ausgeben   
          }            

//            Serial.println(Knotenadresse);
//            Serial.println(DATEN[0]);
//            Serial.println(DATEN[1]);
//            Serial.println(" ");
           
            adresse=DATEN[0]; 
            busstatus=DATEN[1];
           
            if(busstatus == 0)       {sensorbelegt=false;  ledsensoron=false;}
            else if (busstatus == 1) {sensorbelegt=false;  ledsensoron=true;}
            else if (busstatus == 2) {sensorbelegt=true;  ledsensoron=false;}
            else if (busstatus == 3) {sensorbelegt=true;  ledsensoron=true;}
      
         //################################################################################################
         //Testbutton Status lesen und variable testbut entsprechend setzen
       
          buttonState = digitalRead(buttonPin);               //tastereingang einlesen
          if(buttonState == HIGH){                            //wenn taster aktiv dann variable anim setzen
          anim = 1;
          //delay(5); 
          }
            
//            //debug debuginfo tasterstatus auf rs232 ausgeben
//            Serial.println("#######################");
//            Serial.print("Knoten Adresse    :");
//            Serial.println(adresse);
//            Serial.print("Busstatus         :");
//            Serial.println(busstatus);
//            
//            Serial.println("----------------");
//            Serial.print("Fliese belegt    :");
//            Serial.println(sensorbelegt);
//            Serial.print("LED Fliese       :");
//            Serial.println(ledsensoron);
//            Serial.print("#######################");
//            Serial.println(" ");
      
          //################################################################################################
          //Testbutton Status an jeweiligen knoten senden
      
          Wire.beginTransmission(Knotenadresse);           // transmit to device actual in for loop
          //anim schreiben
                    
           if (anim==0) {testbut=leddat1[j]; j++;}
                   else {testbut=leddat2[j]; j++;}
           if (j>8){j=0;}
          
          Wire.write(testbut);                             // senden des tasterstatus
          Wire.endTransmission();                          // ende gelände mit uerbertragung
       
          delay(DELAY);
          

    }
   
}

 

Mit dieser Anordnung ist es jetzt möglich alle Arduinos und deren Eingang auszulesen bzw. die LED über den Bus zu steuern. Im nächsten Schritt wird ein „Sensor“ gebaut, eine Platine gelayoutet und der Arduino Uno auf seinen Microcontroller reduziert. Darüber werde ich in einem der nächsten Posts berichten…

 

 

 

Langzeitmessungen mit Keithley und Matlab

Loading

Keithley2000 Tischmultimeter

Ein alter Begleiter im Bereich Messgeräte ist das Tischmultimeter von Keithley. In unseren Labors werden vorwiegend die Typen der 2000er Serie eingesetzt. Es gibt sie in unterschiedlichen Ausstattungsvarianten betreffend der Schnittstellen zur Außenwelt. Hier ist GBIP-Bus natürlich ein Standard, ebenso wie RS232. Die neueren Geräte besitzen mittlerweile ein LAN Interface mit dem eine Kommunikation über das Internet Protokoll möglich ist. Über jede dieser Schnittstellen kann über „Standard Commands for Programmable Instruments“ (SCPI) mit dem Gerät kommuniziert werden. In diesem Beispiel werde ich das Keithley 2000 über Matlab ansteuern und zyklisch über einen längeren Zeitraum Messwerte auslesen, diese in Matlab speichern und schlussendlich in einem Plot ausgeben – quasi einen simplen Datalogger konfigurieren. Der Zweck dieses Aufbaus ist es, den Spannungsverlauf (bzw. auch Strom) eines Akkus bzw. Batterie eines Low-Energie Device zu erfassen.

Rückseite des Keithley 2000

GPIB Interface (IEEE488)

RS232 Schnittstelle

In diesem Beispiel werde ich die serielle Datenübertragung per klassischer RS232 Schnittstelle verwenden, da diese für meine Anwendung vollkommen ausreicht. Zudem kann ich mir die Installation der Treiberpakete für das GPIP-USB Interface ersparen. 🙂 Da viele der aktuellen Rechner und Laptops auch keine RS232 Ports mehr haben, muss ein USB-RS232 Adapter (beispielsweise FTDI232 etc.) her.

USB-RS232 Adapter am Keithley2000

Ist die Verbindung zwischen dem Multimeter und dem Rechner hergestellt, kann, wie in diesem Beispiel, über ein Matlabskript kommuniziert werden. Dem Keithley muss nur mehr mitgeteilt werden, dass es über die serielle Schnittstelle „sprechen“ soll. Die folgenden Code-Schnipsel zeigen, wie man einfach über SCPI Daten auslesen kann:


serialObject = instrfind('Type', 'serial', 'Port', 'COM26', 'Tag', '');
%serialPort = 'COM23';
%serialObject = serial(serialPort,'BaudRate',9600, 'DataBits',8);

if isempty(serialObject)
serialObject = serial('COM26','BaudRate',57600, 'DataBits',8);
else
fclose(serialObject);
serialObject = serialObject(1)
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Sourcemeter 2000 setup
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
fopen(serialObject)
% fprintf(serialObject,':*RST')

time = now;
voltage = 0;
%%
figureinstanz = figure('NumberTitle','off',...
'Name','Spannungslogg',...
'Color',[0 0 0],'Visible','off');
plotinstanz = plot(voltage,time,'Color','red');

%% Messzeit und evtl Messintervall
stoptime = 10; %60 seconds
timeInterval = 1; % brauch' ma jetzt nicht

% Messgeraet einstellen
fprintf(serialObject,':SOUR:FUNC:MODE CURR'); % current source selection.
fprintf(serialObject,':SOUR:CURR:MODE FIXED'); % changes voltage mode to fixed
fprintf(serialObject,':SOUR:CURR:LEV 0'); % sets current to 0

fprintf(serialObject,':SENS:FUNC &quot;VOLT&quot;');
fprintf(serialObject,':SENS:VOLT:PROT 4');
%fprintf(serialObject,':SENS:CURR:RANG:AUTO ON');
fprintf(serialObject,':SENS:VOLT:RANG 10');
fprintf(serialObject,':FORM:ELEM VOLT');

% %fprintf(serialObject,':TRAC:COUN 1');
% %fprintf(serialObject,':TRAC:FEED:CONT NEV');
%
%
% fprintf(serialObject,':TRAC:CLE');
%
% fprintf(serialObject,':TRAC:POIN 10');
% fprintf(serialObject,'TRAC:FEED:SENS');
% fprintf(serialObject,'TRAC:FEED:CONT NECT');
% fprintf(serialObject,'TRIG:COUN 10');
% fprintf(serialObject,':OUTP ON');
%
% fprintf(serialObject,':INIT');
% fprintf(serialObject,':TRACE:DATA?');

%% Daten abholen
count = 1; voltage(1)=4
tic;
time=toc;
% while time&lt;=stoptime
while voltage&gt;=1.5
% fprintf(serialObject,':INIT');
% fprintf(serialObject,':TRAC:FEED SENS');
% fprintf(serialObject,':TRAC:DATA?');
%
fprintf(serialObject,':READ?');
voltage(count) = fscanf(serialObject,'%f');
time(count) = toc;
set(plotinstanz,'YData',voltage,'XData',time);
set(figureinstanz,'Visible','on');
pause(timeInterval);
count = count +1;
end

figure(1);
plot(time,voltage);
grid on; hold on;
xlabel('Zeit [s]'); ylabel('Batteriespannung [V]')
title('Spannungsverlauf Batterie 3V Lithium (2032 mit Modul) im default mode');

% fprintf(serialObject,':OUTP OFF');
%% Put the instrument in local mode
fprintf(serialObject,'SYSTEM:LOCAL');
fclose(serialObject);

Wie so ein Datalog dann aussieht, ist in der folgenden Grafik dargestellt. Hier ist der Spannungsverlauf einer nahezu entladenen Batterie bis zum Abschalten des Verbrauchers über die Zeit aufgezeichnet worden.

LCR-Meter über Matlab auslesen

Loading

LCR-Meter 4297A Agilent

In diesem Post möchte ich mich einmal etwas anderem widmen. Es geht nicht um Retrotechnik, sondern um eine Kleinigkeit, die mir das Arbeiten im Büro erleichtert. Eines der vielen Messgeräte mit denen ich zu tun habe, ist ein Agilent LCR-Meter. Mit dem LCR-Meter 4297A kann man bekannterweise ja die Induktivität, die Kapazität, etc. von elektrischen Bauteilen und generell von Strukturen, die dem Bereich der Elektronik/Elektrotechnik zugeordnet sind, messen. Grob gesagt, der 4297A misst eigentlich nur Strom / Spannung, die Phasenlage  zwischen den beiden und die Energierichtung. Und das bei einer bestimmten Frequenz. Mathematisch werden dann aus diesen Paramatern alle Größen wie L,C,R,X,Y,Q,PHI,… errechnet und ausgegeben. Die Frequenz hier hierbei vom 1MHz bis 3GHz (in 100kHz Schritten) einstellbar. Idealerweise kann das Messgerät nicht nur in einem Frequenzpunkt messen, sondern auch in vielen. Mit „vielen“ ist hier gemeint, dass das Messgerät Frequenztabellen mit 32 Einträgen erzeugen kann. Von diesen Tabellen existieren acht Stück. So ist es möglich, den Verlauf einer gemessenen Größe in Form einer Kurve darzustellen. Allerdings ist das ziemlich umständlich. Die Inhalte der Tabellen müssen händisch (als „csv“ Dateien) Tabelle für Tabelle exportiert und gespeichert werden. Das bedeutet, jede Tabelle muss einzeln angewählt werden. Danach ist der Dialog „Export List View“ zu selektieren – dann ein Speicherpfad und Dateiname anzugeben. Erst jetzt werden die ersten 32 Datensätze exportiert. Dieser Vorgang ist insgesamt achtmal zu wiederholen. Gespeichert wird auf eine 3,5 Zoll Floppy Disc – das einzige verfügbare Medium. Man könnte den 4297A optional auch in ein LAN hängen und eine Dateifreigabe einrichten. Der händische Export bleibt aber nicht erspart. Auf einem „normalen“ Rechner können die  .csv Files jetzt geöffnet werden. Die müssen dann im postprocessing händisch zusammengefügt werden. Erst jetzt kann aus den Daten ein Diagramm gebastelt werden. Hier bietet sich als Tool Matlab von Matworks an, das in unseren Laboren im Rahmen der Ausbildung häufig eingesetzt wird.

NI GPIB – USB Controller

Um diesen umständlichen Prozess wesentlich zu vereinfachen, habe ich ein kleines Skript erstellt, das über die SCPI – Befehle (Standard Commands for Programmable Instruments) mit dem Messgerät kommuniziert. Das soll heißen: Das Messgerät ist über einen GPIB-USB Controller mit einem PC verbunden. Auf dem PC befindet eine Matworks Matlab Installation samt den benötigten Toolboxen. Das Matlab-Skript soll nun einfach die Tabellen der Reihe nach durchschalten und die Inhalte der einzelnen Parameter auslesen und einem Array speichern. Der Inhalt der Arrays wir dann direkt in einem Plot dargestellt. Diese Methode bedient sich aber nur der Inhalte der Tabellen. Es wäre natürlich auch möglich, über das Skript in einer Schleife jede gewünschte Frequenz direkt einzustellen, die Messwerte auszulesen, die nächste Frequenz anzuwählen usw.  Das würde max. 29990 Punkte über den gesamten Frequenzbereich ergeben. Die acht Tabellen á 32 Punkte erlauben hingegen nur 256 Punkte. Das ist fürs erste aber ausreichend und auch viel schneller.

Transmission Line 50 Ohm mit Abschlusswiderstand

die Leitung ist terminiert

In dem Beispiel ist der Impedanzverlauf (Z-Verlauf) einer 50 Ohm Transmission Line dargestellt. Das Ende der Leitung ist dabei mit einem 50Ohm Widerstand abgeschlossen. Der Frequenzbereich ist 1MHz bis 3 GHz. Anders sieht es aus, wenn die Leitung offen oder kurz geschlossen ist. Die elektromagnetische Welle wird dann nicht, wie bei dem „matched“ (angepassten) System am Ende der Leitung in Wärmeenergie umgewandelt, sondern zurück in das System reflektiert.

die Leitung ist kurzgeschlossen

Das folgende ganz einfache Matlabskript ermöglicht das Auslesen der Messgeräteparameter. Das Skript dient als Beispiel, wie man schnell zu den Messdaten kommt. Im Programmingmanual des Herstellers vom LCR-Meter sind alle SCPI Kommandos und reichlich Beispiele angeführt, mit denen man mit dem Messgerät kommunizieren kann.


%auslesen der agilent LCR Keule 4287A
%gekodet von ingmar bihlo Ende November 2017

%anschluss über gpib ni adapter
%LCR gpip adresse: 5
%%
%vorarbeiten an LCR Keule
%
% Es müssen 8 Tabellen mit je 32 Punkten definiert sein
% (power und average ist egal, wird nicht ausgelesen)
% die CALibration muss gemacht worden sein
% unter "measurement parameters" muessen vier parameter definiert sein
% zb. Z, qhi, R, L, etc... diese sind dann in den variablen param1 bis 4
% enthalten

%%

% gpib interface oeffnen und identifier lesen
g = gpib('ni', 0, 5);
g.InputBufferSize = 100000; % Set the buffer size
fopen(g);
fprintf(g, '*IDN?')
idn = fscanf(g);
fclose(g);

num1all=0; % initialisieren der variablen für den summenvector
num2all=0;
num3all=0;
num4all=0;
freq=0;

fopen(g);
%read list parameters (frequency points)
fprintf(g, ':SOUR:LIST?');
fpoint=fscanf(g);
listchar=strsplit(fpoint,',');
list=[cellfun(@str2num, listchar(:,1:end))]
clear listchat; clear fpoint;

%analyze list content
points=freq(1);

for i=1:8
%Tables selecten
fprintf(g, strcat(':SOUR:LIST:TABL 0',num2str(i)));
pause(1); %pause 1s zum umschalten der tabelle

%parameter1 abholen
fprintf(g, ':DATA:FDAT1?'); %parameter 1 anfragen
par1=fscanf(g); %parameter 1 holen

string1=strsplit(par1,','); %parameter 1 string nach komma zerlegen
%num1=[cellfun(@str2num, string1(:,1:end))] %parameter 1 strings in dec konvertieren
num1=[cellfun(@str2num, string1(:,1:end))];
num1all=[num1all,num1]; %parameter1 aktuell mit parameter1 aus vorherigem durchlauf concentenaten

fprintf(g, ':DATA:FDAT2?');
par2=fscanf(g);
string2=strsplit(par2,',');
num2=[cellfun(@str2num, string2(:,1:end))]
num2all=[num2all,num2];

fprintf(g, ':DATA:FDAT3?');
par3=fscanf(g);
string3=strsplit(par3,',');
num3=[cellfun(@str2num, string3(:,1:end))]
num3all=[num3all,num3];

fprintf(g, ':DATA:FDAT4?');
par4=fscanf(g);
string4=strsplit(par4,',');
num4=[cellfun(@str2num, string4(:,1:end))]
num4all=[num4all,num4];

%read list parameters (frequency points)
fprintf(g, ':SOUR:LIST?');
fpoint=fscanf(g);
listchar=strsplit(fpoint,',');
listraw=[cellfun(@str2num, listchar(:,1:end))];
list=listraw(:,2:end); %von pos2 das feld schreiben (an pos ist die anzahl der zeilen)

for c=1:3:96
freq=[freq,list(c)]; %von jedem 3. wert aus list ein neues array bilden
end

clear listchat; clear fpoint;

pause (1);
end

%%

%ausgabevariablen festlegen
frequency=freq(:,2:end);
param1=num1all(:,2:end);
param2=num2all(:,2:end);
param3=num3all(:,2:end);
param4=num4all(:,2:end);

%%
% Cell array richtig uma drahn
x1=param1(1:32);
y1=param1(33:256);
param1 = [y1 x1];

x2=param2(1:32);
y2=param2(33:256);
param2 = [y2 x2];

x3=param3(1:32);
y3=param3(33:256);
param3 = [y3 x3];

x4=param4(1:32);
y4=param4(33:256);
param4 = [y4 x4];
%%
%uerberflüssige variablen loeschen
clear c; clear i; clear list; %clear freq;
clear par1;clear par2;clear par3;clear par4;
clear string1;clear string2;clear string3;clear string4;
clear num1all;clear num2all;clear num3all;clear num4all;

fclose(g);

%plotten der ergebnisse
figure(1);
plot(frequency,param1);
grid on; hold on;
xlabel('Frequency [Hz]'); ylabel('Measurement Parameter1 |Z| [Ohm]');
title('Agilent LCR Keule');

figure(2);
plot(frequency,param2);
grid on; hold on;
xlabel('Frequency'); ylabel('Measurement Parameter2');
title('Agilent LCR Keule');

figure(3);
plot(frequency,param3);
grid on; hold on;
xlabel('Frequency'); ylabel('Measurement Parameter3');
title('Agilent LCR Keule');

figure(4);
plot(frequency,param4);
grid on; hold on;
xlabel('Frequency'); ylabel('Measurement Parameter4');
title('Agilent LCR Keule');