Slee-Piみたいなボード | Tamesuke-Goto Maker的Blog

Tamesuke-Goto Maker的Blog

地域ISP管理者だけれど、ここ3年ほどMakerなJobが増えたのでまとめてみたいと思います 旧ハンドル Ringoro

仕事でメカトラックスのSlee-Piを使ったのですが、残念ながら少々使いづらい点ががあって、ATTiny85を使って電源コントローラのSlee-Piをコントロールするボードを起こす事になりました。
機能的にはそれほど複雑ではないのでフリースペースをとって後から何か改造できる様なデザインしてみました。
この基板を元にSlee-Piみたいな事は出来ないかとちょとやってみました。

{4AA4E12D-625E-4600-B972-8089C1B103EE}

 

機能は

  • バッテリバックアップのリアルタイムクロック
  • 外部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);
  }  
}

 

===============================================