文書の表示以前のリビジョンバックリンクPDF の出力全て展開する/折り畳むODT 出力文書の先頭へ この文書は読取専用です。文書のソースを閲覧することは可能ですが、変更はできません。もし変更したい場合は管理者に連絡してください。 ====== 簡易RTC(Real Time Clock)(I2C対応) ====== ===== 概要 ===== 通常は、下図のような、I2Cインターフェース(2線式)に対応した、リアルタイムクロックモジュールを使用して、時計機能などを構築します。 今回は、このRTC機能そのものを、PICで実現してみました。 {{:imgpaste:202004:htmikan-20200430-094011.png}} ===== 動作原理 ===== I2Cのスレーブ機能としての、基本的な構造は、以前に製作した、LCDモニター(I2C対応)を参照してください。 時刻の、読み出し/書き込みは、以前に製作した、簡易時計(PIC単体)を参照してください。 <メモリ構造> RTCからの時刻データの読み出し、RTCへの時刻データの書き込みのデータを設定するために、7バイトのメモリを使用します。 【0x00】“時"データ(読み出し用) 【0x01】“分"データ(読み出し用) 【0x02】“秒"データ(読み出し用) 【0x03】“時"データ(書き込み用) 【0x04】“分"データ(書き込み用) 【0x05】“秒"データ(書き込み用) 【0x06】書き込み用のデータを、RTCの基準クロックに設定するための指示用(1:設定有り、0:設定無し) <処理の流れ> - 0.1秒毎に、クロック変数をインクリメント(+1)する。 - クロック変数を換算し、時分秒を、読み出し用のメモリ【0x00~0x02】に、設定する。 - RTCへの時刻データの設定が指示されると、メモリ【0x03~0x05】を換算し、クロック変数に設定する。 - 1.へ戻る。 <マスター側から、本ユニットの時刻データを、読み込む方法および書き込む方法> - 時刻データを読み込む\\ <code> Soft_I2C_Start(); Soft_I2C_Write(0x80); Soft_I2C_Write(0x00); Soft_I2C_Start(); Soft_I2C_Write(0x81); hh = Soft_I2C_Read(ACK); mm = Soft_I2C_Read(ACK); ss = Soft_I2C_Read(NO_ACK); Soft_I2C_Stop(); </code> - 時刻データを書き込む\\ <code> Soft_I2C_Start(); Soft_I2C_Write(0x80); Soft_I2C_Write(0x03); Soft_I2C_Write(12);//12時 Soft_I2C_Write(34);//34分 Soft_I2C_Write(56);//56秒 Soft_I2C_Write(0x01);//設定指示 Soft_I2C_Stop(); </code> ===== 回路図 ===== {{:imgpaste:202004:htmikan-20200430-094221.png}} ===== ソースコード ===== <code c rtc_i2c.c> //********************************************************************** /* <RTC(I2C対応)> */ //********************************************************************** #define ADDR_BASE 0x80 #define ON 1 #define OFF 0 #define MEMORY_SIZE 7 #define LED PORTB.F5 //********************************************************************** void i2c_Write(unsigned short dat) { while (SSPSTAT.BF == 1) ; while (1) { SSPCON.WCOL = 0; SSPBUF = dat; if (SSPCON.WCOL == 1) continue; // SSPCON.CKP = 1; return; } } //********************************************************************** static unsigned short i2c_memory[MEMORY_SIZE], i2c_pnt, i2c_flg, i2c_tmp, i2c_start_flg, i2c_stop_flg; /* i2c_memory[0] 時 i2c_memory[1] 分 i2c_memory[2] 秒 */ //********************************************************************** void i2c_Handler() { if (PIR1.SSPIF != 1) return; // PIR1.SSPIF = 0; // LED = ON; // if (SSPSTAT.S == 1) { //スタートビットを検出。 i2c_start_flg = 1; } if (SSPSTAT.P == 1) { //ストップビットを検出。 i2c_stop_flg = 1; } // i2c_tmp = SSPSTAT & 0b00101101; // if (i2c_tmp == 0b00001001) { //書き込みモード、デバイスアドレス i2c_tmp = SSPBUF; i2c_flg = 0; i2c_pnt = 0; LED = OFF; return; } if (i2c_tmp == 0b00101001) { //書き込みモード、データ if (i2c_flg == 0) { i2c_pnt = SSPBUF; i2c_flg = 1; LED = OFF; return; } if (i2c_flg == 1) { if (i2c_pnt < MEMORY_SIZE) { i2c_memory[i2c_pnt] = SSPBUF; i2c_pnt++; } LED = OFF; return; } } if (i2c_tmp == 0b00001100) { //読み込みモード、デバイスアドレス i2c_Write(i2c_memory[i2c_pnt]); i2c_pnt++; LED = OFF; return; } if (i2c_tmp == 0b00101100) { //読み込みモード、データ(ACK) i2c_Write(i2c_memory[i2c_pnt]); i2c_pnt++; LED = OFF; return; } if (i2c_tmp == 0b00101000) { //読み込みモード、データ(NO_ACK) i2c_tmp = SSPBUF; SSPCON = 0b00111110; LED = OFF; return; } LED = OFF; } //********************************************************************** static long clock; void rtc_Handler() { static short hh, mm, ss; // if (PIR1.CCP1IF != 1) return; // PIR1.CCP1IF = 0; // clock++; if (clock == 864000) clock = 0; // hh = clock / 36000; mm = (clock - (36000 * (long)hh)) / 600; ss = (clock - (36000 * (long)hh) - (600 * (long)mm)) / 10; i2c_memory[0] = hh; i2c_memory[1] = mm; i2c_memory[2] = ss; } //********************************************************************** void interrupt() { i2c_Handler(); } //********************************************************************** void init_rtc() { // TIMER1の設定 PIE1.TMR1IE = 0; PIR1.TMR1IF = 0; T1CON.T1CKPS0 = 1; T1CON.T1CKPS1 = 1; T1CON.TMR1ON = 0; TMR1L = 0; TMR1H = 0; // CCPの設定 PIE1.CCP1IE = 0; PIR1.CCP1IF = 0; CCP1CON.CCP1M3 = 1; CCP1CON.CCP1M2 = 0; CCP1CON.CCP1M1 = 1; CCP1CON.CCP1M0 = 1; CCPR1L = 0xA8; // 0.1sec...10hz...クロックが8Mhzの時 CCPR1H = 0x61; // 0.1sec...(1÷8000000)*4*8*25000 // clock = 0; // T1CON.TMR1ON = 1; } //********************************************************************** void main() { unsigned short cnt; // CMCON = 0b00000111; //コンパレータは使用しない。 ANSEL = 0b00000000; //A/Dコンバータは使用しない。 OSCCON = 0b01110000; //クロックは内臓8MHzを使用する。 TRISA = 0b00111100; //PORTAを設定する。 TRISB = 0b00011111; //PORTBを設定する。 OPTION_REG.NOT_RBPU = 0; //PORTBをプルアップする。 //I2Cを設定する。 SSPSTAT.SMP = 1; SSPSTAT.CKE = 1; SSPCON.WCOL = 0; SSPCON.SSPOV = 0; SSPCON.SSPEN = 1; SSPCON.CKP = 1; SSPCON.SSPM0 = 0; SSPCON.SSPM1 = 1; SSPCON.SSPM2 = 1; SSPCON.SSPM3 = 1; SSPADD = ADDR_BASE; PIE1.SSPIE = 1; PIR1.SSPIF = 0; // LED = OFF; i2c_pnt = 0; i2c_flg = 0; i2c_start_flg = 0; i2c_stop_flg = 0; for (cnt = 0; cnt < MEMORY_SIZE; cnt++) { i2c_memory[cnt] = 0x00; } // for (cnt = 0; cnt < 10; cnt++) { LED = ON; Delay_ms(50); LED = OFF; Delay_ms(50); } // 割り込み(全体)の設定 INTCON.PEIE = 1; INTCON.GIE = 1; // init_rtc(); while (1) { rtc_Handler(); if (i2c_memory[6] == 0x01) { i2c_memory[6] = 0x00; clock = ((long)i2c_memory[3] * 36000) + ((long)i2c_memory[4] * 600) + ((long)i2c_memory[5] * 10); } } } //********************************************************************** </code> <参考> ※テストデータ送信用(I2Cマスター/PIC16F88)のプログラムです。 <code c rtc_i2c_master.c> //********************************************************************** /* <RTCのテストデータ送信用(マスター)> */ //********************************************************************** #define ACK 1 #define NO_ACK 0 //********************************************************************** void main() { static unsigned short cnt, hh, mm, ss; static char buf[8]; // OSCCON = 0b01110000; // クロックを8Mhzに設定する。 ANSEL = 0b00000000; // A/D変換は使用しない。 TRISA = 0b00110000; TRISB = 0b00001111; // Lcd_Custom_Config(&PORTA, 1, 0, 7, 6, &PORTB, 5, 6, 7); Lcd_Custom_Cmd(LCD_CURSOR_OFF); Lcd_Custom_Cmd(LCD_CLEAR); // for (cnt = 0; cnt < 16; cnt++) { Lcd_Custom_Chr(1, cnt + 1, 0xFF); Delay_ms(50); } for (cnt = 0; cnt < 16; cnt++) { Lcd_Custom_Chr(2, cnt + 1, 0xFF); Delay_ms(50); } Lcd_Custom_Cmd(LCD_CLEAR); // // Soft_I2C_Config(&PORTA, 2, 3); // SDA, SCL // while (1) { // Soft_I2C_Start(); Soft_I2C_Write(0x80); Soft_I2C_Write(0x00); Soft_I2C_Start(); Soft_I2C_Write(0x81); hh = Soft_I2C_Read(ACK); mm = Soft_I2C_Read(ACK); ss = Soft_I2C_Read(NO_ACK); Soft_I2C_Stop(); // ByteToStr(hh, buf); buf[1] = buf[1] == ' ' ? '0' : buf[1]; Lcd_Custom_Out(1, 1, &buf[1]); Lcd_Custom_Chr(1, 3, ':'); ByteToStr(mm, buf); buf[1] = buf[1] == ' ' ? '0' : buf[1]; Lcd_Custom_Out(1, 4, &buf[1]); Lcd_Custom_Chr(1, 6, ':'); ByteToStr(ss, buf); buf[1] = buf[1] == ' ' ? '0' : buf[1]; Lcd_Custom_Out(1, 7, &buf[1]); // if (PORTB.F3 == 0) { //時刻設定 Soft_I2C_Start(); Soft_I2C_Write(0x80); Soft_I2C_Write(0x03); Soft_I2C_Write(12); //12時 Soft_I2C_Write(34); //34分 Soft_I2C_Write(56); //56秒 Soft_I2C_Write(0x01); //設定指示 Soft_I2C_Stop(); } // Delay_ms(100); } } //********************************************************************** </code> ===== 動作確認 ===== {{:imgpaste:202004:htmikan-20200430-094345.png?500}} 左側:RTC(スレーブ)※今回の主役です。抵抗3個、LED1個だけです。 右側:RTC(マスター) {{:imgpaste:202004:htmikan-20200430-094408.png?500}} RTC(スレーブ)の拡大図です。 {{:imgpaste:202004:htmikan-20200430-094419.png?500}} 起動直後に、RTC(マスター)がRTC(スレーブ)から時刻データを取得し、表示したところです。 {{:imgpaste:202004:htmikan-20200430-094429.png?500}} RTC(マスター)から、RTC(スレーブ)に対して、時刻を設定(12時34分56秒)したところです。 {{:imgpaste:202004:htmikan-20200430-094441.png?500}} 時刻設定後の、時刻経過を表示したところです。 {{:imgpaste:202004:htmikan-20200430-094451.png?500}} <callout type="warning" title="著作権表示 copyright notice"> このページは稲崎様の閉鎖したHPのコピーで、著作権は稲崎様にあります。[[elechobby:picdic:picdic|詳細]] This page is a copy of Mr. Inasaki's closed website, and the copyright is held by him.[[elechobby:picdic:picdic|Details]] </callout> elechobby/picdic/pic16f88/109.txt 最終更新: 2025/10/17 14:29by 127.0.0.1