米粒AVRでI2C通信(マスター)

公開日: 電子工作 | ,

米粒AVRでI2C通信

米粒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(クロック)

としています。

米粒AVR soft-I2C 回路

 

命令説明

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デバイスとかだと動作しない可能性があります。
一応、このソースを使って通信可能であることを確認したモジュールは以下の物があります。

 

関連記事

no image

USBホストケーブルとUSBケーブルの違い

USBホストケーブル(OTGケーブル)と普通のUSBケーブルの違いは、USBホストケーブルとして振る

記事を読む

熱湯の温度計測実験

パソコンで温度計 #3

今回は、I2C接続の温度センサー STTS751をケーブルを使ってArduinoに接続できるよう

記事を読む

Hello Tiny10

米粒AVRでI2C通信を使ってLCD表示

前の記事で紹介したI2Cライブラリを使った、LCDの表示のライブラリ的なもの  

記事を読む

SDカード・マイクロSDカード

ArduinoでSDカード

電子工作で大量のデータを保存する方法を調べていると、 Arduinoでも比較的簡単にSDカードを

記事を読む

no image

Softmodem Terminal 公開しました。

需要がどれほど有るのか疑問に思いつつ、以前のエントリ(AndroidでSoftModemを試してみた

記事を読む

no image

Arduino + USBホストシールド で ADK を試す(その1)

先日Google IOで発表された Android Open Accessory。みなさん知ってます

記事を読む

Arduino + STTS751

パソコンで温度計

ありきたりのPC温度計ですが、なんとなく作りたくなったので作ってみる。 コントローラーは手軽な

記事を読む

no image

Bimeji Client for Arduino

前回紹介したWimeji Client for Arduinoの最後で予告していた、Wimeji c

記事を読む

米粒AVR リモコン

米粒AVRでリモコン送信機

米粒AVR(tiny10)を使った赤外線リモコン送信機を作ってみました。 これで送信できるのは

記事を読む

Arduinoで温湿度計

Arduinoで温湿度計

秋月電子の温湿度モジュールを使って、温湿度計を作ってみました。 以前「パソコンで温度計」と言うもの

記事を読む

Comment (2件)

  1. ハヤシ

    はじめてコメントさせていただきます。
    よろしくお願い致します。

    私も同じINA226を購入し、LCDに電圧と電流を表示しようとし
    プログラムを勉強していますがなかなかできなくて悩んでいます。

    INA226関連のソースも公開できないでようか?

    よろしくお願いします。

    1. Futaba

      コメントありがとうございます。
      どの辺りがうまく行かないのでしょうか?

Arduinoで温湿度データロガー
Arduinoで温湿度計 #2

今回は、前回作った温湿度計にRTCモジュールとSDカードアダプタを

Arduinoで温湿度計
Arduinoで温湿度計

秋月電子の温湿度モジュールを使って、温湿度計を作ってみました。 以前

SDカード・マイクロSDカード
ArduinoでSDカード

電子工作で大量のデータを保存する方法を調べていると、 Arduin

秋月電子 リアルタイムクロック(RTC)モジュール
秋月のリアルタイムクロック(RTC)モジュール

今回は秋月電子のI2C接続のリアルタイムクロック(RTC)モジュールを

秋月電子 キャラクタLCD
秋月の小型キャラクタLCD

今回秋月電子で売られている小型のキャラクター液晶2種を買ったので、

PAGE TOP ↑