#norelated
#contents
* RTCサンプル [#o86fce4c]

RTCモジュールとI2Cで通信して時計を作る。~
I2Cは前回よくわかってないって書いたけど、前よりはちょっと理解した。~

USARTは、2本の線を使って、1本が送信、1本が受信の役割をするけど、I2Cは同じ二本でも、1本がクロック、1本がデータになっていて、複数の機器を制御できるバス通信らしい。~
複数の機器は、それぞれがマスターにもスレーブにもなれて、それぞれの状態で送信受信ができるらしい。~

AVRと[[秋月のRTCモジュール:http://akizukidenshi.com/catalog/g/gI-00233/]]で、このI2Cという方式でデータのやり取りをすることにより、時刻の設定、読み出し等が可能になると。~

** 回路図 [#s17638b1]

前回書いたように、UART(USART)はRXD(PD0)とTXD(PD1)をクロスに繋いだけど、I2CはSCL(PC5)とSDA(PC4)は、それぞれ同じもの同士を繋ぐ。

SCLとSDAは、RTCモジュールのジャンパをショートすれば、内部でプルアップ抵抗が有効になるらしいけど、なんとなくそのままにしておきたかったので、自前で内部に持っているのと同じ2.2kΩの抵抗をつけてあります。~
プルアップ抵抗値の決め方とかも、理由があるんだろうけど、まだよくわかってません。~

#ref(RtcTest.png,left,nowrap,RTCサンプル)

** ソースコード [#lfaf1c0f]

//まず、メインで参照する各種ライブラリ。~
//&ref(util.h,left,nowrap,ユーティリティヘッダ);&ref(util.c,left,nowrap,ユーティリティソース);&ref(LcdLib.h,left,nowrap,LCDライブラリヘッダ);&ref(LcdLib.c,left,nowrap,LCDライブラリソース);~

とりあえず、読み出しだけはできるようになったデバッグコード。~

 #include <stdio.h>
 #include "LcdLib.h"
 #include "UsartLib.h"
 #include "util.h"
 
 #define RTC_ADDR_WRITE 0xA2
 #define RTC_ADDR_READ  0xA3
 
 #define I2C_BPS	2	// ボーレート設定値
 
 // TWIモード列挙型定義
 typedef enum _tagTWIMode{
 	TWI_MODE_SEND,		// 送信モード
 	TWI_MODE_RECEIVE,	// 受信モード
 } TWIMode;
 typedef enum _tagTWIACKMode{
 	TWI_ACKMODE_ACK,	// ACK送信モード
 	TWI_ACKMODE_NACK,	// NACK送信モード
 } TWIACKMode;
 
 void I2c_init( void )
 {
 	TWSR &= ~0x03;		// BPSの前置分周は等倍にする
 	TWBR = I2C_BPS;		// CPUクロックが1MHzなのに対して、50KHzで通信する
 	TWCR = 0b00000100;	// ピンをTWI(SCL/SDA)として使用する
 }
 
 int8_t I2c_start( void )
 {
 	TWCR = 0b10100100;	// スタート設定
 	while( !( TWCR & 0b10000000 )){
 		;	// 送信開始OKになるまで待つ
 	}
 
 	if( 0x08 == ( TWSR & 0xF8 )){
 		return 0;
 	} else if( 0x10 == ( TWSR & 0xF8 )){
 		return 1;
 	}
 	return -1;
 }
 
 int8_t I2c_setaddr( uint8_t addr, TWIMode mode )
 {
 	TWDR = addr;
 	TWCR = 0b10000100;	// 送信設定
 	while( !( TWCR & 0b10000000 )){
 		;	// 相手の応答まで待つ
 	}
 	if( TWI_MODE_SEND == mode ){
 		if( 0x18 == ( TWSR & 0xF8 )){
 			return 0;
 		} else if( 0x20 == ( TWSR & 0xF8 )){
 			return 1;
 		}
 	} else {
 		if( 0x40 == ( TWSR & 0xF8 )){
 			return 0;
 		} else if( 0x48 == ( TWSR & 0xF8 )){
 			return 1;
 		}
 	}
 	return -1;
 }
 
 int8_t I2c_snddata( uint8_t data )
 {
 	TWDR = data;
 	TWCR = 0b10000100;	// 送信設定
 	while( !( TWCR & 0b10000000 )){
 		;	// 相手の応答まで待つ
 	}
 	if( 0x28 == ( TWSR & 0xF8 )){
 		return 0;
 	} else if( 0x30 == ( TWSR & 0xF8 )){
 		return 1;
 	}
 	return -1;
 }
 
 int8_t I2c_rcvdata( uint8_t *data, TWIACKMode mode )
 {
 	if( TWI_ACKMODE_ACK == mode ){
 		TWCR = 0b11000100;
 	} else {
 		TWCR = 0b10000100;
 	}
 	while( !( TWCR & 0b10000000 )){
 		;	// データを受信するまで待つ
 	}
 	if( 0x50 == ( TWSR & 0xF8 )){
 		*data = TWDR;
 		return 0;
 	} else if( 0x58 == ( TWSR & 0xF8 )){
 		*data = TWDR;
 		return 1;
 	}
 	return -1;
 }
 
 void I2c_stop( void )
 {
 	TWCR = 0b10010100;	// ストップ設定
 }
 
 int main( void )
 {
 	uint8_t data[16];	// 受信データ格納用
 	uint8_t	i	= 0;	// ループ変数
 	char str[5] = "  ";	// 16進コード格納用
 
 	Lcd_init();						// LCD初期化
 	Lcd_setstr( "Receive Data:" );	// 初期表示
 
 	Usart_init();	// シリアル通信初期化
 	I2c_init();		// I2C通信初期化
 
 	while( 1 ){
 		if( 0 > I2c_start() ){
 			Usart_sndstr( "I2c_start_err_1" );
 			continue;
 		}
 		if( 0 != I2c_setaddr( RTC_ADDR_WRITE, TWI_MODE_SEND )){
 			Usart_sndstr( "I2c_setaddr(send)_err" );
 			continue;
 		}
 		if( 0 != I2c_snddata( 0 )){
 			Usart_sndstr( "I2c_snddata_err" );
 			continue;
 		}
 
 		if( 0 > I2c_start() ){
 			Usart_sndstr( "I2c_start_err_2" );
 			continue;
 		}
 		if( 0 != I2c_setaddr( RTC_ADDR_READ, TWI_MODE_RECEIVE )){
 			Usart_sndstr( "I2c_setaddr(receive)_err" );
 			continue;
 		}
 
 		for( i = 0; i < 15; i++ ){
 			if( 0 > I2c_rcvdata( &data[i], TWI_ACKMODE_ACK )) break;
 		}
 		if( 15 != i ){
 			continue;
 		}
 		if( 0 > I2c_rcvdata( &data[i], TWI_ACKMODE_NACK )){
 			continue;
 		}
 		I2c_stop();
 
 		Lcd_setpos( 0, 0 );
 		for( i = 0; i < 8; i++ ){
 			sprintf( str, "%02X", data[i] );
 			Lcd_setstr( str );
 		}
 		Lcd_setpos( 1, 0 );
 		for( i = 8; i < 16; i++ ){
 			sprintf( str, "%02X", data[i] );
 			Lcd_setstr( str );
 		}
 
 		{
 			uint8_t sec = data[2];
 			uint8_t min = data[3];
 			uint8_t hour = data[4];
 			uint8_t day = data[5];
 			uint8_t week = data[6];
 			uint8_t month = data[7];
 			uint8_t year = data[8];
 			char date[24] = "                       ";
 			char weekstr[7][4] = {
 				"Sun",
 				"Mon",
 				"Tue",
 				"Wed",
 				"Thr",
 				"Fri",
 				"Sat",
 			};
 			sec = (( sec >> 4 ) & 0x07 ) * 10 + ( sec & 0x0F );
 			min = (( min >> 4 ) & 0x07 ) * 10 + ( min & 0x0F );
 			hour = (( hour >> 4 ) & 0x03 ) * 10 + ( hour & 0x0F );
 			day = (( day >> 4 ) & 0x03 ) * 10 + ( day & 0x0F );
 			week = week & 0x07;
 			month = (( month >> 4 ) & 0x01 ) * 10 + ( month & 0x0F );
 			year = (( year >> 4 ) & 0x0F ) * 10 + ( year & 0x0F );
 			sprintf( date, "20%02d/%02d/%02d %02d:%02d:%02d %s", year, month, day, hour, min, sec,  weekstr[week] );
 			Usart_sndstr( date );
 		}
 		delay_ms( 500 );
 	}
 
 	return 0;
 }

*** 基本動作 [#v775d1bd]

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS