Arduino Info Display

Im Arduino Smart Home Projekt habe ich mit dem Arduino Info Display angefangen. Es besteht aus mehreren Komponenten die ich in einem Aufputzgehäuse verbaut habe. Das Arduino Info Display kommt später in der Werkstatt an die Wand. Ohne Master Arduino (die zentrale Steuereinheit) zeigt das Arduino Info Display erstmal nur die Temperatur und Uhrzeit. Noch ziemlich unspektakulär aber das ist ja auch erst der Anfang!

Arduino Info Display - Gehäuse

Beschreibung

Das Arduino Info Display kommuniziert später mit dem noch in Umsetzung befindlichen Arduino Master Modul über das RS485 Protokoll. Die Informationen werden über ein 2x2x0,8 J-Y(St)Y Kabel übertragen, welches auch für die Stromversorgung verwendet wird. Auf dem 20×4 Zeichen Display werden dann neben der Temperatur und der Uhrzeit noch weitere Informationen und Warnungen angezeigt. Über einen Rotary Encoder (Drehimpulsgeber) können später bestimmte Meldungen auch quittiert bzw. beantwortet und Befehle ausgeführt werden können. Aufgrund der Komplexität folgt demnächst noch ein extra Beitrag zum Rotary Encoder.

Komponenten

Im nachfolgendem Bild seht ihr alle aktuell verbauten Komponenten.
Arduino Info Display - Bauteile

Gehäuse

Ich habe alle Komponenten in ein 115 x 90 x 55 mm großes Gehäuse verbaut. Dafür habe ich entsprechende Öffnungen für Kabelverschraubung (noch nicht montiert), Buzzer (das kleine Loch unten links auf dem Bild), DHT22 Sensor und LCD in das Gehäuse gebohrt und gefräst. Da ich die zu große Platine vom Display nicht bearbeiten wollte, habe ich noch etwas von der Dichtung im Deckel weggefräst.

Arduino Nano

Anfangs hatte ich einen Arduino Micro Pro geplant, dieser hat aber den Nachteil, dass die für den Rotary Encoder eventuell benötigten Interrupt Pins durch I2C und RX/TX belegt wären. Da ich keine Lust auf noch mehr Experimente hatte, fiel die Wahl dann schließlich auf einen Arduino Nano.

RS485 Modul

Das RS485 Modul wird zur Kommunikation mit dem Arduino Master benötigt. Es könnte natürlich auch eine andere Übertragungmethode gewählt werden. Platz ist ja noch genug im Gehäuse. Vielleicht gibt es ja auch bald eine kleine Version mit ESP8266 WLAN-SoC Modul und TFT Display ;-).

I2C 20×4 LCD Modul

Das 20×4 Zeichen LCD Modul habe ich jetzt schon mehrfach verwendet. Ich habe es einfach mit Heißkleber am Deckel festgeklebt. Zusätzlich wird es aber noch durch dich die Klemmung zwischen Deckel und Gehäuse fixiert.

DS3231 Echtzeituhr

Der Arduino besitzt wie der Raspberry Pi keine Echtzeituhr und benötigt daher für eine genaue Uhrzeit eine entsprechendes Quelle. Das RTC Modul habe ich mit Heißkleber an das LCD Modul geklebt da beide per I2C kommunizieren und somit alle Kabel zusammengeführt werden können.

Achtung! Bei günstigen China Modellen ist in den Echtzeituhren nur eine CR2032 Batterie verbaut! Da diese normalerweise über das Modul geladen wird, sollte man hier etwas mehr investieren und entweder ein Modul mit LIR2032 Akku kaufen oder gleich einen mitbestellen!

DHT22 Temperatur- und Feuchtigkeitsmesser

Als kleines Gimmick habe ich noch einen Temperatur- und Feuchtigkeitsmesser verbaut. Vielleicht kann man diese Informationen ja noch mal irgendwo gebrauchen.

Aktiver Buzzer

Neben der visuellen Meldung über Display und LED (Rotary Encoder mit RGB LED) kann sich das Arduino Info Display mit dem kleinen aktiven Buzzer auch akustisch bemerkbar machen.

Verkabelung

Nach langem überlegen und zwei Fehlstarts, habe ich mich für eine relativ einfache Verkabelung entschieden. An die Stiftleiste der einzelnen Komponenten habe ich Kabel angelötet und diese mit Schrumpfschlauch zusätzlich fixiert. Dann habe ich die Kabel direkt auf die Pins vom Arduino Nano gelötet. So kann ich zwar Teile nur mit recht hohem Aufwand austauschen aber es ist platzsparend und ohne anfällige Steckverbindungen.

In der nachfolgenden Tabelle seht ihr die verwendeten Pins auf dem Arduino Nano. Die Pins mit einem Sternchen (*) sind für den Rotary Encoder und in dem Sketch noch nicht in Verwendung. Pins mit speziellen Funktionen wie Interrupt, PWM und I2C habe ich in Klammern dazu geschrieben.

Nano / Uno Device
* D2 (INT) Rotary Encoder – Pin A
* D3 (INT) Rotary Encoder – Pin B
D5 DHT22
D6 RS485 – Serial RX
D7 RS485 – Serial TX
D8 RS485 – Serial Control
* D9 (PWM) Rotary Encoder – LED rot
* D10 (PWM) Rotary Encoder – LED grün
* D11 (PWM) Rotary Encoder – LED blau
D12 Buzzer
* D13 Rotary Encoder – Taster
A4 (SDA) 20×4 LCD / DS3231
A5 (SCL) 20×4 LCD / DS3231

Display

Oben werden die aktuelle Uhrzeit, Temperatur und mit Symbolen zum Beispiel “Kompressor aktiv” oder “Klingel betätigt” dargestellt. In der zweiten Zeile werde ich versuchen Informationen über den aktuellen Stream anzuzeigen. Da mir der Aufwand das Bluetooth AutoPlay Script entsprechend anzupassen sehr groß erscheint, schiebe ich das noch etwas 🙂 Die dritte Zeile soll für die Anzeige von Informationen, Warnungen und sonstigen Meldungen genutzt werden. In der untersten Zeile wird ein Menü eingeblendet um Befehle oder Antworten zu senden.

Sketch

Es sind alle Komponenten mit einfachen Funktionen im Sketch verbaut. Fertig ist er natürlich noch nicht! Mit dem Rotary Encoder kommt dann der nächste Abschnitt.

/******************************* Libraries *******************************/
#include <Wire.h> // I2C Bus
#include <SoftwareSerial.h> // Software Serial Serial Library (RS485)

#include <LiquidCrystal_I2C.h> // I2C LCD
//=> http://www.dfrobot.com/image/data/DFR0154/LiquidCrystal_I2Cv1-1.rar

#include <DHT.h> // DHT Sensor Library written by Adafruit Industries
// => https://learn.adafruit.com/dht

#include <RTClib.h>  // RTC Library written by Adafruit Industries
//=> https://learn.adafruit.com/ds1307-real-time-clock-breakout-board-kit

/******************************* Pins / Variables *******************************/

  /****************** Buzzer ******************/
#define buzzerPin 12


  /****************** RTC ******************/
RTC_DS1307 RTC;
DateTime now;

  /****************** DHT ******************/
#define DHTPin 5
#define DHTType DHT22
DHT dht(DHTPin, DHTType);

float temp;
float hum;

  /****************** LCD ******************/
LiquidCrystal_I2C lcd(0x27, 20, 4);

char lcdtext[] = "Arduino Info Display - www.nikolaus-lueneburg.de";

int lcd_start = 0; // start position for text
byte DisplayActive = 1; // Backlight on/off & Screen info refresh
const int LCD_COLS = 20; // cols per line

  /****************** RS485 ******************/
#define SSerialRX        6  // Serial Receive Pin
#define SSerialTX        7  // Serial Transmit Pin
#define SSerialTxControl 8   // RS485 Direction Control Pin

#define RS485Transmit    HIGH
#define RS485Receive     LOW

SoftwareSerial RS485Serial(SSerialRX, SSerialTX);

char byteRead; // Variable
char string[32];
char *command;
char *text;


  /****************** Refresh rate ******************/
unsigned long TimerClock = 0; 
const long TimerClockInterval = 10000; // interval milliseconds

unsigned long TimerDHT = 0; 
const long TimerDHTInterval = 20000; // interval milliseconds

/******************************* Begin setup *******************************/

void setup()
{
  // Serial.begin(9600); // only for debug

  /****************** RS485 ******************/
  pinMode(SSerialTxControl, OUTPUT);
  digitalWrite(SSerialTxControl, RS485Receive);
  RS485Serial.begin(9600);   // Set RS485 baud rate

  /****************** Buzzer ******************/
  pinMode(buzzerPin, OUTPUT);
  digitalWrite(buzzerPin, HIGH);
  buzzerdouble();
  
  /****************** LCD ******************/
  lcd.init();                      // initialize the lcd
  delay (200);
  lcd.backlight();
  clearScreen();
  
  clock();  // Display Clock
  DHTSensor();  // Display Temperature
  
  /****************** DHT ******************/
  dht.begin();

  /****************** RTC ******************/
  Wire.begin();
  RTC.begin();

   // This section grabs the current datetime and compares it to
   // the compilation time.  If necessary, the RTC is updated.
   DateTime now = RTC.now();
   DateTime compiled = DateTime(__DATE__, __TIME__);
   if (now.unixtime() < compiled.unixtime())
   {
     Serial.println("RTC is older than compile time! Updating");
     RTC.adjust(DateTime(__DATE__, __TIME__));
  }

  // This line sets the RTC with an explicit date & time, for example to set
  // January 21, 2014 at 3am you would call:
  // RTC.adjust(DateTime(2014, 1, 21, 3, 0, 0));

}

/******************************* Begin loop *******************************/
void loop()
{
  /****************** Read RS485 ******************/
  int availableBytes = RS485Serial.available();
  for (int i = 0; i < availableBytes; i++)
  {
    string[i] = RS485Serial.read();
  }
  //  Serial.println(string);

  char delimiter[] = ";";

  char *c1 = strtok(string, delimiter);
  char *c2 = strtok(NULL, delimiter);
  command = c1;
  text = c2;

  // Clear Array string
  memset(string, 0, sizeof(string)); // Clear Array

  /****************** Commands ******************/

  if (strncmp(command, "1011", 4)  == 0)
  {
    Acknowledge();
    
    text == "ON" ? DisplayActive = 1 : DisplayActive = 0;
  }

  if (strncmp(command, "1211", 4)  == 0)
  {
    Acknowledge();
    
    Serial.println("Incoming Songtitle");
    Serial.println(text);
  }

  if (strncmp(command, "1311", 4)  == 0)
  {
    Acknowledge();
    
    Serial.println("Arduino - Eingang 1 - Licht - An");
  }

  /****************** Show scrolling text ******************/
  DisplayText();

  /****************** DHT Timer ******************/
  unsigned long currentMillisDHT = millis();
  if (currentMillisDHT - TimerDHT >= TimerDHTInterval)
  {
    TimerDHT = currentMillisDHT; 
    
    DHTSensor(); // Refresh DHT Sensor
  }

  /****************** Clock Timer ******************/
  unsigned long currentMillisClock = millis();
  if (currentMillisClock - TimerClock >= TimerClockInterval)
  {
    TimerClock = currentMillisClock; 
    
    clock(); // Refresh Clock
  }
}

/******************************* Begin functions *******************************/

/****************** Function Clock ******************/
void clock()
{
  now = RTC.now();

  if (DisplayActive == 1)
  {
    DisplayClock(); // Display Temperature on LCD  
  }
}

/****************** Function DHT Sensor ******************/
void DHTSensor()
{

  hum = dht.readHumidity();
  // Read temperature as Celsius (the default)
  temp = dht.readTemperature();

  float hic = dht.computeHeatIndex(temp, hum, false);
  
  if (DisplayActive == 1)
  {
    DisplayDHT(); // Display Temperature on LCD  
  }
  
/*
  // Luftfechte
  Serial.print("Humidity: ");
  Serial.print(hum);
*/

/*
  // Error Handling
  if (isnan(hum) || isnan(temp)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }
*/
}

/****************** Functions LCD ******************/
void DisplayText()
{
  int TEXT_LEN = (sizeof(lcdtext) / sizeof(char)) - 1;
  int LCD_LIMIT = TEXT_LEN - LCD_COLS;
  
  if (TEXT_LEN <= 20)
  {
    lcd.setCursor(0, 1);
    lcd.print(lcdtext);
  }
  else
  {
    if (lcd_start > LCD_LIMIT)
    {
      delay(1500);
      for(int i = 0; i < LCD_COLS; i++)
      {
        lcd.setCursor(i, 1);
        lcd.print(lcdtext[i]);
      }
      delay(1500);
      lcd_start = 0;
    }
    
    if (lcd_start <= LCD_LIMIT)
    {
      for(int i = 0; i < LCD_COLS; i++)
      {
        lcd.setCursor(i, 1);
        lcd.print(lcdtext[lcd_start + i]);
      }
      lcd_start++;
      delay(350);
    }
  }
}

void DisplayDHT()
{
  lcd.setCursor(0, 0);
  lcd.print(temp,1);

  lcd.write(223);  //  223 = ° Zeichen
  lcd.print("C");
}

void DisplayClock()
{
  lcd.setCursor(15, 0);
  if (now.hour() <= 9) lcd.print("0");
  lcd.print(now.hour(), DEC);
  lcd.print(':');
  if (now.minute() <= 9) lcd.print("0");
  lcd.print(now.minute(), DEC);
}
/****************** LCD ******************/

void clearScreen()
{
  lcd.setCursor(0,0);
  lcd.print("                    ");
  lcd.setCursor(0,1);
  lcd.print("Arduino Info Display");
  lcd.setCursor(0,2);
  lcd.print(" www.nikolaus-      ");
  lcd.setCursor(0,3);
  lcd.print("       lueneburg.de ");
}

/****************** RS485 *****************/

void Acknowledge()
{
    digitalWrite(SSerialTxControl, RS485Transmit);
    RS485Serial.write("1000");
    delay(10);
    digitalWrite(SSerialTxControl, RS485Receive);
}
/****************** Functions Buzzer ******************/

void buzzershort()
{
  digitalWrite(buzzerPin, LOW);
  delay(150);
  digitalWrite(buzzerPin, HIGH);
}


void buzzerdouble()
{
  digitalWrite(buzzerPin, LOW);
  delay(150);
  digitalWrite(buzzerPin, HIGH);
  delay(30);
  digitalWrite(buzzerPin, LOW);
  delay(150);
  digitalWrite(buzzerPin, HIGH);
}

void buzzerlong()
{
  digitalWrite(buzzerPin, HIGH);
  delay(500);
  digitalWrite(buzzerPin, LOW);
}

 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert