機能的にはそれほど複雑ではないのでフリースペースをとって後から何か改造できる様なデザインしてみました。
この基板を元にSlee-Piみたいな事は出来ないかとちょとやってみました。

機能は
- バッテリバックアップのリアルタイムクロック
- 外部SWによる電源ON、シャットダウン
- 一定時間後に自動電源オフ
- 一定時間後に自動電源オン
回路はこんな感じ。。。でもこの通り配線していません。面倒なので抵抗省いたりRTCは市販品DS1307ボードをくっつけて試験したりしています。試作・思索中で最終版ではないのでテキトウではあります。レギュレータはATTiny用3.3Vのみ、RaspberryPi用電源は普通の5Vタイプをそのまま使うものとしています。
i2cの通信とGPIOのデジタル入力1chを使ってRaspberryPiとの間でやりとりをさせました。
スイッチ長押しのシャットダウン信号はGPIO13を通してRaspberryPiへ伝えています。
ATtiny85がi2cスレーブデバイス(アドレス0x5Bを設定)として動かしており、レジスタの構成は
byt0: 起動タイマー (分)
byt1: 起動タイマー (時間)
byt2: 起動タイマー (日)
byt3: 起動タイマーフラグ
byt4:シャットダウンタイマー(秒)
となります。指定は i2csetコマンドで行います。例えば、
i2cset 0x5B 0 60
i2cset 0x5B 3 1
i2cset 0x5B 4 10
sudo halt
としますと約10秒後に電源が落ちて、約60分後に電源が入りRaspberryPiがスタートします。
ATTiny85では使えるGPIOが少なく、RaspiberryPiのhaltを検出して電源オフ仕組みにはできなかったので、この様な使い方になってしまいました。ATTinyは時間が来たら無条件にOFFしますので、シャットダウンタイマーをセットした後は速やかにRaspi自らhaltをしておかないとなりません。
ATTiny側のクロックはどうしているか、というとi2cスレーブのATTinyからスレーブのDS1307を参照することが出来ないので、millis()関数で1msecをソフトでカウントしながら時間を測っています。なので、はっきり言いまして不正確です。8MHz内蔵クロックをそのまま使うので誤差は1000ppmとかでしょうか。起動時間などはアバウトになりますが絶対時刻についてはRTCから読み出すので支障は無いものと考えています。
ATTiny85側のスケッチはこちら
i2cの参考URL https://github.com/rambo/TinyWire
ATTiny85の書込時に 2.7V B.O.D はイネーブルにしておきます。それをしませんと元電源を抜いた時にRaspberryPi側に残留した+1.7V程度の電圧がmosfetを通して逆流してATTinyが動作しっぱなしになりリセットがされない変な状態になってしまいます。
スケッチ訂正入れました。時間計算の際オーバーフローしてしまうので定数にLを追加
しました。
===============================================
/*
*
* + ON Switch
SW ON Blink for RELAY controle
ATTiny85
RST |1---O---8| VCC
PCINT3/A3/D3 |2 7| D2/A1/INT0/PCINT2
PCINT4/A2/D4 |3 6| D1/PWM/PCINT1
GND |4-------5| D0/PWM/A0/PCINT0
*/
#include <TinyWireS.h>
#define I2C_SLAVE_ADDRESS 0x5B // the 7-bit address
#include "TinyWireS.h"
// #include <TimeLib.h>
#ifndef TWI_RX_BUFFER_SIZE
#define TWI_RX_BUFFER_SIZE ( 16 )
#endif
// #define led 3
#define FET 3 // GPIO FET pin
#define SW1 1 // PowerON SW
#define DOWN 4 // Shutdown Signal for Rpi
bool run=false;
char stopping=0;
/*
* bit0 ... min
* bit1 ... hour
* bit2 ... day
* bit3 ... WakeupSTART
* bit4 ... ShutDownTimer
*/
enum {mins,hours,days,wakereg,downreg};
volatile uint8_t i2c_regs[] =
{
0x01,
0x00,
0x00,
0x00,
0x00,
};
volatile byte reg_position;
const byte reg_size = sizeof(i2c_regs);
unsigned long tim;
unsigned long last;
unsigned long wakeup;
unsigned long downtimer=0;
unsigned long waketimer=0;
void requestEvent()
{
reg_position %= reg_size;
TinyWireS.send(i2c_regs[reg_position]);
reg_position++;
}
void receiveEvent(uint8_t howMany)
{
// Sanity check
if ((howMany < 1) || (howMany > TWI_RX_BUFFER_SIZE)) return;
reg_position = TinyWireS.receive();
howMany--;
while(howMany--)
{
reg_position %= reg_size;
i2c_regs[reg_position] = TinyWireS.receive();
reg_position++;
}
if(i2c_regs[downreg]){
downtimer=i2c_regs[downreg];
}
if(i2c_regs[wakereg]){
waketimer = i2c_regs[mins]*60L+i2c_regs[hours]*60L*60L+i2c_regs[days]*60L*60L*24L;
} else {waketimer=0;}
}
void blinkled(int p,int c,int dly);
void poweron(void);
void setup(){
tim = millis()/1000;
last =tim;
pinMode(FET,OUTPUT);
digitalWrite(FET ,LOW); // Normal Power OFF
pinMode(DOWN,OUTPUT);
pinMode(SW1, INPUT_PULLUP); // power on sw
blinkled(DOWN,3,300);
TinyWireS.begin(I2C_SLAVE_ADDRESS);
TinyWireS.onReceive(receiveEvent);
TinyWireS.onRequest(requestEvent);
}
bool timchk()
{
tim = millis()/1000;
if(tim==last)
return false;
last=tim;
return true;
}
/*
* Main Loop
*
*/
void loop()
{
TinyWireS_stop_check();
if(!stopping && !run && !digitalRead(SW1)){
delay(200);
if(!digitalRead(SW1)){
poweron();
}
}
if(!timchk())
return;
if(!run && (tim & 0x01)){
blinkled(DOWN,1,20);
}
if(run && downtimer){
downtimer--;
i2c_regs[downreg] = downtimer;
if(downtimer==0){
stopping=5;
digitalWrite(DOWN,HIGH);
}
}
if(!run && waketimer){
waketimer--;
blinkled(DOWN,1,20);
if(waketimer==0){
i2c_regs[wakereg]=0;
poweron();
}
}
if(stopping){
stopping--;
if(stopping==0){
digitalWrite(FET, LOW);
digitalWrite(DOWN, LOW);
run=false;
}
}
if(run && !digitalRead(SW1)&& !stopping ){
delay(2500);
if(!digitalRead(SW1)){
digitalWrite(DOWN, HIGH);
stopping=15;
} else {stopping = 0;}
}
}
/*
* Sub funcitons...
*/
void poweron()
{
digitalWrite(FET, HIGH);
digitalWrite(DOWN, LOW);
run=true;
}
void blinkled(int p,int c,int dly)
{
int i;
for(i=0;i<c;i++){
digitalWrite(p, HIGH);
delay(dly);
digitalWrite(p, LOW);
delay(dly);
}
}
===============================================