// Ovladani specialniho displeje (5x 7 segmentu + bargraf + 3 LED) // s budicem MAX7219 bez pouziti knihoven // // http://www.astromik.org/raspi/dis5x7/ //--------------------------------------------------------------------- // 12.3.2020 //===================================================================== #define data_pin 12 // Prirazeni pinu k displeji #define clk_pin 11 #define load_pin 10 // Graficka definice cisel na sedmisegmentovkach // 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 byte graf_def[10] = {0b01111110 , 0b00110000 , 0b01101101 , 0b01111001 , 0b00110011 , 0b01011011 , 0b01011111 , 0b01110000 , 0b01111111 , 0b01111011 }; byte D_pamet[8]; // V tomto poli se bitove uchovava aktualni stav vsech rozsvicenych segmentu na vsech zobrazovacich jednotkach a LED byte pozice_tecky; // Pocet desetinnych mist pro zobrazeni cisla (0 az 4) - na pozici 0 ale tecka nikdy nesviti long posledni_n; // Pri aktualizaci pozice desetinne tecky se znovu zobrazi posledni zadane cislo long vstup; // Zadane cislo pres seriovy terminal //================================================================================================= void setup() { Serial.begin(9600); pinMode(data_pin ,OUTPUT); pinMode(clk_pin ,OUTPUT); pinMode(load_pin ,OUTPUT); displej_init(); // Zakladni nastaveni displeje (vcetne jasu) displej_CLS(); // Zhasnuti displeje D_pamet[5] = 0; // Vsechny 3 horni LED zhasnout SPI_kom(6 ,D_pamet[5]); Serial.println(F("Ovladani ukazkoveho programu:")); Serial.println(F("-----------------------------")); Serial.println(F("Do serioveho terminalu se zadavaji prikazy a displej na ne reaguje.")); Serial.println(F("Priklady prikazu:")); Serial.println(F(" d0 ... zrusi desetinnou tecku u zobrazeneho cisla")); Serial.println(F(" n123 ... zobrazi cislo (\" 123\")")); Serial.println(F(" r10,15 ... zapis do registru (nastaveni maximalniho jasu)")); Serial.println(F(" d4 ... nastavi 4 desetinna mista (\"0.0123\")")); Serial.println(F(" d2 ... nastavi 2 desetinna mista (\" 1.23\")")); Serial.println(F(" n-57 ... zobrazi cislo \"- 0.57\"")); Serial.println(F(" b2 ... rozsviti 2 z 5 LED na bargrafu")); Serial.println(F(" l2,1 ... (na zacatku je male L) rozsviti prostredni LED")); Serial.println(F(" l2,0 ... (na zacatku je male L) zhasne prostredni LED")); Serial.println(F(" r4,38 ... znak \"C\" na 4. jednotce zprava - ostatni beze zmeny")); // testovaci ukazka zobrazeni cisla "45.678" pozice_tecky = 3; // kolik desetinnych mist se ma zobrazit zobraz_cislo(45678); // zobrazeni zadaneho cisla zobraz_bargraf(4); // rozsviceni 4 z 5 LED na bargrafu zobraz_LED(3,true); // rozsviti 3. LED nad displejem (pravou) } //================================================================================================= void loop() { if (Serial.available() == true) { delay(50); char funkce = Serial.read(); if (funkce == 'n') // Podprogram pro zobrazeni cisla { vstup = Serial.parseInt(); // Cislo v rozsahu -9999 az 99999 pro zobrazeni na displeji zobraz_cislo(vstup); } if (funkce == 'l') // Podprogram pro rozsveceni a zhasinani 3 LED { vstup = Serial.parseInt(); // Cislo LED (1,2, nebo 3) boolean sviti = Serial.parseInt(); // 1=rozsvit ; 0=zhasni zobraz_LED(vstup,sviti); } if (funkce == 'b') // Podprogram pro nastaveni bargrafu { vstup = Serial.parseInt(); // Pocet LED k rozsviceni zobraz_bargraf(vstup); } if (funkce == 'd') // Nastaveni polohy desetinne tecky { pozice_tecky = Serial.parseInt(); // Pocet desetinnych mist zobraz_tecku(); // Aktualizace zobrazeni cisla s novou pozici desetinne tecky } if (funkce == 'r') // Primy zapis do obvodu MAX7219 { vstup = Serial.parseInt(); // Adresa registru v obvodu MAX7219 (0 az 15) byte data = Serial.parseInt(); // Data k zapsani do registru SPI_kom(vstup, data); // Komunikacni podprogram } while (Serial.available()) Serial.read(); // Vymazani prijimaciho bufferu } } //================================================================================================= // Nastaveni pozice desetinne tecky a aktualizace prave zobrazeneho cisla (pripadne doplneni nul pred teckou nebo za teckou) // 0 .... bez desetinne tecky // 1 az 4 .... pocet desetinnych mist void zobraz_tecku() { pripoj_tecku(); zobraz_cislo(posledni_n); } //================================================================================================= // Ovladani 3 LED v horni casti displeje // (pozice jednotlivych bitu jsou prizpusobene plosnaku) void zobraz_LED(byte cislo_LED, boolean stav) { if (cislo_LED == 1) // Leva LED { if (stav == true) D_pamet[5] = D_pamet[5] | 0b01000000; else D_pamet[5] = D_pamet[5] & 0b10111111; } if (cislo_LED == 2) // Prostredni LED { if (stav == true) D_pamet[5] = D_pamet[5] | 0b00010000; else D_pamet[5] = D_pamet[5] & 0b11101111; } if (cislo_LED == 3) // Prava LED { if (stav == true) D_pamet[5] = D_pamet[5] | 0b00100000; else D_pamet[5] = D_pamet[5] & 0b11011111; } SPI_kom(6 ,D_pamet[5]); // Aktualizace stavu 3 LED } //================================================================================================= // Ovladani 5xLED bargrafu pod displejem // (pozice jednotlivych bitu jsou prizpusobene plosnaku) void zobraz_bargraf(byte cislo) { switch (cislo) { case 5: D_pamet[7] = 0b10011101; // Sviti vsech 5 LED (maximum) break; case 4: D_pamet[7] = 0b10011100; // Sviti 4 LED (vsechny krome prave LED) break; case 3: D_pamet[7] = 0b00011100; // Sviti 3 LED (prvni + druha + treti zleva) break; case 2: D_pamet[7] = 0b00001100; // Sviti 2 LED (prvni + druha zleva) break; case 1: D_pamet[7] = 0b00000100; // Sviti 1 LED (prvni vlevo) break; case 0: D_pamet[7] = 0b00000000; // Vsechno zhasnuto break; } SPI_kom(8 ,D_pamet[7]); // Aktualizace bargrafu } //================================================================================================= // Zobrazeni cisla na displeji // Uvodni nuly se nezobrazuji. (cislo 56 se zobrazi jako " 56") // Jedna nula pred desetinnou teckou se zobrazuje. Pri nastaveni napriklad 3 desetinnych mist a zobrazovanem cisle 6 ukaze displej " 0.006" // Nula pred desetinnou teckou se nezobrazi pouze v pripade zaporneho cisla se 4 desetinnymi misty: napriklad "-0,1234" se zobrazi jako "-.1234" ). // Znamenko minus se zobrazuje vzdycky na nejvyssi pozici (leva sedmisegmentovka). (-7 = "- 7") // Pri prekroceni minimalni nebo maximalni povolene hodnoty se na displeji vypise "- Err" nebo " Err". // Pri zobrazeni cisla bez desetinnych mist se desetinna tecka vpravo nezobrazuje. (78 = " 78") void zobraz_cislo(long cislo) { posledni_n = cislo; // Pamet posledniho zadaneho cisla kvuli aktualizaci zobrazeni pri zmene polohy desetinne tecky if (cislo < -9999) // Chyba: moc zaporne cislo { D_pamet[4] = 0b00000001; // Znamenko '-' na prvnim znaku zleva err(); return; } if (cislo > 99999) // Chyba: moc velke cislo { D_pamet[4] = 0b00000000; // Prvni znak zleva prazdny err(); return; } // Tady uz je cislo v prijatelnem intervalu (-9999 az 99999) boolean znamenko = false; // Zapamatovat si znamenko, ktere se pak zobrazi na 1. segmentovce zleva (index 4) if (cislo < 0) // Zaporna cisla ... { znamenko = true; // ... se prevedou na kladna, ale zapamatuje se znamenko cislo=abs(cislo); } boolean zobraz_nuly = false; // Nuly pred cislem se normalne nezobrazuji // Prepnutim na true se zacnou zobrazovat uz od 1.pozice zleva na displeji // ------------ Rad desetitisicu (nebo znamenka) - leva sedmisegmentovka)-------------------- if (pozice_tecky == 4) zobraz_nuly = true; // Pokud se ale jedna o nulu pred desetinnou teckou, tak se nuly zacnou zobrazovat if (cislo > 9999) { D_pamet[4] = graf_def[cislo / 10000]; cislo = cislo % 10000; zobraz_nuly = true; } else { if (zobraz_nuly == true and znamenko == false) D_pamet[4] = graf_def[0]; // Znak '0' else D_pamet[4] = 0; // nebo prazdny znak } // pripadne zaporne znamenko se zapise na pozici desetitisicu if (znamenko == true) D_pamet[4] = 0b00000001; // Znamenko "-" // ------------------ rad tisicu ---------------------- if (pozice_tecky == 3) zobraz_nuly = true; if (cislo > 999) { D_pamet[3] = graf_def[cislo / 1000]; cislo = cislo % 1000; zobraz_nuly = true; } else { if (zobraz_nuly == true) D_pamet[3] = graf_def[0]; // Znak '0' else D_pamet[3] = 0; // nebo prazdny znak } // ------------------- rad stovek ---------------------- if (pozice_tecky == 2) zobraz_nuly = true; if (cislo > 99) { D_pamet[2] = graf_def[cislo / 100]; cislo = cislo % 100; zobraz_nuly = true; } else { if (zobraz_nuly == true) D_pamet[2] = graf_def[0]; // Znak '0' else D_pamet[2] = 0; // nebo prazdny znak } // -------------------- rad desitek -------------------- if (pozice_tecky == 1) zobraz_nuly = true; if (cislo > 9) { D_pamet[1] = graf_def[cislo / 10]; cislo = cislo % 10; } else { if (zobraz_nuly == true) D_pamet[1] = graf_def[0]; // Znak '0' else D_pamet[1] = 0; // nebo prazdny znak } // ------- rad jednotek (prava sedmisegmentovka) ------- D_pamet[0] = graf_def[cislo]; pripoj_tecku(); // Na pozaovanou pozici jeste pripravi desetinnou tecku aktual_dis(); // Presype cele pole 'D_pamet[]' po seriove komunikaci do displeje } //================================================================================================= // Napis " Err"(pripadne zaporne znamenko zustava) void err(void) { D_pamet[3] = 0b00000000; // Prazdny znak na druhe jednotce zleva D_pamet[2] = 0b01001111; // 'E' na tretim znaku zleva D_pamet[1] = 0b00000101; // 'r' na ctvrtem znaku zleva D_pamet[0] = 0b00000101; // 'r' na patem znaku zleva aktual_dis(); } //================================================================================================= // Zakladni nastaveni displeje void displej_init(void) { digitalWrite(load_pin ,HIGH); SPI_kom(0b00001011, 7 ); // Scan limit: nejvyssi index ovladanych zobrazovacich jednotek (jako zobrazovaci jednotky se pocitaji i bloky LED na indexech 5 a 7) SPI_kom(0b00001001, 0 ); // Rezim NO-decode pro vsechny zobrazovaci jednotky i LED (prime nastavovani bitoveho zobrazeni) SPI_kom(0b00001100, 1 ); // 1= normal; 0= shutdown (zhasnuti a snizeni spotreby) SPI_kom(0b00001111, 0 ); // 0= normalni funkce displeje; 1=test displeje (vsechny segmenty a LED se rozsviti) SPI_kom(0b00001010, 4 ); // Jas displeje (0 az 15) } //================================================================================================= // K jedne sedmisegmentovce prida jeste desetinnou tecku, ostatni tecky smaze void pripoj_tecku(void) { for (byte i = 1; i < 5 ; i++) // (na nulte pozici tecka nikdy nesviti, proto zacina smycka od 1) { if (pozice_tecky == i) D_pamet[i] = D_pamet[i] | 0b10000000; // rozsvit nejvyssi bit else D_pamet[i] = D_pamet[i] & 0b01111111; // zhasni nejvyssi bit } } //================================================================================================= // Aktualizace displeje na zaklade globalniho pole 'D_pamet[]', ve kterem se uchovava stav vsech segmentu a LED void aktual_dis(void) { for (byte i = 0 ; i < 8 ; i++) SPI_kom(i+1 ,D_pamet[i]); } //================================================================================================= // Postupne odeslani 16 bitu na datovy pin // - Prvni bajt je adresa registru (funkce, nebo pozice sedmisegmentovky) // - Druhy bajt jsou data void SPI_kom(byte d_registr, byte d_data) { digitalWrite(load_pin, LOW); shiftOut(data_pin , clk_pin, MSBFIRST , d_registr); shiftOut(data_pin , clk_pin, MSBFIRST , d_data); digitalWrite(load_pin, HIGH); } //================================================================================================= // Zhasnuti displeje vcetne tecky (LED a bargraf zustavaji beze zmeny) void displej_CLS(void) { D_pamet[0] = 0; // rad jednotek D_pamet[1] = 0; // rad desitek D_pamet[2] = 0; // rad stovek D_pamet[3] = 0; // rad tisicu D_pamet[4] = 0; // rad deetitisicu // ... pro pripad, ze by se pri prikazu "displej_CLS()" mely zahasinat i LED, odkomentovat nasledujici radky: // D_pamet[5] = 0; // 3 LED nad displejem // D_pamet[7] = 0; // bargraf pod displejem aktual_dis(); }