arik.fi / Projektit / Elektroniikka

Digitaalikello

Kirjoitettu 2.1.2017

Ominaisuudet

Mikrokontrolleriohjattu 6-numeroinen digitaalikello, joka näyttää haluttaessa myös päivämäärän. Kellon toiminta on varmistettu patterilla, jonka pitäisi pyörittää kelloa ilman sähköä useita vuosia. Kellon näytön kirkkaus säätyy automaattisesti ympäröivän valon mukaan. Takapaneelista löytyy neljä nappia, joilla voidaan säätää kellonaika ja päivämäärä, sekä vaihtaa kellonaikanäytön ja päivämääränäytön välillä. Nappien vieressä on USB Type B -liitin, jonka kautta kellolle syötetään 5 volttia tavallisesta USB-virtalähteestä tai tietokoneesta.

Kotelo on tehty 9mm vanerista ja sillä on kokoa L145mm x K70mm x S140mm. Kaikki puukappaleet on liimattu yhteen, ainoastaan takaseinä tulee kiinni kahdella ruuvilla. Kotelo on pohjamaalattu ja maalattu mattamustalla spraylla. Etupaneeliin on kiinnitetty kaksipuoleisella teipillä tummennettu 3mm pleksi.

En ota mitään vastuuta laitteen toimivuudesta, turvallisuudesta, tai mahdollisista virheistä. Jokainen seuraa näitä ohjeita täysin omalla vastuullaan.

Kellon toiminta

Koodia muuttamalla takaseinän nappien toiminnot voi määritellä haluamikseen, mutta oletuksena toiminnot ovat seuraavat: 4-napilla voidaan vaihtaa tilaa kellon ja päivämäärän välillä. Napit 2 ja 3 eivät tee mitään, mutta 1-napilla pääsee kellon/päivämäärän säätötilaan. Säätötilassa 2-nappi muuttaa tunteja/päivää, 3-nappi minuutteja/kuukautta ja 4-nappi sekunteja/vuotta. 1-nappi tallentaa mahdolliset muutokset ja palaa normaalinäyttöön. Jos säätötilassa on tehnyt muutoksia mutta haluaa poistua tallentamatta muutoksia, painetaan 2- ja 3-nappia yhtäaikaa.

Kellotilassa kaksoispisteet vilkkuu noin puolen sekunnin välein päälle/pois, ja samaan aikaan luetaan kellonaika DS1307:sta. ATmegaa ei kuitenkaan saa tekemään vilkutusta täsmälleen puolen sekunnin välein, joten välillä käy niin että hypätään 2 sekuntia eteenpäin 1 sijaan, tai sitten sama sekuntimäärä näytetään tupla-ajan. Lisäsin koodiin paljon kommentteja, lisäinfoa sieltä.

Luettelo sähköisistä osista

ATmega328P -mikrokontrolleri
DS1307 -reaaliaikakello
MAX7219 -näytönohjauspiiri
Sininen 7-segment (CC) -näyttö (6kpl)
Sininen LED (4kpl)
16MHz kide
32,768kHz kide
0,1µF keraaminen kondensaattori (2kpl)
15pF keraaminen kondensaattori (2kpl)
22pF keraaminen kondensaattori (2kpl)
47kΩ vastus
10kΩ vastus (7kpl)
6,8kΩ vastus
510Ω vastus
LDR -vastus
CR2032 -paristo ja sille pidike
Kytkin (4kpl)
Piikkirimaa
Piirikannat
USB Type B -liitin

Komponenttien kytkentä

ATmega328P

Mikrokontrollerina on Atmelin ATmega328P. Piiri on sama joka on käytössä Arduino Uno R3 -kortissa, joten Arduinoa voi käyttää helposti piirin ohjelmointiin. ATmegan kideliitäntöihin (9, 10) on kytketty 16MHz kide, joka on kytketty maahan 22pF keraamisilla kondensaattoreilla. Kontrolleri mittaa ympäröivää valoa analogiseen inputtiin (23) kytketyn jännitteenjakokytkennän avulla, jossa on tavallinen 6,8kΩ vastus sekä LDR-vastus. Piirin syöttöjännitteen (7, 20) ja maan (8, 22) välille on kytketty häiriönpoistoa varten 0,1µF keraaminen kondensaattori. Digitaalisiin tuloihin (11-14) on kytketty neljä nappia 10kΩ alasvetovastuksineen, joilla säädetään kellonaika. I²C-väylän pinneihin (27, 28) on kytketty DS1307-reaaliaikakellopiiri, ja digitaalisiin lähtöihin (4-6) näytönohjauspiiri MAX7219. ATmegan ohjelmointia varten piirin sarjaliitännöistä (2, 3) sekä resetointipinnistä (1) on vedetty piuhat piikkirimalle. Resetointipinni on kytketty 10kΩ ylösvetovastuksella syöttöjännitteeseen.

DS1307

Reaaliaikakelloa DS1307 ohjataan I²C-väylän (5, 6) kautta, joka tarvitsee 10kΩ ylösvetovastukset. Kideliitäntöihin (1, 2) on kytketty 32,768kHz kide, joka on datalehdestä poiketen kytketty maahan 15pF keraamisilla kondensaattoreilla, jotta kello ei edistäisi. Kondensaattorien arvot riippuu paljon piirilevyn komponenttien sijoittelusta; koekykentälevylle kasatussa testiversiossa sopiva arvo oli 7pF. Piirille kytketään 3V jännite CR2032 patterin plus-navalta (3) ja patterin miinus kytketään maahan. Lisäksi piirille kytketään käyttöjännite (8) ja maa (4).

MAX7219

LED-näyttöjen ohjauspiiriä MAX7219 ohjataan kolmella johdolla kontrollerilta (1, 12, 13). ISET-pinniin (18) kytketyllä 47kΩ vastuksella säädetään LED-näytöille syötettävä virta. Jokainen LED-segmentti saa ISET-pinniin tulevan virran noin satakertaisena. Piirin syöttöjännitteen (19) ja maan (4, 9) välille on kytketty häiriönpoistoa varten 0,1µF keraaminen kondensaattori. SegA-SegG pinnit (14, 16, 20, 23, 21, 15, 17) kytketään jokaisen 7-segment-näytön segmenteille A-G (näytön pinnit 7, 6, 4, 2, 1, 9, 10). SegA (14) kytketään ensimmäisen kaksoispisteen alemman ledin anodille, SegB (16) toisen kaksoispisteen alemmalle anodille, SegF (15) ensimmäisen kaksoispisteen ylemmälle anodille ja SegG (17) toisen kaksoispisteen ylemmälle anodille. Kaksoispisteiden ledien katodit kytketään yhteen ja tuodaan 510Ω vastuksen kautta piirin Dig6 pinniin (5). Ledien vastus tarvitaan sovittamaan ledien kirkkaus 7-segment-näyttöjen kirkkauteen, ilman sitä kaksoispisteet ovat huomattavasti kirkkaammat kuin näytöt. Dig0-Dig5 pinnit (2, 11, 6, 7, 3, 10) kytketään järjestyksessä näyttöjen common cathode -pinniin (näytön pinni 3).

Muut

Näyttömoduuli on erillinen piirilevy, joka pitää sisällään 6kpl näyttöjä, LED-kaksoispisteet sekä LDR-vastuksen valonmittaukseen. Moduulissa on 16-pinninen piikkirima, josta lähtee johdot pääpiirilevylle. Pääpiirilevy on vedettävissä ulos kotelon takaseinän mukana. Takapaneelin napeille on myös oma 8-napainen piikkirima. Ohjelmiston päivittämistä varten USB-liittimen vieressä on 2-napainen piikkirima jolla voi syöttää suoraan 5V-jännitteen Arduinolta, sekä 3-napainen rima sarjaliikennettä ja resetointia varten.

Kytkentäkaavio

Alla Eaglella piirretty kytkentäkaavio kellosta. Sama kaavio löytyy ladattavassa muodossa pdf:nä sivun alaosasta.

Clock

Arduino IDE ja kirjastot

Koodin siirtoa varten täytyy Arduino IDE ja Arduinon ajurit olla asennettuna. Ohjelmakoodi itsessään on täysin omaa käsialaa, mutta käyttää kahta valmista kirjastoa: WSWire ja RTClib. RTClib löytyy suoraan Library Managerista nimellä "RTClib by Adafruit". RTClib hoitaa kommunikoinnin DS1307 -piirin kanssa. Arduino IDE tarjoilee vakiona Wire -kirjaston, mutta sillä on tapana jäätyä koska siinä ei ole mitään aikakatkaisua while -loopille, toisin kun muokatussa WSWire -kirjastossa. WSWireä ei löydy Library Managerista, joten se on ladattava täältä ja asennettava käsin. Tämän takia myös RTClib asennuskansiosta täytyy muokata tiedostoa RTClib.cpp, ja muuttaa neljänneltä riviltä Wire.h muotoon WSWire.h. (WS)Wire -kirjasto hoitaa I²C-väylän kommunikoinnin. Nämä kaksi kirjastoa on mukana zip-paketissa, joten haluttaessa ne voi asentaa suoraan sieltäkin.

Bootloaderin siirto

Mikrokontrollerin ohjelmisto on siirretty käyttäen Arduino Uno R3:sta. Toimiakseen Arduinon kanssa ATmega328P:lle täytyy ensin siirtää Arduinon oma Bootloader -ohjelmisto. Bootloader tarkistaa aina mikrokontrollerin käynnistyessä, onko sarjaliikennepinneistä tulossa dataa sisään. Jos on, se kirjoitetaan ATmegan tallennusmuistiin (edellisen ohjelmiston päälle), ja jos taas ei ole, käynnistetään tallennusmuistissa oleva ohjelma normaalisti. Bootloaderin kirjoittamista varten kannattaa ATmega johdottaa koekytkentälevylle alla olevan kuvan mukaisesti. Tarvittavat komponentit: 10kΩ vastus, 16MHz kide ja 22pF keraaminen kondensaattori (2kpl).

1. Muokataan kansiosta "C:\Program Files (x86)\Arduino\hardware\arduino\avr" tiedostoa "boards.txt" (tarvitaan Admin-oikeudet), ja muutetaan rivi 69 uno.bootloader.extended_fuses=0x05 muotoon uno.bootloader.extended_fuses=0xFD jotta ei saada virheimoitusta kirjoitettaessa Bootloaderia (lisätietoa täältä).

2. Arduino IDEstä avataan valmis Bootloaderin kirjoittamiseen tarkoitettu ohjelma: "File / Examples / ArduinoISP / ArduinoISP". Auenneesta tiedostosta poistetaan kommenttiviivat riviltä 81, eli // #define USE_OLD_STYLE_WIRING muutetaan muotoon #define USE_OLD_STYLE_WIRING, jolloin käytetään esimerkkikytkennän pinnejä erillisen 6-pinnisen ICSP piikkiriman sijaan.

3. Valitaan oikea kortti: "Tools / Board / Arduino/Genuino Uno".

4. Valitaan oikea COM-portti: "Tools / Port / COMx".

5. Siirretään muokattu ohjelma Arduinoon: "Sketch / Upload".

6. Valitaan programmeriksi Arduino: "Tools / Programmer / Arduino as ISP".

7. Kirjoitetaan Bootloaderi ATmegaan: "Tools / Burn Bootloader".

Jos kaikki meni hyvin, on ATmegassa nyt Arduinon Bootloaderi.

Arduino Bootloader

Ohjelman siirto

Arduinosta pitää irrottaa sen oma ATmega-piiri päivityksen ajaksi. Alla koekytkentälevyn kytkentä muutettu päivitykseen sopivaksi. Valmista laitetta (jossa on mikrokontrolleri jo kiinni) päivitettäessä laitteeseen ei kytketä ulkoista jännitettä, vaan käyttöjännite otetaan suoraan Arduinon pinneistä. Nyt ohjelmisto voidaan päivittää ATmegaan täysin samoin kuin päivitettäisi Arduinoa, eli: "Sketch / Upload".

Arduino Update

Lähdekoodi

Alla lähdekoodi, joka löytyy myös zipattuna alempaa. Koodissa olisi moni asia voitu jälkeenpäin ajateltuna tehdä helpommin ja järkevämmin, mutta kun se toimii niin antaa olla.


/*
 * AriK / 2.1.2017 / Rev 01
 * 
 * 2 -> MAX7219 pin1 DIN
 * 3 -> MAX7219 pin12 LOAD
 * 4 -> MAX7219 pin13 CLK
 * 8 -> button1
 * 7 -> button2
 * 6 -> button3
 * 5 -> button4
 * A5 -> DS1307 pin6 SLC
 * A4 -> DS1307 pin5 SDA
 * A0 -> photoresistor
 * 
 */

#include <WSWire.h>
#include "RTClib.h"

RTC_DS1307 rtc;

// LDR-vastuksen pinni
const int pinResistor = A0;

// Nappien pinnit
const int pinButton1 = 8;
const int pinButton2 = 7;
const int pinButton3 = 6;
const int pinButton4 = 5;

// MAX7219 ohjauspinnit
const int pinData = 2;
const int pinLoad = 3;
const int pinClock = 4;

// MAX7219 ohjausrekisterit
const int NO_OP = 0x0;
const int DECODE_MODE = 0x9;
const int INTENSITY = 0xA;
const int SCAN_LIMIT = 0xB;
const int SHUTDOWN = 0xC;
const int DISPLAY_TEST = 0xF;

int button1, button2, button3, button4;               // Nappien arvo
int button1Old, button2Old, button3Old, button4Old;   // Nappien edellinen arvo

int intensity;          // Näytön kirkkaus
int hysteresis = 20;    // Vaadittava muutos valoisuudessa että näytön kirkkautta muutetaan
int value;              // A0-pinniltä luettava valoisuusarvo
int oldValue = 0;       // A0-pinnin edellinen valoisuusarvo
int blinkCount = 0;     // Käytetään kellon säätötilan vilkuttamiseen tietyssä tahdissa

bool dotsOn = false;    // Kellotilan piste pois päältä
int mode = 1;           // Kellotila = 1, päivämäärätila = 2

void setup () {
  pinMode(pinData, OUTPUT);
  pinMode(pinLoad, OUTPUT);
  pinMode(pinClock, OUTPUT);

  pinMode(pinResistor, INPUT);

  pinMode(pinButton1, INPUT);
  pinMode(pinButton2, INPUT);
  pinMode(pinButton3, INPUT);

  digitalWrite(pinData, LOW);
  digitalWrite(pinLoad, HIGH);
  digitalWrite(pinClock, HIGH);

  max7219(DECODE_MODE, 0x3F);       // Kuudelle ensimmäiselle näytölle DECODE_MODE päällä (kaksoispisteet on seitsemäs näyttö)
  max7219(INTENSITY, 0xF);          // Alkuun näytöille täysi kirkkaus
  max7219(SCAN_LIMIT, 0x6);         // Otetaan käyttöön seitsemän näyttöä
  max7219(SHUTDOWN, 0x1);           // 0x1 = näyttö päällä, 0x0 = näyttö pimeänä
  max7219(DISPLAY_TEST, 0x0);       // DISPLAY_TEST pois päältä

  // Kuuteen ensimmäiseen näyttöön tyhjä merkki, ja seitsemänteen (kaksoispisteet) kaikki ledit pois päältä
  max7219(1, 0xF);
  max7219(2, 0xF);
  max7219(3, 0xF);
  max7219(4, 0xF);
  max7219(5, 0xF);
  max7219(6, 0xF);
  max7219(7, 0x0);
  
  // Säädetään näyttöön --:--:-- ja jäädään ikuiseen looppiin jos kellopiiri ei kommunikoi
  if (!rtc.begin()) {
    max7219(1, 0xA);
    max7219(2, 0xA);
    max7219(3, 0xA);
    max7219(4, 0xA);
    max7219(5, 0xA);
    max7219(6, 0xA);
    max7219(7, 0xFF);
    while (true);
  }

  // Jos kello ei ole käynnissä (eli kelloa ei säädetty aikaan), säädetään kellonajaksi se aika jolloin ohjelma on
  // käännetty, samalla kello käynnistyy
  if (!rtc.isrunning()) {
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
}

void loop () {
  setIntensity();     // Säädetään näytön kirkkaus

  // Looppi kymmenen kertaa, ja jokaisen loopin jälkeen 49ms tauko = yhteensä 490ms + pinnien luenta, kirkkauden säätö yms = ~500ms,
  // eli saadaan noin puolen sekunnin välein kaksoispiste vilkkumaan (ei kovin tarkka)
  for (int d = 0; d < 10; d++) {

    // luetaan nappien arvot
    button1 = digitalRead(pinButton1);
    button2 = digitalRead(pinButton2);
    button3 = digitalRead(pinButton3);
    button4 = digitalRead(pinButton4);

    // Jos nappi 1 on painettu, mutta ei edellisellä kierroksella ollut painettu, siirrytään joko kellon tai päivämäärän säätötilaan,
    // riippuen ollaanko modessa 1 (kello) vai modessa 2 (päivämäärä)
    if (button1 && !button1Old) {
      if (mode == 1) setupClock();
      else setupDate();
    }
    
    // Jos nappi 4 on painettu, mutta ei edellisellä kierroksella ollut painettu, siirrytään joko kellon tai päivämäärän näyttötilaan,
    // mode 1 = kello, mode 2 = päivämäärä
    if (button4 && !button4Old) {
      if (mode == 1) mode = 2;
      else mode = 1;
    }

    button1Old = button1;
    button2Old = button2;
    button3Old = button3;
    button4Old = button4;

    delay(49);
  }

  if (mode == 1)
  {
    // Sytytetään kaksoispisteet
    if (dotsOn)
    {
      max7219(7, 0xFF);
      dotsOn = false;
    }
    
    // Sammutetaan kaksoispisteet, luetaan kellonaika ja tulostetaan näytölle
    else 
    {
      DateTime now = rtc.now();
      displayTime(now.hour(), now.minute(), now.second());
  
      max7219(7, 0x0);
      dotsOn = true;
    }
  }

  // Sytytetään pelkät alimmat pisteet päivämäärän välisiksi pisteiksi, luetaan päivämäärä ja tulostetaan näytölle
  else if (mode == 2)
  {
    max7219(7, 0x60);
    DateTime now = rtc.now();
    displayDate(now.day(), now.month(), now.year());
    dotsOn = false;
  }
  
}

void setIntensity()
{
  // Luetaan valoisuusarvo A0-pinniltä
  value = analogRead(pinResistor);
  
  // Jos arvo poikkeaa edellisestä näytön kirkkausarvosta enemmän kuin "hysteresis" -muuttujan (oletuksena 20) verran,
  // muutetaan näytön kirkkautta. Luettu kirkkausarvo vaihtelee kokoajan vähäsen, joten ei päivitetä näytön kirkkautta
  // ellei arvo muutu selvästi.
  if (value < oldValue - hysteresis || value > oldValue + hysteresis)
  {
    if      (value > 850) intensity = 0xF;
    else if (value > 800) intensity = 0xE;
    else if (value > 750) intensity = 0xD;
    else if (value > 700) intensity = 0xC;
    else if (value > 650) intensity = 0xB;
    else if (value > 600) intensity = 0xA;
    else if (value > 550) intensity = 0x9;
    else if (value > 500) intensity = 0x8;
    else if (value > 400) intensity = 0x7;
    else if (value > 300) intensity = 0x6;
    else if (value > 200) intensity = 0x5;
    else if (value > 150) intensity = 0x4;
    else if (value > 90)  intensity = 0x3;
    else if (value > 60)  intensity = 0x2;
    else if (value > 30)  intensity = 0x1;
    else                  intensity = 0x0;

    oldValue = value;
    max7219(INTENSITY, intensity);
  }
}

void setupClock()
{
  max7219(SHUTDOWN, 0x0);                       // Pimennetään näyttö
  blinkCount = 0;                               // Vilkkumisarvo nollaan
  bool changed = false;                         // Asetuksia ei ole vielä muutettu, arvo false

  DateTime now = rtc.now();                     // Luetaan kellonaika
  int setHour = now.hour();
  int setMinute = now.minute();
  int setSecond = now.second();
  displayTime(setHour, setMinute, setSecond);   // Tulostetaan kellonaika
  
  max7219(7, 0xFF);                             // Sytytetään kaksoispisteet
  delay(1000);

  while (true)
  {
    int button1 = digitalRead(pinButton1);
    int button2 = digitalRead(pinButton2);
    int button3 = digitalRead(pinButton3);
    int button4 = digitalRead(pinButton4);

    // Jos mitään nappia ei painettu, kaikki näytöt päällä n*200 ajan, ja pois n*50 ajan, eli vilkkuu
    if (!button1 && !button2 && !button3 && !button4)
    {
      blinkCount++;
      if (blinkCount < 200)      max7219(SHUTDOWN, 0x1);
      else if (blinkCount < 250) max7219(SHUTDOWN, 0x0);
      else blinkCount = 0;
    }

    // Poistutaan säätötilasta eikä tallenneta muutoksia jos 2- ja 3-nappia painetaan yhtäaikaa
    if ((button2 && button3))
    {
      max7219(SHUTDOWN, 0x1);
      break;
    }

    // Jos 1-nappia on painettu, poistutaan säätötilasta
    // Jos muutoksia on tehty (changed = true), tallennetaan säädetty kellonaika
    if (button1)
    {
      max7219(SHUTDOWN, 0x1);
      if (changed) rtc.adjust(DateTime(now.year(), now.month(), now.day(), setHour, setMinute, setSecond));
      break;
    }
    
    // 2-napilla säädetään tunteja ylöspäin, kunnes 23 tunnin jälkeen pudotaan takaisin 0 tuntiin
    else if (button2)
    {
      changed = true;
      max7219(SHUTDOWN, 0x1);
      blinkCount = 0;

      if (setHour < 23) setHour++;
      else setHour = 0;
      displayTime(setHour, setMinute, setSecond);
      delay(150);
    }

    // 3-napilla säädetään minuutteja ylöspäin, kunnes 59 minuutin jälkeen pudotaan takaisin 0 minuuttiin
    else if (button3)
    {
      changed = true;
      max7219(SHUTDOWN, 0x1);
      blinkCount = 0;

      if (setMinute < 59) setMinute++;
      else setMinute = 0;
      displayTime(setHour, setMinute, setSecond);
      delay(150);
    }

    // 4-napilla säädetään sekunteja ylöspäin, kunnes 59 sekunnin jälkeen pudotaan takaisin 0 sekuntiin
    else if (button4)
    {
      changed = true;
      max7219(SHUTDOWN, 0x1);
      blinkCount = 0;

      if (setSecond < 59) setSecond++;
      else setSecond = 0;
      displayTime(setHour, setMinute, setSecond);
      delay(150);
    }
  }
}

// Päiväyksen säätö, toimii samoin kuin kellonajan säätö
void setupDate()
{
  max7219(SHUTDOWN, 0x0);
  blinkCount = 0;
  bool changed = false;
  
  DateTime now = rtc.now();
  int setYear = now.year();
  int setMonth = now.month();
  int setDay = now.day();
  displayDate(setDay, setMonth, setYear);
  
  max7219(7, 0x60);
  delay(1000);

  while (true)
  {
    int button1 = digitalRead(pinButton1);
    int button2 = digitalRead(pinButton2);
    int button3 = digitalRead(pinButton3);
    int button4 = digitalRead(pinButton4);

    if (!button1 && !button2 && !button3 && !button4)
    {
      blinkCount++;
      if (blinkCount < 200)      max7219(SHUTDOWN, 0x1);
      else if (blinkCount < 250) max7219(SHUTDOWN, 0x0);
      else blinkCount = 0;
    }
    
    if ((button2 && button3))
    {
      max7219(SHUTDOWN, 0x1);
      break;
    }

    if (button1)
    {
      max7219(SHUTDOWN, 0x1);
      if (changed) rtc.adjust(DateTime(setYear, setMonth, setDay, now.hour(), now.minute(), now.second()));
      break;
    }
    
    else if (button2)
    {
      changed = true;
      max7219(SHUTDOWN, 0x1);
      blinkCount = 0;
      
      if (setDay < 31) setDay++;
      else setDay = 1;
      displayDate(setDay, setMonth, setYear);
      delay(150);
    }

    else if (button3)
    {
      changed = true;
      max7219(SHUTDOWN, 0x1);
      blinkCount = 0;

      if (setMonth < 12) setMonth++;
      else setMonth = 1;
      displayDate(setDay, setMonth, setYear);
      delay(150);
    }

    else if (button4)
    {
      changed = true;
      max7219(SHUTDOWN, 0x1);
      blinkCount = 0;

      if (setYear < 2050) setYear++;
      else setYear = 2000;
      displayDate(setDay, setMonth, setYear);
      delay(150);
    }
  }
}

// Tulostetaan kellonaika näytölle
void displayTime(int hours, int minutes, int seconds)
{
  String h = String(hours);
  String m = String(minutes);
  String s = String(seconds);

  if (h.length() == 1) h = '0' + h;
  if (m.length() == 1) m = '0' + m;
  if (s.length() == 1) s = '0' + s;

  int dig1 = h.substring(0, 1).toInt();
  int dig2 = h.substring(1, 2).toInt();
  int dig3 = m.substring(0, 1).toInt();
  int dig4 = m.substring(1, 2).toInt();
  int dig5 = s.substring(0, 1).toInt();
  int dig6 = s.substring(1, 2).toInt();
  
  if (dig1 == 0) max7219(1, 0xF);
  else max7219(1, dig1);
  
  max7219(2, dig2);
  max7219(3, dig3);
  max7219(4, dig4);
  max7219(5, dig5);
  max7219(6, dig6);
}

// Tulostetaan päivämäärä näytölle
void displayDate(int days, int months, int years)
{
  String d = String(days);
  String m = String(months);
  String y = String(years);

  if (d.length() == 1) d = '0' + d;
  if (m.length() == 1) m = '0' + m;
  if (y.length() == 1) y = '0' + y;

  int dig1 = d.substring(0, 1).toInt();
  int dig2 = d.substring(1, 2).toInt();
  int dig3 = m.substring(0, 1).toInt();
  int dig4 = m.substring(1, 2).toInt();
  int dig5 = y.substring(2, 3).toInt();
  int dig6 = y.substring(3, 4).toInt();

  if (dig1 == 0) max7219(1, 0xF);
  else max7219(1, dig1);

  max7219(2, dig2);

  if (dig3 == 0) max7219(3, 0xF);
  else max7219(3, dig3);
  
  max7219(4, dig4);
  max7219(5, dig5);
  max7219(6, dig6);
}

// Alla MAX7219 ohjaukseen liittyvät komennot, lisäinfoa datalehdestä

void max7219(int address, int data) {
  max7219(toBin(address), toBin(data));
}

void max7219(int address, String data) {
  max7219(toBin(address), data);
}

void max7219(String address, String data) {
  String str = address + data;
  
  digitalWrite(pinLoad, HIGH);

  for (int i = 0; i < str.length(); i++) {
    digitalWrite(pinClock, LOW);
    digitalWrite(pinData, str.substring(i, i + 1).toInt());
    digitalWrite(pinClock, HIGH);
  }

  digitalWrite(pinLoad, LOW);
  digitalWrite(pinLoad, HIGH);
}

String toBin(int number) {
  String s = String(number, BIN);
  if (s.length() == 1) s = "0000000" + s;
  else if (s.length() == 2) s = "000000" + s;
  else if (s.length() == 3) s = "00000" + s;
  else if (s.length() == 4) s = "0000" + s;
  else if (s.length() == 5) s = "000" + s;
  else if (s.length() == 6) s = "00" + s;
  else if (s.length() == 7) s = "0" + s;
  return s;
}

Ladattavat tiedostot

Kytkentäkaavio (.pdf)
Koodi ja tarvittavat kirjastot (.zip)

Valokuvat



Kommentit

Nimi

Kommentti

Kirjoita ilman välimerkkejä: e.n, o.l.e, r.o.b.o.t.t.i!

Admin

Käyttäjätunnus

Salasana