ホーム > カテゴリ > ロボット・電子工作・マイコン >

時計の作り方 [Arduino]

Arduinoで「リアルタイムクロック」(RTC)と「液晶ディスプレイ」(LCD)を使用して「時計」を作る方法です。

Windowsやスマホなどのソフトウェアだと数行で時計を作れますが、ハードウェアだと15本程度の配線と150行ぐらいのプログラムコードが必要となります。(ハードウェア屋さんはタイヘン)

※LCDの液晶部分は透明の保護フィルムを貼ったままですので、少し見ずらいかも知れません。

使用部品・材料

総額で約1,620円です。(Arduino本体の値段を除く)

部品/材料値段備考
ブレッドボード¥270秋月電子の通販コード(P-00315)
LCDキャラクタディスプレイモジュール
16x2行 バックライト付白抜き
¥800秋月電子の通販コード(P-02919)
リアルタイムクロック(RTC) モジュール¥500秋月電子の通販コード(I-00233)
半固定ボリューム 10kΩ [103]¥50秋月電子の通販コード(P-08012)
カーボン抵抗器数円1kΩ(2個)を使用。

配線図

※詳細は記事冒頭の関連記事を参照。

スケッチ(プログラム)

2017年12月25日(月) 12時20分15秒から時計を開始します。

#include <Wire.h>
#include <LiquidCrystal.h>

// ピン番号を指定してライブラリを初期化する
LiquidCrystal lcd(5,6,7,10,11,12,13);

// 外部割り込みの状態
volatile int state = LOW; 
 
// RTCのレジスタテーブル(16byte)
int RegTbl[16];  
 
// スレーブアドレス
byte SLAVE_ADDRESS = 0x51;  
 
// 2進化10進数(BCD)を10進数に変換
byte BCDtoDec(byte value){
  return ((value >> 4) * 10) + (value & 0x0F) ;
}
 
// 外部割り込みが発生した時に動作します。
void myInterrupt() {
  state = !state;     
}
 
void setup() {
  // LCDの列と行を設定する
  lcd.begin(16, 2);  
    
  // 2ピンの状態がLOWからHIGHに変化した場合に外部割り込みを発生させる
  attachInterrupt(digitalPinToInterrupt(2), myInterrupt, RISING);
  
  // マスタとしてI2Cバスに接続する
  Wire.begin(); 
  
  // I2Cスレーブに対して送信処理を開始する
  Wire.beginTransmission(SLAVE_ADDRESS);
    
    // レジスタのアドレスを指定する(0-15の内、先頭から)
    Wire.write(0x00);
 
    // ---------------------------------
    //  コントロールレジスタ
    // ---------------------------------    
    // [00]Control1
    Wire.write(0x00);
    // [01]Control2    
    Wire.write(0x00);
    
    // ---------------------------------
    //  時計・カレンダーレジスタ
    // ---------------------------------     
    // アドレスの[02-05]及び[08-11]は2進化10進数(BCD)で指定します。
     
    // [02]Seconds(15秒)
    Wire.write(0x15);
    // [03]Minutes(20分)
    Wire.write(0x20);
    // [04]Hours(12時)
    Wire.write(0x12);
    // [05]Days(25日)    
    Wire.write(0x25);
    // [06]Weekdays(月) 
    // 0:日 1:月 2:火 3:水 4:木 5:金 6:土 
    Wire.write(0x01);    
    // [07]Month/Century(21世紀の12月)
    // ・Month(01-12) BCD形式
    // ・Century(先頭bit 0:20世紀[19xx年代],1(0x80):21世紀[20xx年代])
    Wire.write(0x12 | 0x80);        
    // [08]Years(2017年)     
    Wire.write(0x17);
    
    // ---------------------------------
    //  アラームレジスタ
    // ---------------------------------  
    // 0x80はアラーム対象外となる   

    // [09]Minutes Alarm
    Wire.write(0x80);
    // [0A]Hours Alarm
    Wire.write(0x80);
    // [0B]Days Alarm
    Wire.write(0x80);
    // [0C]Weekdays Alarm
    Wire.write(0x80);
 
    // ---------------------------------
    //  クロック出力レジスタ
    // --------------------------------- 
    
    // [0D]CLKOUT Frequency
    // ・クロック出力機能を有効にする。
    //   ※有効:0x80 無効 :0x00
    // ・クロック周波数は1Hz(1秒間に1回)とする
    //   ※0x00:32768Hz, 0x01:1024Hz, 0x02:32Hz, 0x03:1Hz
    // 
    // 次の設定だと2ピン[CLKOUT]から1秒に1回、クロック出力される     
    Wire.write(0x80 | 0x03);
 
  // I2Cスレーブへの送信完了
  Wire.endTransmission();
}
 
void loop(){
  int i;
  String myClock= "";
  
  // 外部割込みが発生した場合
  if(state == HIGH){
    
    // このメソッドは画面をクリアする便利な機能ですが、
    // 毎秒、実行すると画面がちらつきます。
    // lcd.clear();
    
    // レジスタのアドレスを先頭にする
    Wire.beginTransmission(SLAVE_ADDRESS);
    Wire.write(0x00);
    Wire.endTransmission(); 
 
    // スレーブの16byteのレジスタデータを要求する
    Wire.requestFrom(SLAVE_ADDRESS,16);
                
    // 16byteのデータを取得する
    for (i=0; i<16; i++){
      while (Wire.available() == 0 ){}
      RegTbl[i] = Wire.read();
    }
    
    // 現在の年月日
    myClock += String(BCDtoDec(RegTbl[8])+ 2000)  + "/";
    myClock += String(BCDtoDec(RegTbl[7] & 0x1F)) + "/";
    myClock += String(BCDtoDec(RegTbl[5] & 0x3F)) + "";
    
    switch(RegTbl[6] & 0x07){
      case 0 :  myClock += "(Sun)";break;
      case 1 :  myClock += "(Mon)";break;
      case 2 :  myClock += "(Tue)";break;
      case 3 :  myClock += "(Wed)";break;
      case 4 :  myClock += "(Thu)";break;
      case 5 :  myClock += "(Fri)";break;
      case 6 :  myClock += "(Sat)";break;
    }

    // LCDの1行目
    lcd.setCursor(0,0);
    lcd.print(myClock);
    myClock = "";

    // 現在の時刻
    myClock += String(BCDtoDec(RegTbl[4] & 0x3F)) + ":";
    myClock += String(BCDtoDec(RegTbl[3] & 0x7F)) + ":";

    // 秒が1桁の場合は2桁にする
    // ※時/分も同じようにして下さい。
    String s = String(BCDtoDec(RegTbl[2] & 0x7F))  ;
    if(s.length()==1){
      s = "0" + s; 
    }
    myClock +=  s;
    
    // LCDの2行目
    lcd.setCursor(0,1);
    lcd.print(myClock);
        
    state = !state;  
  }
}

以上です。





掲示板

ArduinoやRaspberry Piなどの電子工作の掲示板を作成しました。質問やわからない事は電子工作 (Arduino・ラズパイ等)でユーザー同士で情報を共有して下さい。

関連記事



公開日:2017年05月27日 最終更新日:2017年08月20日
記事NO:02398