今日は去年開発したGPS端末について報告したいと思います。当初、ソロバンの
初期バージョン上で構築しました。今日はソフトの更新を考えて、CCEで
開発されたコードをIARでコンパイルしました。割り込み関数の宣言を変えて、
再コンパイルしただけで動きました。
GPSモジュール
このモジュールはパッチアンテナを搭載するので小型です。

厚さの方は9mm以下です。写真がうまく撮れてなくてすみません。カメラは
7年前に買ったキャノンの初期PowershotG1.

開発プラットホーム
今回はソロバンを使って、電源は小型のリチウムポリマーにしました。GPSモジュールの
仕様書によると、消費電力は28mAです。ソロバン自体(MSP430+RTC+LCD)は合計5mA
位です。バッテリーの方は650mAh。楽観的な値が書いてあるとしても多分400mAhは
期待できると思われます。10時間位連続使用できるので殆どの場合には十分だと考えら
れます。

ソロバン拡張ボードにモジュールを配線する。
配線する前は、アンテナの3ピンはピッチからずれているので穴を開ける事にしました。

モジュールの配線は7本で済みました。電源、UART、Reset. Resetのほうは、
そのままMSP430から配線したら動作できなかった。理由は仕様書によると、Resetは
2V位でなければならないからと分かりました。(モジュールは無事でした)
3.3から2Vに変換するためにチップ抵抗を2個使用して、電圧を3.3から1.65に落しました。
次の写真はチップ抵抗を示しています。左の抵抗はMSP430のP4.3(ピン39)に、右側の
抵抗はGNDに接続されていて、その間の線はGPSモジュールのReset信号になります。

ソフトウエア
ソフトウエアは以下の通りです。
UARTを制御する関数を書きました。下記ソースコードはデモのため大雑把に書いたので
ご了承下さい。
UARTソースコード
ヘッダーファイル(.h)は以下の通り: (types.h defines uint8, uint16, etc...)
- Code: Select all
#ifndef _USART_H_
#define _USART_H_
#include <msp430x16x.h>
#include "types.h"
// Non-realtime functions. These are configuration functions.
// This is to be changed to reduce the number of functions.
// USART0 inits:
void InitUsart0(void);
void USART0Enable(void);
void USART0Disable(void);
void SetUSART0Rate(uint16 freq);
void Enable_IE_USART0(void);
void Disable_IE_USART0(void);
void SetTimeout(uint8 which, uint16 t);
// Realtime functions (USART0 send and receive functions)
void USART0SendByte(uint8 byte);
void USART0SendBuffer(uint8 * buf, uint16 len);
uint8 USART0RecvByte(void);
uint16 USART0RecvBuffer(uint8 * buf, uint16 len);
#endif
Cファイルは以下の通り。
globals.h は外付け水晶の周波数を定義する。(以下XTFREQ).
Timeoutは、UARTデータ待機タイムアウト。
データはだいたい200~300バイトずつ受信されます。データブロックを受信する間は
バイトがほぼ連続的に受信される。すき間はタイムアウトより長ければブロックが
受信完了ですのでリターンする。
- Code: Select all
#include <msp430x16x.h>
#include "USART.h"
#include "globals.h"
static uint16 timeout0;
//---------------------------------------------------------
// Initializatons USART0
//---------------------------------------------------------
void InitUsart0(void) {
// P3.4,5 = USART0 TXD/RXD
P3SEL |= 0x30;
P3DIR |= 0x10; //P3.4 = output direction
P3DIR &= ~0x20; // P3.5 = input direction
// 8-bit, UART
U0CTL = (CHAR | SWRST);
// UCLK= SMCLK
U0TCTL |= SSEL1;
// Set baud rate to 9600 (might be changed later).
SetUSART0Rate(9600);
// Initalize USART state machine
U0CTL &= ~SWRST;
// Enable USART0 RX interrupt
USART0Enable();
Enable_IE_USART0();
}
// Enable USART0 TXD/RXD
void USART0Enable(void) {
// Enable module
ME1 = UTXE0 | URXE0;
// Remove reset flag
U0CTL &= ~SWRST;
}
// Disable USART0
void USART0Disable(void) {
// Set reset flag
U0CTL |= SWRST;
// Disable module
ME1 &= ~UTXE0;
ME1 &= ~URXE0;
}
// Set USART baud rate
void SetUSART0Rate(uint16 BaudRate) {
uint16 divisor;
uint8 * div;
// Temporarily disable the module
U0CTL |= SWRST;
// Calculate the divisor
divisor = XTFREQ / BaudRate;
timeout0 = 2* divisor;
// Superpose a uint8 pointer
div = (uint8 *)(&divisor);
U0BR1 = div[1];
U0BR0 = div[0];
// Re-enable the module
U0CTL &= ~SWRST;
}
// Enable USART0 Rx Interrupt
void Enable_IE_USART0(void){
IE1 |= URXIE0;
}
// Disable USART0 Rx Interrupt
void Disable_IE_USART0(void){
IE1 &= ~URXIE0;
}
void SetTimeout(uint16 t) {
timeout0 = t;
}
//---------------------------------------------------------
// Transmit and receive USART0
//---------------------------------------------------------
// Send a single byte
void USART0SendByte(uint8 byte) {
IFG1 &= ~UTXIFG0;
/* Send the byte */
U0TXBUF = byte;
/* Wait for the byte to be sent */
while (!(IFG1 & UTXIFG0)) { }
}
void USART0SendBuffer(uint8 * buf, uint16 len) {
int i;
for(i = 0 ; i < len ; ++i) {
USART0SendByte(buf[i]);
}
}
// Receive a single byte
uint8 USART0RecvByte(void) {
uint8 retval;
IFG1 &= ~URXIFG0;
// Wait for the receive flag.
while (!(IFG1 & URXIFG0)) {}
retval = U0RXBUF;
return retval;
}
uint16 USART0RecvBuffer(uint8 * buffer, uint16 len) {
uint16 retlength = 0;
uint16 timeout;
while(retlength < len) {
timeout = 0;
IFG1 &= ~URXIFG0;
while(!(IFG1 & URXIFG0) && (timeout++ < timeout0)) {}
if(timeout >= timeout0) break;
buffer[retlength] = U0RXBUF;
retlength++;
}
return retlength;
}
以上です。
GPSモジュールソースコード
GPSモジュールソースコードは以下の通り。
- Code: Select all
#ifndef _GPS_H_
#define _GPS_H_
#include "Types.h"
#define GPSRESET 0x08
// GPS specific
void InitGPS(void);
void ResetGPS(void);
uint16 ReadNMEA(void);
// Custom functions for parsing NMEA data
uint8 GetAltitude(uint8 * str);
uint8 GetCap(uint8 * str);
uint16 GetCompass();
uint8 GetGMTTime(uint8 * str);
uint8 GetLatitude(uint8 * str);
uint8 GetLongitude(uint8 * str);
uint8 GetLocalTime(uint8 * str);
uint8 GetNSats(void);
uint8 GetSpeed(uint8 * str);
void SetTimeZone(int8 zone);
#endif
受信データはNMEA
データとなっています。この説明によると、NMEAデータはただのテキストデータ
です。モジュールの仕様書によると、1秒毎に1組のデータが受信される。実験の結果、
最高400バイト位受信することが分かりました。そこで、搭載には512バイトのバッファーを
使用しました。
Staticバッファーでデータを保管する。18文字の文字列を用意して、その文字列で
NMEAデータから適切な情報を取り出す。
TimezoneではGMT時刻を使用される現地時刻に合わせます。
以下はGPS端末のソースコードの一部です。データを取り出す関数はただの文字列処理
なので省略しました。
- Code: Select all
#include <msp430x16x.h>
#include "GPS.h"
#include "Usart.h"
#include "Clock.h"
#include "AltitudeFilter.h"
// This implementation is a "hardcoded" implementation which assumes
// that the GPS module has been set to UART0.
// This file keeps a buffer of the NMEA data.
#define NMEA_BUF_LEN 0x200
// Static variables and buffers
static uint8 NMEABuffer[NMEA_BUF_LEN];
static uint8 RawString[18];
static int8 timezone;
// Configures the UART first for 9600 baud. This will be subject to
// changes later.
void InitGPS(void) {
empty_buffer(NMEABuffer, NMEA_BUF_LEN);
SetTimeZone(9);
ResetGPS();
InitUsart0();
}
void ResetGPS(void) {
P4DIR |= GPSRESET;
P4OUT &= ~GPSRESET;
delay(100);
P4OUT |= GPSRESET;
}
uint16 ReadNMEA(void) {
uint16 len;
empty_buffer(NMEABuffer, NMEA_BUF_LEN);
len = USART0RecvBuffer(NMEABuffer, 0x200);
return len;
}
ソースコードは以上です。NMEAデータが受信できたら、適切な部分を取り出して
表示する。
結果
GPS端末の外観は以下の通り。

写真は歩きながら撮ったものです。南方向に進んでいたので写真が示す179度は妥当
と思われます。黒い領域はコンパスです。中心の表示は現在の移動方角です。左は
SE(South-Est, 南東)、右はSW(South-West, 南西)です。
モジュール以外ボードに乗っているチップは気圧センサーです。GPSは標高の値が
不正確なので、気圧センサーにより調整できます。これについては、また別の機会に
お話します。
次の画像は画面の詳細を示す。

結論
この報告では、ソロバンに新しいハードウエアを開発・搭載する一例を示しました。
完全に動作するGPS端末器をわずか7本の配線で開発できました。ハードウエア的に
データが蓄積可能ですが今回はその機能は未開発です。
ソースコードは改善の余地があります。
現在のバージョンは立ち上がり難いです。理由は、現在地不明で起動する「cold start」
と呼ばれる起動方法によります。現在地を常にマイコンのフラッシュに書き込むこと
により、起動時間は短縮できます。
注意
完全に動作できるサンプルコードはSoroban+GPSモジュールを購入された方に
提供致します。GPSモジュールは4月中旬に発売予定です。
