torstai 28. huhtikuuta 2016

LCD-kello, UT, talviaika ja kesäaika

Arduino mikrokontrollereihin on tarjolla runsas valikoima erilaisia oheislaitteita ja onneksi myös ohjelmia. Tarjolla on myös laaja valikoima kirjasto-ohjelmia, joita voidaan sujuvasti liittää omiin ohjelmiin. Kaikkea ei tarvise tehdä itse. Tämä jakso käsittelee kaksirivistä, 16 merkin LCD-näyttöä, minkä piirilevyyn on sisälletty myös kuusi (6) ohjauspainiketta. LCD-näytön käyttöön tulee Arduino-ohjelmiston mukana kirjasto-ohjelma LiquidCrystal.h, mikä liitetään ohjelman alkuun (#include <LiquidCrystal.h>). Lisäksi määritellään näytön käyttämät pinnit, mitkä vaihtelevat LCD-tyypin mukaan. Nyt käyttämäni näyttö sopii suoraan työnnettäväksi UNO:n pinneihin. Painikkeet on kytketty analogiatuloihin, ja niistä saadaan kustakin oma kokonaislukunsa, mikä määrää sen, mitä on painettu.
Tässä sovelluksessa painikkeella SELECT valitaan UT (yleisaika Universal Time), talviaika ja kesäaika. Nämä kiertävät tässä järjestyksessä jokaisella painamisella. Teksti on näytön ylärivillä. Seuraava painike on LEFT. Sen painamisesta alemman rivin vasempaan laitaan ilmestyy t-kirjain. Se merkitsee sitä, että painikkeilla UP kasvaa tuntilukema yhdellä (1) ja painikkeella DOWN vähenee yhdellä (Huom! EI kierrä nollan kautta edelliseen vuorokauteen). Vastaavasti painamalla RIGHT, ylös- ja alas-painikkeet vaikuttavat minuuttilukemaan. Vasempaan laitaan merkiksi tulee m-kirjain. Uudelleen painaminen (LEFT ja RIGHT) vapauttavat toiminnon. Samoin jos tuntimuuton on aktiivinen, minuutin painaminen vapauttaa tunnit. Ja päinvastoin. Kun kumpikaan ei ole aktiivinen, vaikuttavat ylös- ja alas-painikkeet sekuntilukemaan. Vaikka mikrokontrolleri on kideohjattu, on niiden aikatarkkuudessa yksilöllisiä eroja, joten oikeaa käyntinopeutta joutuu hiukan hakemaan. Hyvä apu siihen on teksti TV, missä on myös sekuntilukemat. Arvoa CoL_EroSekunti  joutuu hiukan hakemaan. Kun löytää mahdollisimman tarkan käyntinopeuden, voi helposti sekunteja korjata tarpeen mukaan. Jos on halua, voi sen tehdä tietysti automaattiseksikin.

Toinen pääteema tässä jaksossa on tehosyöttö. Tähän asti Arduino on saanut tehonsa (5V DC) USB-liitynnän kautta. Kello pitää kuitenkin saada irti tietokoneesta. Analogiatulojen vieressä sijaitsevat pinnit VIN, GND, GND, 5V, 3,3V ja RESET. Arduinolle voi ulkopuolelta syöttää käyttöjännitettä 7 .. 12VDC. Joko tuon VIN-pinnin (+) kautta, tai sitä varten olevan pistokeliittimen kautta (keskipiikki on +). Jännitteen napaisuuden on oltava oikea, muutoin ardu voi tuhoutua. Tarkkana pitää olla myös tulo- / lähtö-pinnien kanssa. Ne eivät kestä juurikaan ylijännitettä (EI yli 5V). Nuo 5VDC ja 3,3VDC muodostetaan piirilevyllä ja on tarkoitettu ulkopuolisten laitteiden syöttöjännitteeksi. Tällöinkin on huolehdittava siitä, ettei kokonaiskulutus ylitä 400mA

Arduinoa voi syöttää esim. 9V nappiparistolla. Sen kapasiteetti on kuitenkin melko pieni, joten se tyhjenee varsin pian. Parempi on 6kpl AA-paria, joista muodostuu myös 9V. Nämä kestävät jo pidempään. Yksi hyvä vaihtoehto on pieni akku, mutta sen jännite ylittä ladattaessa 12V, joten väliin pitää sijoitta stabilisaattoripiiri (esim LM7809 tai LM7808 tai vastaava). Siitä hiukan myöhemmin.


Ohjelma 18
/*****************************************
 * Ohjelma 18
 * 27.04.2016
 * LCD-näyttö kellonajoille:
 * Uneversal Time, talviaika ja kesäaika
 *****************************************/

#include <LiquidCrystal.h>
// Näytön pinnit
LiquidCrystal lcd(8, 9, 4, 5,6,7);

int lcd_key = 0;
int adc_key_in = 0;
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5
 
// MÄÄRITTELYT:
// Kellon määrittley
unsigned long Ulo_MilliSek = 0;
unsigned long Ulo_UusiMilliSek = 0;
const long CoL_EroSekunti = 985;
int Int_Sekunti = 0;
int Int_Minuutti = 0;
int Int_Tunti = 0;
boolean Bol_Tulosta = false;

int Seq_YlaRivi = 1;
int Seq_TuntiAsetus = 1;
boolean Kep_TuntiAs = false;
int Seq_MinAsetus = 1;
boolean Kep_MinAs = false;
int Seq_AjanEtAsetus = 1;
int Seq_AjanTaAsetus = 1;

// ASETUKSET:
void setup(){                
 Serial.begin(9600);         
 lcd.begin(16,2);
}// Asetuksen loppu

// PÄÄLOOPPI                 
void loop(){
// Sisäisen kellon käyttö
Ulo_MilliSek = millis();
  if(Ulo_MilliSek - Ulo_UusiMilliSek > CoL_EroSekunti){
    Ulo_UusiMilliSek = Ulo_MilliSek;
    Int_Sekunti++;
     if(Int_Sekunti > 59){
      Int_Minuutti++;Int_Sekunti = 0;
      lcd.setCursor(2, 1);
      lcd.print("              ");}
     if(Int_Minuutti > 59){
      Int_Tunti++;Int_Minuutti = 0;
      lcd.setCursor(2, 1);
      lcd.prin("              "); }
     if(Int_Tunti > 23){Int_Tunti = 0;       
      lcd.setCursor(2, 1);
      lcd.prin("              "); }    
    if(Bol_Tulosta == true){Fun_Tulostus();}
  }

lcd_key = read_LCD_buttons(); // Näytön painikkeet

// Näytön valintasekvenssi
switch (Seq_YlaRivi) {
  case 1:
    lcd.setCursorr(0, 0);
    lcd.prin("                ");
    lcd.setCursor(1, 0);
    lcd.prin("UNIVERSAL TIME");
    delay(20);
    if(lcd_key == 4){Seq_YlaRivi = 2;
    Int_Tunti = Int_Tunti +2;}
    break;
  case 2:
    if(lcd_key == 5){Seq_YlaRivi = 3;}
    break;
  case 3:
    lcd.setCursor(0, 0);
    lcd.prin("                ");
    lcd.setCursor(3, 0);
    lcd.prin("TALVIAIKA");
    delay(20);
    if(lcd_key == 4){Seq_YlaRivi = 4;
    Int_Tunti = Int_Tunti +1;}
    break;
  case 4:
    if(lcd_key == 5){Seq_YlaRivi = 5;}
    break;
  case 5:
    lcd.setCursor(0, 0);
    lcd.prin("                ");
    lcd.setCursor(3, 0);
    lcd.prin("KESA-AIKA");
    delay(20);
    if(lcd_key == 4){Seq_YlaRivi = 6;
    Int_Tunti = Int_Tunti -3;}
    break;
  case 6:
    if(lcd_key == 5){Seq_YlaRivi = 1;}
    break;
  }// Näytön valintojen loppu

lcd.setCursor(4, 1);
 if(Int_Tunti < 10){ 
  lcd.prin("0");
  lcd.prin(Int_Tunti);
 }else{lcd.prin(Int_Tunti);}
  lcd.prin(":");
 if(Int_Minuutti < 10){ 
  lcd.prin("0");
  lcd.prin(Int_Minuutti);
 }else{lcd.print(Int_Minuutti);}
lcd.prin(":");
 if(Int_Sekunti < 10){ 
  lcd.prin("0");
  lcd.prin(Int_Sekunti);
 }else{lcd.prin(Int_Sekunti);}

// Tunnin asetus
switch (Seq_TuntiAsetus) {
  case 1:
    if(lcd_key == 3){
      Kep_TuntiAs = true;
      lcd.setCursor(0, 1);
      lcd.prin("t");
      Seq_MinAsetus = 1; Kep_MinAs = false;
      Seq_TuntiAsetus = 2;}
    break;
  case 2:
    if(lcd_key == 5){Seq_TuntiAsetus = 3;}
    break;
  case 3:
    if(lcd_key == 3){
      Kep_TuntiAs = false;
      lcd.setCursor(0, 1);
      lcd.prin(" ");     
      Seq_TuntiAsetus = 4;}
    break;
  case 4:
    if(lcd_key == 5){Seq_TuntiAsetus = 1;}
    break;
} // Tuntiasetus loppu

// Minuutin asetus
switch (Seq_MinAsetus) {
  case 1:
    if(lcd_key == 0){
      Kep_MinAs = true;
      lcd.setCursor(0, 1);
      lcd.prin("m");
      Seq_TuntiAsetus = 1; Kep_TuntiAs = false;
      Seq_MinAsetus = 2;}
    break;
  case 2:
    if(lcd_key == 5){Seq_MinAsetus = 3;}
    break;
  case 3:
    if(lcd_key == 0){
      Kep_MinAs = false;
      lcd.setCursor(0, 1);
      lcd.prin(" ");     
      Seq_MinAsetus = 4;}
    break;
  case 4:
    if(lcd_key == 5){Seq_MinAsetus = 1;}
    break;
} // Minuuttiasetus loppu

// Ajan asetus eteenpäin
switch (Seq_AjanEtAsetus) {
  case 1:
    if(lcd_key == 1){
      if(Kep_TuntiAs == true){Int_Tunti++;}
      if(Kep_MinAs == true){Int_Minuutti++;} 
      if(Kep_TuntiAs == false && Kep_MinAs == false){
       Int_Sekunti++;  
      }
      Seq_AjanEtAsetus = 2;}
    break;
  case 2:
    if(lcd_key == 5){Seq_AjanEtAsetus = 1;}
    break;
} // Ajan eteenpäin asetuksen loppu

// Ajan asetus taaksepäin
switch (Seq_AjanTaAsetus) {
  case 1:
    if(lcd_key == 2){
      if(Kep_TuntiAs == true){Int_Tunti--;}
      if(Kep_MinAs == true){Int_Minuutti--;} 
      if(Kep_TuntiAs == false && Kep_MinAs == false ){
       Int_Sekunti--;  
      }
      Seq_AjanTaAsetus = 2;}
    break;
  case 2:
    if(lcd_key == 5){Seq_AjanTaAsetus = 1;}
    break;
} // Ajan taaksepäin asetuksen loppu

Int_Sekunti = constrain(Int_Sekunti, 0, 59);
Int_Minuutti = constrain(Int_Minuutti, 0, 59);
Int_Tunti = constrain(Int_Tunti, 0, 59);

delay(1);
} // Pääohjelma LOPPU

// FUNKTIOT
void Fun_Tulostus(){
//Serial.print("Teksti :");  Serial.println(Muuttuja);
}
// Funktio Lue painikkeet:
int read_LCD_buttons(){
  adc_key_in = analogRead(0);
  if(adc_key_in > 1000)   return btnNONE;
  if(adc_key_in < 50)    return btnRIGHT;
  if(adc_key_in < 195)   return btnUP;
  if(adc_key_in < 380)   return btnDOWN;
  if(adc_key_in < 555)   return btnLEFT;
  if(adc_key_in < 790)   return btnSELECT;
  return btnNONE;

}
Muutama sana ohjelmasta. Alun määrittelyjä määrää aika paljon kirjasto-ohjelma. Muutenkin monia toimintoja on kopioitu netistä löytyvistä esimerkeistä. Ylärivin kirjoitusosiossa olevat 20ms viiveet (delay82) rauhoittavat näyttöä. Painikkeiden luvun aliohjelma ei ole nyt void,vaan tyyppiä int, koska se palauttaa (return) painiketta vastaavan kokonaisluvun. Muutoin ohjelma on varsin tyypillistä sekvensseillä toteutettuja suoritusnauhoja.

Ei kommentteja:

Lähetä kommentti