送信波形

●アンドロイド版
音声を利用してスマートフォンからマイコンにFSK方式でデータを送信する実験です。すでにいろいろな方が実施されていますし、BANDAIのスマートドッグという商品にも使われていた方法かと思います。
Baud Rateは630Hzとかなり低速ですが、マイコン側でWiFiやBTの通信手段が不要なのでコスト的には有利です。出力される音声信号は非常に微細なので、LM358でアンプしています。

import android.app.Activity;
import android.graphics.Color;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.LinearLayout;

public class FskTest extends Activity implements View.OnClickListener{

    private final static int MP = LinearLayout.LayoutParams.MATCH_PARENT;
    private final static int WC = LinearLayout.LayoutParams.WRAP_CONTENT;

    static int SAMPLE_RATE = 44100; //44.1KH
    static int FREQ_LOW = 3150;
    static int FREQ_HIGH = 6300;
    static int BAUD = 630;
    static int BITS_ALL = 17;
    private int bufSize;
    AudioTrack track;

    @Override
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        requestWindowFeature(Window.FEATURE_NO_TITLE);

        LinearLayout layout = new LinearLayout(this);
        layout.setBackgroundColor(Color.WHITE);
        layout.setOrientation(LinearLayout.VERTICAL);
        layout.setGravity(Gravity.CENTER_VERTICAL);
        setContentView(layout);

        layout.addView(makeButton("SEND!"));

        bufSize = android.media.AudioTrack.getMinBufferSize(44100,
                AudioFormat.CHANNEL_OUT_STEREO,
                AudioFormat.ENCODING_PCM_16BIT);
        track = new AudioTrack(
                AudioManager.STREAM_MUSIC,        //streamType
                SAMPLE_RATE/2,                      //sampleRateInHz:サンプリング周波数
                AudioFormat.CHANNEL_OUT_MONO,    //channelConfig(モノラル指定)
                AudioFormat.ENCODING_PCM_16BIT,  //audioFormat
                bufSize,                              //bufferSizeInBytes:バッファサイズ
                AudioTrack.MODE_STATIC);
    }

    private Button makeButton(String text) {
        Button button = new Button(this);
        button.setText(text);
        button.setOnClickListener(this);
        button.setLayoutParams(new LinearLayout.LayoutParams(MP,WC));
        button.setGravity(Gravity.CENTER);
        return button;
    }

    public void onClick(View view) {
        sendVal('a');
    }

    private void sendVal(int cmd) {
        if(track.getPlayState()==AudioTrack.PLAYSTATE_PLAYING){
            track.stop();
            track.reloadStaticData();
        }
        byte[] audioData = createSquareWave(cmd);
        track.write(audioData, 0, audioData.length);
        track.play();
    }

    private byte[] createSquareWave(int command) {
        byte[] b = new byte[SAMPLE_RATE/BAUD*BITS_ALL];
        int counter=0;

        //leader
        for (int i = 0; i < 8; i++) {
            // data=low
            for(int j = 0; j < (FREQ_LOW/BAUD); j++){
                b[counter++] = 0;
                b[counter++] = 56;
                b[counter++] = 100;
                b[counter++] = 125;
                b[counter++] = 125;
                b[counter++] = 100;
                b[counter++] = 56;
                b[counter++] = 0;
                b[counter++] = -56;
                b[counter++] = -100;
                b[counter++] = -125;
                b[counter++] = -125;
                b[counter++] = -100;
                b[counter++] = -56;
            }
        }
        //start bit
        for(int j = 0; j < (FREQ_HIGH/BAUD); j++){
            b[counter++] = 0;
            b[counter++] = 100;
            b[counter++] = 125;
            b[counter++] = 56;
            b[counter++] = -12;
            b[counter++] = -125;
            b[counter++] = -100;
        }
        // data
        for (int i = 6; i >= 0; i--) {
            if(((1<<i) & command)==0){
                for(int j = 0; j < (FREQ_LOW/BAUD); j++){
                    b[counter++] = 0;
                    b[counter++] = 56;
                    b[counter++] = 100;
                    b[counter++] = 125;
                    b[counter++] = 125;
                    b[counter++] = 100;
                    b[counter++] = 56;
                    b[counter++] = 0;
                    b[counter++] = -56;
                    b[counter++] = -100;
                    b[counter++] = -125;
                    b[counter++] = -125;
                    b[counter++] = -100;
                    b[counter++] = -56;
                }
            }else{
                for(int j = 0; j < (FREQ_HIGH/BAUD); j++){
                    b[counter++] = 0;
                    b[counter++] = 100;
                    b[counter++] = 125;
                    b[counter++] = 56;
                    b[counter++] = -12;
                    b[counter++] = -125;
                    b[counter++] = -100;
                }
            }
        }
        // stop bit
        for(int j = 0; j < (FREQ_HIGH/BAUD); j++){
            b[counter++] = 0;
            b[counter++] = 100;
            b[counter++] = 125;
            b[counter++] = 56;
            b[counter++] = -12;
            b[counter++] = -125;
            b[counter++] = -100;
        }
        return b;
    }
}