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

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

前回と同じく、リモコンのプロトコルを使います。
Androidのイヤホンジャックに接続するリモコン送信機と米粒AVRで行うリモコン受信処理をくっつけるとAndroidから米粒AVRへデータを送ることができる計算です。

前回の回路で、米粒AVRからAndroidへ送ったデータを、そのまま今回の回路に送り直すことで、LEDのOn/Offを制御してみます。

 

回路

回路は、リモコン送信機の回路の、LED1を通常のLEDに変えて、LED2(PB3)を足した物となっています。
このLED1・LED2の点灯/消灯を、Androidでコントロールします。

Android→tiny10 送信テスト回路

 

 

Tiny10用ソース

リモコン受信処理のものを少しだけ修正して使っています。
前のリモコン受信処理ではint0割り込みを使っていたのですが、このソースではコンパレータを使うように修正しています。
コンパレータを使うとピンがどうしても2本必要になるので、本当はピンが1本ですむint0で処理したかったのですが、色々と試行錯誤するも結果うまく出来ず、コンパレータに逃げた次第ですw

#define F_CPU 8000000UL        // 2MHz以上で動作<br />
<br />
#include <avr/io.h><br />
#include <avr/interrupt.h><br />
#include <avr/sleep.h><br />
#include <util/delay.h><br />
<br />
#define LED1            PB2<br />
#define LED2            PB3<br />
<br />
#define THRESHOLD_HEADER_HIGH_MIN        162        // 9000 * 0.9 / 50<br />
#define THRESHOLD_HEADER_HIGH_MAX        198        // 9000 * 1.1 / 50<br />
#define THRESHOLD_HEADER_LOW_MIN        81        // 4500 * 0.9 / 50<br />
#define THRESHOLD_HEADER_LOW_MAX        99        // 4500 * 1.1 / 50<br />
#define THRESHOLD_HEADER_REP_LOW_MIN    40        // 2250 * 0.9 / 50<br />
#define THRESHOLD_HEADER_REP_LOW_MAX    49        // 2250 * 1.1 / 50<br />
#define THRESHOLD_STOP_LOW_MIN            72        // 40000 * 0.9 / 50<br />
<br />
#define DATA_BYTE_COUNT        4<br />
#define DATA_BIT_COUNT        (DATA_BYTE_COUNT*8)<br />
<br />
uint8_t ch_data[][DATA_BYTE_COUNT]=<br />
{<br />
    {0x01,0x00,0x00,0x01},    // ch0<br />
    {0x01,0x00,0x00,0x02},    // ch1<br />
    {0x01,0x00,0x00,0x03},    // ch2<br />
};<br />
<br />
typedef enum<br />
{<br />
    MODE_CHECK_HEADER = 0,<br />
    MODE_ANALYZE,<br />
    MODE_RECEIVED,<br />
    MODE_REPEAT,<br />
    MODE_REPEAT_RECEIVED,<br />
    MODE_OVERFLOW = 0x10,<br />
} modeStatus;<br />
<br />
ISR(ANA_COMP_vect)<br />
{<br />
}<br />
<br />
int main(void)<br />
{<br />
    CCP = 0xD8;<br />
    CLKMSR = 0x00;<br />
    CCP = 0xD8;<br />
    #if F_CPU == 8000000UL<br />
    CLKPSR = 0x00;<br />
    #elif F_CPU == 4000000UL<br />
    CLKPSR = 0x01;<br />
    #elif F_CPU == 2000000UL<br />
    CLKPSR = 0x02;<br />
    #elif F_CPU == 1000000UL<br />
    CLKPSR = 0x03;<br />
    #endif<br />
    <br />
    DDRB |= _BV(LED1) | _BV(LED2);        // 出力設定<br />
    <br />
    ACSR = 0b00001011;                    // コンパレータ許可・割り込み許可<br />
    DIDR0 = 0b00000011;                    // AIN0 AIN1 デジタル入力禁止<br />
    PRR = _BV(PRADC) | _BV(PRTIM0);        // AD変換停止+timer0停止<br />
    <br />
    set_sleep_mode(SLEEP_MODE_IDLE);    // アイドルモードに設定<br />
    sei();                                // 全体の割り込み許可<br />
<br />
    uint8_t data[DATA_BYTE_COUNT];<br />
    uint8_t mode;<br />
    uint8_t timeHigh,timeLow;<br />
    uint8_t fBit;<br />
    uint8_t byteCount;<br />
    uint8_t bitCount=0;<br />
<br />
    while(1)<br />
    {<br />
        ACSR |= _BV(ACIE);<br />
        sleep_mode();<br />
        ACSR &= ~_BV(ACIE);<br />
<br />
        mode=MODE_CHECK_HEADER;<br />
        <br />
        while(1)<br />
        {<br />
            timeHigh=0;<br />
            timeLow=0;<br />
            <br />
            while(ACSR&_BV(ACO))<br />
            {<br />
                timeHigh++;<br />
                if(timeHigh==0)<br />
                {<br />
                    timeHigh=0xFF;<br />
                    while(ACSR&_BV(ACO));<br />
                    break;<br />
                }<br />
                _delay_us(50);<br />
            }<br />
            while(!(ACSR&_BV(ACO)))<br />
            {<br />
                timeLow++;<br />
                if(timeLow==0)<br />
                {<br />
                    timeLow=0xFF;<br />
                    timeHigh=0xFF;<br />
                    break;<br />
                }<br />
                _delay_us(50);<br />
            }<br />
<br />
            if(mode==MODE_CHECK_HEADER)<br />
            {<br />
                if(timeHigh>=THRESHOLD_HEADER_HIGH_MIN && timeHigh<=THRESHOLD_HEADER_HIGH_MAX)<br />
                {<br />
                    if(timeLow>=THRESHOLD_HEADER_LOW_MIN && timeLow<=THRESHOLD_HEADER_LOW_MAX)<br />
                    {<br />
                        mode=MODE_ANALYZE;<br />
                        fBit=0x80;<br />
                        byteCount=0;<br />
                        bitCount=0;<br />
                        data[0]=0;<br />
                        data[1]=0;<br />
                        data[2]=0;<br />
                        data[3]=0;<br />
                    }<br />
                    else if(timeLow>=THRESHOLD_HEADER_REP_LOW_MIN && timeLow<=THRESHOLD_HEADER_REP_LOW_MAX)<br />
                    {<br />
                        mode=MODE_REPEAT;<br />
                    }<br />
                }<br />
            }<br />
            else if(mode==MODE_ANALYZE)<br />
            {<br />
                if(timeLow>=THRESHOLD_STOP_LOW_MIN)<br />
                {<br />
                    mode=MODE_RECEIVED;<br />
                }<br />
                else if(timeLow>=(timeHigh+timeHigh))<br />
                {<br />
                    data[byteCount]|=fBit;<br />
                }<br />
                fBit>>=1;<br />
                if(fBit==0)<br />
                {<br />
                    byteCount++;<br />
                    fBit=0x80;<br />
                    if(byteCount>=DATA_BYTE_COUNT)<br />
                    {<br />
                        mode=MODE_OVERFLOW;<br />
                    }<br />
                }<br />
                bitCount++;<br />
            }<br />
            else if(mode==MODE_REPEAT)<br />
            {<br />
                if(timeLow>=THRESHOLD_STOP_LOW_MIN)<br />
                {<br />
                    mode=MODE_REPEAT_RECEIVED;<br />
                }<br />
                else<br />
                {<br />
                    mode=MODE_OVERFLOW;<br />
                }<br />
            }<br />
            else if(mode==MODE_OVERFLOW)<br />
            {<br />
                if(timeLow>=THRESHOLD_STOP_LOW_MIN)<br />
                {<br />
                    mode=MODE_RECEIVED;<br />
                }<br />
            }<br />
            <br />
            if(mode==MODE_RECEIVED)<br />
            {<br />
                if(bitCount==DATA_BIT_COUNT)<br />
                {<br />
                    uint8_t ch,i;<br />
                    for(ch=0;ch<3;ch++)<br />
                    {<br />
                        for(i=0;i<DATA_BYTE_COUNT;i++)<br />
                        {<br />
                            if(ch_data[ch][i]!=data[i])<br />
                            {<br />
                                break;<br />
                            }<br />
                        }<br />
                        if(i==DATA_BYTE_COUNT)<br />
                        {<br />
                            if(ch==0)<br />
                            {<br />
                                PORTB^=_BV(LED1);<br />
                            }<br />
                            else if(ch==1)<br />
                            {<br />
                                PORTB^=_BV(LED2);<br />
                            }<br />
                            break;<br />
                        }<br />
                    }<br />
                }<br />
                break;<br />
            }<br />
            else if(mode==MODE_REPEAT_RECEIVED)<br />
            {<br />
                if(bitCount!=0)<br />
                {<br />
                }<br />
                break;<br />
            }<br />
            else if(mode==MODE_CHECK_HEADER)<br />
            {<br />
                bitCount=0;<br />
                break;<br />
            }<br />
        }<br />
        while(ACSR&_BV(ACO));<br />
    }<br />
}<br />

コンパイル済みHEXファイル

 

米粒AVRのデータ受信のテスト

Androidから送る音声データは こちらのSoundIR Analyzerというリモコンデータの解析アプリを使って作ります。

tiny10→Android 送信テスト3
まず、前回の「米粒AVRからAndroidへデータを送る」の回路を使って、スイッチ1を押した時のデータをアプリで受信して、メニューから保存を選び、「リモコン操作用ファイル」として保存しておきます。
あと、スイッチ2を押した時のデータも同様にして保存しておきます。
(この方法で作ったサウンドデータ

 

softmodem ファイル一覧
次に、Androidと今回の回路を接続し、作成したサウンドデータを再生します。
再生前に予めAndroidの「音の設定」で「タッチ操作音」を消しておいて下さい。
タッチ操作音を消しておかなければ、再生しようと画面をタッチした時に別の音が混ざって正しくデータ転送できません。

 

LED1点灯
スイッチ1のデータを再生すると、LED1が点灯/消灯します。同様にスイッチ2のデータを再生すれば、LED2が操作できます。

 

今回のプログラムでは、LEDのトグルに4バイト(32ビット)のデータの一致をチェックしています。
まだ少ししか試していませんが、割とエラーも少なく送受信できているんじゃないかと思います。
と言っても完璧では無いので、チェックサム等を付けてデータの整合性チェックは欠かせません。

 

関連記事

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

ArduinoでSDカード

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

記事を読む

no image

Bimeji Client for Arduino

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

記事を読む

Arduino + STTS751

パソコンで温度計

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

記事を読む

no image

AndroidとArduinoの接続で使えそうなBluetoothモジュール

1ヶ月ほど前に書いた、Android + Bluetooth + Arduino が割と人気があるよ

記事を読む

no image

AVRISPmk2

米粒AVR(ATtiny10)のプログラム書き込み用にAVRISPmk2を購入しました。 先人

記事を読む

no image

Android + Arduino でリモコン

今こんなのを作ってますと言う動画です。   DoCoMoのFOMA携帯

記事を読む

no image

米粒AVRでLチカ

  米粒AVR(ATtiny10)でLチカしてみました。 LチカとはLEDをチカチカと

記事を読む

no image

Wimeji Client for Arduino

前回紹介したWimeji Client for WindowsXPをArduinoでやってみました。

記事を読む

米粒AVR リモコン

米粒AVRでリモコン送信機

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

記事を読む

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

米粒AVRでSoftModem的なこと

米粒AVRとAndroidを繋いで、データのやりとりを行ってみたいと思います。 2つを繋ぐイン

記事を読む

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

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

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

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

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

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

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

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

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

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

PAGE TOP ↑