Schlagwort-Archive: RS232

CO2-Messung mit SCD30, Arduino und Matlab

Loading

Dieses Projekt – eigentlich Miniprojekt – könnte vielleicht auch für den einen oder anderen interessant sein. Es handelt sich um den mittlerweile bekannten und häufig verwendeten Kohlendioxid Sensor SCD30 (CO2-Sensor) des Herstellers Sensirion. Es gibt etliche Projekte die man dazu im Netz findet. Im Rahmen eines schnellen Testaufbaues habe ich versucht, die Daten des Sensors mithilfe eines Arduino Uno Boards auszulesen, um sie dann mit der Software Matlab in einem Plot darzustellen. Die Datenübertragung erfolgt über die Serielle Schnittstelle bzw. über serielles Protokoll des USB-UART.

Um den SCD30 am Arduino anzuschließen, benötigt man die Spannungsversorgung und den I²C Datenbus – also in Summe gerade einmal vier Drähte. Damit ist die minimale Konfiguration erfüllt und die Daten können ausgelesen werden.

Der Sensor selbst arbeitet nach dem Prinzip der NDIR Technologie.  (NDIR = non-dispersive-infrared). Das bedeutet, der Sensor ist also ein kleines Spektrometer. Hierbei wird das zu untersuchende Medium in eine Probenkammer geleitet. Die Probenkammer wird von einer Infrarotquelle durchleuchtet und das IR-Licht durchstrahlt das Medium und einen sehr schmalbandigen Wellenlängenfilter und trifft dann auf den IR-Detektor auf. Die Wellenlänge des Filters ist dabei so ausgelegt, dass genau diejenigen Wellenlängen durchgelassen werden, die von den Molekülen des Mediums (Gases) absorbiert werden. Je nach Anzahl der Moleküle, oder Dichte des Gases, werden entsprechend weniger Lichtstrahlen vom Detektor erkannt.  Eine zweite Messkammer, die mit einem Referenzgas gefüllt ist, dient dabei als Referenz. Ein Controller am Sensor wertet diese Informationen aus und gibt sie in Form von ppm über die I²C (oder umschaltbar auch MOD-Bus) Schnittstelle weiter. Zusätzlich befindet sich auch ein Temperatur und Luftfeuchtesensor am Board, deren Daten ebenso über den Bus ausgelesen werden können. Die voreingestellte I²C Adresse des SCD30 ist 0x61. Die genauen Informationen zum Datenprotokoll sind in den Dokumentationen der Firma Sensirion zu finden.

Idealerweise gibt es, wie fast immer, schon eine fertige, studententaugliche Library für die diversen Microcontroller. So braucht man sich keine Gedanken mehr zu machen und kann die Daten des angeschlossenen Sensors direkt auslesen. Die Beispielprogramme findet man unter den Examples der Libraries.

electrical specifications

Für die Versorgungsspannung des Sensors kann der Arduino mit 3.3V oder 5V dienen. Vorsicht ist jedoch geboten, wenn man den I²C Bus, verwendet: Hier ist der Input High-Level mit 1,75-3.0V festgelegt und der Output High Level mit max. 2.4V. An einem Arduino sind die Pegel aber 5V!! Also muss hier ein Levelshifter eingebaut werden – oder zumindest, für einen schnellen Test geeignete Widerstände.

Der hier angeführte Programmcode stammt im Wesentlichen aus dem Beispiel der Library von Nathan Seidle von SparkFun Electronics:

 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
/*
By: Nathan Seidle SparkFun Electronics  
Library: http://librarymanager/All#SparkFun_SCD30  
*/

#include <Wire.h>
#include "SparkFun_SCD30_Arduino_Library.h" 
SCD30 airSensor;

void setup()  
{
  Wire.begin();
  Serial.begin(9600);
  //Serial.println("SCD30 Example");
  airSensor.begin(); //This will cause readings to occur every two seconds
}

void loop()  
{
  if (airSensor.dataAvailable())
  {
   // Serial.print("co2(ppm):");
   
    Serial.print(airSensor.getCO2());

    //Serial.print(" temp(C):");
    Serial.print(",");
    Serial.print(airSensor.getTemperature(), 1);

   // Serial.print(" humidity(%):");
    Serial.print(",");
    Serial.print(airSensor.getHumidity(), 1);

    Serial.println();
  }
  else
    //Serial.println("No data");

  delay(500);
}

 

Mit diesen Codezeilen im Arduino Uno und der korrekten Verdrahtung (SDA -> an Arduino A4 und SCL -> an Arduino A5 über einen geeigneten Pegelwandler) geht’s dann mit Matlab weiter. Der Arduino sollte jetzt in einem seriellen Terminal folgende Zeilen ausgeben: (Beispiel)

473,28.5,12.9
473,28.5,13.0
470,28.5,13.1
469,28.5,12.9
466,28.5,12.9
465,28.5,12.7
465,28.5,12.5
463,28.6,12.6
461,28.6,12.5
463,28.5,12.4 … und so weiter

Diese gilt es nun in Matlab einzulesen und über einen definierbaren Zeitraum aufzuzeichnen und gleichzeitig in einem Plot darzustellen. Das Matlabskript hier macht es möglich… (pn falls es jemand benötigt)

Als Ergebnis erhält man dann einen Plot, der den CO2 Verlauf im Raum (in dem Fall am Schreibtisch meines Büros) darstellt.

 

 

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:

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.