/********************************(RTC-DS1307.c)***
* RTC (DS1307) ライブラリ
****************************************************/
#include "string.h"
#include "myProject.h"
#define DS1307 0x68 // RTCのI2Cアドレス
#define NO_PRINTF
//=== RTC用変数(2進数で格納)
uint16_t J_Week[]={'日','月','火','水','木','金','土'};
char D_Week[][4]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
uint8_t DayTm[] = { 0, // Seconds
30, // minutes
10, // Hours(24h)
4, // day[week]
1, // date
1, // month
25, // year (下2桁)
0 // SQW/OUT
};
static uint8_t ClockMd = 1; // 起動時は時計表示モード
static uint8_t Sec = 0;
/****** 汎用関数 ***************************/
//---- BCD数を2進数に変換
uint8_t bcd2bin(uint8_t bcd){
return ((bcd >> 4)& 0x0F) * 10 + (bcd & 0x0F);
}
//---- 2進数をBCD数に変換
uint8_t bin2bcd(uint8_t bin){
return (uint8_t)((uint16_t)(bin/10) << 4)+(bin % 10);
}
//---- 文字列から数値を取り出し、1バイト配列に逆順で格納
/* buf: 取り出した数値を格納する1バイト配列
* src: 数値を取り出す文字列
* delim: 区切り文字を文字列にしたもの
* (戻り値): 取得出来た数値の数 */
uint8_t get_NumRev(uint8_t *buf, char *src, char *delim){
char *ptr;
uint8_t bt, n = 0;
ptr = strtok(src, delim);
while(ptr != NULL){
bt = (uint8_t)atoi(ptr); //無効データでも0を返す
*buf-- = bt;
n++;
ptr = strtok(NULL, delim);
}
return n;
}
/****** RTC用関数 ******************************/
//--- RTCのadr番地にdatデータを書き込む
void RTC_write(uint8_t adr, uint8_t dat){
uint8_t bf[3];
bf[0] = adr; // Address = adr
bf[1] = dat; // Set Data
I2C1_WriteNBytes(DS1307, bf, 2); // Write Data
}
//--- RTCのadr番地のデータを読み込む
uint8_t RTC_read(uint8_t adr){
uint8_t bf[3];
bf[0] = adr; // Address = adr
I2C1_WriteNBytes(DS1307, bf, 1); // Set Address
I2C1_ReadNBytes(DS1307, bf, 1); // Read Data
return bf[0];
}
//--- RTCの全てのrtcデータをbuf[]読み込む
void RTC_readAll(uint8_t *buf,uint8_t bcd){
uint8_t rtc[8],i;
rtc[0] = 0; // Address = 0
I2C1_WriteNBytes(DS1307, rtc, 1); // Set Address
I2C1_ReadNBytes(DS1307, rtc, 8); // Read Data
for(i = 0; i < 8; i++){
if(bcd) buf[i] = bcd2bin(rtc[i]);
else buf[i] = rtc[i];
}
}
//--- RTCの全てにrtcデータを書き込む
void RTC_writeAll(uint8_t *buf){
uint8_t rtc[8],i;
rtc[0]=0; // Address = 0
for(i=0; i < 8; i++){
rtc[i+1] = bin2bcd(buf[i]);
}
I2C1_WriteNBytes(DS1307, rtc, 9);
}
//--- RTCの指定アドレスからnバイトのデータを書き込む
void RTC_writePrt(uint8_t *buf, uint8_t adr, uint8_t n){
uint8_t rtc[9],i;
rtc[0] = adr; // Address = adr
for(i = 0;i < n; i++){
rtc[i+1] = bin2bcd(buf[adr+i]);
}
I2C1_WriteNBytes(DS1307, rtc, n+1);
}
//--- RTCの初期化(通常は使用しない)
void RTC_init(){
RTC_writeAll(DayTm);
}
/*======================================
* BCDデータ表示サブルーチン
*=====================================*/
//--- BCDデータを文字変換し文字列に差し込む
char *RTC_HsetBCD(char *str, uint8_t bcd,uint8_t zero){
uint8_t hcd;
if( (zero>0) & ((bcd>>4)==0) )
hcd = 0x20;
else
hcd = 0x30 + (bcd >> 4);
*str++ = hcd;
hcd = 0x30 + (bcd & 0x0F);
*str++ = hcd;
return str;
}
//--- BCDデータを全角文字列に変換して表示
/* x:表示x位置、pg:表示ページ位置、gap:表示文字間ドット数
* bcd:表示したいBCD文字、zero:ゼロサプレスが無し(0)/有り(1) */
void RTC_ZprtBCD(uint8_t x, uint8_t pg, uint8_t gap, uint8_t bcd,uint8_t zero){
uint16_t kcd;
if( (zero>0) & ((bcd>>4)==0) )
kcd = 0x2121;
else
kcd = 0x2330 + (bcd >> 4);
i2cOLED_ZchrX(x,pg,kcd,2);
kcd = 0x2330 + (bcd & 0x0F);
i2cOLED_ZchrX(x+16+gap,pg,kcd,2);
}
//--- BCDデータを拡張全角文字列に変換して表示
/* x:表示x位置、pg:表示ページ位置、gap:表示文字間ドット数
* bcd:表示したいBCD文字、zero:ゼロサプレスが無し(0)/有り(1) */
void RTC_2ZprtBCD(uint8_t x, uint8_t pg, uint8_t gap, uint8_t bcd,uint8_t zero){
uint16_t kcd;
if( (zero>0) & ((bcd>>4)==0) ){
kcd = 0x2121;
i2cOLED_ZchrX(x,pg,kcd,2);
i2cOLED_ZchrX(x,pg+2,kcd,2);
}else{
kcd = 0x2659 + (bcd >> 4)*2;
i2cOLED_ZchrX(x,pg,kcd,2);
i2cOLED_ZchrX(x,pg+2,kcd+1,2);
}
kcd = 0x2659 + (bcd & 0xF)*2;
i2cOLED_ZchrX(x+16+gap,pg,kcd,2);
i2cOLED_ZchrX(x+16+gap,pg+2,kcd+1,2);
}
//---- RTC データをOLED に表示(BCDデータを利用)
void RTC_prtOLED(){
char buf[20];
uint8_t d;
uint16_t kcd;
RTC_readAll(DayTm,0);
strcpy(buf,"2000/01/01(");
RTC_HsetBCD(buf+2,DayTm[6],0);
RTC_HsetBCD(buf+5,DayTm[5],1);
RTC_HsetBCD(buf+8,DayTm[4],1);
d = DayTm[3] & 0x0F;
i2cOLED_HstrX(0,0,buf);
i2cOLED_ZchrX(92,0,J_Week[d],0);
i2cOLED_HchrX(112,0,')');
RTC_2ZprtBCD(0,3,4,DayTm[2],1);
i2cOLED_HchrX(40,3,0xA5); i2cOLED_HchrX(40,5,0xA5);
RTC_2ZprtBCD(50,3,4,DayTm[1],0);
RTC_ZprtBCD(90,5,0,DayTm[0],0);
}
/***** コマンド処理 *********************/
//---- I(read_tIme)コマンド(テスト用) "I"
void i2cRTC_cmd_I(){
char buf[20];
RTC_readAll(DayTm,0);
strcpy(buf,"2000/01/01( )");
RTC_HsetBCD(buf+2,DayTm[6],0);
RTC_HsetBCD(buf+5,DayTm[5],0);
RTC_HsetBCD(buf+8,DayTm[4],0);
buf[12] = 0x30 + (DayTm[3]& 0x0F);
puts(buf); i2cOLED_HstrX(0,0,buf);
strcpy(buf," 00:00:00 ");
RTC_HsetBCD(buf+1,DayTm[2],0);
RTC_HsetBCD(buf+4,DayTm[1],0);
RTC_HsetBCD(buf+7,DayTm[0],0);
puts(buf);i2cOLED_HstrX(0,2,buf);
}
//---- Jコマンド (OLED表示切り替え)) "J"
void cmd_J(){
ClockMd ^= 1;
i2cOLED_Clr(0,7,0);
}
//---- Y(Year)コマンド(日付設定用) "Yyy/MM/dd/w"
void i2cRTC_cmd_Y(char *str){
uint8_t n;
n = get_NumRev(DayTm+6, str+1, "/");
if((n > 0)&&(n < 5)){
RTC_writePrt(DayTm, 3, 4);
}
}
//---- T(Time)コマンド(時刻設定用) "Thh:mm:ss"
void i2cRTC_cmd_T(char *str){
uint8_t n;
n = get_NumRev(DayTm+2, str+1, ":");
if((n > 0)&&(n < 4)){
RTC_writePrt(DayTm, 0, 3);
}
}
//---- 時刻を読出しOLEDに表示
void OLED_Clock(){
uint8_t t;
RTC_readAll(DayTm,1);
t = DayTm[0];
if(Sec != t){ // 表示は秒単位
if(ClockMd) RTC_prtOLED();
Sec = t;
IO_RA4_Toggle();
}
}
|