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

米粒AVRの動作周波数

  米粒AVR(ATtiny10)のデフォルトでは内臓発振器利用の1MHzが指定されてい

記事を読む

no image

ボツネタ~CAN的な何か

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

記事を読む

raspi-colortest

Raspbianの起動

Raspbianの起動画面をキャプチャしてみた。 SDカードにイメージを書き込んだままのデフォ

記事を読む

no image

SoundIRModemライブラリのサンプル

 SoundIRModemライブラリは、米粒AVR(Tiny10)とAndroid端末をイ

記事を読む

Hello Tiny10

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

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

記事を読む

no image

PIC24FJ64GB002でADKを試す(その1)

先日、MicrochipからPIC向けのAndroid Open Accessoryのライブラリが公

記事を読む

Androidから米粒AVRへデータを送る

米粒AVRでSoftModem的なこと その2

前回は「米粒AVRからAndroidへデータを送る」ことを試しました。 今回はその逆の「And

記事を読む

no image

Android+Arduinoでリモコン4(Microbridge接続)

前回AndroidAccessory接続で作った赤外線学習リモコンを、今回はMicrobridge接

記事を読む

Raspberry Pi - Ethernet

Raspberry Pi インターネット接続

Raspberry Piをインターネットに接続してみた。 有線で接続(Ethern

記事を読む

no image

AndroidでSoftModemを試してみた

今回、ここで言うSoftModemとは、携帯電話のオーディオ端子(イヤホン・マイク端子)を利用し

記事を読む

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 ↑