// //  RTC-8564NB RTC-I2C テストプログラム // 2007/7/12 by TEP 時間設定できるバージョン完成 // for R8C/Tiny // #include #include #define CLOCK 20000 // 定数の定義 #define SW_ON 0 #define SW_OFF 1 #define LOW 0 #define HIGH 1 #define IN 0 #define OUT 1 // 定数の定義(入出力ピン名など) #define SCL p1_0 // I2C SCL #define SDA p1_1 // I2C SDA #define SCL_DIRECTION pd1_0 #define SDA_DIRECTION pd1_1 #define SW1 p1_2 #define SW2 p1_3 #define LCD_DB p1 #define LCD_DB4 p1_4 #define LCD_DB5 p1_5 #define LCD_DB6 p1_6 #define LCD_DB7 p1_7 #define LCD_STB p3_3 #define LCD_RS p3_4 // 関数プロトタイプ宣言 I2C関連 void I2C_write( unsigned char Ad_data, unsigned char Tx_data ); void I2C_read( unsigned char Ad_data ); void I2C_start(void); void I2C_end(void); void I2C_ackcheck(void); void I2C_ackout(void); void I2C_nonackout(void); void I2C_dout( char a ); void I2C_din(void); void I2C_delay(void); // 関数プロトタイプ宣言 文字列作成 void Itostring(int digit, unsigned long data, char *buffer); // 関数プロトタイプ宣言--液晶 void Lcd_init(void); void Lcd_output(char *str); void Lcd_clear(void); void Lcd_cmd(char cmd); void Lcd_data(char asci); void Lcd_out(char code, char flag); void Lcd_locate(char x, char y); void Lcd_cursol(char c_mode); void Lcd_line_print(char y,char *str); void Delay(long usec); void Delay_ms(unsigned long msec); // 関数プロトタイプ宣言 その他 void sfr_iod(void); void main_ck(void); void Get_sw_data(void); void Wkd_string ( char *Wkd, char *buffer ); void Set_time(void); void Set_value( char *Display_string, char *Number, char Min, char Max ); // 変数の定義 unsigned char I2C_flag = 0; unsigned char I2C_rxdata = 0; unsigned char I2C_slaveadrs = 0; unsigned char I2C_slaveadrs_W = 0b10100010; unsigned char I2C_slaveadrs_R = 0b10100011; char Sw_state = 0; // タクトスイッチ用 char MsgSpace[] = " \0"; // 表示メッセージバッファ char Msg_opning1[] = "RTC8564 RTC TEST\0"; char Msg_opning2[] = "by TEP 2007/7/11\0"; char Msg_date[] = "2000/00/00 Sun \0"; char Msg_time[] = "TIME 00:00:00 \0"; char Msg_set1[] = "SET TIME MODE \0"; char Msg_set2[] = "00000= 00 \0"; char Sec, Min, Hour, Weekday, Year, Month, Day; // 時刻表示用変数 //-------------------------------------------------------------- // メインルーチン //-------------------------------------------------------------- void main(void){ main_ck(); // メインクロック切替 sfr_iod(); // ポート入出力設定 SCL_DIRECTION = HIGH; // I2Cイニシャライズ SDA_DIRECTION = HIGH; SCL = 1; SDA = 1; Lcd_init(); // LCD初期化 Lcd_line_print(1,Msg_opning1); // オープニングメッセージ Lcd_line_print(2,Msg_opning2); Delay_ms(3000); while(1){ I2C_read( 0x02 ); // 秒のアドレスをセットしデータを読み込む Min = I2C_rxdata; Min = Min & 0b01111111; // 不要ビットのマスク処理 Min = Min / 16 * 10 + Min % 16; // 秒のBCD形式から10進変換 Itostring( 2, Min, Msg_time+11); // 秒数を表示文字列バッファに記入 I2C_read( 0x03 ); // 分のアドレスをセットしデータを読み込む Sec = I2C_rxdata; Sec = Sec & 0b01111111; Sec = Sec / 16 * 10 + Sec % 16; Itostring( 2, Sec, Msg_time+8 ); // 分の数値を表示文字列バッファに記入 I2C_read( 0x04 ); // 時のアドレスをセットしデータを読み込む Hour = I2C_rxdata; Hour = Hour & 0b00111111; Hour = Hour / 16 * 10 + Hour % 16; Itostring( 2, Hour, Msg_time+5 ); // 時の数値を表示文字列バッファに記入 I2C_read( 0x05 ); // 日のアドレスをセットしデータを読み込む Day = I2C_rxdata; Day = Day & 0b00111111; Day = Day / 16 * 10 + Day % 16; Itostring( 2, Day, Msg_date+8 ); // 日の数値を表示文字列バッファに記入 I2C_read( 0x07 ); // 月のアドレスをセットしデータを読み込む Month = I2C_rxdata; Month = Month & 0b00111111; Month = Month / 16 * 10 + Month % 16; Itostring( 2, Month, Msg_date+5 ); // 月の数値を表示文字列バッファに記入 I2C_read( 0x08 ); // 年のアドレスをセットしデータを読み込む Year = I2C_rxdata; Year = Year / 16 * 10 + Year % 16; Itostring( 2, Year, Msg_date+2 ); // 月の数値を表示文字列バッファに記入 I2C_read( 0x06 ); // 曜日のアドレスをセットしデータを読み込む Weekday = I2C_rxdata; Weekday = Weekday & 0b00000111; switch ( Weekday ){ case 0: // 読み込んだ数値によって文字列を入れ替える Wkd_string ( "Sun", Msg_date ); break; case 1: Wkd_string ( "Mon", Msg_date ); break; case 2: Wkd_string ( "Tue", Msg_date ); break; case 3: Wkd_string ( "Wed", Msg_date ); break; case 4: Wkd_string ( "Thu", Msg_date ); break; case 5: Wkd_string ( "Fri", Msg_date ); break; case 6: Wkd_string ( "Sat", Msg_date ); break; default: Wkd_string ( " ", Msg_date ); } Lcd_line_print( 1, Msg_date ); // 日付けを表示 Lcd_line_print( 2, Msg_time ); // 時間を表示 Get_sw_data(); // SW1で時刻設定へ if ( Sw_state == 1 ){ Sw_state = 0; Set_time(); } Delay_ms(100); } } // mainルーチン終了 ---------------------------------------------------------- // 曜日文字列を表示用バッファに書き込むサブルーチン -------------------------- void Wkd_string ( char *Wkd, char *buffer ){ char i; buffer = buffer + 11; for(i=1; i<=3; i++){ *buffer = *Wkd; buffer ++; Wkd ++; } } //-------------------------------------------------------------- // 日時設定処理 //-------------------------------------------------------------- void Set_time(void){ unsigned char Temp = 0; Lcd_line_print( 1, Msg_set1 ); Set_value ( "Year ", &Year, 0, 99); Temp = ( Year / 10 ) << 4; Temp = Temp | (Year % 10); I2C_write( 0x08 , Temp ); Set_value ( "Month", &Month, 1, 12); Temp = ( Month / 10 ) << 4; Temp = Temp | (Month % 10); I2C_write( 0x07 , Temp ); Set_value ( "Day ", &Day, 1, 31); Temp = ( Day / 10 ) << 4; Temp = Temp | (Day % 10); I2C_write( 0x05 , Temp ); Set_value ( "Hour ", &Hour, 0, 23); Temp = ( Hour / 10 ) << 4; Temp = Temp | (Hour % 10); I2C_write( 0x04 , Temp ); Set_value ( "Sec ", &Sec, 0, 59); Temp = ( Sec / 10 ) << 4; Temp = Temp | (Sec % 10); I2C_write( 0x03 , Temp ); Set_value ( "Min ", &Min, 0, 59); Temp = ( Min / 10 ) << 4; Temp = Temp | (Min % 10); I2C_write( 0x02 , Temp ); } // 日時設定処理用サブルーチン -------------------------------- void Set_value( char *Display_string, char *Number, char Min, char Max ) { int i; char *Msg_pointer; Msg_pointer = Msg_set2; for ( i=1; i<=5; i++ ){ // 表示用文字列バッファにDisplay_stringで *Msg_pointer = *Display_string; // 与えられた文字列を書き込む Msg_pointer++; Display_string++; } Itostring( 2, *Number, Msg_set2+7 ); // 各々現在の数値をセットし表示 Lcd_line_print( 2,Msg_set2 ); do{ Get_sw_data(); // スイッチ入力 if ( Sw_state == 1 ){ // SW1なら if ( *Number >= Max ){ // 各々最低数値と最大数値が異なる *Number = Min; } else { *Number = *Number + 1; } Itostring( 2, *Number, Msg_set2+7 ); Sw_state = 0; } Lcd_line_print( 2, Msg_set2 ); Delay_ms(100); } while ( Sw_state != 2 ); // SW2ならこのサブルーチンを出る } //-------------------------------------------------------------- //   ポート入出力の設定 //-------------------------------------------------------------- void sfr_iod(void) { pd1_4 = 1; // LCD pd1_5 = 1; // LCD pd1_6 = 1; // LCD pd1_7 = 1; // LCD pd3_3 = 1; // LCD pd3_4 = 1; // LCD pd1_2 = 0; // SW pd1_3 = 0; // SW pd1_0 = 1; // I2C SCL 出力に設定 pd1_1 = 1; // I2C SDA 出力に設定 } //-------------------------------------------------------------- //   クロックの切替 (20MHz) //-------------------------------------------------------------- void main_ck(void) { asm("FCLR I"); prcr = 1; cm13 = 1; cm15 = 1; cm05 = 0; cm16 = 0; cm17 = 0; cm06 = 0; asm("nop"); asm("nop"); asm("nop"); asm("nop"); ocd2 = 0; prcr = 0; } //-------------------------------------------------------------- //   RTC I2C 関連サブルーチン //-------------------------------------------------------------- // ***** RTCへのデータ書込み ***** void I2C_write( unsigned char Ad_data, unsigned char Tx_data ){ I2C_start(); I2C_dout( I2C_slaveadrs_W ); // スレーブアドレス(Write)送出 I2C_ackcheck(); I2C_dout( Ad_data ); // 書き込むアドレスを送出 I2C_ackcheck(); I2C_dout( Tx_data ); // 書き込むデータを送出 I2C_ackcheck(); I2C_end(); } // ***** RTCからのデータ読込 ***** void I2C_read( unsigned char Ad_data ){ I2C_start(); I2C_dout( I2C_slaveadrs_W ); // スレーブアドレス(Write)送出 I2C_ackcheck(); I2C_dout( Ad_data ); // 読み込むアドレスを送出 I2C_ackcheck(); I2C_start(); // 再送開始条件を送出 I2C_dout( I2C_slaveadrs_R ); // スレーブアドレス(Read)送出 I2C_ackcheck(); I2C_din(); // データを読み込む I2C_nonackout(); // "1"のアクノリッジを送出 I2C_end(); } // ビット順データの送出処理 void I2C_dout( unsigned char Out_data ){ char Mask = 0b10000000; char i; char j; for (i=0; i<=7; i++){ // 左より1ビットずつ送信する j = Out_data & Mask; if ( j == 0x80 ){ I2C_nonackout(); } else { I2C_ackout(); } Out_data <<= 1; } } // ビット順データの読込処理 void I2C_din(void){ unsigned char i; SDA_DIRECTION = IN; I2C_rxdata = 0; for ( i=0; i<=7; i++){ I2C_rxdata = I2C_rxdata << 1; SCL = HIGH; I2C_delay(); I2C_rxdata = I2C_rxdata + SDA; SCL = LOW; I2C_delay(); } SDA_DIRECTION = OUT; } // I2C開始条件処理 void I2C_start(void){ SCL = HIGH; SDA = HIGH; I2C_delay(); SDA = LOW; I2C_delay(); SCL = LOW; I2C_delay(); } // I2C終了条件処理 void I2C_end(void){ SCL = HIGH; I2C_delay(); SDA = HIGH; I2C_delay(); } // ACK確認処理 void I2C_ackcheck(void){ SDA = HIGH; SDA_DIRECTION = IN; SCL = HIGH; I2C_delay(); if (SDA != 1){ I2C_flag = 1; // RTCエラー } SCL = LOW; SDA_DIRECTION = OUT; SDA = LOW; I2C_delay(); } // ACK出力処理 void I2C_ackout(void){ SDA = LOW; SCL = HIGH; I2C_delay(); SCL = LOW; SDA = LOW; I2C_delay(); } // non ACK出力処理 void I2C_nonackout(void){ SDA = HIGH; SCL = HIGH; I2C_delay(); SCL = LOW; SDA = LOW; I2C_delay(); } // タイミング用 delay void I2C_delay(void){ char i; i = 30; while(i--){} } //-------------------------------------------------------------- // 数値から文字列に変換 //-------------------------------------------------------------- void Itostring(int digit, unsigned long data, char *buffer) { char i; char f = 0; buffer += digit; //文字列の最後 for(i=digit; i>0; i--){ //最下位桁から上位へ buffer--; //ポインター1 *buffer = (data % 10) + '0'; //その桁数値を文字にして格納 data = data / 10; //桁-1 } } //-------------------------------------------------------------- // スイッチ入力処理(ディレイによるチャタリング除去) //-------------------------------------------------------------- void Get_sw_data(void) { if (SW1 == SW_ON){ Delay_ms(30); if (SW1 == SW_ON){ Sw_state = 1; Delay_ms(30); } } else if (SW2 == SW_ON){ Delay_ms(30); if (SW2 == SW_ON){ Sw_state = 2; Delay_ms(30); } } else { Sw_state = 0; } } //---------------------------------------------------- // 液晶表示器制御ライブラリ // // for R8C/Tiny by. TEP 2007/07/07 // //---------------------------------------------------- //----- LCD初期化関数 ----- void Lcd_init() { Delay(20000); //20msec wait Lcd_out(0x03, 1); //8bit mode set Delay(5000); //5msec wait Lcd_out(0x03, 1); //8bit mode set Delay(1000); Lcd_out(0x03, 1); //8bit mode set Delay(1000); Lcd_out(0x02, 1); //4bit mode set Delay(1000); Lcd_cmd(0x2C); //DL=0 4bit mode Lcd_cmd(0x08); //display off C=D=B=0 Lcd_cmd(0x0E); //display on D=B=1 C=0 Lcd_cmd(0x06); //entry I/D=1 S=0 Lcd_cmd(0x01); //all clear } //----- データ出力サブ関数 ----- void Lcd_out(char code, char flag) { LCD_DB = (LCD_DB & 0b00001111) | (code << 4); //出力データ下位4ビットを出力 if (flag == 0) //表示データかコマンドか LCD_RS = 1; //表示データの場合RS=1 else LCD_RS = 0; //コマンドデータの場合RS=0 asm("NOP"); //NOP スキュー確保 LCD_STB = 1; //STB ON asm("NOP"); asm("NOP"); //パルス幅確保230nsec以上 asm("NOP"); asm("NOP"); LCD_STB = 0; //STB OFF } //----- 1文字表示関数 ----- void Lcd_data(char asci) { Lcd_out(asci>>4, 0); //上位4ビット出力 Lcd_out(asci, 0); //下位4ビット出力 Delay(50); //50μsec待ち } //----- コマンド出力関数 ----- void Lcd_cmd(char cmd) { Lcd_out(cmd>>4, 1); //上位4ビット出力 Lcd_out(cmd, 1); //下位4ビット出力 if((cmd == 0x01) || (cmd == 0x02)) Delay(2000); //2msec待ち else Delay(50); //50usec待ち } //----- 全消去関数 ----- void Lcd_clear() { Lcd_cmd(0x01); //初期化コマンド出力 } //----- 文字列出力関数 ----- void Lcd_output(char *str) { while(*str != 0x00) //文字列の終わり判定 { Lcd_data(*str); //文字列1文字出力 str++; //ポインタ+1 } } //----- カーソル位置に移動 ----- void Lcd_locate(char x, char y) { char i; if (y == 1){ Lcd_cmd(0x02); x--; while ( x ){ Lcd_cmd(0x14); x--; } }else if (y == 2){ Lcd_cmd(0x02); x--; for (i=1;i<=40;i++){ Lcd_cmd(0x14); } while ( x ){ Lcd_cmd(0x14); x--; } } } //----- カーソル表示制御 ----- void Lcd_cursol(char c_mode) { switch ( c_mode){ case 1: // 1.カーソルOFF、ブリンクOFF Lcd_cmd(0x0c); break; case 2: // 2.カーソルOFF、ブリンクON Lcd_cmd(0x0d); break; case 3: // 3.カーソルON、ブリンクOFF Lcd_cmd(0x0e); break; case 4: // 4.カーソルON、ブリンクON Lcd_cmd(0x0f); break; } } //----- 文字列出力関数(行指定あり) ----- void Lcd_line_print(char y,char *str) { if (y == 1){ Lcd_cmd(0x80); } else if(y == 2){ Lcd_cmd(0xC0); } while(*str != 0x00){ //文字列の終わり判定 Lcd_data(*str); //文字列1文字出力 str++; //ポインタ+1 } } //----- ディレイ関数 msec単位 ----- void Delay_ms(unsigned long msec) { while(msec--){ Delay(1000); } } //----- ディレイ関数 1usec単位 ----- void Delay(long usec) { usec = (usec * CLOCK) / 45000; while(usec--){} }