torstai 9. kesäkuuta 2016

”Arpakuutio”

Pyrkimykseni on tällä kerralla valottaa sattumalukukäskyn random(min, max) ja siihen liittyvän randomSeed(parametri) käyttöä sekä sarjana sisään ja rinnan ulos –piirin (74HC595) käyttöä 7-segmenttinäyttöelementin ohjauksessa. Tässä näyttömoduulissa on kahdeksan (8) LEDiä, joista seitsemällä muodostetaan luku 0 .. 9 ja näiden lisäksi piste. Näitä näyttöjä on saatavissa erilaisia ja erikokoisia. Eri tyypit poikkeavat myös kytkennältään. Tässä olen käyttänyt tyyppiä MAN4640A. Ohjaimen ja näyttöpiirin LEDien välissä on vastuspiiri, missä on 8 kpl 330 ohmin vastuksia. Jos tarvitaan useamman numeron näyttöjä, voidaan näitä piirejä kytkeä sarjaan. Arduinosta tarvitaan silti vain kolme lähtöpinniä.
Tällä piirilevyllä on myös sellaisia komponentteja (toinen painike ja kaksivärinen LED), joita en käytä tässä sovelluksessa. Niiden on tarkoitus tulla mukaan seuraavan kerran blogissa. Sähköiset kytkennät näkyvät oheisista kuvista. Tuon Vero-levy-hahmotelman mukaan ei kannata lähteä sellaisenaan kytkemään, sillä se kuuluu enemminkin osastoon: ”etsi viisi virhettä!” On siitä kyllä hyötyäkin, sillä on se enimmäkseen oikein. Paint-ohjelma on vain melko alkeellinen, joten myöhemmät korjaukset sillä on varsin hankalia.






 Asetuksessa olevalla käskyllä randomSeed(analogRead(5)); alustetaan sattumageneraattori. Parametrinä voi olla myös kiinteä luku, jolloin ”sattumasarja” on aina sama numerojono. Tätä voi käyttää testeissä, mutta muuten se ei ole mielekästä. Ohjekirja suosittelee parametriksi jotain vapaana olevaan pinniä. Tässä olen käyttänyt analogiatuloa 5. Vapaassa tulossa ilmenee kohinaa, jolloin lähtöluku on sattumanvarainen ja saatu lukusarja todella perustuu sattumaan. Varsinainen sattumakäsky random(min, max) suorittaa arpomisen. Min on lukualueen minimi ja max on suurin arvottava luku lisättynä yhdellä (1). Siksi tässä on rajana luku seitsemän (7), jolloin saadaan aikaan noppien lukualue. Sattumalukukäskyn arpoma luku voi olla hyvin suuri. Siksi muuttujan tulee olla tyyppiä long.

Käynnistyessään ohjelma alkaa pyörittää myötäpäivään kutakin segmentin (A..F, G poisluettuna) LEDiä peräjälkeen. Pistettä ei polteta lainkaan. Siksi LEDien talukossa oikean puoleisin bitti on nolla (0). Bitit ovat käänteisessä järjestyksessä, koska ensimmäinen taulukon bitti Arr_DataA[0] menee sarjasyötössä ensimmäisenä ja bitti 7 viimeisenä (8 bittiä, taulukon bitit 0 .. 7). Tällöin bitti 7 siirtyy viimeisenä muunnospiiriin ja siirtyy pistettä vastaavaan kohtaan Q0. Vastaava taulukkoluettelo on numeroista.
Kun ohjelma käynnistyy, käynnistyy pyörityssekvenssi, ja kun vasenta painiketta painetaan, pysähtyy pyöritys ja ohjelma hyppää arpomista vastaavaan numerosekvenssin askeleeseen. Kun painike päästetään, pysähtyy numerosekvenssi ja pyörityssekvenssi käynnistyy jälleen. Video antinarduvideo22. youtube.com havainnollistaa tapahtumaa parhaiten. Sekvenssiaskeleissa ladataan kukin taulukon bittijono ensin talukkoon Arr_Data[8], mikä välitetään aliohjelmalle varsinaista näyttöön tulostusta varten.

Pyörityssekvenssin viive käsitellään aliohjelmassa int Fun_Viive(int Viive){, mikä on nyt tyyppiä int (eikä void), koska se palauttaa (return) kokonaisluvun. Sinne välitetään kutsussa viiveen hetkelline arvo, sitä kasvatetaan aliohjelmassa ja palautetaan uusi arvo pääohjelmaan. Pääohjelmassa tutkitaan, onko raja-arvo ylitetty, ja jos on, niin hypätään seuraavaan asekeleeseen.





Ohjelma 22
/***************************************
 *  Ohjelma 22
 *  08.06.2016
 *  Noppa
 **************************************/

// MÄÄRITTELYT:
const int Con_PainVas = 2;
boolean Bol_PainVas = false;
int Seq_PainVas = 1;
const int Con_PainVasVii = 5;
int Int_PainVasVii = 0;

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

//Sekvenssin pyöritys
int Seq_Pyoritus = 1;
const int Con_PyorViive = 47;
int Int_PyorViive = 0;

// Numerosekvenssi
int Seq_Arpa = 0; // Näyttösekvenssiä ei käynnistetä alustuksessa
long Lng_Arpa = 0;
boolean Arr_Data[8] = {0,0,0,0,0,0,0,0};

// Näytön LEDit pyörityksessä
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};

// Numerot 1 .. 6
boolean Arr_Data1[8] = {0,0,0,0,1,1,0,0};
boolean Arr_Data2[8] = {0,1,1,1,0,1,1,0};
boolean Arr_Data3[8] = {0,1,0,1,1,1,1,0};
boolean Arr_Data4[8] = {1,1,0,0,1,1,0,0};
boolean Arr_Data5[8] = {1,1,0,1,1,0,1,0};
boolean Arr_Data6[8] = {1,1,1,1,1,0,1,0};

// ASETUKSET:
void setup(){                 
 Serial.begin(9600);         
 pinMode(Con_PainVas, INPUT);
 pinMode(Con_DS_Data, OUTPUT);
 pinMode(Con_SHCP_Kello, OUTPUT);
 pinMode(Con_STCP_Siirto, OUTPUT);
 randomSeed(analogRead(5)); // Sattumageneraattorin alustus
}// Asetuksen loppu

// PÄÄLOOPPI 
void loop(){
Lng_Arpa = random(1,7);
Bol_PainVas = digitalRead(Con_PainVas);

// KOSKETTIMEN-tilan käsittely
switch (Seq_PainVas) {
  case 1:
    if (Bol_PainVas == true){
      Int_PainVasVii ++;
        if (Int_PainVasVii > Con_PainVasVii){
          Seq_Pyoritus = 0; // Pysäytetään pyöritys
          Seq_Arpa = Lng_Arpa; // Valitaan näytettävä numero
          Fun_Tyhjenna(); // Tyhjennetään näyttö
          Int_PainVasVii = 0;
          Seq_PainVas = 2;
        }
    }
    break;
  case 2:
    if (Bol_PainVas == false){
          Seq_Arpa = 0; // Pysäytettän numeronäyttö
          Seq_Pyoritus = 1; // Käynnistettän pyöritys
          Seq_PainVas = 1;
    }
    break;
}// Vasen painike loppu

// Pyörityksen sekvenssi
switch (Seq_Pyoritus) {
  case 1:
   for(int i = 0; i < 8; i++){
    Arr_Data[i] = Arr_DataA[i];}
      Fun_Naytto();
      Int_PyorViive = Fun_Viive(Int_PyorViive);
      if (Int_PyorViive > Con_PyorViive){
        Int_PyorViive = 0;
        Seq_Pyoritus = 2;
      }
    break;
  case 2:
   for(int i = 0; i < 8; i++){
    Arr_Data[i] = Arr_DataB[i];}
      Fun_Naytto();
      Int_PyorViive = Fun_Viive(Int_PyorViive);
      if (Int_PyorViive > Con_PyorViive){
        Int_PyorViive = 0;
        Seq_Pyoritus = 3;
      }
    break;
  case 3:
   for(int i = 0; i < 8; i++){
    Arr_Data[i] = Arr_DataC[i];}
      Fun_Naytto();
      Int_PyorViive = Fun_Viive(Int_PyorViive);
      if (Int_PyorViive > Con_PyorViive){
        Int_PyorViive = 0;
        Seq_Pyoritus = 4;
      }
    break;
  case 4:
   for(int i = 0; i < 8; i++){
    Arr_Data[i] = Arr_DataD[i];}
      Fun_Naytto();
      Int_PyorViive = Fun_Viive(Int_PyorViive);
      if (Int_PyorViive > Con_PyorViive){
        Int_PyorViive = 0;
        Seq_Pyoritus = 5;
      }
    break;
  case 5:
   for(int i = 0; i < 8; i++){
    Arr_Data[i] = Arr_DataE[i];}
      Fun_Naytto();
      Int_PyorViive = Fun_Viive(Int_PyorViive);
      if (Int_PyorViive > Con_PyorViive){
        Int_PyorViive = 0;
        Seq_Pyoritus = 6;
      }
    break;
  case 6:
   for(int i = 0; i < 8; i++){
    Arr_Data[i] = Arr_DataF[i];}
      Fun_Naytto();
      Int_PyorViive = Fun_Viive(Int_PyorViive);
      if (Int_PyorViive > Con_PyorViive){
        Int_PyorViive = 0;
        Seq_Pyoritus = 1;
      }
    break;
}// Pyörityksen loppu

// Arvotun numeron sekvenssi
switch (Seq_Arpa) {
  case 1:
   for(int i = 0; i < 8; i++){
    Arr_Data[i] = Arr_Data1[i];}
      Fun_Naytto();
      break;
  case 2:
   for(int i = 0; i < 8; i++){
    Arr_Data[i] = Arr_Data2[i];}
      Fun_Naytto();
    break;
  case 3:
   for(int i = 0; i < 8; i++){
    Arr_Data[i] = Arr_Data3[i];}
      Fun_Naytto();
    break;
  case 4:
   for(int i = 0; i < 8; i++){
    Arr_Data[i] = Arr_Data4[i];}
      Fun_Naytto();
    break;
  case 5:
   for(int i = 0; i < 8; i++){
    Arr_Data[i] = Arr_Data5[i];}
      Fun_Naytto();
    break;
  case 6:
   for(int i = 0; i < 8; i++){
    Arr_Data[i] = Arr_Data6[i];}
      Fun_Naytto();
    break;
}// Numeronäytön loppu
delay(1);
} // Pääohjelma LOPPU

// FUNKTIOT
void Fun_Naytto(){
// Datan siirto sarjamuodossa
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 rinnakkaisiin lähtöihin
  digitalWrite(Con_STCP_Siirto, HIGH);
  digitalWrite(Con_STCP_Siirto, LOW);
}// Näytön loppu

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

int Fun_Viive(int Viive){
  Viive++;
  return(Viive);

}// Viiveen loppu

Ei kommentteja:

Lähetä kommentti