lauantai 25. helmikuuta 2017

Tosi lyhyt matikka!

Ohjelma kysyy käynnityksen jälkeen ensimmäistä lukua ja kehoittaa painamaan ENTteriä. Kun tämä on tehty näytetään kehoitus toisen luvun antamiseen. Toisen ENTterin jälkeen ohjelma laskee neljä laskutehtävää (summa, erotus, tulo ja osamäärä) ja näytön alarivin hallinta siirtyy ylös- ja alas-painikkeille. Näillä voidaan siirtyä edestakaisin noiden tulosten katselussa. Tästä tilasta paistutaan painamalla MENU-painiketta, jolloin ohjelma siirtyy kysymään ensimmäistä numeroa uudestaan. Suositeltavaa on käyttää lukualuetta välillä 1 .. 99, sillä ohjelma on ajateltu tällaista suoritusta varten. Rajoituksia ja tarkastuksia ei ohjelmassa ole, mutta kahden suuren luvun kertominen (tulo > 2exp15 = 32768) antaa tulokseksi negatiivisen luvun, koska käytetyt muuttujat ovat int-tyyppiä.
Tässä sovelluksessa sarjaluenta kehittyy hiukan pidemmälle. Sitä sovelletaan nelilaskimena. Hyviä laskimia voi ostaa edullisesti, joten jos nelilaskin olisi päämäärä, ei siinä olisi juuri järkeä. Tavoite onkin synnyttää luotettava luenta ja huolimatta pitkästä painamisesta (siis millisekuntiskaalassa), siihen reagoidaan ainoataan yhden ohjelmakierroksen ajan. Jos tätä toteutusta hiukan muuttamalla haluaisi käyttää johonkin ”järkevään”, voisi sen tehdä tulostamaan sattumanvaraisesti sekä oikeita sanoja että epäsanoja. Käyttäjä painaisi heti tulkinnan jälkeen kummasta on kyse. Aivoilta menee nimittäin kauemmin epäsanan kuin tutun sanan tulkitsemiseen. Myöhemmin voisi tulostaa aikaerot. Kyse on samasta ilmiöstä kun PUNAINEN kirjoitetaan vihreällä värillä ja sana pitäisi lukea ääneen, aiheuttaa se hiukan hankaluutta.
Näppäimistön painikejärjestys.
     Aluksi ajattelin tehdä kytkinvärähtelyn eliminoimisen huolella, mutta satojen painamisten yhteydessä ei syntynyt ainuttakaan virhetulkintaa, joten jätin sen pois kasvattamasta ohjelmaa. Se voitaisiin tehdä seuraaavasti: Kun ohjelma havaitsee painalluksen, tehdään uusi luenta vaikkapa viiden (5) millisekunnin kulutta, ja verrataan näin saatua kahta taulukkoa toisiinsa. Jos ne ovat yhteneväiset, hyväksytään tulkinta. Jos eivät, toistetaan uusi luenta, kunnes ne ovat samat.
     Toinen tavoite oli laajentaa kaksirivisen näytön mahdollisuuksia lisäämällä MENU-ominaisuus. Listaa voi selata ylös- ja alaspainikkeilla. Sivuttaisnuolet eivät ole käytössä tässä ohjelmassa.
     Ohjelma on hyvin aliohjelmapainotteinen. Pääohjelma ei käsitä juurikaan muuuta kuin aliohjelmakutsuja. Ensimmäisenä tunnistetaan, että jotain on painettu (Int_Nappain > 0). Sen jälkeen suljetaan uusi tunnistaminen (= painaminen jatkuu). Sitten ohjelma katsoo, onko kyse numerosta (Näppäin välillä 1 .. 10). Seuraaavaksi tunnistetaan muut painikkeet ja sijoitetaan niihin koodi. Tämän ryhmän viimeisenä suljetaan uusi luenta (Bol_NappVapa = false), jolloin uusi luenta estyy. Suraavaksi jäädään odottamaan painikkeiden vapautusta (ja eston vapauttamista). Pääohjelman lopuksi suoritetaan halutut aliohjelmaketjut (aliohjelma kutsuu toista aliohjelmaa).


Ohjelma kysyy käynnityksen jälkeen ensimmäistä lukua ja kehoittaa painamaan ENTteriä. Kun tämä on tehty näytetään kehoitus toisen luvun antamiseen. Toisen ENTterin jälkeen ohjelma laskee neljä laskutehtävää (summa, erotus, tulo ja osamäärä) ja näytön alarivin hallinta siirtyy ylös- ja alas-painikkeille. Näillä voidaan siirtyä edestakaisin noiden tulosten katselussa. Tästä tilasta paistutaan painamalla MENU-painiketta, jolloin ohjelma siirtyy kysymään ensimmäistä numeroa uudestaan. Suositeltavaa on käyttää lukualuetta välillä 1 .. 99, sillä ohjelma on ajateltu tällaista suoritusta varten. Rajoituksia ja tarkastuksia ei ohjelmassa ole, mutta kahden suuren luvun kertominen (tulo > 2exp15 = 32768) antaa tulokseksi negatiivisen luvun, koska käytetyt muuttujat ovat int-tyyppiä.

Aliohjelmat ovat tällä sivulla kokonaisina, sillä niitä on siten helpompi kopioida ja muokatta kuin etsiskellä eri paikoista. LCD-aliohjeman parametreihin EN ole lisännyt liukulukua, vaan osamäärän tulostus näytölle tapahtuu suoraan Fun_Laskenta-aliohjelman askeleesta kahdeksan (8). Saman aliohjelman askel neljä (4) voi halutessa tulostaa laskutoimitukset ohjelmointityökalun ruudulle testejä varten. Painikkeiden tunnistamista varten on oma aliohjelma (Fun_NappTulkki(int askel){). Sitä kutsutaan pääohjelmasta siten, että kutsuparametri ohjaa painiketta vastaavaan sekvenssin askeleeseen. Numerot (0 .. 9) käsitellään askeleessa 1 ja muille painikkeille on omat askeleensa. Aliohjelmien toimintaketjut lopetetaan syöttämällä sekvenssin valinta-arvoksi nolla (0).





OHJELMA 38
/*************************
* Ohjelma 38
* 23.02.2017
* Tosi lyhyt matikka
*************************/

// MÄÄRITTELYT:
// LCD-näyttö
#include <LiquidCrystal.h>
LiquidCrystal lcd(3, 2, 7,6,5,4);

// Muut määrittelyt
const int Con_Pit = 16; // Datataulukon pituus
int Int_Nappain = 0;
int Int_Numero = 0;
boolean Bol_NappPain = false;
boolean Bol_NappVapa = true;
int Int_LaskVaihe = 1; //Laskentatapahtuman vaihe
int Seq_Laskenta = 0;
int Seq_NappOhjaus = 0; // Näppäinten ohjaussekvenssi
int Int_NappOhjaus = 0; // Näppäimen numero
int Int_Luku1 = 0;
int Int_Luku2 = 0;
int Int_Summa = 0;
int Int_Erotus = 0;
int Int_Tulo = 0;
float Flo_Osamaara = 0.0;
float L1 = 0.0; float L2 = 0.0;

// ALIOHJELMAT
// Funktio Parallel IN serial OUT (Rinnan sisään, sarjassa ulos)
// SarjaIN_Ali_v3.No2Hel17
   int Fun_LueRsSu(int PL, int CP, int Data, int Pituus){
      int NappainNumero = 0;
      int i = 0;
      boolean Taulukko[Pituus];
      boolean Bitti = false;
   pinMode(PL, OUTPUT); // Rinnan -> sarja siirto, pinnin numero
   pinMode(CP, OUTPUT); // Kellotus, pinnin numero
   pinMode(Data, INPUT);// Dataluennan pinnin numero
// Rinnakkaisdatan siirto
   digitalWrite(PL, LOW);
   digitalWrite(PL, HIGH);
      for( i = 0; i < Pituus; i++){ // Sarjadatan talletus
      Taulukko[i] = digitalRead(Data);
   digitalWrite(CP, HIGH);
   digitalWrite(CP, LOW);
}// sarjaluennan loppu
   for( i = 0; i < Pituus; i++){ // Onko taulukossa 1-bitti
      if(Taulukko[i] == true){
         NappainNumero = Pituus - i; // "bittien kääntö"
      }// if oli 1-bitti loppu
   }// Näppäin numeron tulkinta 0 == 1
return NappainNumero;
}// Funtion loppu

// Lukujen käsittelyfunktio
void Fun_Laskenta(int askel, int painike){
   Seq_Laskenta = askel;
   switch (Seq_Laskenta) {
   case 1:
      Int_Luku1 = Int_Luku1 * 10 + painike - 1;
         if(Int_Luku1 < 10){
           Fun_LCD(11,1,10,Int_Luku1);
         }else{
            Fun_LCD(11,1,9,Int_Luku1);
         } // if Luvun pituusvalinnan loppu
   Seq_Laskenta = 0;
   break;
   case 2:
      Int_Luku2 = Int_Luku2 * 10 + painike - 1;
         if(Int_Luku2 < 10){
            Fun_LCD(11,1,10,Int_Luku2);
         }else{
            Fun_LCD(11,1,9,Int_Luku2);
         } // if Luvun pituusvalinnan loppu
   Seq_Laskenta = 0;
   break;
   case 3:
      Int_Summa = Int_Luku1 + Int_Luku2;
      Int_Erotus = Int_Luku1 - Int_Luku2;
      Int_Tulo = Int_Luku1 * Int_Luku2;
      L1 = Int_Luku1; L2 = Int_Luku2;
      Flo_Osamaara = L1 / L2;
   lcd.clear();
   Seq_Laskenta = 0;
   break;
      case 4: // Tämä askel on vain testiä varten, ei suorituksessa
      Serial.print("Summa =: "); Serial.println(Int_Summa);
      Serial.print("Erotus =: "); Serial.println(Int_Erotus);
      Serial.print("Tulo =: "); Serial.println(Int_Tulo);
      Serial.print("Osamaara =: "); Serial.println(Flo_Osamaara);
      Seq_Laskenta = 0;
   break;
   case 5: // Summa näyttöön
      Fun_LCD(4,0,0,0);
      Fun_LCD(11,0,8,Int_Luku1);
      Fun_LCD(5,0,11,0);
      Fun_LCD(11,0,14,Int_Luku2);
      Fun_LCD(6,1,0,0);
      Fun_LCD(11,1,10,Int_Summa);
   Seq_Laskenta = 0;
   break;
   case 6: // Erotus näyttöön
      Fun_LCD(23,1,0,0);
      Fun_LCD(7,1,0,0);
      Fun_LCD(11,1,11,Int_Erotus);
   Seq_Laskenta = 0;
   break;
   case 7: // Tulo näyttöön
      Fun_LCD(23,1,0,0);
      Fun_LCD(8,1,0,0);
      Fun_LCD(11,1,11,Int_Tulo);
   Seq_Laskenta = 0;
   break;
   case 8: // Osamäärä näyttöön
      Fun_LCD(23,1,0,0);
      Fun_LCD(9,1,0,0);
         lcd.setCursor(15, 1);
         lcd.print(Flo_Osamaara);
   Seq_Laskenta = 0;
   break;
   }// sekvenssin loppu
}// Laskentafunktion loppu

// Nappain_Ali_v1.No2Hel17
   void Fun_NappTulkki(int askel){
    Seq_NappOhjaus = askel;
    switch (Seq_NappOhjaus) {
   case 1: // Numerot 0 .. 9
      Fun_Laskenta(Int_LaskVaihe, Int_Numero);
      Seq_NappOhjaus = 0;
   break;
   case 2: // ENTER no: 10
      if(Int_LaskVaihe == 1){Fun_LCD(2,1,0,0);}
         Fun_LCD(22,1,9,0); // Luvun syöttöpaikan tyhjennys
         Int_LaskVaihe++;
      if(Int_LaskVaihe == 3){
         Fun_Laskenta(3, 0);
         Fun_Laskenta(5, 0);
         Int_LaskVaihe = 5;
      } // if Numeroiden sijoitus näyttöön
   Seq_NappOhjaus = 0;
   break;
   case 3: // Nuoli oikealle no: 11 (ei nyt käytössä)
      Seq_NappOhjaus = 0;
   break;
   case 4: // Nuoli ylös no: 12 (paluu tulostusmenussa)
      Fun_LCD(23,1,0,0);
      Int_LaskVaihe--;
         if(Int_LaskVaihe < 5){Int_LaskVaihe = 5;} // Rajoitus
         if(Int_LaskVaihe >= 5){Fun_Laskenta(Int_LaskVaihe, 0);}
            Seq_NappOhjaus = 0;
   break;
   case 5: // Nuoli vasemmalle no: 13 (ei nyt käytössä)
      Seq_NappOhjaus = 0;
   break;
   case 6: // Nuoli alas no: 14 (eteenpäin tulostusmenussa)
      Fun_LCD(23,1,0,0);
      Int_LaskVaihe++;
      if(Int_LaskVaihe > 8){Int_LaskVaihe = 8;}
      if(Int_LaskVaihe < 9){Fun_Laskenta(Int_LaskVaihe, 0);}
   Seq_NappOhjaus = 0;
   break;
   case 7: // MENU, keskipainike, no: 15 (paluu alkuun)
      Int_LaskVaihe = 1;
      Int_Luku1 = 0;
      Int_Luku2 = 0;
      Fun_LCD(3,0,0,0);
      Fun_LCD(23,1,0,0);
      Fun_LCD(1,1,0,0);
   Seq_NappOhjaus = 0;
   break;
   }// Näppäinohjaus loppu
}// Näppäimenkäsittelyfunktion loppu

// LCD aliohjelman määrittelyt
void Fun_LCD(int start, int rivi, int paikka, int data){
// Näytön valintasekvenssi
   int Seq_LCD = start;
   switch (Seq_LCD){
   case 1:
      lcd.setCursor(paikka, rivi);
      lcd.print("Luku 1:");
      Seq_LCD = 0;
   break;
   case 2:
      lcd.setCursor(paikka, rivi);
      lcd.print("Luku 2:");
   Seq_LCD = 0;
   break;
   case 3:
      lcd.setCursor(paikka, rivi);
      lcd.print("ANNA LUKU ja ENT!");
   Seq_LCD = 0;
   break;
   case 4:
      lcd.setCursor(paikka, rivi);
      lcd.print("LUKUJEN");
   Seq_LCD = 0;
   break;
   case 5:
      lcd.setCursor(paikka, rivi);
      lcd.print("ja");
   Seq_LCD = 0;
   break;
   case 6:
      lcd.setCursor(paikka, rivi);
      lcd.print("SUMMA ON:");
   Seq_LCD = 0;
   break;
   case 7:
      lcd.setCursor(paikka, rivi);
      lcd.print("EROTUS ON:");
   Seq_LCD = 0;
   break;
   case 8:
      lcd.setCursor(paikka, rivi);
      lcd.print("TULO ON:");
   Seq_LCD = 0;
   break;
   case 9:
      lcd.setCursor(paikka, rivi);
      lcd.print("OSAMAARA ON:");
   Seq_LCD = 0;
   break;
   case 11: // Lukujen tulostus(paitsi liukuluku)
      lcd.setCursor(paikka, rivi);
      lcd.print(data);
   Seq_LCD = 0;
   break;
   case 21:
      lcd.setCursor(paikka, rivi);
      lcd.print("   ");
   Seq_LCD = 0;
   break;
   case 22:
      lcd.setCursor(paikka, rivi);
      lcd.print("     ");
   Seq_LCD = 0;
   break;
   case 23:
      lcd.setCursor(paikka, rivi);
      lcd.print("                    ");
   Seq_LCD = 0;
   break;
   case 24: // Koko näytön tyhjennys
      lcd.clear();
   Seq_LCD = 0;
   break;
   }// Valintasekvenssin loppu
}// Funktion LCD loppu

// ASETUKSET:
void setup(){
Serial.begin(9600);
lcd.begin(20,2);
lcd.clear();
// Yläteksti näyttöön, suoritetaan kerran
Fun_LCD(3,0,0,0);
Fun_LCD(1,1,0,0);
}// Asetuksen loppu

// PÄÄLOOPPI
void loop(){

Int_Nappain = Fun_LueRsSu(8, 9, 10, Con_Pit); // luetaan näppäimistö
if(Int_Nappain > 0){Bol_NappPain = true;} // tunnistetaan painaminen
if(Bol_NappPain == true && Bol_NappVapa == true){ // suoritetaan
if(Int_Nappain > 0 && Int_Nappain < 11){
   Int_NappOhjaus = 1;
   Int_Numero = Int_Nappain;
}// Numerot loppu
   if(Int_Nappain == 11){Int_NappOhjaus = 2; }
   if(Int_Nappain == 12){Int_NappOhjaus = 3; }
   if(Int_Nappain == 13){Int_NappOhjaus = 4; }
   if(Int_Nappain == 14){Int_NappOhjaus = 5; }
   if(Int_Nappain == 15){Int_NappOhjaus = 6; }
   if(Int_Nappain == 16){Int_NappOhjaus = 7; }
Fun_NappTulkki(Int_NappOhjaus);
Bol_NappVapa = false;
}// Näppäinten hallinta loppu
if(Int_Nappain == 0){ // == ei mitään painettu
Bol_NappPain = false;
Bol_NappVapa = true;
}// if vapautuksen loppu
if(Seq_Laskenta == 3){ // Suoritetaan nelilaskenta
Int_LaskVaihe = 5;
Fun_Laskenta(Int_LaskVaihe, 0);
} // Laskennan loppu
delay(1);
} // Pääohjelma LOPPU


Ei kommentteja:

Lähetä kommentti