米粒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ビット)のデータの一致をチェックしています。
まだ少ししか試していませんが、割とエラーも少なく送受信できているんじゃないかと思います。
と言っても完璧では無いので、チェックサム等を付けてデータの整合性チェックは欠かせません。

 

関連記事

no image

PIC24FJ64GB002でADKを試す(その2)

 前回「PIC24FJ64GB002でADKを試す(その1)」では回路の説明までしたので、

記事を読む

no image

米粒AVR(ATtiny10)

通称「米粒AVR」で知られるTiny10を使ってみたくて、秋月の通販で買ってみました。 超小型

記事を読む

no image

Android + Arduino でリモコン

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

記事を読む

no image

Softmodem Terminal 公開しました。

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

記事を読む

ssh_connected

Raspberry PiをWindowsで操作する(SSH)

SSHを使って、Raspberry Piを外部PC(Windows)で操作する。

記事を読む

熱湯の温度計測実験

パソコンで温度計 #3

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

記事を読む

soundIR 送信機

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

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

記事を読む

Androidで気圧高度計

androidで気圧・高度計(LPS331AP使用)

Androidと大気圧センサー(LPS331AP)をイヤフォンジャックで繋いで気圧と高度、ついで

記事を読む

no image

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

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

記事を読む

no image

Android+Arduinoでリモコン3 その1(AndroidAccessory接続)

何度か、Android+リモコンのネタを書いたことがあるのですが、今回はAndroid Access

記事を読む

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

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

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

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

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

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

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

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

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

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

PAGE TOP ↑