Created
May 7, 2016 22:59
-
-
Save weldtype/1f3dcbeb007cec08d43da628a9ce099a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// RTC-8564をつないでみる。 | |
// 2016/04/29:edy | |
// 2016/04/30:detachInterrupt を使う。 | |
// 2016/05/01:変数名の変更、RTCとのやり取りはBCDで行うが、内部ではDECIMAL | |
// 2016/05/07:初期電源投入時の問題を回避 | |
// 2016/05/08:デジット6行16桁7セグメントLCDとつなぐ | |
// | |
//参考にしたサイト | |
// | |
//Arduinoで実験 (RTCモジュール) | |
//http://baticadila.dip.jp/arduino_104.html | |
// | |
//RTC8564リアルタイムクロック | |
//http://iizukakuromaguro.sakura.ne.jp/365_rtc8564/365_rtc8564.html | |
// | |
//曜日を調べるプログラム | |
//http://edu.clipper.co.jp/pg-2-47.html | |
// | |
//Arduino 割り込みについてのメモ | |
//http://genine.web.fc2.com/contents/arduino_memo.html | |
// | |
//シリアルモニタから入力した数字列を数値に変換する | |
//forum.arduino.cc/index.php?topic=100429.msg753262#msg753262 | |
#include <Wire.h> | |
// デジットLCD用配列 | |
// 上から4行目(CS3)のアドレス変換 | |
const uint8_t addrCS3[] = {8, 9, 6, 7, 4, 5, 2, 3, 0, 1, 10, 11, 12, 13, 14, 15, | |
16, 17, 18, 19, 20, 21, 30, 31, 28, 29, 26, 27, 24, 25, 22, 23 | |
}; | |
// 上から5行目(CS2)のアドレス変換 | |
const uint8_t addrCS2[] = {18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, | |
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 | |
}; | |
// 7segmentパターン | |
// 0,1,2,3,4,5,6,7,8,9,,A,b,C,d,E,F, | |
// 空白,-,H,L,n,o,P,u,μ,°,左縦,両縦 | |
const int seg_pattern[] = {235, 96, 199, 229, 108, 173, 175, 232, 239, 237, 238, 47, 7, 103, 143, 142, | |
0, 4, 110, 11, 38, 39, 206, 35, 78, 204, 10, 106 | |
}; | |
// row to CS | |
const uint8_t rowToCS[] = {0, 5, 6, 4, 3, 2, 1}; | |
#define I2C_ADDR (0xA2 >> 1) // 1ビット目未使用のため1ビット右シフトする。 | |
// 年月日時分秒用グローバル変数、DECIMAL not BCD | |
int gYear, gMonth, gDay, gSec, gMin, gHour, gWeek; | |
//割り込み処理 | |
void clk_IRQ(void) | |
{ | |
interrupts();// wireライブラリが割り込みを使うので、割り込みを有効にする。 | |
Wire.beginTransmission(I2C_ADDR); | |
Wire.write(0x02); | |
Wire.endTransmission(); | |
delay(1);//不要のはずだからコメントアウトする。 | |
Wire.requestFrom(I2C_ADDR, 7); | |
//RTC-8564の読み出しデータの不要ビットマスク及びBCD->DECIMAL変換する。 | |
gSec = bcd2dec(Wire.read() & 0x7f) ; // 秒 | |
gMin = bcd2dec(Wire.read() & 0x7f) ; // 分 | |
gHour = bcd2dec(Wire.read() & 0x3f) ; // 時 | |
gDay = bcd2dec(Wire.read() & 0x3f) ; // 日 | |
gWeek = bcd2dec(Wire.read() & 0x07) ; // 曜日 | |
gMonth = bcd2dec(Wire.read() & 0x1f) ; // 月 | |
gYear = bcd2dec(Wire.read()); // 年 | |
Serial.print(gYear); | |
Serial.print("/"); | |
Serial.print(gMonth); | |
Serial.print("/"); | |
Serial.print(gDay); | |
Serial.print("("); | |
Serial.print(gWeek); | |
Serial.print(")"); | |
Serial.print(gHour); | |
Serial.print(":"); | |
Serial.print(gMin); | |
Serial.print(":"); | |
Serial.println(gSec); | |
//デジットLCDに表示 | |
// 年表示 | |
DispNum(1, 0, gYear / 10, 0); //"恒春"セグメントは表示しない | |
DispNum(1, 1, gYear % 10, 1 );// "年"セグメント表示 | |
//月表示 | |
DispNum(1, 2, (gMonth / 10 == 0) ? 16 : gMonth / 10, 0); //月表示をゼロサプレス | |
DispNum(1, 3, gMonth % 10, 1);// "月"セグメント表示 | |
//日表示 | |
DispNum(1, 4, (gDay / 10 == 0) ? 16 : gDay / 10, 0); //日表示をゼロサプレス | |
DispNum(1, 5, gDay % 10, 1 );// "日"セグメント表示 | |
//時表示 | |
DispNum(1, 6, (gHour / 10 == 0) ? 16 : gHour / 10, 0); //時表示をゼロサプレス | |
DispNum(1, 7, gHour % 10 , 1);// コロンセグメント表示 | |
//分表示 | |
DispNum(1, 8, gMin / 10, 0); //分表示はゼロサプレスしない | |
DispNum(1, 9, gMin % 10, 1 );// コロンセグメント表示 | |
//秒表示 | |
DispNum(1, 10, gSec / 10, 0); //秒表示はゼロサプレスしない | |
DispNum(1, 11, gSec % 10, 0 ); //"星期"セグメントは表示しない | |
} | |
void setup() { | |
// デジットLCD用設定値 | |
// コマンドのビットデータ: modeID(100)+各コマンドのビットデータ | |
#define SYS_EN 0b100000000010 | |
#define LCD_ON 0b100000000110 | |
#define BIAS2_2 0b100001000000 | |
#define BIAS2_3 0b100001001000 | |
#define BIAS2_4 0b100001010000 | |
#define BIAS3_2 0b100001000010 | |
#define BIAS3_3 0b100001001010 | |
#define BIAS3_4 0b100001010010 | |
#define CS1 3 | |
#define CS2 4 | |
#define CS3 5 | |
#define CS4 6 | |
#define CS5 7 | |
#define CS6 8 | |
#define WR 9 | |
#define DATA 10 | |
pinMode(CS1 , OUTPUT); | |
pinMode(CS2 , OUTPUT); | |
pinMode(CS3 , OUTPUT); | |
pinMode(CS4 , OUTPUT); | |
pinMode(CS5 , OUTPUT); | |
pinMode(CS6 , OUTPUT); | |
pinMode(WR , OUTPUT); | |
pinMode(DATA , OUTPUT); | |
digitalWrite(CS1, HIGH); | |
digitalWrite(CS2, HIGH); | |
digitalWrite(CS3, HIGH); | |
digitalWrite(CS4, HIGH); | |
digitalWrite(CS5, HIGH); | |
digitalWrite(CS6, HIGH); | |
digitalWrite(WR, HIGH); | |
digitalWrite(DATA, HIGH); | |
Serial.begin(9600); | |
Serial.println("segment check"); | |
// 各HT1621を初期化 | |
for (int row = 1 ; row <= 6 ; row++) { | |
WriteCommand(row, SYS_EN); | |
WriteCommand(row, LCD_ON); | |
WriteCommand(row, BIAS3_4); | |
//WriteCommand(row, BIAS2_4); | |
} | |
// チェックのため全表示 | |
for (int row = 1 ; row <= 6 ; row++) { | |
for (int addr = 0 ; addr < 32 ; addr++) { | |
WriteData(row, addr, 0b1111); | |
} | |
} | |
delay(1000); | |
// 全消去 | |
for (int row = 1 ; row <= 6 ; row++) { | |
for (int addr = 0 ; addr < 32 ; addr++) { | |
WriteData(row, addr, 0b0000); | |
} | |
} | |
delay(100); | |
Serial.println("RTC Test Start"); | |
Wire.begin(); // I2C の初期化 | |
// | |
//0Vからの初期電源投入時には、パワーオンリセットによってVLビットは1にセットされるので | |
//初期化する必要がある。 | |
Wire.beginTransmission(I2C_ADDR); | |
Wire.write(byte(0x02)); // RTCモジュールへレジスタの先頭番号を指定(レジスタアドレス:0x02) | |
Wire.endTransmission(); | |
Wire.requestFrom(I2C_ADDR, 1); // レジスタの先頭より1バイト転送依頼 | |
byte b = Wire.read(); // 1バイト受信 | |
if (b & 0x80) { // データの bit7(VLbit)を判定し true なら | |
setRTC(16, 1, 1, 12, 0, 0); // 暫定的に日時を2016年1月1日12時0分0秒にセット | |
Serial.println("temporary date/time set"); | |
Serial.println("Set correct date/time"); | |
} | |
attachInterrupt(0, clk_IRQ, CHANGE); | |
} | |
void loop() { | |
String sInput; | |
while (Serial.available()) { | |
delay(3); //delay to allow buffer to fill | |
if (Serial.available() > 0) { | |
char c = Serial.read(); //gets one byte from serial buffer | |
sInput += c; //makes the string readString | |
} | |
} | |
//入力が12桁以上なら設定データ(年月日時分秒・各2桁)とみなす。 | |
//データの正当性はチェックしていない。 | |
if (sInput.length() >= 12) { | |
Serial.print("length:"); Serial.println(sInput.length());//確認のため表示 | |
Serial.println(sInput); | |
//年月日時分秒・各2桁を切り分けて数値化し変数へ代入 | |
int year = (sInput.substring(0, 2)).toInt(); | |
int month = (sInput.substring(2, 4)).toInt(); | |
int day = (sInput.substring(4, 6)).toInt(); | |
int hour = (sInput.substring(6, 8)).toInt(); | |
int min = (sInput.substring(8, 10)).toInt(); | |
int sec = (sInput.substring(10, 12)).toInt(); | |
detachInterrupt(0);//RTCに書き込む前にRTCからの割り込みを無効にしておく。 | |
setRTC(year, month, day, hour, min, sec); | |
attachInterrupt(0, clk_IRQ, CHANGE); | |
} | |
// 秒が30以上なら分を切り上げ、未満なら切捨て。切り捨て。 | |
if (sInput.substring(0, 1) == "*") | |
{ | |
Serial.println("sec clear"); | |
if (gSec >= 30) { | |
// 処理が複雑になるので59分では切り上げはしない | |
if (gMin < 59) { | |
gMin++; | |
} | |
} | |
gSec = 0; | |
detachInterrupt(0);//RTCに書き込む前にRTCからの割り込みを無効にしておく。 | |
setRTC(gYear, gMonth, gDay, gHour, gMin, gSec); | |
attachInterrupt(0, clk_IRQ, CHANGE); | |
} | |
sInput = ""; | |
} | |
void setRTC(int year, int month, int day, int hour, int min, int sec) | |
{ | |
Wire.beginTransmission(I2C_ADDR); | |
Wire.write((0x00)); // データを転送する先頭のレジスタ番号を指定 | |
Wire.write((0x20)); // 00 Control 1 STOP(bit5)-1 をセットし動作を停止させる。 | |
Wire.write((0x00)); // 01 Control 2 | |
Wire.write(byte(dec2bcd(sec))); // 02 Seconds 初期値を転送(秒)0 ~ 59 | |
Wire.write(byte(dec2bcd(min))); // 03 Minutes 〃 (分)0 ~ 59 | |
Wire.write(byte(dec2bcd(hour))); // 04 Hours 〃 (時)0 ~ 23 | |
Wire.write(byte(dec2bcd(day))); // 05 Days 〃 (日)1 ~ 31 | |
Wire.write(byte(dec2bcd(subZeller(year + 2000, month, day)))); // 06 Weekdays 〃 (曜日)0 ~ 6 | |
Wire.write(byte(0x80 | dec2bcd(month))); // 07 Months 〃 (月)1 ~ 12 | |
Wire.write(byte(dec2bcd(year))); // 08 Years 〃 (年)0 ~ 99 | |
Wire.write(byte(0x00)); // 09 Minutes Alarm アラームの初期値を転送(分)0 ~ 59 | |
Wire.write(byte(0x00)); // 0A Hours Alarm 〃 (時)0 ~ 23 | |
Wire.write(byte(0x00)); // 0B Days Alarm 〃 (日)1 ~ 31 | |
Wire.write(byte(0x00)); // 0C Weekdays Alarm 〃 (曜日)0 ~ 6 | |
Wire.write(byte(0xff)); // 0D CLKOUT CLKOUT用レジスタ CLKOUT Enable freq=1Hzに設定 | |
Wire.write(byte(0x00)); // 0E Timer control タイマー用レジスタ | |
Wire.write(byte(0x00)); // 0F Timer 〃 | |
Wire.write(byte(0x00)); // 00 Control 1 STOP(bit5)-0 をリセットし動作を開始する。 | |
// アドレス 0F の次は先頭アドレスの 00 に戻る。 | |
Wire.endTransmission(); | |
} | |
// row 1...6 | |
// digit_pos 0...15 | |
// num 表示データ,配列seg_pattern参照のこと。 | |
// 0,1,2,3,4,5,6,7,8,9,,A,b,C,d,E,F, | |
// 空白,-,H,L,n,o,P,u,μ,°,左縦,両縦 | |
// dp:dpセグメントオンオフ、LSB(bit0)=1でオン | |
void DispNum(int row, int digit_pos, int num, int dp) | |
{ | |
WriteData(row, digit_pos * 2, seg_pattern[num] & 0x0f ); | |
WriteData(row, digit_pos * 2 + 1, (seg_pattern[num] >> 4) | (dp & 1)); | |
} | |
// row 1...6 | |
void WriteData(int row, int addr , int data) | |
{ | |
int bitdata = 0x1400 | (addr << 4) | reverse4bit(data) ;// 0x1400: modeID 101 を10ビット左シフト | |
CS_LOW(row); | |
for (int i = 1 ; i <= 13 ; i++) { | |
if ((bitdata & 0x1000) == 0) { | |
digitalWrite(DATA, LOW); | |
} | |
else { | |
digitalWrite(DATA, HIGH); | |
} | |
bitdata <<= 1; | |
digitalWrite(WR, LOW); | |
digitalWrite(WR, HIGH); | |
} | |
CS_HIGH(row); | |
} | |
void WriteCommand(int row, int bitdata) | |
{ | |
CS_LOW(row); | |
for (int i = 1 ; i <= 12 ; i++) { | |
if ((bitdata & 0x0800) == 0) { | |
digitalWrite(DATA, LOW); | |
} | |
else { | |
digitalWrite(DATA, HIGH); | |
} | |
bitdata <<= 1; | |
digitalWrite(WR, LOW); | |
digitalWrite(WR, HIGH); | |
} | |
CS_HIGH(row); | |
} | |
void CS_HIGH(int row) | |
{ | |
switch (rowToCS[row]) { | |
case 1: digitalWrite(CS1, HIGH); | |
break; | |
case 2: digitalWrite(CS2, HIGH); | |
break; | |
case 3: digitalWrite(CS3, HIGH); | |
break; | |
case 4: digitalWrite(CS4, HIGH); | |
break; | |
case 5: digitalWrite(CS5, HIGH); | |
break; | |
case 6: digitalWrite(CS6, HIGH); | |
break; | |
default: break; | |
} | |
} | |
void CS_LOW(int row) | |
{ | |
switch (rowToCS[row]) { | |
case 1: digitalWrite(CS1, LOW); | |
break; | |
case 2: digitalWrite(CS2, LOW); | |
break; | |
case 3: digitalWrite(CS3, LOW); | |
break; | |
case 4: digitalWrite(CS4, LOW); | |
break; | |
case 5: digitalWrite(CS5, LOW); | |
break; | |
case 6: digitalWrite(CS6, LOW); | |
break; | |
default: break; | |
} | |
} | |
// ビット逆順(4ビット) | |
int reverse4bit(int data) | |
{ | |
int rev = 0; | |
rev = data & 1 ; | |
for (int i = 1 ; i <= 3 ; i++) { | |
data >>= 1; | |
rev <<= 1; | |
rev |= data & 1; | |
} | |
return rev; | |
} | |
int subZeller( int y, int m, int d ) | |
{ | |
if ( m < 3 ) { | |
y--; m += 12; | |
} | |
return ( y + y / 4 - y / 100 + y / 400 + ( 13 * m + 8 ) / 5 + d ) % 7; | |
} | |
// DECIMAL -> BCD | |
byte dec2bcd( byte data ) | |
{ | |
return ((( data / 10) << 4) + (data % 10)); | |
} | |
// BCD -> DECIMAL | |
byte bcd2dec( byte data ) | |
{ | |
return ((( data >> 4) * 10) + (data % 16)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment