//=========================================================================================== // Zapinani, vypinani a RESET "Raspberry Pi 4" pomoci jednoho tlacitka pres ATtiny85 //=========================================================================================== // verze: 3.5.2020 // Detaily: http://www.astromik.org/raspi/rpi4_onoff // Video: https://youtu.be/KDIDN2p9lDw // // Zapojeni: //============= // ATtiny85 // +--\_/--+ // informacni LED - PB5 1| |8 Vcc - 5V napajeni z GPIO // Global_EN - PB3 2| |7 PB2 - ovladaci tlacitko proti GND (kvuli "Power-down sleep" rezimu musi byt pripojene na INT0=PB2) // GPIO25 (test internetu a bootovani) - PB4 3| |6 PB1 - GPIO14 (test, jestli RPi jeste bezi) // GND 4| |5 PB0 - PI_stop (zadost o korektni ukonceni systemu) // +-------+ // // // ATtiny RPi4 // GND <------------------- GND // Vcc <------------------- 5V // PB0 (PI_stop) -------- R/R ------> GPIO7 // PB1 (GPIO14) <------------------- GPIO14 // PB3 (Global_EN) -------------------> Global_EN // PB4 (pin_boot) <---- Pull-Down ---- GPIO25 // // R/R ......... delic napeti z 5V na 3V3 (napriklad 10k + 18k) // Pull-Down ... GPIO25 je hned po zapnuti pridrzovan v LOW stavu pomoci odporu 4k7 proti GND // // Pri pouziti informacni LED na pinu PB5 je nutne po nahrani programu prepsat FUSE: LFuse=0xE2, HFuse=0x5F, EFuse=0xFF // ISP programovani pak ale uz nebude mozne (pri potrebe prepsani programu se bude muset pouzit "vysokonapetovy" reset FUSE) // (detaily: http://astromik.org/raspi/refusatorv4/index.htm) // // Informacni LED signalizuje stav RPi: // Vypnute napajeni pro procesor .............................. LED je zhasnuta // Normalni beh ............................................... LED trvale sviti // System je uz zastaveny, ale procesor porad pod napetim ..... LED pravidelne blika s periodou 1 sekundy (strida 3:7 - delsi tma) // System nabiha .............................................. LED pravidelne blika s periodou 1 sekundy (strida 7:3 - delsi svetlo) // Po nabehu systemu je dostupny internet pro SSH ............. LED nekolikrat rychle zablika //============================================================================================================================================================== // Prirazeni pinu ATtiny #define pin_PI_stop 0 // Signal pro ukonceni RPi #define pin_GPIO14 1 // Vstup pro sledovani, jestli RPI bezi #define pin_tlacitko 2 // Vstup pro ovladaci tlacitko #define pin_Global_EN 3 // Signal pro vypnuti napajeni #define pin_boot 4 // Signal, ze je RPi plne nastartovane a pripadne, ze je k dispozici i internet #define pin_LED 5 // Informacni LED #define max_auto_off 60 // Pocet sekund, po kterych se na zastavenem systemu v RPi automaticky vypne i napajeni (max 6553 s - to je asi 100 minut) #define max_timeout 60 // Maximalni doba trvani v sekundach mezi vydanim pokynu pro vypnuti RPi a jeho skutecnym ukoncenim // Po vyprseni timeoutu se napajeni RPi vypne i v pripade, ze neni jeste korektne ukonceny system #include // Knihovny pro sleep rezim a probouzeni pomoci interruptu na pinu INT0 #include // Globalni promenne: byte trvani_stisku; // Mereni delky drzeni tlacitka - kvuli rozpoznani kratkeho nebo dlouheho stisku boolean predchozi_stav_tlacitka = HIGH; // Kvuli rozeznani sestupne hrany pri stisku tlacitka boolean stav_pwr; // Pamet jestli je RPi ve vypnutem stavu, nebo jesli je napeti pro procesor dostupne byte pocitadlo_timeout; // Ocekava se, ze se RPi do 60 sekund (max_timeout) od vydani pokynu k ukonceni skutecne vypne. Kdyby ne, ATtiny by se zaseklo v nekonecne smycce. Proto se po 60 sekundach vypne RPi natvrdo. unsigned int auto_off; // Odpocet smycek zastaveneho systemu pred automatickym vypnutim napajeni byte pocitadlo_smycek; // Jen pomocna promenna pro bliknuti LED kazdou 10. smycku pri nabehu byte faze; // Aktualni faze, ve ktere se nachazi RPi (podle toho se odviji blikani/sviceni LED) // 0 ... od zapnuti napajeni az do stavu, kdy se "pin_boot" poprve preklopi do HIGH // 1 ... nekolik sekund po rezimu 0, kdy "pin_boot" signalizuje dostupnost internetu // 2 ... pokud byla na "boot_pinu" znacka o dostupnosti internetu, zablika i infoLED // 3 ... RPi normalne bezi // 4 ... pomoci tlacitka byl vydan pokyn k ukonceni systemu // 5 ... system byl ukonceny programove nebo na dalku - bez stisku tlacitka // 6 ... napajeni pro procesor bylo vypnuto //============================================================================================================================================================== void setup(void) { pinMode(pin_PI_stop ,OUTPUT); pinMode(pin_Global_EN ,OUTPUT); pinMode(pin_LED ,OUTPUT); pinMode(pin_tlacitko ,INPUT_PULLUP); pinMode(pin_GPIO14 ,INPUT); // Bez Pull-Upu !!! (Pull_Up by pripojil 5V na GPIO pin v RPi) pinMode(pin_boot ,INPUT); // Bez Pull-Upu !!! (Pull_Up je zvenku pripojeny na 3,3V, takze zaroven kontroluje napajeci napeti pro procesor) digitalWrite(pin_PI_stop , HIGH); // Pri startu programu se nebude pozadovat ukonceni systemu (GPIO xx do HIGH) digitalWrite(pin_Global_EN , HIGH); // Pri startu programu se v RPi zapne napajeni (Global_EN do HIGH) digitalWrite(pin_LED , LOW); // Pri startu programu se na chvili zhasne Info LED stav_pwr = HIGH; // Pamet, ze je generator napeti v RPI zapnuty (Global_EN) faze = 1; // Nastala faze spousteni RPi pocitadlo_smycek = 0; // Pocitadlo smycek kvuli blikani LED pri nabehu } //============================================================================================================================================================== void loop(void) { if (digitalRead(pin_tlacitko) == LOW and predchozi_stav_tlacitka == HIGH) // Prave bylo stisknuto tlacitko { trvani_stisku = 0; // Vynulovani pocitadla trvani stisku predchozi_stav_tlacitka = LOW; // Priste se bude detekovat nabezna hrana delay(20); // Odruseni zakmitu tlacitka } if (digitalRead(pin_tlacitko) == LOW) // Pri stisknutem tlacitku bezi pocitadlo smycek { trvani_stisku ++; if (trvani_stisku > 10) // Po 1 sekunde drzeni tlacitka blikne informacni LED (signalizace, ze doslo k dlouhemu stisku) { trvani_stisku = 10; digitalWrite(pin_LED , LOW); // Zhasnout info LED delay(100); digitalWrite(pin_LED , HIGH); // Rozsvitit info LED delay(100); digitalWrite(pin_LED , digitalRead(pin_GPIO14)); // LED se nastavi do stavu podle GPIO14 (vypnuty system = zhasnuta, spusteny system = rozsvicena) while (digitalRead(pin_tlacitko) == LOW) // Cekani na uvolneni dlouze stisknuteho tlacitka {} } } if (digitalRead(pin_tlacitko) == HIGH and predchozi_stav_tlacitka == LOW) // Prave bylo uvolneno tlacitko { predchozi_stav_tlacitka = HIGH; // Priste se bude detekovat nabezna hrana delay(20); // Odruseni zakmitu tlacitka // vyhodnoceni delky stisku if (trvani_stisku < 10) // Stisk je kratsi, nez 1 sekunda { if (digitalRead(pin_GPIO14) == LOW) // Kdyz byl system pri kratkem stisku uz ukonceny, tak se nic nedeje { digitalWrite(pin_Global_EN , LOW); // Pouze pro pripad, ze by jeste nebylo vypnute napajeni RPi, tak se vypne (Global_EN do LOW) stav_pwr = LOW; // Pamet stavu napajeni do LOW digitalWrite(pin_LED , LOW); // Zhasnout info LED (RPi je vypnute) sleep(); // ATtiny muze klidne zase usnout } else // Pri kratkem stisku bylo RPi zapnute - vykona se vypinaci sekvence: { faze = 4; // Faze vypinani RPi po stisku tlacitka digitalWrite(pin_PI_stop, LOW); // Zadost o vypnuti pres STOP pin pocitadlo_timeout = max_timeout; // Do 60 sekund (max_timeout) by se mel na pinu GPIO14 objevit signal LOW (informujici, ze system je vypnuty) while (pocitadlo_timeout > 0 and digitalRead(pin_GPIO14) == HIGH) // Po dobu vypinani blika infoLED { pocitadlo_timeout --; digitalWrite(pin_LED , LOW); // (zhasnout) delay(300); digitalWrite(pin_LED , HIGH); // (rozsvitit) delay(700); } for (byte i = 0; i < 8 ; i++) // Po korektnim ukonceni systemu (nebo po vyprseni timeoutu) se jeste asi 6.5 sekundy pocka (zaverecne blikani ACT LED) { // Trochu rychlejsi blikani nez v predchozim pripade digitalWrite(pin_LED , HIGH); // (rozsvitit) delay(550); digitalWrite(pin_LED , LOW); // (zhasnout) delay(250); } digitalWrite(pin_PI_stop , HIGH); // Pozadavek na vypnuti RPi se zrusi digitalWrite(pin_Global_EN , LOW); // Natvrdo vypnout napajeni RPi (Global_EN do LOW) stav_pwr = LOW; // Pamet stavu napajeni do LOW digitalWrite(pin_LED , LOW); // Zhasnout info LED (RPi je vypnute) sleep(); // RPi je vypnute, ATtiny muze take usnout } } else // Stisk je delsi, nez 1 sekunda, provede se zapnuti napajeni a RESET { digitalWrite(pin_Global_EN , LOW); // Na chvilku vypnout a pak zapnout napajeni (Global_EN do HIGH) delay(200); // Chvilku pauza na dobeh zdroje digitalWrite(pin_Global_EN , HIGH); // Zapnout napajeni (Global_EN do HIGH) stav_pwr = HIGH; // Pamet stavu napajeni do HIGH faze = 1; // Po zapnuti napajeni nebo resetunastava spousteci faze s pomalym blikamim LED } } // Test ukonceni rezimu 1 (RPi nabehlo a testuje se, jestli je dostupny internet) if (faze == 1 and digitalRead(pin_boot) == HIGH) { faze = 2; // faze kontoly, dostupnosti internetu digitalWrite(pin_LED , HIGH); // InfoLED se trvale rozsvecuje boolean internet = false; // Pred zacatkem testu internet NENI dostupny // kdyz je dostupny internet, melo by se na boot_pinu objevit nekolik LOW impulzu dlouhych asi 100000 mikrosekund (0.1 sek) s HIGH mezerou asi 0,2 sek for (byte i = 0 ; i < 3 ; i++) // Provedou se 3 pokusy o zjisteni techto impulzu { unsigned long sirka_LOW = pulseIn(pin_boot , LOW, 400000); if (sirka_LOW > 70000 and sirka_LOW < 130000) // Staci, aby 1 pokus byl uspesny ... { internet = true; // ... a znacka o dostupnosti internetu se nastavi na TRUE } } if (internet == true) // Kdyz je internet dostupny, 15x se rychle zablika infoLEDkou { for (byte i = 0 ; i < 15 ; i++) { digitalWrite(pin_LED , LOW); // zhasnout delay(100); digitalWrite(pin_LED , HIGH); // rozsvitit delay(50); } } faze = 3; // nasleduje faze normalniho behu RPi (LED uz od predchozi faze sviti) delay(500); // bezpecnostni pauza pro preklenuti pripadneho vysilani impulzu z RPi na boot_pinu } if ((faze == 3 or faze == 5) and digitalRead(pin_boot) == LOW) // system byl vypnuty programem, nebo na dalku - bez pouziti tlacitka { faze = 5; // Pauza pred vypnutim napajeni auto_off --; // Odpocet automatickeho vypnuti napajeni if (auto_off % 10 == 0) digitalWrite(pin_LED, LOW); // ... info LED v tomto rezimu kazdou sekundu na 0,7 sekundy blikne if (auto_off % 10 == 7) digitalWrite(pin_LED, HIGH); if (auto_off == 0) { faze = 6; // Faze vypnuteho napajeni digitalWrite(pin_Global_EN , LOW); // Natvrdo vypnout napajeni RPi (Global_EN do LOW) stav_pwr = LOW; // Pamet stavu napajeni do LOW digitalWrite(pin_LED , LOW); // Zhasnout info LED (uz by ale mela byt vypnuta) sleep(); // Arduino usne a vzbudi se az dalsim stiskem tlacitka } } else { auto_off = max_auto_off * 10; // Kdyz system normalne bezi, odpocet se nastavuje na maximalni zadanou hodnotu } // ------------------------------------------------------- // obsluha informacni LED (na pinu PB5) pocitadlo_smycek ++; if (pocitadlo_smycek == 10) pocitadlo_smycek = 0; // pocitadlo smycek se kazdou sekundu nuluje if (faze == 1) // System v RPi nabiha ... { if (pocitadlo_smycek == 0) digitalWrite(pin_LED, HIGH); // ... info LED kazdou sekundu na 0,3 sekundy blikne if (pocitadlo_smycek == 3) digitalWrite(pin_LED, LOW); } if (stav_pwr == LOW) // Napajeni pro procesor je vypnute ... { digitalWrite(pin_LED, LOW); // ... info LED je zhasnuta } // ------------------------------------------------------- delay(100); // Jeden pruchod hlavni smyckou trva asi 0,1 sekundy } //============================================================================================================================================================== // Podprogram pro uspani a opetovne probuzeni ATtiny // Opsano ze stranek : // http://www.avrfreaks.net/forum/attiny85-wake-pin-interrupt-not-working void sleep() { MCUCR &= ~_BV(ISC01); MCUCR &= ~_BV(ISC00); // The low level of INT0 generates an interrupt request. ADCSRA &= ~_BV(ADEN); // ADC off MCUCR |= _BV(SM1); MCUCR &= ~_BV(SM0); // Select "Power-down" sleep mode sleep_enable(); // Enable sleep mode GIMSK |= _BV(INT0); // Enable External Interrupt INT0 sei(); // Enable all interrupts sleep_cpu(); // GO TO SLEEP cli(); // Disable all interrupts GIMSK &= ~_BV(INT0); // Disable External Interrupt INT0 sleep_disable(); // Disable sleep mode ADCSRA |= _BV(ADEN); // ADC on sei(); // Enable all interrupts } // Podprogram pro obslouzeni preruseni ISR(INT0_vect) { } //==============================================================================================================================================================