// Univerzalni Display - Teplomer s DS18B20 // (c) Copyright, Pavel Kaspar, 2022 // kaspar@pk.cz // version 0.1; 23.1.2022 #define PinData 9 // Data MM5450 = PB0 #define PinClock 10 // Clock MM5450 = PB1 #define PinDS 8 // Dallas = PD6 - rutiny cteni/zapisu 1-Wire jsou natvrdo !!! #define PinBright 7 // Jas displeje = PD5 = T1 - lze PWM #define PinBeep 6 // Beeper = PD4 = T0 #define PinTSel 4 // Tlacitko Sel = PD2 = INT0 #define PinTPlus 5 // Tlacitko Plus = PD3 = INT1 #define PinTMinus 14 // Tlacitko Minus = PB5 = MOSI // Prirazeni segmentu k pinum MM5450 // 0- 6, 7 X... // 8-14, 15 .X.. // 16-22, 23 ..X. // 24-30, 31 ...X // 32 - dvojtecka // 33 - tecka // 34 - N.C. byte Tabulka[16] = { // Pomocna tabulka pro vytvoreni znaku na displeji 0x3F,0x06,0x5B,0x4F, 0x66,0x6D,0x7D,0x07, 0x7F,0x6F,0x77,0x7C, 0x39,0x5E,0x79,0x71 }; boolean Dvojtecka; // Zobrazit dvojtecku ? boolean Tecka; // Zobrazit tecku ? boolean Nastaveno; // Urcuje, zda probehlo nastaveni hodin po reset/vypadku proudu byte Hodina; // Pro vyuziti Displeje jako hodiny byte Minuta; byte Sekunda; static union { // Buffer pro cteni/zapis dat do DS18x20 byte DataBuffer[9]; int TeplotaDS; // Na zacatku Bufferu je teplota ve formatu DS }; unsigned long Pom; // Pomocna promenna pro nacteni millis - pro hodiny // -------------------------------------------------------------------- void Clock_Pulse() { delay(1); digitalWrite(PinClock, HIGH); delay(1); digitalWrite(PinClock, LOW); } void Zhasni_display() { digitalWrite(PinData, HIGH); // Start bit = "1" Clock_Pulse(); digitalWrite(PinData, LOW); for (byte i = 0; i < 35; i++) { // Zhasni display Clock_Pulse(); } } void Zobraz(unsigned long Cislo) { // Zobrazi bitovou reprezentaci predanou jako parametr digitalWrite(PinData, HIGH); // Start bit = "1" Clock_Pulse(); for (byte i = 0; i < 32; i++) { digitalWrite(PinData, (Cislo % 2)); Clock_Pulse(); Cislo = Cislo >> 1; } digitalWrite(PinData, Dvojtecka); Clock_Pulse(); digitalWrite(PinData, Tecka); Clock_Pulse(); digitalWrite(PinData, LOW); Clock_Pulse(); } void Zobraz_Cislo(unsigned int Cislo) { // Zobraz cislo v parametru unsigned int Zbytek; unsigned long Vysledek; Vysledek = 0; for (byte i = 0; i < 4; i++) { // Vygeneruj bitovou reprezentaci Zbytek = Tabulka[Cislo % 10]; Cislo = Cislo / 10; Vysledek = Vysledek << 8; Vysledek = Vysledek + Zbytek; } Zobraz(Vysledek); // a zobraz ji } void Zobraz_Cas() { // Zobraz cas v promennych (Hodina,) Minuta, Sekunda unsigned long Vysledek; Vysledek = Tabulka[Sekunda % 10]; Vysledek = Vysledek << 8; Vysledek = Vysledek + Tabulka[Sekunda / 10]; Vysledek = Vysledek << 8; Vysledek = Vysledek + Tabulka[Minuta % 10]; Vysledek = Vysledek << 8; if (Minuta >= 10) { Vysledek = Vysledek + Tabulka[Minuta / 10]; // Nezobrazuj pocatecni nulu } Zobraz(Vysledek); } void Zobraz_Teplotu(int TempDS) { // Zobraz Teplotu predanou v parametru ve formatu DS18B20 unsigned int long Vysledek; // Promenna pro prekodovane znaky na displeji unsigned int Desetiny; // Pomocna promenna pro desetiny a setiny stupnu unsigned int Temp; boolean Zaporna; // Je teplota Zaporna ? boolean Sto_a_vice; // Je vyssi nez 100 stupnu ? = jiny format zobrazeni boolean Deset_a_vice; // Je vyssi nez 10 stupnu ? = jiny format zobrazeni Vysledek = 0; Zaporna = TempDS < 0; Temp = (abs(TempDS) >> 4) & 0x7F; // Stupne - bez desetin Desetiny = (abs(TempDS) & 0x0F) * 625; // Desetiny a setiny stupne Sto_a_vice = Temp >= 100; Deset_a_vice = Temp >= 10; Temp = (Temp * 100) + (Desetiny / 100); // Preved na setiny stupnu for (byte i = 0; i < 4; i++) { Vysledek = Vysledek << 8; Vysledek = Vysledek + Tabulka[Temp % 10]; // Prekoduj na displej Temp = Temp / 10; } if (Sto_a_vice) { // 100,0 .. 127,9 Vysledek = Vysledek << 8; // Budou se zobrazovat desetiny Vysledek = Vysledek + Tabulka[1]; // Na zacatku je "1" = stovka Vysledek = Vysledek | 0x800000; // Desetinna tecka } else { // 0,00 .. 99,93 if (!Deset_a_vice) { // 0,00 .. 9,93 Vysledek = Vysledek & 0x0FFFFFF00; // Potlaceni prvni nuly pri hodnotach 0..9,93 Vysledek = Vysledek | 0x8000; // Desetinna tecka } else { // 10,00 .. 99,93 -> zobraz xx.xx nebo -xx.x if (Zaporna) { Vysledek = Vysledek << 8; // -xx.x Vysledek = Vysledek | 0x800000; // Desetinna tecka } else Vysledek = Vysledek | 0x8000;// Desetinna tecka } } if (Zaporna) { // Zaporna teplota -> zobraz znamenko Minus Vysledek = Vysledek | 0x40; // Znamenka Minus } Zobraz(Vysledek); } // -------------------------------------------------------------------- void Pip(unsigned int Delka) { // Pipne do reprodutoru for (byte i = 0; i < Delka; i++) { digitalWrite(PinBeep, LOW); delay(8); digitalWrite(PinBeep, HIGH); delay(8); } digitalWrite(PinBeep, LOW); } // -------------------------------------------------------------------- Rutiny pro obsluhu 1-Wire sbernice // Casy podle doporuceni v Application Notes AN126 byte OneWire_Reset () { byte Data; DDRD = DDRD | 0x40; // Prepni PinDS do OUTPUT = OneWire do LOW delayMicroseconds(480); DDRD = DDRD & 0xBF; // Prepni PinDS do INPUT = uvolni OneWire sbernici -> Pull-Up pres rezistor 4k7 delayMicroseconds(70); Data = (PIND >> 6) & 0x01; // 0 => Senzor pritomen delayMicroseconds(410); return Data; } byte OneWire_Read_Byte () { byte Data; Data = 0; for (int i = 0; i < 8; i++) { DDRD = DDRD | 0x40; // Prepni PinDS do OUTPUT = OneWire do LOW delayMicroseconds(6); DDRD = DDRD & 0xBF; // Prepni PinDS do INPUT = uvolni OneWire sbernici -> Pull-Up pres rezistor 4k7 delayMicroseconds(9); Data = Data | ((PIND >> 6) & 0x01) << i; delayMicroseconds(55); } return Data; } void OneWire_Write_Byte (byte Data) { for (int i = 0; i < 8; i++) { if ((Data & 0x01) == 0) { // Zapis 0 DDRD = DDRD | 0x40; // Prepni PinDS do OUTPUT = OneWire do LOW delayMicroseconds(60); DDRD = DDRD & 0xBF; // Prepni PinDS do INPUT = uvolni OneWire sbernici -> Pull-Up pres rezistor 4k7 delayMicroseconds(10); } else { // Zapis 1 DDRD = DDRD | 0x40; // Prepni PinDS do OUTPUT = OneWire do LOW delayMicroseconds(6); DDRD = DDRD & 0xBF; // Prepni PinDS do INPUT = uvolni OneWire sbernici -> Pull-Up pres rezistor 4k7 delayMicroseconds(64); } Data = Data >> 1; } } byte Vypocti_CRC () { // Vypocti CRC Bufferu - Vyjde-li 0, je CRC v poradku byte CRC = 0; for (int j = 0; j < 9; j++) { CRC = CRC ^ DataBuffer[j]; for (int i = 0; i < 8; i++) if (CRC & 0x01) CRC = CRC >> 1 ^ 0x8C; else CRC = CRC >> 1 ^ 0x00; } return CRC; } void Zmer_Teplotu () { // Nacte teplotu z jednoho cidla DS18B20 cli(); // Zakaz preruseni if (OneWire_Reset() != 0) { // Zadna odezva na prikaz Reset -> na sbernici neni zadny senzor sei(); // Povol preruseni TeplotaDS = 0xF9C1; // Nastav do Bufferu chybovy priznak = -99,9 } else { OneWire_Write_Byte(0xCC); // Prikaz Skip ROM OneWire_Write_Byte(0x44); // Prikaz Convert T while (OneWire_Read_Byte() != 0xFF); // Nefunguje pro Parazitni napajeni -> pouzit delay(750) // delay(750); OneWire_Reset(); OneWire_Write_Byte(0xCC); // Prikaz Skip ROM OneWire_Write_Byte(0xBE); // Prikaz Read Scratchpad for (int i = 0; i < 9; i++) { // Nacti Scratchpad (9 bajtu) z 1-Wire do Bufferu DataBuffer[i] = OneWire_Read_Byte(); } sei(); // Povol preruseni if (Vypocti_CRC() != 0) { // Chyba CRC TeplotaDS = 0xF9C3; // Nastav do Bufferu chybovy priznak = -99,8 } } } void setup() { pinMode(PinData, OUTPUT); // Nastaveni I/O pinu digitalWrite(PinData, LOW); pinMode(PinClock, OUTPUT); digitalWrite(PinClock, LOW); // pinMode(PinBright, OUTPUT); pinMode(PinBeep, OUTPUT); digitalWrite(PinBeep, LOW); pinMode(PinDS, OUTPUT); // Priprava pinu pro 1-Wire komunikaci = teplotni cidlo digitalWrite(PinDS, LOW); pinMode(PinDS, INPUT); pinMode(PinTSel, INPUT); pinMode(PinTPlus, INPUT); pinMode(PinTMinus, INPUT); for (byte i = 0; i < 36; i++) { // Pro pripad resetu uprostred vysilani na displej Clock_Pulse(); } Zhasni_display(); Dvojtecka = false; Tecka = false; Nastaveno = false; Hodina = 0; Minuta = 0; Sekunda = 0; } void loop() { Zmer_Teplotu(); Zobraz_Teplotu(TeplotaDS); /* Pom = millis(); // Zobrazovani casu od startu systemu Dvojtecka = (Pom % 1000) > 500; Pom = Pom / 1000; Sekunda = Pom % 60; Pom = Pom / 60; Minuta = Pom % 60; Pom = Pom / 60; Hodina = Pom % 24; Zobraz_Cas(); /* */ }