はじめに
AzureSphereの開発ボードが巷に届き始めてますが、筆者にも無事届きましてとりいそぎAzureADとの紐づけも行いさっそくいろいろ繋いでみてたりします。
今回は太陽誘電製のGPSモジュール[GYSFDMAXB]を載せたGPS受信キットが在庫品の中に眠ってたので繋いでみました。
今回使ったGPS受信キットはこちら
GPS受信機キット 1PPS出力付き 「みちびき」3機受信対応
PCにつないで専用ソフトで設定を行うことでUARTの速度など設定変更できるようですが、今回はつなぐだけなのでデフォルトで動作してもらいます。
AzureSphereとの接続
キットのUARTは3.3Vということなので、特に電圧変換など行わずに直接AzureSphereのUSRT3に接続します。キットへの電源供給は5Vなので、VCCには5Vを接続、今回キットからの受信しか行わないのでUARTはRXのみの接続です。
繋ぐのは3本、VCC(5V)、UART3のRX、GNDです。
AzureSphereの向かって右側上半分がHeader3で、左上が5V、その隣がGNDです。左側の上から5番目がUART3のRX(受信)です。
キットのTX(送信)をこいつに接続です。
AzureSphereにUSBコネクタを刺して通電するとキットにも通電され赤いLEDが暗めに点灯します。キットは勝手に受信を開始し、測位可能な状態になると1秒間隔でこのLEDが明るく点滅します。
受信部分のコード
受信コードはサンプルコードを利用します。VisualStudioを立ち上げて新しいプロジェクトを作成します。筆者の環境ではVisualC++→テストにあるサンプルプロジェクトを選択します。(VisualC++→クロスプラットフォーム→AzureSphereにある場合もあるような気がします)
サンプルプロジェクトは、UARTSample for MT3620 RDB(Azure Sphere)となっています。
全体は飛ばしますが、ざっくりとした内容としては、
- InitPeripheralsAndHandlers()を呼んでUARTその他の初期化とイベントハンドラの登録を行う
- WaitForEventAndCallHandler(epollFd)をループで呼んでイベント待ちする。
と、これだけです。
ArduinoやLPCなどのマイコンよりは若干面倒な感じです。
サンプルの修正点として重要なのはInitPeripheralsAndHandlers(void)内の以下の部分です。
// Create a UART_Config object, open the UART and set up UART event handler
UART_Config uartConfig;
UART_InitConfig(&uartConfig);
//uartConfig.baudRate = 115200;
uartConfig.baudRate = 9600;
uartConfig.flowControl = UART_FlowControl_None;
uartFd = UART_Open(MT3620_UART_ISU3, &uartConfig);
もともとのuartConfig.baudRate = 115200;→uartConfig.baudRate = 9600;と修正しています。
これはキットの通信速度に合わせています。
このまま実行するとキットからの通信を12バイトずつくらい受信してデバッグウインドウにぞろぞろと表示されます。
GPSはNMEAセンテンスで送られてくるので、データを整形して位置情報の取得に必要なGGAだけ出力するようにしてみます。
キットからの通信があるとUARTの受信イベントUARTEventHandler()が発火します。
このなかで各NMEAセンテンスを抜き出すようにします。
NMEAセンテンスは$で始まり\nで終わる1行で構成されます。
パラパラやってくるデータをこの文字で切り出します。
グローバル変数として、
uint8_t gpssent[1024];
int gpssentcount = 0;
を宣言しておきます。
UARTEventHandler()内でデータをreceiveBufferに読み込んだ後、bytesRead(読み込んだバイト数)>0のとき取ったデータを1文字ずつ見ていき、'$'があったらgpssentcount = 0にしてgpssent[gpssentcount]に文字をコピーしていきます。
'\n'があった時点で1行データが出来たのでセンテンスがGGAの場合デバッグウインドウに出力しています。
NMEAセンテンスはカンマ区切りですが、あとから切り出すのに都合がいいので、カンマが来た場合は'\t'をコピーしています。
:main.c
for (int i = 0; i < bytesRead; i++){
switch ((char)receiveBuffer[i]) {
case '$':
gpssentcount = 0;
gpssent[gpssentcount] = receiveBuffer[i];
break;
case ',':
gpssent[gpssentcount] = '\t';
case '\r':
gpssent[gpssentcount] = '\n';
gpssent[gpssentcount+1] = '\0';
if(gpssent[0] == '$') {
char buf[5][20];
sscanf(gpssent, "%s%s%s%s%s", buf[0], buf[1], buf[2], buf[3], buf[4]);
if (strcmp(buf[0], "$GPGGA") == 0) {
Log_Debug("%s--%s--%s--%s--%s\n", buf[0], buf[1], buf[2], buf[3], buf[4]);
}
}
break;
default:
gpssent[gpssentcount] = receiveBuffer[i];
}
gpssentcount++;
}
うまく動くと以下のような結果が得られます。
$GPGGA--013704.000--3583.1739--N--13916.9567
$GPGGA--013704.000--3583.1739--N--13916.9567
$GPGGA--013704.000--3583.1739--N--13916.9567
$GPGGA--013704.000--3583.1739--N--13916.9567
$GPGGA--013704.000--3583.1739--N--13916.9567
$GPGGA--013704.000--3583.1739--N--13916.9567
まとめ
普通のマイコンのコードと比べて若干冗長気味に書かないといけない感じはありますが、基本的なUARTの動作はサンプルのおかげで簡単に記述できました。
今回はUARTの受信のみでしたが、サンプル内には送信部分もあります。
デバッグ用に(Log_Debugあるからいらないといえばいりませんけど)RaspberryPiのUARTに送信して動作状況を確認したり、LPWAな通信モジュールにつないでデータ送信のテストも行いましたがこちらもスムーズに書くことができます。
UARTがOKなら次はI2CかSPIの通信かな?いいサンプルがあるといいんですけどねえ。
全体的には、コードの記述はVisualStudioなのでインテリセンスもバッチリだし、ボタン一つでプログラムの書き込みと実行ができるので、オンラインコンパイラを使うマイコンなどより開発効率はよさそうです。
Wi-Fiも搭載なので通信にもこまらなそうだし、BLEが載っててもう少しボードが小さくできれば使い道はさらに広がりそう。
やっぱりMSと手を結んでMCU自体を供給してもらって独自のボードを開発してからが本番ですかねwww