米粒AVRでI2C通信(マスター)
公開日:
電子工作 | I2C, 米粒AVR(tiny10)
米粒AVRことATtiny10は3つまたは4つのI/Oピンしか使えないのですが、I2Cなら2つのピンを使うだけで複数のモジュールと通信ができると言うことで、I2Cが使えれば便利だろうと試行錯誤してみました。
結論を言うと、一応出来たのは出来たのですが、凝ったことをやろうとするとすぐにメモリオーバーになっちゃいます(´・ω・`)
そもそもプログラムメモリが1kバイトしかないので、当たり前といえば当たり前なんですが・・・I2C使いたいなら、素直にtiny45とかtiny2313とか使うべきなんだろうと思いました。
そもそも、I2Cモジュール自体が大きいので、小さいことが売りである米粒AVRでやる意味は無いと言えば無いので・・・
ま、とりあえず出来たので、ソースを公開しておきます。
ソース
tiny10softI2C.h
/*<br /> tiny10softI2C.h<br /> Software I2C Library for ATTiny10<br /> http://s2jp.com/<br /> <br /> Copyright (c) 2012 Futaba. All Rights Reserved.<br /> */<br /> <br /> #ifndef _S2_TINY10_SOFTI2C_H_<br /> #define _S2_TINY10_SOFTI2C_H_<br /> <br /> #include <avr/io.h><br /> #include <util/delay.h><br /> <br /> #define I2C_SDA_PIN PB0<br /> #define I2C_SCL_PIN PB1<br /> <br /> #define I2C_SDA_PIN_BV _BV(I2C_SDA_PIN)<br /> #define I2C_SCL_PIN_BV _BV(I2C_SCL_PIN)<br /> <br /> #define _I2C_SDA_HIGH (PORTB |= I2C_SDA_PIN_BV)<br /> #define _I2C_SDA_LOW (PORTB &= ~I2C_SDA_PIN_BV)<br /> <br /> #define _I2C_SCL_HIGH (PORTB |= I2C_SCL_PIN_BV)<br /> #define _I2C_SCL_LOW (PORTB &= ~I2C_SCL_PIN_BV)<br /> <br /> void I2C_clkWait()<br /> {<br /> #if F_CPU == 1000000<br /> __asm__ __volatile__("nop");<br /> #elif F_CPU == 1200000<br /> __asm__ __volatile__("nop");<br /> #elif F_CPU == 2000000<br /> __asm__ __volatile__("nop");<br /> __asm__ __volatile__("nop");<br /> __asm__ __volatile__("nop");<br /> __asm__ __volatile__("nop");<br /> __asm__ __volatile__("nop");<br /> #elif F_CPU == 2400000<br /> __asm__ __volatile__("nop");<br /> __asm__ __volatile__("nop");<br /> __asm__ __volatile__("nop");<br /> __asm__ __volatile__("nop");<br /> #elif F_CPU == 4000000<br /> _delay_us(2);<br /> #elif F_CPU == 4800000<br /> _delay_us(2);<br /> #else<br /> _delay_us(4);<br /> #endif<br /> }<br /> <br /> void I2C_clkWait2()<br /> {<br /> #if F_CPU == 1000000<br /> #elif F_CPU == 1200000<br /> #elif F_CPU == 2000000<br /> #elif F_CPU == 2400000<br /> #elif F_CPU == 4000000<br /> _delay_us(2);<br /> #elif F_CPU == 4800000<br /> _delay_us(2);<br /> #else<br /> _delay_us(3);<br /> #endif<br /> }<br /> <br /> inline static void I2C_init()<br /> {<br /> DDRB |= I2C_SDA_PIN_BV;<br /> DDRB |= I2C_SCL_PIN_BV;<br /> <br /> _I2C_SCL_HIGH;<br /> _I2C_SDA_HIGH;<br /> }<br /> <br /> void I2C_start()<br /> {<br /> _I2C_SDA_HIGH;<br /> I2C_clkWait();<br /> _I2C_SCL_HIGH;<br /> <br /> I2C_clkWait();<br /> _I2C_SDA_LOW;<br /> I2C_clkWait();<br /> _I2C_SCL_LOW;<br /> }<br /> <br /> void I2C_stop()<br /> {<br /> _I2C_SDA_LOW;<br /> I2C_clkWait();<br /> _I2C_SCL_HIGH;<br /> I2C_clkWait();<br /> _I2C_SDA_HIGH;<br /> I2C_clkWait();<br /> }<br /> <br /> uint8_t I2C_write(uint8_t data)<br /> {<br /> uint8_t temp;<br /> for(temp=0x80; temp; temp>>=1)<br /> {<br /> if(data & temp) _I2C_SDA_HIGH;<br /> else _I2C_SDA_LOW;<br /> I2C_clkWait2();<br /> _I2C_SCL_HIGH;<br /> I2C_clkWait();<br /> _I2C_SCL_LOW;<br /> }<br /> <br /> DDRB &= ~I2C_SDA_PIN_BV;<br /> <br /> I2C_clkWait();<br /> temp=PINB;<br /> _I2C_SCL_HIGH;<br /> I2C_clkWait();<br /> <br /> _I2C_SCL_LOW;<br /> <br /> DDRB |= I2C_SDA_PIN_BV;<br /> <br /> if(temp & I2C_SDA_PIN_BV)<br /> {<br /> return 1;<br /> }<br /> return 0;<br /> }<br /> <br /> uint8_t I2C_read(uint8_t ACK)<br /> {<br /> uint8_t data=0;<br /> uint8_t temp;<br /> <br /> DDRB &= ~I2C_SDA_PIN_BV;<br /> <br /> for(temp=0x80; temp; temp>>=1)<br /> {<br /> I2C_clkWait();<br /> if(PINB & I2C_SDA_PIN_BV) data |= temp;<br /> _I2C_SCL_HIGH;<br /> <br /> I2C_clkWait();<br /> _I2C_SCL_LOW;<br /> }<br /> <br /> DDRB |= I2C_SDA_PIN_BV;<br /> <br /> if(ACK) _I2C_SDA_LOW;<br /> else _I2C_SDA_HIGH;<br /> <br /> I2C_clkWait();<br /> _I2C_SCL_HIGH;<br /> I2C_clkWait();<br /> _I2C_SCL_LOW;<br /> <br /> return data;<br /> }<br /> <br /> #endif<br />
ソースはヘッダーファイル用に作っています。
Atmel Studio 6で、tiny10softI2c.h として保存し、#inlude して利用することを想定してます。
他のコンパイラとかでは動かないかもしれません。
ソースを分割してたりして複数のソース内でincludeする場合は工夫が必要です。(米粒AVRでそこまでやってる人っているのだろうか・・・)
ピン
デフォルトでは、
PB0 が SDA(データ)
PB1 が SCL(クロック)
としています。
命令説明
void I2C_init();
ライブラリの初期化。
void I2C_start();
start condition発行。
void I2C_stop();
stop condition発行。
uint8_t I2C_write(uint8_t data);
引数 data をI2Cへ送信
戻り値 0=ACK 1=NACK
uint8_t I2C_read(uint8_t ACK);
I2Cからデータを読み込む。
引数 ack == 1 でACK、ack == 0 でNACK
戻り値 読み込んだデータ
クロック
このライブラリでは、I2Cのクロックは米粒AVRが内臓8MHzで動作している時に、約100kHzとなっています。
ただし、ソフトI2Cなのでクロックやデューティ比には、かなりのばらつきがあり、必ずしもこの通りとは限りません。
だいたい100k・・・と言うことで
注意
僕自身I2Cの知識に乏しく、今回初めてI2C通信をやりました。
そんな勉強がてらに作ったものなので、かなりいい加減な作りになっています。
ですので、通信のタイミングに厳格なI2Cデバイスとかだと動作しない可能性があります。
一応、このソースを使って通信可能であることを確認したモジュールは以下の物があります。
関連記事
-
-
Raspberry Pi SDカードのクラスと起動速度
SDカードにOSをインストールするので、起動にはそれなりに時間がかかります。 では、どれくらい
-
-
Raspberry PiをWindowsで操作する(SSH)
SSHを使って、Raspberry Piを外部PC(Windows)で操作する。
-
-
米粒AVRでリモコン受信処理
米粒AVR(Tiny10)で赤外線リモコンを受信して処理をするサンプルを作ってみまし
-
-
Raspberry Piを買った
先日、Raspberry Pi(ラズベリーパイ)を買いました。 Raspberry Piは噂で
-
-
米粒AVRでI2C通信を使ってLCD表示
前の記事で紹介したI2Cライブラリを使った、LCDの表示のライブラリ的なもの
-
-
秋月のリアルタイムクロック(RTC)モジュール
今回は秋月電子のI2C接続のリアルタイムクロック(RTC)モジュールを買ったので、ちょっと試してみま
-
-
Arduinoで温湿度計
秋月電子の温湿度モジュールを使って、温湿度計を作ってみました。 以前「パソコンで温度計」と言うもの
-
-
Raspbianの起動
Raspbianの起動画面をキャプチャしてみた。 SDカードにイメージを書き込んだままのデフォ
-
-
オシロスコープを手に入れた
ついにオシロスコープを買っちゃいました。 と言っても、DSO QUADと言うポータブルタイプの
-
-
パソコンで温度計 #2
今回は温度表示とログ取りアプリを作ったので公開。 前回にArduino+STTS751で作った
Comment (2件)
はじめてコメントさせていただきます。
よろしくお願い致します。
私も同じINA226を購入し、LCDに電圧と電流を表示しようとし
プログラムを勉強していますがなかなかできなくて悩んでいます。
INA226関連のソースも公開できないでようか?
よろしくお願いします。
コメントありがとうございます。
どの辺りがうまく行かないのでしょうか?