目次

簡易緯度/経度表示ユニット(GPS-52D)

概要

GPS(Global Positioning System)を利用して、自分が地球上の何処(緯度/経度)にいるのかを、表示させるユニットを製作しました。

動作原理

秋月電子で販売されている、「GPSレシーバモジュールキット」に含まれる、GPSモジュール(GPS-52D)をPICで制御し、経度と緯度をLCDに表示させるユニットです。

<GPSレシーバモジュールキットの特長>

<GPS-52Dの性能仕様>

GPS-52Dが出力する、NMEAは、米国海洋電子機器協会(National Marine Electronics Association)が定めた規格で、受信機とナビゲーション機器の通信に使用されるプロトコルです。
中でも、NMEA-0183は、GPS受信機とナビゲーション機器の間を、シリアルポートを利用して通信するための規格で、すべての文字がASCIIテキストの「センテンス」で送られます。
各データ項目は、カンマ(,)で区切られており、行末には、CR/LFコードが含まれます。

<GPS-52Dが出力するデータ(文字列)>

$GSU-50 : Position Co.,Ltd.2003
$Firmware Checksum: 4d50
$TOW: 0
$WK: 1491
$POS: 6378137 0 0
$CLK: 96000
$CHNL:12
$Baud rate: 9600 System clock: 12.277MHz
$HW Type: S2AM
$Asic Version: 0x23
$Clock Source: GPSCLK
$Internal Beacon: None
$PSRF150,1,*12

$GPGGA,235948.000,3600.0000,N,13600.0000,E,0,00,99.9,00000.0,M,0000.0,M,000.0,0000*4A
$GPGSA,A,1,,,,,,,,,,,,,99.9,99.9,99.9*09
$GPRMC,235948.000,V,3600.0000,N,13600.0000,E,9999.99,999.99,020808,,*2F
$GPVTG,999.99,T,,M,9999.99,N,9999.99,K*59
$GPZDA,235949.000,02,08,2008,,*56

※以降、<$GPGGA~$GPZDA>までが、約1秒周期で繰り返されます。

<GGAセンテンスを利用した、経度、緯度の取得>
例:$GPGGA,123519.00,4807.038247,N,01131.324523,E,1,08,0.9,545.42,M,46.93,M,5.0,1012*42
123519.00 =測位時刻(UTC)12:35:19.00
4807.038247,N =緯度48度07.038247分(北緯)
01131.324523,E =経度11度31.324523分(東経)
1 =GPSのクオリティ; 0 = 受信不能, 1 = 単独測位,2 = DGPS
08 =受信衛星数
0.9 =水平測位誤差
545.42, M =平均海水面からのアンテナ高度(m)
46.93, M =WGS-84楕円体から平均海水面の高度差(m)
5.0 =DGPSデータのエイジ(秒)
1012 =DGPS基準局のID
*42 =チェックサム

<測地系の設定>
GPS-52Dは、デフォルトでは、測地系設定値が、「178:TOKYO Mean Solution」になっています。
このままでは、世界測地系「21:WGS-84」の経緯度で表わすと、北西方向へ約450mずれてしまうので、起動時に、「21:WGS-84」に変更します。(SW1で切り替え可能)

回路図

ソースコード

nmea0183.c
//********************************************************************** 
 
/*
  【NMEA-0183簡易モニタ】
*/
 
//********************************************************************** 
 
#define		LED		PORTB.F3
#define		CR		0x0D
#define		LF		0x0A
 
//********************************************************************** 
 
void	interrupt()
{
	if (INTCON.T0IF == 1) {
		INTCON.T0IF = 0;
	}
	if (PIR1.TMR1IF == 1) {
		LED = ~LED;
		PIR1.TMR1IF = 0;
	}
}
 
//********************************************************************** 
 
void	Pwm_Change_DutyEx(unsigned int duty_ratio)
{
    CCPR1L = duty_ratio >> 2;
    CCP1CON.F6 = duty_ratio & 0b00000001;
    CCP1CON.F7 = (duty_ratio & 0b00000010) >> 1; 
}
 
//********************************************************************** 
 
void	Usart_Write_String(char *buf)
{
	static	int	len, i;
	len = strlen(buf);
	for (i = 0; i < len; i++) {
		Usart_Write(buf[i]);
	}
}
 
//********************************************************************** 
 
void	GetFieldData(char* msg, short number, char* result)
{
	short	cnt1, cnt2, pnt1, pnt2, len;
	//
	len = StrLen(msg);
	cnt2 = 0;
	pnt1 = 0;
	pnt2 = 0;
	for (cnt1 = 0; cnt1 < len; cnt1++) {
		if (msg[cnt1] == ',') {
			pnt1 = pnt2;
			pnt2 = cnt1 + 1;
			cnt2++;
			if (cnt2 == number)
				break;
		}
	}
	strncpy(result, msg + pnt1, pnt2 - 1 - pnt1);
	result[pnt2 - pnt1] = 0x00;
}
/*
012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
$GPGGA,235948.000,3600.0000,N,13600.0000,E,0,00,99.9,00000.0,M,0000.0,M,000.0,0000*4A
*/
//********************************************************************** 
 
void	main()
{
	static	char	rd, buf[50], tmp[20], cnt, cnt2, mode;
	//
	OSCCON = 0b01110000;	// クロックは8Mhz 
	CMCON = 0b00000111;		// コンパレータは使用しない。
	ANSEL = 0b00000000;		// A/D変換は使用しない。 
	TRISA = 0b01111100;
	TRISB = 0b00000100;
	OPTION_REG = 0b10000111;
	PIE1.TMR1IE = 1;
	PIR1.TMR1IF = 0;
	T1CON = 0b00110001;
	INTCON = 0b01100000;
	//
	Pwm_Init(3000);	// 3Khz
	Pwm_Change_DutyEx(1024 / 2);
	//
	Lcd_Custom_Config(&PORTB, 4, 6, 7, 1, &PORTA, 1, 0, 7);
	TRISA = 0b01111100;
	Lcd_Custom_Cmd(LCD_CURSOR_OFF);
	for (cnt = 0; cnt < 5; cnt++) {
		Lcd_Custom_Out(1, 1, "NMEA0183 Monitor");
		Pwm_Start();
		Delay_ms(300);	
		Pwm_Stop();
		Lcd_Custom_Cmd(LCD_CLEAR);
		Delay_ms(300);
	}
	//
	Usart_Init(9600);
	//
	INTCON.GIE = 1;	// これ以降の処理で割り込みを許可する。 
	//
	Pwm_Start();
	Delay_ms(300);	
	Pwm_Stop();
	//
	cnt = 0;
	mode = 0;
	while (1) {
		if (Usart_Data_Ready() == 0)
			continue;
		rd = Usart_Read();
		buf[cnt] = rd;
		if (cnt < 49)
			cnt++;
		buf[cnt] = 0x00;
		//
		if (rd == LF) {
			if (strncmp(buf, "$GPGGA", 6) == 0) {
				Pwm_Start();
				Delay_ms(100);	
				Pwm_Stop();
				//
				GetFieldData(buf, 3, tmp);	//緯度の表示 
				Lcd_Custom_Out(1, 1, "N=");
				Lcd_Custom_Out(1, 3, tmp);
				//
				GetFieldData(buf, 5, tmp);	//経度の表示 
				Lcd_Custom_Out(2, 1, "E=");
				Lcd_Custom_Out(2, 3, tmp);
				//
				GetFieldData(buf, 7, tmp);	//GPSクオリティの表示 
				Lcd_Custom_Out(1, 16, tmp);
				//
				GetFieldData(buf, 8, tmp);	//受信衛星数 
				Lcd_Custom_Out(2, 15, tmp);
			}
			cnt = 0;
			if (mode == 0) {
				Usart_Write_String("$PSRF106,21*0F\r\n");	//測地系:WGS-84に設定 
				mode = 1;
			}
		}
	}
}
 
//**********************************************************************

動作確認

GPS-52Dの下部には、銅テープやアルミ箔でGND層を形成することが推奨されていましたので、手持ちの銅板を使いました。

左側から順に、3.3Vの3端子レギュレータ、圧電スピーカ、LED、PIC16F88、LCD周りの結線です。

左上:緯度
左下:経度
右上:受信クオリティ
右下:受信衛星数(最高8を示しました)
表示された値が正しいかどうかを確認する方法の一つとして、住所やランドマーク名から経度、緯度を検索可能な「Geocoding(世界測地系(WGS84)に対応)」で値を入力してみてください。

如何ですか?
これをコンパクトに組み立て、持ち歩き可能にすれば、自分の歩行軌跡がわかりますね。^_^

著作権表示 copyright notice

このページは稲崎様の閉鎖したHPのコピーで、著作権は稲崎様にあります。詳細
This page is a copy of Mr. Inasaki's closed website, and the copyright is held by him.Details