0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

digisparkもどき - 電波時計(D606C)

Last updated at Posted at 2026-01-14

Digisparkもどき - 温湿度計付き時計(DHT11 DS1307)を電波時計にしました。aitendoのD606Cを使いました。
PXL_20260114_093434861~2.jpg

私の家は木造です。作業テーブルから高くすると電波をつかみました。

D606Cの動作チェック

出力信号にLEDをつけてチェックします。
最初は、動きませんでした。

  • 5Vでは動作しない
  • TPは信号を出さない
  • Fは反対
  • TPをDigisparkもどきにつないでおくと動作しない
  • 使った電源が弱かった(PsLab)

など、なかなか難しかったです。
かっぱのひとりごとさんのところが参考になりました。
うまくいくと、TNからの信号でLEDが点滅します。

回路

2kΩと1kΩで分圧しました。レベル変換モジュールでTNをdigisparkもどきに入力しました。回路チェックプログラムでチェックできます。

プログラム

 受信処理は長いのでI2C slave化はできずmasterで動かします。
 よかひよりさんのを改変して作りました。
 電波受信チェックプログラムで電波の強いところを見つけます。スマホのJJYエミュレータでまず試しました。
 2分間続けて受信成功するとDS1307(RTCモジュール)に書き込みます。

#include <Wire.h>
#include <DS1307.h>
#include <LCD_I2C.h>
LCD_I2C lcd(0x23, 16, 2);
DS1307 clock;

char curr; //現在の読み込み値
char prev = HIGH; //前回の読み込み値
long c_time = 0; //ループ処理の経過時間
long p_time = 0; //前回のループ処理の経過時間
long s_time = 0; //ループ処理の経過時間の差分
char m01_code = '0'; //コード仕分け値(M、0、1)
int rp; //秒のカウント
int ct = 0; //ループ回数のカウント、積算値
int ct_prev = 0; //前回ループ時の回数
int ct_subt = 0; //ループ回数の差分、正常読み込みであれば毎ループ終了時は「60」
int st_rec = 0;  //受信フラグ(初期化、成功、失敗)
char bits[61]; //60間の読み込み値格納、null終端

struct res {
  byte min;
  byte hour;
  byte day;
  int year;
  byte weekday;
} prev_res, cur_res;

void setup() {
  pinMode(1,INPUT);
  bits[60] = 0;

  lcd.init();
  clock.begin();
  
  clock.fillByYMD(2026, 1, 2); //Jan 19,2013
  clock.fillByHMS(18, 24, 0); //15:28 30"
  clock.fillDayOfWeek(FRI);//Saturday
  clock.setTime();//write time to the RTC chip
  
  Wire.begin();
}

void success() {
  cur_res = {};
  //配列bitsから1bit毎に時刻データ取り出し、重みづけ
  //分
  if (bits[8] == '1') { cur_res.min += 1; }
  if (bits[7] == '1') { cur_res.min += 2; }
  if (bits[6] == '1') { cur_res.min += 4; }
  if (bits[5] == '1') { cur_res.min += 8; }
  if (bits[3] == '1') { cur_res.min += 10; }
  if (bits[2] == '1') { cur_res.min += 20; }
  if (bits[1] == '1') { cur_res.min += 40; }
  //時
  if (bits[18] == '1') { cur_res.hour += 1; }
  if (bits[17] == '1') { cur_res.hour += 2; }
  if (bits[16] == '1') { cur_res.hour += 4; }
  if (bits[15] == '1') { cur_res.hour += 8; }
  if (bits[13] == '1') { cur_res.hour += 10; }
  if (bits[12] == '1') { cur_res.hour += 20; }
  //通算日
  if (bits[33] == '1') { cur_res.day += 1; }
  if (bits[32] == '1') { cur_res.day += 2; }
  if (bits[31] == '1') { cur_res.day += 4; }
  if (bits[30] == '1') { cur_res.day += 8; }
  if (bits[28] == '1') { cur_res.day += 10; }
  if (bits[27] == '1') { cur_res.day += 20; }
  if (bits[26] == '1') { cur_res.day += 40; }
  if (bits[25] == '1') { cur_res.day += 80; }
  if (bits[23] == '1') { cur_res.day += 100; }
  if (bits[22] == '1') { cur_res.day += 200; }
  //西暦(下2桁)
  if (bits[48] == '1') { cur_res.year += 1; }
  if (bits[47] == '1') { cur_res.year += 2; }
  if (bits[46] == '1') { cur_res.year += 4; }
  if (bits[45] == '1') { cur_res.year += 8; }
  if (bits[44] == '1') { cur_res.year += 10; }
  if (bits[43] == '1') { cur_res.year += 20; }
  if (bits[42] == '1') { cur_res.year += 40; }
  if (bits[41] == '1') { cur_res.year += 80; }
  //曜日
  if (bits[52] == '1') { cur_res.weekday += 1; }
  if (bits[51] == '1') { cur_res.weekday += 2; }
  if (bits[50] == '1') { cur_res.weekday += 4; }

  boolean fault = false;
  if (cur_res.min != prev_res.min || cur_res.hour != prev_res.hour ||
      cur_res.day != prev_res.day || cur_res.year != prev_res.year ||
      cur_res.weekday != prev_res.weekday) {
    fault = true;
  }
  
  //1分加算と分、時、日、年、うるう年、曜日への影響反映
  //西暦(4桁)
  int ayear = ( cur_res.year + 2000 ) ;
  int leap_year = ( (1 / (ayear % 4 + 1)) * (1 - 1 / (ayear % 100 + 1)) + (1 / (ayear % 400 + 1)) );

  cur_res.min++; //1分加算
  if (cur_res.min >= 60) {
    cur_res.min=0;
    cur_res.hour++;
    if (cur_res.hour >= 24) {
      cur_res.hour = 0;
      cur_res.day++;
      int set_year = ( 365 + leap_year );
      if (cur_res.day > set_year ) {
        cur_res.day = 1;
        cur_res.year++;
      }
      cur_res.weekday++;
      if (cur_res.weekday >= 7) {
        cur_res.weekday = 0;
      }
    }
  }
  //通算日から月、日への変換
  int t_day = 0; //通算日の計算用
  int mm; //月
  int dd; //日
  int mdtable[2][12] = { 31,28,31,30,31,30,31,31,30,31,30,31, 31,29,31,30,31,30,31,31,30,31,30,31 }; //通年とうる年の日数
  //1月から順に月の日数を引いて月、日を算出
  for(int i = 0; i < 12; i++) {
    if ((t_day + mdtable[leap_year][i]) >= cur_res.day) {
      mm = i + 1;
      dd = cur_res.day - t_day;
      break;
    }
    t_day = t_day + mdtable[leap_year][i];
  }

  if (!fault) {
    clock.fillByYMD(ayear, mm, dd);
    clock.fillByHMS(cur_res.hour, cur_res.min, rp);
    clock.fillDayOfWeek(cur_res.weekday);
    clock.setTime();
  }

  prev_res = cur_res;
}

void loop() {
  //D2ポートから受信データの読み込み
  curr = digitalRead(1);
  //前回読み込み値と現在の読み込み値の比較
  if (prev != curr) {
    c_time = millis(); //ループ処理の経過時間(ms) 
    s_time = c_time - p_time;
    if (curr != HIGH) {
      printTime();
      printTemp();
    } else {
      //コード仕分け(パルス幅:M、P0~P5 200ms < 1:500ms < 0:800ms )
      //、P0~P5 (200ms)の判定:マージンを見込んで(300ms)
      if (s_time < 280) { //マージンを見込んで300ms
        ct++;
        //前のコードがMか(Mが2回続いているか)のチェック、初期マーカー位置の判定
        //毎時15分と45分のコールサイン(モールス符号)受信時にctとct_prevの値はリセット
        if ( m01_code == 'M' ) {
          rp = 0; //60回(秒のカウント)のリセット、初期マーカー位置
          ct_subt = ct - ct_prev;
          byte mp_chk = 0;
          if (bits[0] == 'M' && bits[9] == 'M' && bits[19] == 'M' && bits[39] == 'M' && bits[49] == 'M' && bits[59] == 'M') { 
            mp_chk = 1;
          } else{
            mp_chk = 2; 
          }
          //60秒間のデータが揃ったか、マーカー位置チェックOKかの判定
          if ( ct_subt == 60 && mp_chk == 1) {
            st_rec  = 1; //受信フラグ:成功
            success();
          } else {
            //配列クリア
            for(byte i = 0; i < 60; i++) {
              bits[i] = ' ';
            }
            //受信フラグ:失敗
            st_rec  = 9;
          }
          ct_prev = ct; 
        }
        m01_code = 'M';
        if (rp < 60)
          bits[rp] = 'M'; //rp番目の配列に格納
        rp++; //60ループ回のカウントアップ
        //1(500ms)の判定:マージンを見込んで(600ms)
      } else if (s_time < 590) {
        ct++;
        //        lcd.print( "1" );
        if (rp < 60)
          bits[rp] = '1'; //rp番目の配列に格納
        m01_code = '1';
        rp++; //60回ループのカウントアップ
        //0(800ms)の判定
      } else if (s_time < 1000) {
        ct++;
        //lcd.print( "0" );
        if (rp < 60)
          bits[rp] = '0'; //rp番目の配列に格納
        m01_code = '0'; 
        rp++; //60回ループのカウントアップ
      } else {
        lcd.print(s_time);
      }
    }
  }
  prev = curr;  //現在の読み込み値を保存
  p_time = c_time; //現在の経過時間(ms)を保存
}

struct vals {
  int result;
  int temperature;
  int humidity;
};

union uni {
  struct vals vals;
  byte b[6];
};

void printTime() {
  clock.getTime();
  lcd.home();
  if (clock.hour < 10) lcd.print("0");
  lcd.print(clock.hour, DEC);
  lcd.print(":");
  if (clock.minute < 10) lcd.print("0");
  lcd.print(clock.minute, DEC);
  lcd.print(":");
  if (clock.second < 10) lcd.print("0");
  lcd.print(clock.second, DEC);
  lcd.setCursor(0, 1);
  lcd.print(clock.year, DEC);
  lcd.print("/");
  if (clock.month < 10) lcd.print("0");
  lcd.print(clock.month, DEC);
  lcd.print("/");
  if (clock.dayOfMonth < 10) lcd.print("0");
  lcd.print(clock.dayOfMonth, DEC);
  lcd.print(" ");
  char dayofweek[][3] = {"Su","Mo","Tu","We","Th","Fr","Sa"} ;
  lcd.print(dayofweek[clock.dayOfWeek]);
}

void printTemp() {
  uint8_t num_byte = Wire.requestFrom(0x25, 6);
  if (num_byte != 6) {
    lcd.clear();
    lcd.home();
    lcd.print("i2c");
    lcd.setCursor(0, 1);
    lcd.print("error");
    return;
  }
  union uni uni;
  uint8_t i = 0;
  while (Wire.available() > 0) {
    byte b = Wire.read();
    uni.b[i++] = b;
  }
  if (uni.vals.result == 0) {
    lcd.setCursor(12, 0);
    lcd.print("    ");
    lcd.setCursor(12, 0);
    lcd.print(uni.vals.temperature);
    lcd.write(0xdf);
    lcd.print("C");
    lcd.setCursor(13, 1);
    lcd.print("   ");
    lcd.setCursor(13, 1);
    lcd.print(uni.vals.humidity);
    lcd.print("%");
  } else {
    lcd.clear();
    lcd.home();
    lcd.print("ERROR");
    lcd.setCursor(0, 1);
    lcd.print(uni.vals.result);
  }
}

TODO

  • 基板を起こす

開発途中で使ったプログラム

回路チェック

レベル変換を通して(P1へ)入力されたTNの信号をLED(P4)に出力します。うまくいくと、D606CにつないだLEDと同じに点滅します。

void setup() {
  pinMode(1, INPUT);
  pinMode(4, OUTPUT);
}

void loop() {
  byte input = digitalRead(1);
  digitalWrite(4, input);
}

電波受信チェック

マーカーを受信するとLCDがクリアされ以後0か1が出力されます。1分間のくぎり(マーカーが2連続)で2行目に各マーカーがあるはずのビットの値を表示します。すべて'M'なら日時が表示されます。

#include <LCD_I2C.h>
LCD_I2C lcd(0x23, 16, 2);

char curr; //現在の読み込み値
char prev = HIGH; //前回の読み込み値
long c_time; //ループ処理の経過時間
long p_time; //前回のループ処理の経過時間
long s_time; //ループ処理の経過時間の差分
char m01_code; //コード仕分け値(M、0、1)
int rp; //秒のカウント
int ct; //ループ回数のカウント、積算値
int ct_prev; //前回ループ時の回数
int ct_subt; //ループ回数の差分、正常読み込みであれば毎ループ終了時は「60」
int st_rec;  //受信フラグ(初期化、成功、失敗)
char d2bits[61]; //60間の読み込み値格納、null終端

void setup() {
  pinMode(4, OUTPUT);
  pinMode(1,INPUT); //D2ピンをINPUTモードに設定
  c_time = 0;
  p_time = 0;
  s_time = 0;
  m01_code = '0';
  ct = 0;
  ct_prev = 0;
  ct_subt = 0;
  st_rec  = 0; //受信フラグ:初期化

  lcd.init();
}

void success() {
  //配列d2bitsから1bit毎に時刻データ取り出し、重みづけ
  //分
  int min = 0;
  if(d2bits[8]=='1'){ min = min + 1; }
  if(d2bits[7]=='1'){ min = min + 2; }
  if(d2bits[6]=='1'){ min = min + 4; }
  if(d2bits[5]=='1'){ min = min + 8; }
  if(d2bits[3]=='1'){ min = min + 10; }
  if(d2bits[2]=='1'){ min = min + 20; }
  if(d2bits[1]=='1'){ min = min + 40; }
  //時
  int hour = 0;
  if(d2bits[18]=='1'){ hour = hour + 1; }
  if(d2bits[17]=='1'){ hour = hour + 2; }
  if(d2bits[16]=='1'){ hour = hour + 4; }
  if(d2bits[15]=='1'){ hour = hour + 8; }
  if(d2bits[13]=='1'){ hour = hour + 10; }
  if(d2bits[12]=='1'){ hour = hour + 20; }
  //通算日
  int day = 0;
  if(d2bits[33]=='1'){ day = day + 1; }
  if(d2bits[32]=='1'){ day = day + 2; }
  if(d2bits[31]=='1'){ day = day + 4; }
  if(d2bits[30]=='1'){ day = day + 8; }
  if(d2bits[28]=='1'){ day = day + 10; }
  if(d2bits[27]=='1'){ day = day + 20; }
  if(d2bits[26]=='1'){ day = day + 40; }
  if(d2bits[25]=='1'){ day = day + 80; }
  if(d2bits[23]=='1'){ day = day + 100; }
  if(d2bits[22]=='1'){ day = day + 200; }
  //西暦(下2桁)
  int year = 0;
  if(d2bits[48]=='1'){ year = year + 1; }
  if(d2bits[47]=='1'){ year = year + 2; }
  if(d2bits[46]=='1'){ year = year + 4; }
  if(d2bits[45]=='1'){ year = year + 8; }
  if(d2bits[44]=='1'){ year = year + 10; }
  if(d2bits[43]=='1'){ year = year + 20; }
  if(d2bits[42]=='1'){ year = year + 40; }
  if(d2bits[41]=='1'){ year = year + 80; }
  //西暦(4桁)
  int ayear = ( year + 2000 ) ;
  //曜日
  int youbi = 0;
  if(d2bits[52]=='1'){ youbi = youbi + 1; }
  if(d2bits[51]=='1'){ youbi = youbi + 2; }
  if(d2bits[50]=='1'){ youbi = youbi + 4; }
  //1分加算と分、時、日、年、うるう年、曜日への影響反映
  min++; //1分加算
  if(min>=60){ min=0; hour++;
    if(hour>=24){ hour=0; day++;
      int leap_year = ( (1 / (ayear % 4 + 1)) * (1 - 1 / (ayear % 100 + 1)) + (1 / (ayear % 400 + 1)) ); //うるう年判定
      int set_year = ( 365 + leap_year );
      if(day > set_year ){ day=1; year++; }
      youbi++;
      if( youbi>=7){ youbi=0; }
    }
  }
  //通算日から月、日への変換
  int t_day = 0; //通算日の計算用
  int mm; //月
  int dd; //日
  int leap_year = ( (1 / (ayear % 4 + 1)) * (1 - 1 / (ayear % 100 + 1)) + (1 / (ayear % 400 + 1)) ); //うるう年判定
  int mdtable[2][12] = { 31,28,31,30,31,30,31,31,30,31,30,31, 31,29,31,30,31,30,31,31,30,31,30,31 }; //通年とうる年の日数
  //1月から順に月の日数を引いて月、日を算出
  for(int i=0;i<12;i++){
    if((t_day + mdtable[leap_year][i])>=day){
      mm = i+1;
      dd = day - t_day;
      break;
    }
    t_day = t_day + mdtable[leap_year][i];
  }
  //曜日を3桁英字への変換
  char dayofweek[7][4] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"} ;
  char f_youbi[4];
  strcpy(f_youbi, dayofweek[youbi]);
  //日時をシリアルモニタに表示して確認
  lcd.home();
  lcd.print(ayear);
  lcd.print( "/" );
  lcd.print(mm);
  lcd.print( "/" );
  lcd.print(dd);
  lcd.print( "(" );
  lcd.print(f_youbi);
  lcd.print( ")" );
  lcd.setCursor(0, 1);
  lcd.print(hour);
  lcd.print( ":" );
  lcd.print(min);
  lcd.print( ":" );
  lcd.print(rp); //秒
}

void printMarker() {
  lcd.setCursor(0, 1);
  lcd.print( d2bits[0] );
  lcd.print( "-" );
  lcd.print( d2bits[9] );
  lcd.print( "-" );
  lcd.print( d2bits[19] );
  lcd.print( "-" );
  lcd.print( d2bits[29] );
  lcd.print( "-" );
  lcd.print( d2bits[39] );
  lcd.print( "-" );
  lcd.print( d2bits[49] );
  lcd.print( "-" );
  lcd.print( d2bits[59] );
  lcd.home();
}

boolean toggle = false;

void loop() {
  curr = digitalRead(1);
  //前回読み込み値と現在の読み込み値の比較
  if( prev != curr ) {
    c_time = millis(); //ループ処理の経過時間(ms) 
    s_time = c_time - p_time;
    if( curr == HIGH ) {
      //前回処理と時間差がある場合のみ実行
      //コード仕分け(パルス幅:M、P0~P5 200ms < 1:500ms < 0:800ms )
      //、P0~P5 (200ms)の判定:マージンを見込んで(300ms)
      if(s_time < 280 ) { //マージンを見込んで300ms
        ct++;
        toggle = !toggle;  
        digitalWrite(4, toggle);
        //lcd.print(s_time);
        //lcd.print(" ");
        //lcd.print("M");
        lcd.home();
        lcd.clear();
        //前のコードがMか(Mが2回続いているか)のチェック、初期マーカー位置の判定
        //毎時15分と45分のコールサイン(モールス符号)受信時にctとct_prevの値はリセット
        if( m01_code == 'M' ) {
          rp = 0; //60回(秒のカウント)のリセット、初期マーカー位置
          ct_subt = ct - ct_prev;
          //配列(タイムコード)内のマーカー位置の確認
          int mp_chk = 0;
          if(d2bits[0]=='M' && d2bits[9]=='M' && d2bits[19]=='M' && d2bits[39]=='M' && d2bits[49]=='M' && d2bits[59]=='M'){ 
            mp_chk = 1;
          } else{
            mp_chk = 2; 
          }
          if( mp_chk == 1 ){ lcd.print( "OK" );}
          //if( mp_chk == 2 ){ lcd.print( "NG" );}
          printMarker();
          //60秒間のデータが揃ったか、マーカー位置チェックOKかの判定
          if( ct_subt == 60 && mp_chk == 1) {
            st_rec  = 1; //受信フラグ:成功
            success();
          } else {
            //配列クリア
            for(int i=0;i<60;i++){
              d2bits[i] = ' ';
            }
            //受信フラグ:失敗
            st_rec  = 9;
          }
          ct_prev = ct; 
        }
        m01_code = 'M';
        if (rp < 60)
          d2bits[rp] = 'M'; //rp番目の配列に格納
        rp++; //60ループ回のカウントアップ
        //1(500ms)の判定:マージンを見込んで(600ms)
      } else if(s_time < 590) {
        ct++;
        lcd.print( "1" );
        if (rp < 60)
          d2bits[rp] = '1'; //rp番目の配列に格納
        m01_code = '1';
        rp++; //60回ループのカウントアップ
        //0(800ms)の判定
        //} else {
      } else if (s_time < 1000) {
        ct++;
        lcd.print( "0" );
        if (rp < 60)
          d2bits[rp] = '0'; //rp番目の配列に格納
        m01_code = '0'; 
        rp++; //60回ループのカウントアップ
      } else {
        lcd.print(" ");
        lcd.print(s_time);
        lcd.print(" ");
      }
    }
  }
  prev = curr;  //現在の読み込み値を保存
  p_time = c_time; //現在の経過時間(ms)を保存
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?