In diesem Artikel wird an einem Beispiel erklärt, wie man mit der quelloffenen Hard- und Software von Arduino analoge Signale messen und Relais steuern kann. Das Beispiel basiert auf der Messschaltung aus dem Artikel /Aus_der_Praxis_fuer_die_Praxis/Guelle-Alarmanlage. Die Schaltung besteht aus einem Arduino Nano Microcontroller, einem Drucksensor, einem Relaisboard, einem LCD Modul und einigen weiteren Elektronikbauteilen (Bild 1).
Der Drucksensor gibt ein analoges Stromsignal aus, das auf den gemessenen Druck skaliert ist. Das Stromsignal wird über einen Präzisionswiderstand geleitet. Der Arduino Nano Mirocontroller misst die abfallende Spannung am Präzisionswiderstand und rechnet diesen Spannungswert in den entsprechenden Druck um. Der Mikrocontroller stellt den aktuell und den maximal gemessenen Druck auf einem Display dar. Außerdem schaltet der Arduino Nano zwei Relais, wenn parametrierbare Druckgrenzen überschritten sind.
Einige Bestandteile der Schaltung wie z.B. die Ansteuerung eines Displays werden separat beschrieben, sodass diese Teilschaltungen auch in anderen Projekten verwendet werden können. Die Beschreibung setzt grundsätzliche Kenntnisse in der Hard- und Software von Arduino sowie in Elektronik voraus. Listen der benötigten Bauteile und Werkzeuge sind am Ende des Artikels aufgeführt. Die nötige Software und Tutorials von Arduino können auf der Arduino Webseite abgerufen werden [1].
Eine Kunststoffplatte dient zur Befestigung der Elektronikbauteile. Die Platte kann später in einem Gehäuse verbaut werden. Die Grundplatte mit passenden Schraubenlöchern wurde mit einem CAD (computer-aided design) Programm gezeichnet und mit einem 3D Drucker gedruckt. Die Bauteile werden mit Abstandsbolzen und Schrauben auf die Platte geschraubt. Das Design der Grundplatte ist auf der Webseite MakerBot's Thingiverse abrufbar. [2]
Alternativ können passende Löcher in eine beliebige etwa 4 mm dicke Kunststoffplatte gebohrt werden.
|
Zur Messwertanzeige wird ein LCD (Liquid Crystal Display) Modul mit 2x16 Zeichen (2 Zeilen mit jeweils 16 Zeichen) eingesetzt, das unter der Bezeichnung “1602” von verschiedenen Herstellern und mit verschiedenen Hintergrundfarben erhältlich ist. Diese Displays gibt es mit rückseitig angelötetem LCD-Controller nach HD44780-Standard. Der LCD-Controller ermöglicht die Ansteuerung des Displays über den seriellen I²C (Inter-Integrated Circuit) Bus. Dies verringert die Anzahl der nötigen elektrischen Anschlüsse von 16 auf 4. Mit dem Drehpotentiometer auf dem LCD-Controller kann der Kontrast des Displays eingestellt werden (Bild 6). Die Anschlüsse “VCC” (5 V) und “GND” (0 V) dienen der Spannungsversorgung. Die Anschlüsse “SCL" (Serial Clock - Taktleitung) und “SDA” (SDA Serial Data - Datenleitung) sind die I²C Datenleitungen. Über die Adressierung ist es auch möglich mehrere I2C-Geräte parallel an einem Microcontroller zu betreiben [3].
Die Verbindung zwischen dem Display und dem Arduino Nano besteht aus 4 Leitungen mit Dupont Steckverbindern. Das Beispielprogramm wird über das USB-Kabel mit USB Mini-B Anschluss auf den Arduino übertragen. Für die Ansteuerung des Displays benötigt die Arduino Entwicklungsumgebung die Bibliothek “LiquidCrystal_I2C” [4]. Nach dem Upload des Programms kann die Schaltung mit 12 V Gleichspannung versorgt werden (Siehe Schaltplan Bild 5). Es ist aber auch möglich die Schaltung über das USB-Kabel zu versorgen (siehe Bild 4). Das Programm stellt alternierend 2 verschiedene Zeichenketten auf dem Display dar.
|
Beispielprogramm Display:
/*
* Test LCD
* Rainer Kock
* Version 20.09.2022
*/
#include <LiquidCrystal_I2C.h> // include LiquidCrystal I2C library
LiquidCrystal_I2C lcd(0x27,16,2); // LCD parameters: I2C bus address 0x27, 16 characters/line, 2 lines
void setup() {
lcd.init(); // initialize the lcd
lcd.backlight(); // turn on LCD backlight
}
void loop() {
// first message
lcd.setCursor(0,0); // set cursor to position 0 in line 0, means first position in first line
lcd.print("Hello, "); // display message, write 16 characters to be sure no characters left from an old message
lcd.setCursor(0,1); // set cursor to position 0 in line 1, means first position in second line
lcd.print(" World ! "); // display message
delay(2000); // wait for 2 Seconds
// second message
lcd.setCursor(0,0);
lcd.print("farmwiki.de ");
lcd.setCursor(0,1);
lcd.print(" farmwissen.de ");
delay(2000);
}
Für die Versorgungsspannung des Relaisboards werden dessen Anschlüsse “DC+” und “DC-” mit den Anschlüssen “+5V” und “GND” vom Arduino Nano verbunden. Die Ansteuerung der beiden Relais geschieht über die Kontakte “IN1” und “IN2”, die im Beispiel mit den digitalen Ein- und Ausgängen “D6” und “D7” vom Arduino Nano verbunden werden (Bilder 7 und 8). In dem Arduino Beispielprogramm werden die Pins “D6” und “D7” als digitaler Ausgang definiert und mit dem Spannungspegel “High” initialisiert. Der Spannungspegel des Zustands “High” entspricht 5 V und der Pegel des Zustands “Low” 0 V. Im Beispiel schalten die Relais, wenn am jeweiligen Eingang der Spannungspegel “Low” anliegt (active low). Durch Umsetzen der Drahtbrücke (Jumperkontakte) auf dem Relaisboard kann die Logik des Relais geändert werden, sodass es dann beim Eingangspegel “High” schaltet (active high). Der Relaisausgang kann bei einer Wechselspannung bis 230 V bzw. einer Gleichspannung bis 30 V Ströme bis zu 10 A schalten. Die Relais haben einen Öffner- und einen Schließerausgang. Im Beipielprogramm werden beide Relais in einer Schleife nacheinander ein- und ausgeschaltet.
Beispielprogramm Relaisboard:
/*
* Test Relais
* Rainer Kock
* Version 28.09.2022
*/
#include <Wire.h>
const int outputPins[] = {6,7}; // digital output pin numbers
int i;
bool state;
void setup() {
// set digital outputs and set initial state high
for (i=0; i<2; i++) {
digitalWrite(outputPins[i], HIGH); // set internal pullup resistor to get initial state high
pinMode(outputPins[i], OUTPUT); // define pin as output
}
}
void loop() {
state = not(state); // toggle boolean state
digitalWrite(outputPins[0], state); // set first digital output
delay(1000); // wait 1 Second
digitalWrite(outputPins[1], state); // set second digital output
delay(1000); // wait 1 Second
}
Im Beispiel wird ein Drucksensor der Firma Baumer (Artikelnummer PP20H-2.3B26R.A114.412020.000) eingesetzt (Bild 9). Der Sensoranschluss “VIN” wird mit 10 bis 30 V Gleichspannung versorgt. Der Anschluss “IOUT” wird über den Präzisionsmesswiderstand mit “GND” 0 V vom Arduino Nano verbunden. Der Sensor skaliert den gemessenen Druck von 0 bis 25 bar linear zu 4 bis 20 mA Gleichstrom am Messausgang “IOUT”. Der Messbereich des verwendeten Sensors beträgt 0 bis 25 bar relativ zum umgebenden Luftdruck. Das Bild 10 zeigt den elektrischen Anschluss des Drucksensors. Der Arduino Microcontroller misst den Spannungsfall am Präzisionswiderstand und rechnet diesen auf den entsprechenden Druck um. Dabei gilt die Formel “Spannung = Widerstand × Strom” oder “U = R × I ” [5].
Das Bild 11 zeigt die Messung der Spannung am Analogeingang “A0” des Arduino Nano. Für die präzise Messung von elektrischen Spannungen benötigt der Arduino Nano eine Referenzspannung am Eingang “REF”. Diese wird durch die Reihenschaltung von einem Widerstand und der Spannungsreferenz “LM 336” realisiert. Der Vorwiderstand von 2,4 kOhm dient der Strombegrenzung. An der Spannungsreferenz fallen nominell 2,5 V Spannung ab. Die genaue Höhe der Referenzspannung unterliegt jedoch Bauteiltoleranzen und ist temperaturabhängig [6]. Eine höhere Genauigkeit und einen geringeren Temperaturkoeffizienten als der “LM 336” bietet die teurere Spannungsreferenz “LM 1009”, die alternativ verwendet werden kann.
Die zusätzlichen Bauteile wie Widerstände, Spannungsreferenz und Steckleisten sind auf einer Leiterplatte aufgelötet (Bild 12). Die Verwendung von Steckleisten bietet den Vorteil, dass der Arduino erst nach dem Löten aufgesteckt werden muss und somit während der Lötarbeiten nicht zu heiß werden kann. Die Verbindungen der Bauteile sind auf der Rückseite der Leiterplatte ausgeführt. Die Bauteile und Verbindungen sind im Gesamtschaltplan (Bild 13) dargestellt.
Die Verbindungen zwischen der gelöteten Leiterplatte und den übrigen Bauteilen werden mit Leitungen und Dupont Steckverbindern hergestellt (siehe Bild 1). Der Resetschalter setzt den Maximalwert des Drucks auf den aktuellen Druckwert zurück.
/*
* Guelle-Alarm
* Rainer Kock
* Version 08.08.2022
*/
#include <Wire.h> // Wire library for I2C bus
#include <LiquidCrystal_I2C.h> // LiquidCrystal I2C library for LCD
LiquidCrystal_I2C lcd(0x27,16,2); // LCD address 0x27, 16 chars, 2 lines
const unsigned long averagingTime = 5000UL; // averaging time pressure [ms]
const float pressureLimits[] = {3.0,7.0}; // pressure limit values [bar]
const float referenceVoltage = 2.5; // external voltage reference LM 336
const float resistor = 100.0; // measurement shunt [Ohm]
const int analogInPressure = A0; // analog input pin pressure
const int pressureLimitPins[] = {6,7}; // digital outputs pins pressure limit
const int resetPin = 2; // reset input pin maximum pressure
const float factorPressure = 25.0/16.0; // 0...25 bar = 4...20 mA factor
const float offsetPressure = 4.0; // 4 mA offset
int i; // counter
float maxPressure = -100.0, pressure; // (max) pressure value
unsigned long nSample = 0UL; // sample counter
unsigned long sumSensorPressure = 0UL; // sum pressue raw value
unsigned long timeLastRefresh = 0UL; // start time averaging
void setup() {
Serial.begin(9600); // set serial 9600 baud, 8 bits,
// no parity, 1 stop bit
analogReference(EXTERNAL); // activate External voltage reference
// initialize output pins pressure limit
for (i=0; i<2; i++) {
digitalWrite(pressureLimitPins[i], HIGH);
pinMode(pressureLimitPins[i], OUTPUT);
}
// initialize output pin reset max pressure
pinMode(resetPin , INPUT_PULLUP);
// LCD
lcd.init(); // initialize the LCD
lcd.backlight(); // turn on LCD backlight
timeLastRefresh = millis(); // start time averageing
}
void loop() {
sumSensorPressure += analogRead(analogInPressure); // sum raw integer input pressure value
nSample += 1; // count samples
// reset maximum pressure if reset button pressed
if (!digitalRead(resetPin)) {
maxPressure = pressure;
lcd.setCursor(0,1);
lcd.print("p_max= ");
lcd.print(maxPressure, 2);
lcd.print(" bar ");
}
// calculate and display pressure after averageing time
if(millis() - timeLastRefresh >= averagingTime) {
// start time next averageing
timeLastRefresh += averagingTime;
// Calculate pressure
pressure = (sumSensorPressure / nSample * referenceVoltage / 1023.0 /
resistor * 1000 - offsetPressure) * factorPressure;
maxPressure = max(pressure, maxPressure); // store max value
// set alert if pressure limit exceeded
for (i=0; i<2; i++) {
if (pressure > pressureLimits[i]) {
digitalWrite(pressureLimitPins[i], LOW);
}
else {
digitalWrite(pressureLimitPins[i], HIGH);
}
}
// output on LCD display
lcd.setCursor(0,0);
lcd.print("p = ");
lcd.print(pressure, 2);
lcd.print(" bar ");
lcd.setCursor(0,1);
lcd.print("p max= ");
lcd.print(maxPressure, 2);
lcd.print(" bar ");
// output serial
Serial.println(pressure);
// reset values for next averaging
sumSensorPressure = nSample = 0UL;
}
}
Im Folgenden werden einige Aspekte des Programms näher erläutert.
Zeile 31: Aktivierung der Verwendung der externen Spannungsreferenz am Eingang “A_ref”
Zeilen 48 bis 51: Digitalisieren und aufsummieren des Spannungswerts am analogen Eingang und zählen der Summierungen in einer Schleife. Pro Sekunde wird der analoge Spannungswert einige tausend mal eingelesen. Die Analog-Digitalwandlung geschieht im Arduino mit einer Auflösung von 10 bit. Die Wandlung hat daher 210 = 1024 Stufen und ergibt somit eine Ganzzahl zwischen 0 und 1023. Mit der Skalierung auf die Referenzspannung wird der Spannungswert berechnet.
Zeilen 63 bis 70: Jeweils nach der parametrierten Mittelungszeit ("averagingTime" = 5000 ms) wird der Druck berechnet und ausgegeben. Die Summe der eingelesenen Spannungswerte ("sumSensorPressure") wird durch die Anzahl der Lesevorgänge ("nSample") geteilt, um den Mittelwert zu berechnen. Die übrigen Faktoren ergeben sich aus der Referenzspannung ("referenceVoltage" = 2,5 V), der Auflösung des Analog-Digitalwandlers (Maximalwert = "210-1 = 1023.0"), dem Wert des Präsisionswiderstands ("resistor" = 100 Ohm), der Umrechnung von Ampere in Milliampere ("1000" mA/A), dem Skalierungsoffset des Drucksensors ("offsetPressure" = 4 mA) und dem Skalierungsfaktor des Drucksensors ("factorPressure" = (25 bar) / (16 mA)).
Berechnungsformel Druck im Quelltext:
pressure = (sumSensorPressure / nSample * referenceVoltage / 1023.0 / resistor * 1000 - offsetPressure) * factorPressure;
Beispielrechnung:
Zeile 98: Nullsetzen der Variablen für die nächste Mittelwertbildung
Zeilen 74 bis 81: Schalten der Relais bei Überschreitung der parametrierten Werte aus Zeile 17
Zeilen 54 bis 60: Ist der Resetknopf gedrückt wird der maximale Druck auf den aktuellen Druck gesetzt und anschließend auf dem Display ausgegeben
Zeile 40: Initialisierung des digitalen Eingangs und Aktivierung des internen Pullup Widerstandes. Der Pullup-Widerstand “zieht” die Spannung des digitalen Eingangs stabil auf den logischen Zustand “High”, solange der Resetknopf nicht gedrückt ist.
Zeilen 84 bis 92: Ausgabe des aktuellen und maximalen Messwerts auf dem Display
Zeile 95: Ausgabe des aktuellen Messwerts über die serielle Schnittstelle
Dipl. Ing. (FH) Rainer Kock, Technischer Mitarbeiter im Experimentierfeld Betriebsleitung und Stoffstrommanagement - Vernetzte Agrarwirtschaft in Schleswig-Holstein (BeSt-SH)