- 追加された行はこの色です。
- 削除された行はこの色です。
#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]