米粒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

Androidで一眼レフカメラのシャッターを制御する

またSoftModemネタです。 調子に乗って arms22さんの記事 iPhoneで一眼レフカメ

記事を読む

no image

米粒AVRでシリアル通信(ただし送信だけ)

米粒AVR(ATtiny10)にUART機能は搭載されていないので、シリアル通信を行う為には自前

記事を読む

no image

ボツネタ~CAN的な何か

少し前に必死になって作ってたデバイス+アプリですが、気持ちが萎えてしまい、結果ボツと

記事を読む

no image

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

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

記事を読む

sdcards

Raspberry Pi SDカードのクラスと起動速度

SDカードにOSをインストールするので、起動にはそれなりに時間がかかります。 では、どれくらい

記事を読む

米粒AVR リモコン

米粒AVRでリモコン送信機

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

記事を読む

no image

米粒AVRでアナログ入力を試してみた

米粒AVR(ATtiny10)に搭載されている8ビット4チャンネルのアナログ入力を試してみました

記事を読む

soundIR 送信機

赤外線リモコン送信機(イヤホンジャック接続)の回路

前回は受信機で、今回は送信機を作ってみました。 受信機と違って、送信機の作成は少し面倒です。

記事を読む

no image

Androidとオーブントースターを繋いでみた

Android端末とオーブントースターを、Arduino+USBホストシールドで作ったADKっぽい奴

記事を読む

soundIR 受信機 回路図

赤外線リモコン受信機(イヤホンジャック接続)の回路

  前回からだいぶと時間が経ってしまっていますが、今回はイヤホンジャック接続のリモコン受

記事を読む

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 ↑