Arduino ve 2x16 LCD ile basit bir saat + sıcaklık/nem göstergesi

Arduino ve LCD ekran ile yapılabilecek hemen hemen en basit saat ve sıcaklık/nem gösterici devrenin breadboard çizimi yukarıda ve şeması aşağıda verilmiştir. LCD'nin ilk satırında saat, ikinci satırında ise değişimli olarak sıcaklık/nem ve tarih/haftanın günü gösteriliyor.

Saati ayarlamak için ayar butonuna basmak, daha sonra çıkan ekranlarda yıl/ay/gün/saat/dakika ayarlarını (+) ve (-) butonlarını kullanmak gerekiyor. Her bir ayardan sonra ayar butonuna basıldığında bir sonraki ayarlanacak parametre ekrana getiriliyor. Dakika ayarlandıktan sonra tekrar ayar butonuna basıldığında, saniye sıfırlanarak normal çalışma moduna geri dönülüyor.

Gerekli parçalar;

- Arduino (Uno, Nano veya diğerleri. Ben Uno kullandım)
- 2x16 LCD Tek renk Display (Gösterge)
- DS1302 RTC (Gerçek Zamanlı Saat) Modülü
- DHT 11 Sıcaklık ve Nem Sensörü
- Ayarlar için 3 adet buton
- Breadboard
- Saat modülünün yedek gücü olarak CR2032 pil
- Kablolar
- USB'den beslemek için 5V, güç konnektöründen beslemek için 7.5-9V arası DC güç kaynağı.

Şemaların üzerine tıklayarak büyütülmüş hallerini görebilirsiniz.

Son derece hızlı bir şekilde yazdığım kodu da yazının sonuna ekliyorum. Hızlı yazıldığından pek çok eksiği olabilir. O da programlama çalışması olarak sizlere kalsın. Ben de ikinci versiyonu yaparsam kendime ödev olarak bırakıyorum.

Benim aklıma gelen iyileştirmeler şunlar;

- LCD display sık sık güncellenmesi nedeniyle hafif titriyor. Sadece değişen rakamları yazarak titreşimi azaltmak denenebilir.

- Butonların gecikme süreleri ile oynanarak cevap süreleri iyileştirilebilir.

- Kontrastı genelde kullanılan bir değerde bıraktım. Ayar menüsüne kontrast ayarları için ekleme yapılabilir. Aynı şekilde arka aydınlatma LED'i için de ayar olabilir. Arka aydınlatma LED'i için programa yazdığım değer, LED'den yaklaşık 7 mA geçmesini sağlıyor ve son derece yeterli. Daha fazla arttırmanızı çok önermem.

- Tarih ve sıcaklık/nem göstergelerinin zamanlamaları değiştirilebilir.

- Ayar yapılırken tüm Şubat ayları 29 gün farzediliyor. Yani 29 Şubat 2021 gibi bir tarih girerseniz RTC sapıtabilir. Biraz da üşendiğimden o kısıma bir kontrol yazmadım. Diğer ayların gün sayıları doğru çalışıyor.

- Ayar moduna girip hiçbir ayar yapılmasa dahi tarih ve saat bilgisi RTC'ye yazılıyor. Yani ayar menüsüne girip, hiçbir şey yapmadan çıkınca bile saniyeyi sıfırlamış oluyorsunuz :)

- Elimde o anda DS1302 olduğu için onu kullandım ama RTC olarak DS3231 kullanmanızı tavsiye ederim. Çok daha hassas çalışan bir modül ve DS1302 3 giriş/çıkış kullanırken, DS3231'e 2 tanesi (SDA-SCL) yetiyor. Elbette bunun için kodda değişiklikler de gerekecek.

- Haftanın günlerini (Pazartesi, Salı vb.) RTC'ler bulamıyor. Bunun için küçük bir fonksiyon eklemek zorunda kaldım. DS3231 library'lerinde bunu otomatik hesaplıyorlar. DS1302 library'de yoktu.

- Bu LCD'lerde 8 adet özel (custom) karakter üretilebiliyor. Böylece Türkçe karakter eklemek de mümkün oluyor. Bunu da deneyebilirsiniz.

Kodu aşağıya kopyalıyorum. Kullanılan 3 adet library de biraz arama ile kolayca bulunabilir. Yine de bağlantılara tıklayarak da erişebilirsiniz.

* LiquidCrystal.h (Arduino IDE'de zaten var)
* DHT.h
* virtuabotixRTC.h


2x16 LCD Display ile Saat ve Sıcaklık/Nem Gösterici Programı:

/* 16 x 2 LCD gösterge ile basit bir saat
 * RTC olarak en basit modül olan DS1302 kullanılıyor
 * DHT-11 ile sıcaklık ve nem ölçümü
 * (c) Fırat Tarman Nisan 2020
 */

#include "LiquidCrystal.h"  // 2 x 16 karakter LCD
#include "DHT.h"            // DHT-11 Sensör
#include "virtuabotixRTC.h" // DS 1302 için library

// DS1302 İÇİN BAĞLANTILAR
// DS1302 RST/CE   --> A0
// DS1302 DAT/IO   --> A1
// DS1302 CLK/SCLK --> A2
// DS1302 VCC      --> 5v
// DS1302 GND      --> GND

virtuabotixRTC myRTC(A2,A1,A0); // CLK/SCLK, DAT/IO, RST

// LCD Ekran
const int RST = 2, EN = 3, d4 = 4, d5 = 5, d6 = 6, d7 = 7;
LiquidCrystal lcd(RST, EN, d4, d5, d6, d7);

const int KontrastPin=9;  // LCD Kontrast ayar pini
const int ArkaLEDPin=10;  // LCD Arkaplan aydınlatma LED'i için pin
int Kontrast = 100;       // Varsayılan değer
int ArkaLED=120;          // akımı sınırlıyoruz (yaklaşık 7 mA)
int CalismaModu=1;        // Normal Saat Ekranı
boolean AyarModundayiz=false;
int saat=1;               // Program içindeki saat ve tarih bilgileri
int dakika=11;
int saniye=0;
int yil=2020;
int ay=4;
int gun=15;
int HaftaninGunu=0;      // Pazar=0; Pazartesi=1 şeklinde
int ButonArti;           // (+) Butonu
int ButonEksi;           // (-) Butonu
int ButonAyar;           // Ayar Menüsü Butonu
const int PinArti=0;     // (+) Buton pini
const int PinEksi=1;     // (-) Buton pini
const int PinAyar=11;    // Ayar Menüsü Buton pini
const int Gecikme=50;    // Pek çok yerde kullanılan gecikme (delay) için katsayı
float sicaklikC=0.0;     // Santigrad olarak sıcaklık
float nem=0.0;           // % olarak havanın nemi
int EkranSayaci=20;      // İkinci satırda tarih ve sıcaklık/nem için sayaç.
                         // Her 20 döngüde bir iki alternatiften biri gösterilir.
#define DHTPIN 8         // Sıcaklık/Nem sensörü için pin numarası
#define DHTTYPE DHT11    // Sıcaklık/Nem sensörü türü
DHT dht(DHTPIN, DHTTYPE);

void setup()             // Bir kere çalışan başlangıç fonksiyonu
    {
    Serial.begin(9600);
    lcd.begin(16,2);
    dht.begin();
    pinMode(PinArti,INPUT_PULLUP);
    pinMode(PinEksi,INPUT_PULLUP);
    pinMode(PinAyar,INPUT_PULLUP);
    analogWrite(KontrastPin,Kontrast);    // Kontrast ayarı
    analogWrite(ArkaLEDPin,ArkaLED);      // Aydınlatmayı açıyoruz
    CalismaModu=1;                        // Saat modunda başlıyoruz
    }

void HaftaGunuHesapla () // Haftanın gününü RTC otomatik hesaplamıyorsa
                         // kullanılacak fonksiyon (DS1302 hesaplamıyor)
{
  int ekleme, a1, y1;
  if (yil<2000) yil+=2000;
  ekleme = (14 - ay) / 12;
  a1 = ay + 12 * ekleme - 2;
  y1 = yil - ekleme;
  HaftaninGunu=(gun + (13 * a1 - 1) / 5 +
    y1 + y1 / 4 - y1 / 100 + y1 / 400) % 7;
}

void saatiyazdir()                         // İlk satıra saat bilgisini yazdıran fonksiyon
{
    int gosterilensaat;
    int OOOS;                              // AM-PM yani Öğleden Önce (0), Öğleden Sonra (1) : ÖÖÖS :)
    myRTC.updateTime();                    // RTC güncelleme
    saat=myRTC.hours;                     
    if (saat>11) OOOS=1;                   // PM
    else OOOS=0;                           // AM
    dakika=myRTC.minutes;
    saniye=myRTC.seconds;
    yil=myRTC.year;
    ay=myRTC.month;
    gun=myRTC.dayofmonth;
    HaftaninGunu=myRTC.dayofweek;          // Pazar=0; Pazartesi=1 vd...
    if (saat>12) gosterilensaat=saat-12;   // AM/PM için 12'ye kadar sayıyoruz
    else
    gosterilensaat=saat;                   // 24 saatlik gösterim yerine 12'li karşılığı
    lcd.setCursor(0,0);                    // Satır başı
    lcd.print("                ");         // Tüm ekranı güncellemek yerine satırı silelim
    lcd.setCursor(0,0);                    // Tekrar satır başı
    lcd.print("   ");
    if((gosterilensaat<10)&&(OOOS==0))lcd.print("0"); // Sadece sabahları saatin başına 0 koyuyoruz  
    lcd.print(gosterilensaat);
    lcd.print(":");
    if(dakika<10)lcd.print("0");           // Dakika 10'dan küçükse başına 0 koymak lazım
    lcd.print(dakika);
    lcd.print(":");
    if(saniye<10)lcd.print("0");           // 10'dan küçük saniyenin başına da 0 koyuyoruz
    lcd.print(saniye);
    if(OOOS==0) lcd.print(" AM");          // Öğleden önce
    if(OOOS==1) lcd.print(" PM");          // Öğleden sonra
}

void sicaklikyazdir()                      // İkinci satıra sıcaklık ve nem bilgilerini yazan fonksiyon
    {
    static int olcumsayisi=20;             // Her 20 döngüden birinde ölçüm alalım, sıcaklık ve nem rakamları
                                           // fazla hareketli olmasın.
    if (olcumsayisi==20)                   // Başlarken ilk ölçümü alabilmek için ilk "if" çalışmalı
    {
    olcumsayisi=0;
    sicaklikC = (dht.readTemperature());   // Sensörü oku
    nem = dht.readHumidity();
    }
    olcumsayisi++;
    lcd.setCursor(0,1);
    lcd.print("                ");
    lcd.setCursor(0,1);
    lcd.print("  ");
    lcd.print(sicaklikC, 1);
    lcd.print("C  %");
    lcd.print(nem, 1);
    EkranSayaci--;
    }
   
void tarihyazdir()                         // İkinci satıra tarih ve haftanın günü bilgilerini yazan fonksiyon
    {
    char Gunler [7][6] = {"Pazar", "Pzrts", " Sali","Crsmb", "Prsmb", " Cuma", "Cmrts"}; // Pazar=0, Pazartesi=1, ...
    lcd.setCursor(0,1);
    lcd.print("                ");
    lcd.setCursor(0,1);
    lcd.print(gun);
    lcd.print("/");
    lcd.print(ay);
    lcd.print("/");
    lcd.print(yil);
    lcd.setCursor(11,1);
    lcd.print(Gunler[HaftaninGunu]);
    if (EkranSayaci==0) EkranSayaci=41;
    EkranSayaci--;
    }

void ayarlariyap()
// AYAR MODU FONKSİYONU

    switch (CalismaModu){

case 1:
    break;

case 2: // YIL
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("YILI Giriniz");
    lcd.setCursor(0,1);
    lcd.print(yil);
    ButonArti=digitalRead(PinArti);
    delay(Gecikme);
    ButonEksi=digitalRead(PinEksi);
    delay(Gecikme);
    if(ButonArti==0)yil++;
    if(ButonEksi==0)yil--;
    if (yil>=2100) yil=2000;
    if (yil<=1999) yil=2099;
    break;
   
case 3: // AY
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("AYI Giriniz");
    lcd.setCursor(0,1);
    lcd.print(ay);
    ButonArti=digitalRead(PinArti);
    delay(Gecikme);
    ButonEksi=digitalRead(PinEksi);
    delay(Gecikme);
    if(ButonArti==0)ay++;
    if(ButonEksi==0)ay--;
    if (ay>=13) ay=1;
    if (ay<=0) ay=12;
    break;

case 4: // GÜN
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Gunu giriniz");
    lcd.setCursor(0,1);
    lcd.print(gun);
    ButonArti=digitalRead(PinArti);
    delay(Gecikme);
    ButonEksi=digitalRead(PinEksi);
    delay(Gecikme);
    if(ButonArti==0)gun++;
    if(ButonEksi==0)gun--;
    if ((ay==2))
    {
    if (gun==30) gun=1;
    if (gun==0) gun=29;
    }
    if ((ay==1)|(ay==3)|(ay==5)|(ay==7)|(ay==8)|(ay==10)|(ay==12))
    {
    if (gun==32) gun=1;
    if (gun==0) gun=31;
    }
    if ((ay==4)|(ay==6)|(ay==9)|(ay==11))
    {
    if (gun==31) gun=1;
    if (gun==0) gun=30;
    }
    break;

case 5: // SAAT
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Saati giriniz");
    lcd.setCursor(0,1);
    lcd.print(saat);
    ButonArti=digitalRead(PinArti);
    delay(Gecikme);
    ButonEksi=digitalRead(PinEksi);
    delay(Gecikme);
    if(ButonArti==0)saat++;
    if(ButonEksi==0)saat--;
    if (saat==24) saat=0;
    if (saat<0) saat=23;
    break;

case 6: // DAKİKA
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Dakika giriniz");
    lcd.setCursor(0,1);
    lcd.print(dakika);
    ButonArti=digitalRead(PinArti);
    delay(Gecikme);
    ButonEksi=digitalRead(PinEksi);
    delay(Gecikme);
    if(ButonArti==0)dakika++;
    if(ButonEksi==0)dakika--;
    if (dakika==60) dakika=0;
    if (dakika==-1) dakika=59;
    break;

case 7: // ÇIKIŞ
    saniye=0;
    HaftaGunuHesapla ();
    myRTC.setDS1302Time(saniye,dakika,saat,HaftaninGunu,gun,ay,yil);
    lcd.clear();
    lcd.print("Kaydediliyor");
    CalismaModu++;
    for (int i=1;i<5;i++)
    {lcd.print("*");  
    delay(Gecikme*5);}
    break;
} // END OF SWITCH 
} // AYAR MODU FONKSİYONU SONU 

// ANA PROGRAM DÖNGÜSÜ
void loop()
    {  
    if (CalismaModu==1)
    {saatiyazdir();
    if (EkranSayaci>21) sicaklikyazdir();
    else
    tarihyazdir();}

    if(CalismaModu==8)
    {CalismaModu=1;
    AyarModundayiz=false;}
   
    delay(Gecikme*4);
   
    ButonAyar=digitalRead(PinAyar);
    if (ButonAyar==0)
    {CalismaModu++;
    AyarModundayiz=true;}

    if (AyarModundayiz) ayarlariyap();
    else delay (Gecikme*4);
   
    }
// ANA PROGRAM DÖNGÜSÜ SONU
Arduino ve 2x16 LCD ile basit bir saat + sıcaklık/nem göstergesi Arduino ve 2x16 LCD ile basit bir saat + sıcaklık/nem göstergesi Reviewed by Fırat Tarman on 6:43 PM Rating: 5

4 comments:

  1. Lcd de ışık yanıyor fakat hiçbirşey yazmıyor

    ReplyDelete
  2. Bir süre sonra değişik çizgiler harfler falan çıkıor neden olabilir

    ReplyDelete
    Replies
    1. Açıkçası bir fikrim yok, hiç başıma gelmedi öyle bir şey. Mümkünse başka bir LCD ile deneyin.

      Delete

Fırat Tarman Devreler. Powered by Blogger.