maanantai 23. tammikuuta 2017

KEHITYSTÄ III

Tämä jakso ei toteutunut aivan suunnitellusti. KEHITYS III piti olla huomattavasti laajempi, mutta se siirtyy KEHITYS IV:een. Eli jatkoa seuraa. Miksi tästä sitten tuli tällainen pieni ”välipala”. Syy on seuraava: Kun mukana on LCD-näyttö ja inputtien sarjaliikennettä (ja jos vielä lähdönkin sarjaliikennettä), niin digitaliset I/O:t käyvät huolestuttavan vähiin.

Tähän on olemassa helpotus. Myös analogiapuolta voi käyttää binääri-tuloina ja -lähtöinä. Paitsi Arduino MICRO:ssa, minkä alun perin valitsin tämän jakson mikrokontrolliseksi. Syy siihen oli, että sellainen lojui tarpeettomana. Siis se ensi kerralla jaksossa KEHITYS IV.

Pinnin määrittely tapahtuu normaaliin tapaan (pinMode(pin, INPUT / OUTPUT). Tässä tosin se suoritataan I/O-aliohjelmassa. Digitalikäytössä analogiatulon A0 digitaliosoite on 14 ja viimeisen tulon A5 osoite on 19. Koska tässä ei näy aliohjelmaa (pitää kopioda), niin ohjelma typistyy kahteen riviin. Ohjelma toimii siten, että painettaessa vasenta painiketta, palaa LEDi punaisena ja painettaessa oikeaa painiketta, palaa LEDi vihreänä.
Tässä oikeanpuoleinen painike on ohitettu.
OHJELMA 36
/***************************************
* Ohjelma 36
* 23.01.2017
* Analogiapuolen käyttö digitaalisessti
**************************************/

// ALIOHJELMAT
IO_AliOhjelma_v1 IO_Ali_v1.No2Tam17
/*************************************/
boolean Fun_IO(int mode, int pinni, boolean tila){

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

// PÄÄLOOPPI
void loop(){
Fun_IO(2, 18, Fun_IO(1,16,0));
Fun_IO(2, 19, Fun_IO(1,17,0));

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

sunnuntai 22. tammikuuta 2017

KEHITYSTÄ II

Tässä sovelluksessa käytän kahta CMOS-piiriä (74HCT-165N), joissa kummassakin on kahdeksan (8) tuloa rinnan. Siis yhteensä 16 tuloa. Piirit on kytketty sarjaan siten, että toisen piirin sarjalähtö on kytketty toisen sarjatuloon. Piirien ulkoiset liitynnät luetaan bitti kerrallaan peräkkäin. Piireissä on kolme (3) liityntää Arduinon digitalipinneihin. 
     Ensimäinen on PL, minkä laskeva reuna aktivoi rinnakkaisrekistereissä olevan tiedon siirtymisen sarjarekisteriin. Tämä liityntä on kytketty rinnan molempien IC-piirien välillä. Toinen liityntä on CP, kellotus, minkä nouseva reuna siirtää bitti kerrallaan sarjarekisterin dataa lähtöön Q7. Kellotuskin on kytketty rinnan molempien IC-piirien välillä. Kolmas liityntä on data (1. piirin Q7 → 2. piirin Ds → Arduino IN). Toisin sanoen ensimmäisen piirin (alimmat bitit 0 .. 7) sarjalähtö (Q7) kytketään toisen piirin (ylimmät bitit 8 .. 15) sarjatuloon (Ds) ja toisen piirin sarjalähtö (Q7) Arduinon tuloon.
Piirin 74HCT-165N sisäinen rakenne.

On pidettävä tässä yhteydessä mielessä, että eniten merkitsevä (bitti 15) luetaan ensimmäiseksi ja vähiten merkitsevä (bitti 0) viimeisenä. Luentalauseet olen koonnut aliohjelmaksi, minkä löytämiskoodi on: SarjaIN_Ali_v1.No4Tam17. Aliohjelmassa määritellään myös tulot/lähdöt, joten pääohjelmasta kutsuttaessa parametreinä on ainoastaan liityntäpinnien numerot. Yhteistä pääohjelmalle ja tälle aliohjelmalle on 16 bitin taulukko (boolean Arr_DATA[16];), mihin aliohjelma kirjoittaa tulojen tilatiedot ohjelman jatkotoimenpitetä varten.


LCD-näyttöön tulevat tekstit olen valinnut siten, että sekä pienet että isot ääkköset tulevat mukaan. Siltä osin, kun tuo (void Fun_LCD(int start, int rivi, int paikka, int data){) näytön koodi on muuttunut, on tässä esityksessä mukana muuttuneet akeleet. Olen myös jättänyt mukaan tulostuksen aliohjelman, sillä sen avulla on havainnollisempaa tarkastella bittejä tietokoneen ja Arduinon työkaluohjelman avulla. Toiminnallisesti sillä ei ole merkitystä.
     Kuvassa mikropiirejä reunustavat ”mustat liuskat” ovat 8*10kohm vastus-hybridipiirejä. Vastuksilla on yksi (1) yhteinen maa. Tässä jokaiselle vastukselle ei ole käyttöä, koska tuloja on 16 kappaletta. Yläosassa näkyväll ”piuhalla” voi tökkiä eri tuloja. 
Kuvassa olin tökkäissyt pinniä no. 12.

OHJELMA 35
/**************************************
* Ohjelma 35
* 21.01.2017
* Rinnan sisään, sarjassa ulos
* 16 digitaalitulon toteutus
* kahdella 74HCT-165N CMOS-piirillä
**************************************/

// MÄÄRITTELYT:
// Kirjastomoduulit
   #include <LiquidCrystal.h>
   LiquidCrystal lcd(3, 2, 7,6,5,4);

// Bittitaulukko ja järjestysnumero
   boolean Arr_DATA[16];
   int Int_Numero = 0;

// Tulostuksen tahdistus
   const int Con_PrintViive = 1000;
   int Int_PrintViive = Con_PrintViive;

// ALIOHJELMAT
void Fun_Tulostus(){
//Serial.print("Teksti :"); Serial.println(Muuttuja);
for(int i; i < 16; i++){
Serial.print(Arr_DATA[i]);
}
Serial.println();
Serial.print("Tokkasit :"); Serial.println(Int_Numero);
} // Tulostus loppu

// Funktio Parallel IN serial OUT (Rinnan sisään, sarjassa ulos)
// SarjaIN_Ali_v1.No4Tam17
/****************************************************
void Fun_LueRsSu(int PL, int CP, int Data){
   pinMode(PL, OUTPUT); // pinnin numero kutsussa
   pinMode(CP, OUTPUT); // pinnin numero kutsussa
   pinMode(Data, INPUT);// pinnin numero kutsussa
// Rinnakkaisdatan siirto
   digitalWrite(PL, LOW);
   digitalWrite(PL, HIGH);
   for(int i = 0; i < 16; i ++){Arr_DATA[i] = 0;}// tyjennys
   for(int j = 0; j < 16; j++){ // luku
      Arr_DATA[j] = digitalRead(Data);
      digitalWrite(CP, HIGH);
      digitalWrite(CP, LOW);
   }// sarjaluennan loppu
   }// Funtion loppu

// LCD_AliOhjelma_v1 LCD_Ali_v1.No3Tam17
/****************************************************
case 1:
lcd.setCursor(paikka, rivi);
lcd.print("T");
i = 1; lcd.write(i); // Ö - kirjain
lcd.print("KK");
i = 0; lcd.write(i); // Ä - kirjain
i = 0; lcd.write(i); // Ä - kirjain
lcd.print(" ");
lcd.print("PINNI");
i = 0; lcd.write(i); // Ä - kirjain
 
case 2:
lcd.setCursor(paikka, rivi);
lcd.print("t");
lcd.write(opi); // ö - kirjain
lcd.print("kk");
lcd.write(api); // ä - kirjain
lcd.print("sit:");
 
case 11:
lcd.setCursor(paikka, rivi);
lcd.print("    ");
lcd.setCursor(paikka, rivi);
lcd.print(data);*/

// ASETUKSET:
void setup(){
   Serial.begin(9600);
   lcd.begin(20,2);
   lcd.clear();
   lcd.setCursor(0, 0);
   Fun_LCD(1,0,3,0); // Ylärivin kiinteä teksti
   Fun_LCD(2,1,0,0); // Alarivin kiinteä teksti
}// Asetuksen loppu

// PÄÄLOOPPI
void loop(){
   Fun_LueRsSu(8, 9, 10);
   for(int No = 0; No < 16; No++){
      if(Arr_DATA[15-No] == 1){
         Int_Numero = No + 1;
     }// if loppu
   }// for loppu

   Fun_LCD(11,1,10,Int_Numero);

   Int_PrintViive--;
   if(Int_PrintViive == 0){
      Fun_Tulostus();
      Int_PrintViive = Con_PrintViive;
   } // Tulostuskutsu loppu
delay(1);
} // Pääohjelma LOPPU

torstai 19. tammikuuta 2017

KEHITYSTÄ I

Oikea painike oikosuljettu
Tämän ohjelman tarkoitus on luoda LCD-aliohjelma, mitä voidaan yleiskäyttää pääohjelmakutsun kautta. Tämän aliohjelman nimi on: void Fun_LCD(int start, int rivi, int paikka, int data){ ja se voidaan myöhemmin kopioda tästä ohjelmasta viitteellä: LCD_Ali_v1.No3Tam17. Tässä siis aliohjeman nimi ja versio sekä tieto siitä, että se on kolmas blogipäivitys tammikuussa 2017. Toinen aliohjema, mikä pitää hakea edellisestä tämän kuun päivityksestä on: IO_Ali_v1.No2Tam17. Tästä jälkimmäisestä ei ole kokonaista koodia enää tässä ohjelmassa, vaan se on kopiotava edellisestä päivityksestäni.
Tuossa LCD-aliohjelmassa on useita tekstejä ja muita tulosteita. Ne joutuu luonnollisesti sovittamaan halutun toteutuksen mukaan. Tämä on siis vain runko.
Kutsuttaessa pääohjelmasta, pitää siinä olla seuraavat parametrit:
start = viittaus seklvenssin suoritusaskeleeseen
rivi = LCD-näytön rivi 0 = yläriv, 1 = alarivi
paikka = ensimmäisen merkin paikka rivillä ( 0 .. 19)
data = numerotieto (int tai muutettava tarpeen mukaan)

LCD-aliohjemaa varten pitää alun määrittelyosassa antaa kirjastomoduuli (#include <LiquidCrystal.h>) sekä määritellä LCD-näytön pinnit (LiquidCrystal lcd(3, 2, 7,6,5,4);. Olen tähän sovellukseen vaihtanut (yleensä esimerkeissä esiintyvät) Arduinon pinnit voidakseni käyttää yhtä liitintä näytön ja mikrokontrollerin välillä. Niiden paikka ei ole tärkeä, mutta järjestys on oleellinen.
Asetuksissa täytyy määritellä näytön ominaisuudet; montako riviä ja montako merkkipaikkaa. Tässä tapauksessa kaksi (2) riviä ja 20 paikkaa (lcd.begin(20,2);.
Pääohjelmaa varten on neljä (4) määrittelyä: IO-aliohjelmasta palautuva painikkeen tilatieto (Bol_Painike). Painikkeen ”nouseva reuna” (Diu_Painike), minkä avulla huolehditaan siitä, että ohjaustoimenpiteet (tässä painamisten lukumäärä) suoritetaan vain kerran, eikä jokaisella ohjelmakierroksella. Lisäksi molemmille painikkeille on laskurit ( Int_OikLkm ja Int_VasLkm).
     Tämä ohjelma toimii siten, että ylärivin keskellä on pysyvästi teksti YLÄOTSIKKO ja alariville ilmestyy Vasen / Oikea lkm kertaa! Jos mitään ei paineta, on alarivi tyhjä. Painettaessa, vastaava painike näkyy rivillä, sekä painikkeen painamisten lukumäärä, joka kasvaa yhdellä aina painettaessa.
     Tässä ohjemassa on se puute, että painikkeita ei voi painaa samanaikaisesti. Se olisi korjattavissa määrittelemällä molemmille painikkeille omat tilamuuttujat (Bol_ ja Diu_). Tuo ei ole kuitenkaan oleellista tässä yhteydessä. Toinen ”puute” on se, että painamiskertojen ollessa alle 10, numerot tulostuvat yhtä paikkaa liikaa vasemmalle. Tämä olisi korjattavissa testaamalla, onko luku alle 10, ja JOS on, niin lisätään paikkakutsuun yksi (+1).
Tuokaan ei ole tässä yhteydessä kovin oleellista. Merkittävämpää on se, että digitaali IO:t vähenevät kuudella (6) käytettäessä LCD-näyttöä. Onneksi moniin ongelmiin löytyy ratkaisu. Niin tähänkin tulevaisuuden sovelluksissa.

Painikkeiden testaus on toteutettu while-komennolla (while(Bol_Painike = Fun_IO(1,8,0)){). Kutsun parametrit: 1 = INPUT, 8 = I/O-pinni 8 ja 0 = ei tässä merkitse mitään. Se koskee ainoastaan OUTPUT- timintoa. Niin kauan kun painike on painettuna, suoritetaan käskyyn kuuluvat lauseet ja toiminnot. Kun painike päästetään, käskyryhmä ohitetaan. Tämä on siis ehtokäky, kuten if, if .. else, do .. while ja mikseipä myöskin switch .. case.

OHJELMA 34
/***************************************
* Ohjelma 34
* 17.01.2017
* LCD-näyttö ja painikeFunktio
**************************************/
// Kirjastomoduulit
    #include <LiquidCrystal.h>
    LiquidCrystal lcd(3, 2, 7,6,5,4);
// MÄÄRITTELYT:
    boolean Bol_Painike = false;
    boolean Diu_Painike = false;
    int Int_OikLkm = 0;
    int Int_VasLkm = 0;

// ALIOHJELMAT
//IO_Ali_v1 - IO_Ali_v1.No2Tam17

// LCD_AliOhjelma_v1 LCD_Ali_v1.No3Tam17
/****************************************************
    * Kutsuparametrit:
    * 1. start = käynnistää valintasekvenssin
    *                halutulta riviltä
    * 2. rivi = LCD-näytön rivi, 0 = ylä, 1 = ala
    * 3. paikka = merkin paikka rivillä
    * 4. data = numeroiden näyttö ( tässä int,
    *                mutta tarvittaessa float
****************************************************/
// LCD aliohjelman määrittelyt
    void Fun_LCD(int start, int rivi, int paikka, int data){
        int i = 0; // Ä(0) ja Ö(1) kirjainten kirjastoviittaus
        const byte api = B11100001; // ä-kirjain
        const byte opi = B11101111; // ö-kirjain
        const byte ast = B11011111; // aste
        byte Api[8] = // Ä-kirjain
                            {B10001,B00100,B01010,B10001,
                            B11111,B10001,B10001,B00000};
        byte Opi[8] = // Ö-kirjain
                            {B10001,B01110,B10001,B10001,
                             B10001,B10001,B01110,B00000};
        lcd.createChar(0,Api); // Huom! int i yllä!!
        lcd.createChar(1,Opi);
// Näytön valintasekvenssi
        int Seq_LCD = start;
        switch (Seq_LCD){
        case 1:
            lcd.setCursor(paikka, rivi);
            lcd.print("YL");
            i = 0; lcd.write(i); // Ä - kirjain
            lcd.print("OTSIKKO");
            Seq_LCD = 0;
       break;
        case 2:
            lcd.setCursor(paikka, rivi);
            lcd.print("Vasen:");
            Seq_LCD = 0;
       break ;
        case 3:
            lcd.setCursor(paikka, rivi);
            lcd.print("Oikea:");
            Seq_LCD = 0;
       break ;
        case 4:
            lcd.setCursor(paikka, rivi);
            lcd.print("kertaa!");
            Seq_LCD = 0;
       break ;
        case 5:
            lcd.setCursor(paikka, rivi);
            lcd.print(" ");
            Seq_LCD = 0;
       break ;
        case 11:
            lcd.setCursor(paikka, rivi);
            lcd.print(data);
            Seq_LCD = 0;
       break ;
        case 12:
            lcd.setCursor(paikka, rivi);
            lcd.print("kpl");
            Seq_LCD = 0;
       break ;
        case 13: // Koko rivin tyhjennys
           lcd.setCursor(paikka, rivi);
            lcd.print("                    ");
            Seq_LCD = 0;
     break ;
}// Valintasekvenssin loppu
}// Funktion LCD loppu

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

// PÄÄLOOPPI
void loop(){

// Tulostetaan yläteksti "YLÄOTSIKKO"
    Fun_LCD(1,0,5,0);

    while(Bol_Painike = Fun_IO(1,8,0)){
       if(Bol_Painike == true && Diu_Painike == false){
           Fun_LCD(2,1,0,0);
           Fun_LCD(4,1,10,0);
           Int_VasLkm++;
           Fun_LCD(11,1,7,Int_VasLkm);
           Diu_Painike = true ; }}

   while  (Bol_Painike = Fun_IO(1,9,0)){
       if(Bol_Painike == true && Diu_Painike == false){
            Fun_LCD(3,1,0,0);
            Fun_LCD(4,1,10,0);
            Int_OikLkm++;
            Fun_LCD(11,1,7,Int_OikLkm);
            Diu_Painike = true ; }}

// Alarivin tyhjennys, kun kumpaakaan ei paineta
   if(Bol_Painike == false){
        Fun_LCD(13,1,0,0);
        Diu_Painike = false;}

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

perjantai 13. tammikuuta 2017

Koodilukko

Hiukan erilainen koodilukko. Hiukan erilainen on myös ohjelman rakenne. Tässä on pyritty mahdollisimman pieneen pääohjelmaan, mahdollisimman vähiin yleisiin muuttujiin (global variable) sekä keskittämään kaikki toiminnot aliohjelmiin. Tämä on se suunta, mihin ohjelmoinnin rakenteessa pitääkin pyrkiä. Tästä on se etu, että voi kopioida helposti jo aiemmin tehtyjä ohjelmapätkiä ja testattuja toimintoja. Tämä nopeuttaa ja helpottaa ohjelman kirjoittamista sekä parantaa ohjeman luotettavuutta. Kaikilla mitaleilla on myös se toinen puoli. Tässä se on se, että dokumentointi ja versionhallinta nousee hyvin tärkeään rooliin. Korostan tätä samalla ennen kaikkea itselleni, sillä ohjelmaa tehdessä ja testatessa sitä kuvittelee muistavansa miten se toimii, mutta muutaman kuukauden kuluttua on jo huuli pyöreänä.
 
Tässä ohjelmassa paras esimerkki tästä ja tulevasta käytännöstä on digitaali-tulojen ja -lähtöjen käsittely (boolean Fun_IO(int mode, int pinni, boolean tila){). Tuleville blogisivuille en tule enää kirjoittamaan tätä aliohjelmaa, vaan ainostaan viittauksen: IO_AliOhjelma_v1 ja mistä se on poimittavissa: IO_Ali_v1.No2Tam17. Tuossa viittauksessa on aliohjelman otsikko, sekä sivujen päivityksen numero kuukausittain ja vuosittain. Tässä aliohjemassa parametri mode määrittelee sen, onko kyse 1 = tulosta (INPUT), 2 = lähdöstä (OUTPUT), vai Arduinon sisäisesti 3 = ylösvedetystä (INPUT_PULLUP, ei tarvita ulkoista vastusta) tulosta. Toinen parametri: pinni määrittää IO-liitynnän. Kolmas parametri on lähdön ohjaus päälle tai pois. Jos kysytään tuloa, on tämä parametri aliohjemakutsussa nolla (0).
 
Tässä soveluksessa on käytössä 7-segmenttinäyttö, joka aiemmin on ollut noppa-sovelluksessa. Sen kytkentä on nähtävissä siis: ”Arpakuutio”.No2Kes16.
 
Ensimmäinen lause oli:”Hiukan erilainen koodilukko.” Erilaisuus johtuu siitä, että ”lukkoon” ei syötetä numerokoodia, vaan annetaan laitteelle palautetta siitä, onko ”koodilukon” arpoma numero oikea vai väärä. Kuuluuko arvottu numero (1 .. 9) avauskoodiin (tässä 7, 3, 5, 2) vai ei. ”Oven avaus” käynnistyy siitä, että painetaan molempia painikkeita samanaikaisesti. Kun painikkeet on vapautettu, pyörähtää näytön ledit kolme kertaa. Pienen tauon jälkeen näyttöön ilmestyy numero, jolloin pitää valita, onko se oikea (oikea painike) vai väärä (vasen painike). Ohjelma laskee oikeiden painamisten summan ja väärien painamisten summan. Jos molemmat täsmää,”aukeaa ovi” eli vihreä LED palaa hetken. Jos syöte on virheelinen, tai ei ole ehditty painaa ollenkaan, alkaa punainen LED vilkkumaan. Kun nämä palautteet ovat kuluneet ajallisesti loppuun (näiden aikana ohjema ei reagoi painamisiin), voidaan ”astua sisään”, tai yrittää uudestaan.
 
Voisi sanoa, että laitteen arpoma lukusarja on aina erilainen. Se ei pidä paikkaansa, mutta vaihtoehtoja on 362.880 kappaletta. Eli rosvo, joka kyttää nurkan takana, on luultavasti ihmeissään, edellyttäen, että hän ei näe, painetaanko vasenta vai oikeaa painiketta. Jos oletetaan, että joka kerta tulee eri lukusarja (totta kai voi tulla samojakin), ja sisään astutaan kerran päivässä, niin kestäisi 994 vuotta, kun väkisinkin tulisi sama lukusarja. Tätä ei välttämättä näkisi edes Metusalem, sillä hän – kertoman mukaan – eli ainoastaan 969 vuotta.
     Tämän koodilukon varmuutta voisi lisätä vielä siten, että oikea koodi olisi muuttuva esim. päivämäärän mukaan. Tarpeetonta kuitenkin tehdä turhan mutkikkaaksi, sillä ei tässä tuo lukko ole pääasia, vaan nuo ohjelmapätkät.
 
Pääohjema
Pääohjelma koostuu seitsemästä (7) askeleesta. Arduinon käynnistyessä ohjelma odottaa askelleessa yksi (1) molempien painikkeiden samanaikaista painamista. Kun ohjelma tunnistaa molemmat painikkeet, siirrytään askeleeseen kaksi (2) odottamaan painikkeiden vapautumista. Askeleessa kolme (3) pyöräytetään kolme kertaa 7-segmenttinäytön äärimmäisiä ledejä (A .. F, ei keskimmästä eli G). Pienen tauon jälkeen ohjelma hyppää askeleeseen neljä (4). Siinä kirjoitetaan nollaa näytön ohjainpiiriin (74HC595E) sekä täytetään taulukko Arr_Numerot[9]; arvotuilla numeroilla 1 .. 9. Askeleessa neljä (4) tehdään aliohjelmakutsu Fun_Arvonta(){ ja huolehditaan siitä, että taulukkoon tulee kukin numero vain kerran. Askeleessa viisi (5) näytetään 7-segmenttinäytössä kutakin arvottua numeroa pari sekuntia siinä järjestyksessä, missä ne arvottiin. Samalla tutkitaan onko jompaa kumpaa painiketta painettu. Valinta ja painaminen pitää tapahtua numeron näytön aikana. Lopuksi tarkastetaan oikeiden numeroiden summa (if(Int_OikeaSumma == 17 && Int_VaaraSumma == 28){).Mikäli molemmat summat täsmäävät, siirrytään askeleeseen kuusi (6), missä poltetaan hetken aikaa vihreää LEDiä. Mikäli summissa on virhe, tai jonkin numeron kohdalla on jäänyt painamatta, hyppää ohjelma askeleeseen seitsemän (7), missä vilkutetaan punaisata LEDiä. Näiden askelien viiveen kuluttua nollataan summat ja hypätään askelkeeseen yksi (1) odottamaan uutta yritystä.
 
Aliohjemat
Ensimmäisenä on viiveen aliohjelma: int Fun_Viive(int Viive){ . Toisin kuin viive delay(ms) ohjeman suoritus ei keskeydy viiveen ajaksi Tässä aliohjelmassa ainoastaan päivitetään viivelaskuria. Seuraavana on digitaalitulojen ja -lähtöjen käsittely boolean Fun_IO(int mode, int pinni, boolean tila){. Tässä aliohjelmassa määritellään dynaamisesti pinni tuloksi tai lähdöksi, eikä asetuksissa kuten tähän saakka. Kolmantena ja neljäntenä lasketaan oikeiden ja väärien numeroiden summat. Viidentenä on 7-segmenttinäytön tyhjennys void Fun_Tyhjenna(){. Toisin sanoen sarjamuodossa kirjoitetaan nollaa ohjauspiiriin ja siirretään näyttöön. Tämän osan muuttujamäärittelyitä on vielä asetuksissa, koska tämä on kopio ennen käytetystä ohjelmasta. Kuudentena on varsinainen näytön käsittelyn aliohjelma void Fun_Sijoita(int data){. Siinä määritellään bittimuodossa näytön reunat sekä numerot 1 .. 9. Kullekin tapahtumalle on oma sekvenssiaskeleensa. Kahta edellistä ohjelmaa kutsutaan seitsemännestä ohjelmapätkästä void Fun_Naytto(int j){. Tähän funktioon välitetään parametri j (vastaten näytettävää numeroa), mikä määrää suoritettavan askeleen sijoita-aliohjelmassa. Viimeisenä on arvonnan funktio void Fun_Arvonta(){. Siinä arvontaa suoritetaan niin kauan, että kukin numero saadaan sijoitettua taulukkoon int Arr_Numerot[9];. Asetuksissa on vielä muutama pinnimäärittely, mitkä jatkossa siirtyvät omiin aliohjelmiinsa. Sen lisäksi alustetaan sattumageneraattori vapaana olevasta analogiatulosta A5 randomSeed(analogRead(5));. Tässä tyhjennetää myös numerotaulukko.

 OHJELMA 33
 /***************************************
* Ohjelma 33
* 12.01.2017
* Toisenlainen koodilukko
**************************************/

// MÄÄRITTELYT:
// Yleiset muuttujat
// Digitaali tulot ja lähdöt
      boolean Bol_Tila = false; // DigiInputin muuttuja
      const int PainVas = 2; // Vasemman painikkeen pinni
      boolean Bol_PainVas = false;
      boolean Diu_PainVas = false;
      const int LEDPun = 5; // Punaisen LEDin pini
      const int PainOik = 3; // Oikean painikkeen pinni
      boolean Bol_PainOik = false;
      boolean Diu_PainOik = false;
      const int LEDVih = 4; // Vihreän LEDin pinni
// 7-sekvenssinäyttö
      const int Con_DS_Data = 6; // Sarjadatan syöttö
      const int Con_SHCP_Kello = 7; // Sarjadatan kellotus
      const int Con_STCP_Siirto = 8; // Syöttö rinnanlähtöön
      boolean Arr_Data[8] = {0,0,0,0,0,0,0,0};// Näyttö
      int Arr_Numerot[9]; // Arvottujen numeroiden taulukko
      int Int_Numero = 0;
// Avainkoodi: 7352 yhteensä 17, 1 .. 9 yhteensä 45
      int Arr_Oikea[4] = {7,3,5,2}; // Yhteensä 17
      int Arr_Vaara[5] = {1,4,6,8,9}; // Yhteensä 28
      int Int_OikeaSumma = 0;
      int Int_VaaraSumma = 0;
// Sekvenssimääritykset
      int Seq_Hallinta = 1;
      const int Con_Tauko = 25;
      int Int_Tauko = 0;
      const int Con_NayttoVii = 125;
      int Int_NayttoVii = 0;

// ALIOHJELMAT
// Viiveen aliohjelma
      int Fun_Viive(int Viive){
            Viive++;
            delay(1);
      return(Viive);
}// Viiveen loppu

// Tulot/lähdöt IO_Ali_v1
       boolean Fun_IO(int mode, int pinni, boolean tila){
            boolean bol_kosketin = false;
            switch (mode) {
      case 1:
            pinMode(pinni, INPUT);
            bol_kosketin = digitalRead(pinni);
            delay(10);
            return(bol_kosketin);
            mode = 0;
      break;
      case 2:
            pinMode(pinni, OUTPUT);
            digitalWrite(pinni, tila);
           mode = 0;
      break;
      case 3:
            pinMode(pinni, INPUT_PULLUP);
            bol_kosketin = digitalRead(pinni);
            delay(10);
            return(bol_kosketin);
            mode = 0;
      break;
      } //valintojen loppu
      } //funktion loppu

// Lasketaan oikeiden numeroiden summa
      int Fun_VertaaOikea(int num, int arpa){
       for(int i = 0; i < 4; i ++){
            if(arpa == Arr_Oikea[i]){
                  num = num + arpa;
            } // if loppu
      } // for loppu
      return num;
}// Vertailun loppu

// Lasketaan väärien numeroiden summa
      int Fun_VertaaVaara(int num, int arpa){
            for(int i = 0; i < 5; i ++){
                  if(arpa == Arr_Vaara[i]){
                        num = num + arpa;
                  } // if loppu
            } // for loppu
            return num;
      }// Vertailun loppu

      void Fun_Tyhjenna(){
            for(int i = 0; i < 8; i++){
                  digitalWrite(Con_DS_Data, 0);
                  digitalWrite(Con_SHCP_Kello, HIGH);
                  digitalWrite(Con_SHCP_Kello, LOW);
                  digitalWrite(Con_STCP_Siirto, HIGH);
                  digitalWrite(Con_STCP_Siirto, LOW);}
      }// Tyhjennyksen loppu

      void Fun_Sijoita(int data){
            int Seq_sijoita = 0;
// 7-sehmenttinäytön laidat
            boolean Arr_DataA[8] = {0,0,0,0,0,0,1,0};
            boolean Arr_DataB[8] = {0,0,0,0,0,1,0,0};
            boolean Arr_DataC[8] = {0,0,0,0,1,0,0,0};
            boolean Arr_DataD[8] = {0,0,0,1,0,0,0,0};
            boolean Arr_DataE[8] = {0,0,1,0,0,0,0,0};
            boolean Arr_DataF[8] = {1,0,0,0,0,0,0,0};
// 7-segmenttinäytön numerot
            boolean Arr_Data1[8] = {0,0,0,0,1,1,0,0}; // 1
            boolean Arr_Data2[8] = {0,1,1,1,0,1,1,0}; // 2
            boolean Arr_Data3[8] = {0,1,0,1,1,1,1,0}; // 3
            boolean Arr_Data4[8] = {1,1,0,0,1,1,0,0}; // 4
            boolean Arr_Data5[8] = {1,1,0,1,1,0,1,0}; // 5
            boolean Arr_Data6[8] = {1,1,1,1,1,0,1,0}; // 6
            boolean Arr_Data7[8] = {0,0,0,0,1,1,1,0}; // 7
            boolean Arr_Data8[8] = {1,1,1,1,1,1,1,0}; // 8
            boolean Arr_Data9[8] = {1,1,0,1,1,1,1,0}; // 9

      Seq_sijoita = data + 1;
            switch (Seq_sijoita) {
            case 1: for(int i = 0; i < 8; i++){
                 Arr_Data[i] = Arr_DataA[i];}break;
            case 2: for(int i = 0; i < 8; i++){
                  Arr_Data[i] = Arr_DataB[i];}break;
            case 3: for(int i = 0; i < 8; i++){
                  Arr_Data[i] = Arr_DataC[i];}break;
            case 4: for(int i = 0; i < 8; i++){
                  Arr_Data[i] = Arr_DataD[i];}break;
            case 5: for(int i = 0; i < 8; i++){
                  Arr_Data[i] = Arr_DataE[i];}break;
            case 6: for(int i = 0; i < 8; i++){
                  Arr_Data[i] = Arr_DataF[i];}break;
            case 7: for(int i = 0; i < 8; i++){
                  Arr_Data[i] = Arr_Data1[i];}break;
            case 8: for(int i = 0; i < 8; i++){
                  Arr_Data[i] = Arr_Data2[i];}break;
            case 9: for(int i = 0; i < 8; i++){
                  Arr_Data[i] = Arr_Data3[i];}break;
            case 10: for(int i = 0; i < 8; i++){
                  Arr_Data[i] = Arr_Data4[i];}break;
            case 11: for(int i = 0; i < 8; i++){
                  Arr_Data[i] = Arr_Data5[i];}break;
            case 12: for(int i = 0; i < 8; i++){
                  Arr_Data[i] = Arr_Data6[i];}break;
            case 13: for(int i = 0; i < 8; i++){
                  Arr_Data[i] = Arr_Data7[i];}break;
            case 14: for(int i = 0; i < 8; i++){
                  Arr_Data[i] = Arr_Data8[i];}break;
            case 15: for(int i = 0; i < 8; i++){
                  Arr_Data[i] = Arr_Data9[i];}break;
      }} // Sijoituksen loppu

      void Fun_Naytto(int j){
            Fun_Tyhjenna();
            Fun_Sijoita(j);
            for(int i = 0; i < 8; i++){
                  digitalWrite(Con_DS_Data, Arr_Data[i]);
                  digitalWrite(Con_SHCP_Kello, HIGH);
                  digitalWrite(Con_SHCP_Kello, LOW);
      }// Sarjakirjoitus loppu
      // Sarjadatan siirto lähtöihin
            digitalWrite(Con_STCP_Siirto, HIGH);
            digitalWrite(Con_STCP_Siirto, LOW);
      }// Näytön loppu

// Arvonnan aliohjema
      void Fun_Arvonta(){
            long Lng_Arpa = 0;
            int Int_Arpa = 0;
            int Int_No = 0;
            boolean Bol_Sama = false;
      do{
            Bol_Sama = false;
            Lng_Arpa = random(1, 10);
            Int_Arpa = Lng_Arpa;
            for(int k = 0; k < 9; k++){
                  if(Arr_Numerot[k] == Int_Arpa){
                        Bol_Sama = true;}}
                  if(Bol_Sama == false){
            Arr_Numerot[Int_No] = Int_Arpa;
            Int_No++;
            }
      }while(Int_No < 9);
      }//Arvonnan loppu


// ASETUKSET:
      void setup(){
            Serial.begin(9600);
            pinMode(Con_DS_Data, OUTPUT);
            pinMode(Con_SHCP_Kello, OUTPUT);
            pinMode(Con_STCP_Siirto, OUTPUT);
            randomSeed(analogRead(5));// Alustetaan sattuma anatulosta A5
            Fun_Tyhjenna();// Tyhjennetään 7-segmenttinäyttö
                  for(int i = 0; i < 9; i++){// Nollataan arvontataulukko
                        Arr_Numerot[i] = 0;
                  } // NOllaus loppu
      }// Asetuksen loppu

// PÄÄLOOPPI
void loop(){
// Painikkeiden luku
      Bol_PainVas = Fun_IO(1,PainVas,0);
      Bol_PainOik = Fun_IO(1,PainOik,0);

// Suorituksen hallintasekvenssi
      switch (Seq_Hallinta) {
      case 1: // Odotetaan käynnistystä
            Fun_Tyhjenna();
            if(Bol_PainVas == true && Bol_PainOik == true){
                  Seq_Hallinta = 2;
           }
      break;
      case 2: // Painikkeiden vapautus
          if (Bol_PainVas == false && Bol_PainOik == false){
                  for(int i = 0; i < 9; i++){
                       Arr_Numerot[i] = 0;}// Numerotaulukon tyhjennys
                        Seq_Hallinta = 3;
                  }
      break;
      case 3:// Näytön pyöräytys
            for(int k = 0; k < 3; k++){
                  for(int j = 0; j < 6; j++){
                        Fun_Naytto(j); delay(50);
            }}
            Fun_Tyhjenna();
            Seq_Hallinta = 4;
      break;
      case 4:// Numeroiden arvonta
            Int_Tauko = Fun_Viive(Int_Tauko);
            if (Int_Tauko > Con_Tauko){
                  Fun_Tyhjenna();
                  Fun_Arvonta();
                  Int_OikeaSumma = 0;
                  Seq_Hallinta = 5;
            }
      break;
      case 5:// Numeroiden testaus ja summaus
            for(int i = 0; i < 9; i++){
                  Int_Numero = Arr_Numerot[i];
                  Fun_Naytto(Arr_Numerot[i]+5);
            do{
                  Int_NayttoVii = Fun_Viive(Int_NayttoVii);
      //Oikean painikkeen käsittely
                  Bol_Tila = Fun_IO(1, PainOik, 0);
                  if(Bol_Tila == true && Diu_PainOik == false){
                        Diu_PainOik = true;
                        Int_OikeaSumma = Fun_VertaaOikea(Int_OikeaSumma, Int_Numero);
                  }// if painaminen
                  if(Bol_Tila == false){
                        Diu_PainOik = false;
                  }// if päästäminen
                  Bol_Tila = Fun_IO(1, PainVas, 0);
                  if(Bol_Tila == true && Diu_PainVas == false){
                        Diu_PainVas = true;
                        Int_VaaraSumma = Fun_VertaaVaara(Int_VaaraSumma, Int_Numero);
                  }// if päästäminen
                  if(Bol_Tila == false){
                        Diu_PainVas = false;
                  }// if päästäminen
            }while (Int_NayttoVii < Con_NayttoVii);
                  Int_NayttoVii = 0;
            }// for
                  Fun_Tyhjenna();
                  if(Int_OikeaSumma == 17 && Int_VaaraSumma == 28){
                        Seq_Hallinta = 6;
                  }else{
                        Seq_Hallinta = 7;
                  }
       break;
       case 6: // Oven avaus
            Fun_IO(2, LEDVih, HIGH);
            delay(2000);
            Fun_IO(2, LEDVih, LOW);
            Int_OikeaSumma = 0;
            Int_VaaraSumma = 0;
           Seq_Hallinta = 1;
      break;
      case 7: // Virheilmoitus
            for(int i = 0; i < 10; i++){
                  Fun_IO(2, LEDPun, HIGH);
                  delay(200);
                  Fun_IO(2, LEDPun, LOW);
                  delay(200);
            }
            Int_OikeaSumma = 0;
            Int_VaaraSumma = 0;
            Seq_Hallinta = 1;
      break;
      }// hallistasekvenssi loppu
      delay(1);
} // Pääohjelma LOPPU