RTCモジュールと電源リレーモジュールを使用して、特定の時間に接続している別の Arduino を起動してツイート

RTCモジュールと電源リレーモジュールを使用して、特定の時間に接続している別の Arduino を起動してツイートをします。

今回は電源リレーにつながっている Arduino から21時56分に起動してツイートするようにしてみました。
![FireShot Capture 053 - むぎ＠仕事垢さんはTwitterを使っています 「ぷいぷい 温度は 15℃ 気圧は 980 hPa だよ 気をつけて #Arduino」 _ - twitter.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115935/065e45f9-ed8d-eb0d-54af-0228366beb87.png)

接続方法

少しわかりにくいですが、左のメインの Arduino に RTC モジュールと電源リレーモジュールを付けて、電源モジュールの先にはツイート用の別の Arduino と電源供給用のモバイルバッテリーを付けています。
![EugqjE4VEAUyLqT.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115935/7fb9e730-feb1-8220-0036-665f0998cd28.jpeg)

本当はディープスリープなどで実現したいのですが、なんとなく家に電源リレーがあったのでやってみました。

使用機材
あとで書きます。

ソースコードはこちら

````c:PowerRelay.ino
// ========================================================================
// set pin value
// ========================================================================

#define CLK_PIN 8     //(基板上CLK⇒6番ピン)
#define DAT_PIN 7     //(基板上DAT⇒7番ピン)
#define RST_PIN 6     //(基板上RST⇒8番ピン)

#define RELAY_PIN 12  //(電源リレーIN1⇒12番ピン)

// ========================================================================
// set power on time
// ========================================================================

#define POWER_START_HOUR    21  // 電源オンの時間
#define POWER_START_MINUTES 56  // 電源オンの分

// setting date format
struct DateTime{

  boolean CH; //1でClockHalt(停止)だが、0を入れてこの機能使わない前提
  boolean Mode12; //1で12時間表示だが、0を入れて24時間表示で使う前提
  boolean WP; //1でWriteProtectだが0を入れてこの機能使わない前提

  int Date;
  int Month;
  int Week;
  int Year;
  int Seconds;
  int Minutes;
  int Hour;
  
};

// ========================================================================
// init
// ========================================================================
void setup() {

  //シリアル通信準備
  Serial.begin( 9600 );
  Serial.print( "start" );

  // setting power relay pin mode
  pinMode( RELAY_PIN , OUTPUT );
  digitalWrite( RELAY_PIN , LOW ); // power off

  // setting clock pin mode
  pinMode( RST_PIN, OUTPUT );
  pinMode( CLK_PIN, OUTPUT );

  // setting initial time
  //setYear(2021);setMonth(2);setDate(18);setHour(21);setMinutes(37);setSeconds(13);
  //setWeek(4); // 1:月 2:火 3:水 4:木 5:金 6:土 7:日

};

// ========================================================================
//
// ========================================================================
void loop() {

  Serial.print( "looping" );

  byte RTC_clock_image[8];
  DateTime myDateTime;

  read_rtc_byte(RTC_clock_image);
  extract_datetime(RTC_clock_image,myDateTime);

  //yyyy-mm-dd hh:ss:ii week
  Serial.print(myDateTime.Year);    Serial.print("-");
  Serial.print(myDateTime.Month);   Serial.print("-");
  Serial.print(myDateTime.Date);    Serial.print(" ");
  Serial.print(myDateTime.Hour);    Serial.print(":");
  Serial.print(myDateTime.Minutes); Serial.print(":");
  Serial.print(myDateTime.Seconds); Serial.print("(");
  Serial.print(myDateTime.Week);    Serial.println(")");

  // power relay start
  if(  myDateTime.Hour == POWER_START_HOUR && myDateTime.Minutes == POWER_START_MINUTES ){

    digitalWrite( RELAY_PIN , HIGH ); // power on
    Serial.println("start power on");

  }
  else{

    Serial.println("start power off");
    digitalWrite( RELAY_PIN , LOW ); // power off

  }
  
  delay(1000);

}

// ========================================================================
// set read date functions 
// ========================================================================

//RTCからクロックデータをまるごと読みだし、
byte read_rtc_byte(byte image[]){

  pinMode(DAT_PIN, OUTPUT);//DAT_PINのpinmodeをまず送信用で準備
  digitalWrite(RST_PIN, LOW);wait();//最初はRST_PIN下げた状態
  digitalWrite(RST_PIN, HIGH);wait();//開始（RST_PIN 上げ）
  write_1byte(0xbf);//バーストモードのコマンド0xbf送信

  //読み出しに移るのでDAT_PINのピンモード切り替える。CLK_PIN上げのまま
  pinMode(DAT_PIN, INPUT);

  //8byte分続けて読みbyte配列のimageに入れる
  for (int i=0; i<=7; i++){
  read_1byte(image[i]);

  }

  //RST_PIN下げる
  digitalWrite(RST_PIN, LOW); wait(); 

}

void write_1byte(byte data){

  //コマンド等送信　1ビットずつ繰り返し8ビット（1バイト）分送る
  for (int i=0; i <= 7; i++){

    digitalWrite(CLK_PIN, LOW);wait();  //LOW確認
    digitalWrite( DAT_PIN, bitRead(data, i));wait();
    digitalWrite(CLK_PIN, HIGH);wait();  //クロック（LOWからHIGH）で書き込む
    //クロック上げたままで関数を抜ける。

  }  

}

void read_1byte(byte &data){

  //データ受信　1ビットずつ繰り返し8ビット（1バイト）分読みだす
  data = 0;
  for (int i=0; i<=7; i++){ 
    digitalWrite(CLK_PIN, HIGH);wait();//clock上げ。（上げたまま引き継いだ時はそのまま）
    digitalWrite(CLK_PIN, LOW);wait();//clock下げて、
    bitWrite( data,i, digitalRead(DAT_PIN));//読む

    //クロック下げた状態で関数を抜ける
  }  

}

void setImage(byte command, byte image){ //コマンド、書き込みデータ

  pinMode(DAT_PIN, OUTPUT);//DAT_PINのpinmodeを送信用で準備
  digitalWrite(RST_PIN, LOW);wait();//最初はRST_PIN下げた状態
  digitalWrite(RST_PIN, HIGH);wait();//開始（RST_PIN 上げ）
  write_1byte(command);
  write_1byte(image); 
  digitalWrite(CLK_PIN, LOW);wait();//clock下げて、 
  digitalWrite(RST_PIN, LOW);wait();//最後はRST_PIN下げる

}

void getImage(byte command, byte &image){

  pinMode(DAT_PIN, OUTPUT);//DAT_PINのpinmodeを送信用で準備
  digitalWrite(RST_PIN, LOW);wait();//最初はRST_PIN下げた状態
  digitalWrite(RST_PIN, HIGH);wait();//開始（RST_PIN 上げ）
  write_1byte(command);
  pinMode(DAT_PIN, INPUT);//DAT_PINのpinmodeを受信用に切り替え
  read_1byte(image); 
  digitalWrite(RST_PIN, LOW);wait();//最後はRST_PIN下げる  

}

void wait(){

  //Vcc5Vなのでデータシート11ページから待ち時間は1μ秒分とっておけばよい。
  delayMicroseconds(1);

}

//byte配列からの情報抽出
void extract_datetime(byte image[], DateTime &TempDateTime){

  int data10, data1;

  //秒
  data10 = (image[0]>>4)&7; //上位4ビットを0111でマスクする。
  data1 = image[0] & 15; //下位4ビットを1111でマスクする。
  TempDateTime.Seconds =  (data10 * 10) + data1;
  TempDateTime.CH = image[0]>>7;

  //分
  data10 = (image[1]>>4)&7; //上位4ビットを0111でマスクする。
  data1 = image[1] & 15; //下位4ビットを1111でマスクする。
  TempDateTime.Minutes =  (data10 * 10) + data1; 

  //時
  data10 = (image[2]>>4)&3; //上位4ビットを0011でマスクする。
  data1 = image[2] & 15; //下位4ビットを1111でマスクする。
  TempDateTime.Hour =  (data10 * 10) + data1; 
  TempDateTime.Mode12 = image[2]>>7; //12時間表示モード。0にして使わない。

  //日
  data10 = (image[3]>>4)&3; //上位4ビットを0011でマスクする。
  data1 = image[3] & 15; //下位4ビットを1111でマスクする。
  TempDateTime.Date =  (data10 * 10) + data1; 

  //月
  data10 = (image[4]>>4)&1; //上位4ビットを0001でマスクする。
  data1 = image[4] & 15; //下位4ビットを1111でマスクする。
  TempDateTime.Month =  (data10 * 10) + data1; 

  //曜日
  TempDateTime.Week =image[5];

  //年
  data10 = (image[6]>>4) & 15; //上位4ビットを1111でマスクする。
  data1 = image[6] & 15; //下位4ビットを1111でマスクする。
  TempDateTime.Year =  (data10 * 10) + data1 + 2000; 

  //WP
  TempDateTime.WP =image[7]>>7; 

}

// ========================================================================
// set yyyy m d h s i
// ========================================================================

void setYear(int year){  // (ex. 2020
  setImage(0x8C, (((year - 2000)/10)<<4)+(year % 10));
}
void setWeek(byte Week){
  setImage(0x8A, Week); // 1:月 2:火 3:水 4:木 5:金 6:土 7:日
}
void setMonth(int month){ // 1-12
  setImage(0x88,((month/10)<<4)+(month % 10));
}
void setDate(int date){
  setImage(0x86,((date/10)<<4)+(date % 10));
}
void setHour(int hour){//0-23
  setImage(0x84,((hour/10)<<4)+(hour % 10));
}
void setMinutes(int minutes){
  setImage(0x82,((minutes/10)<<4)+(minutes % 10));  
}
void setSeconds(int seconds){
  setImage(0x80,((seconds/10)<<4)+(seconds % 10));  
}
~~~~

####参考リンク
- [リレー制御モジュールをArduinoから使う | Program Resource ](https://programresource.net/2015/05/02/2569.html)
- [RTCモジュール（DS1302）を試す（２）｜LiuK｜note ](https://note.com/liuk_net/n/na52a558f9847)