本文原創(chuàng)淹辞,轉(zhuǎn)載請(qǐng)注明出處。小編可能以后不會(huì)在簡(jiǎn)書上更新了俘侠,因?yàn)檫@里的markdown 編輯器太不好用了象缀,沒(méi)有CSDN 上面的好用,也希望粉絲們多多關(guān)注本人CSDN(一樣的昵稱呦)爷速。點(diǎn)擊友方藍(lán)字即可瀏覽小編CSDN內(nèi)容 csdn
導(dǎo)航是繼移動(dòng)通信之后發(fā)展最快的信息產(chǎn)業(yè)之一央星,只要是設(shè)計(jì)到位置、速度惫东、時(shí)間信息的領(lǐng)域斗魚衛(wèi)星導(dǎo)航技術(shù)相關(guān)莉给。中國(guó)北斗衛(wèi)星導(dǎo)航系統(tǒng)是我國(guó)自主研制的全球?qū)Ш较到y(tǒng),是繼美國(guó)定位系統(tǒng)(GPS)廉沮、俄羅斯格洛納斯衛(wèi)星導(dǎo)航系統(tǒng)之后的第三個(gè)成熟的衛(wèi)星導(dǎo)航系統(tǒng)颓遏。隨著北斗導(dǎo)航系統(tǒng)的不斷完善,基于北斗導(dǎo)航系統(tǒng)的定位也應(yīng)用的越來(lái)越廣泛滞时。小編采用的STC12C5A32S2單片機(jī)結(jié)合衛(wèi)星接收模塊UM220-III設(shè)計(jì)的北斗導(dǎo)航系統(tǒng)接收機(jī)叁幢,UM220-III是三模接收模塊,能夠同時(shí)接受GPS坪稽、北斗的信號(hào)曼玩。這次的設(shè)計(jì)主要完成了導(dǎo)航信息接收機(jī)的基本設(shè)計(jì),實(shí)現(xiàn)了獲取實(shí)時(shí)的位置經(jīng)緯度窒百、標(biāo)準(zhǔn)時(shí)間等相關(guān)信息的顯示功能黍判。
1 原理介紹
采用以單片機(jī)為核心,讀取北斗導(dǎo)航系統(tǒng)模塊的標(biāo)準(zhǔn)數(shù)據(jù)篙梢,并在 LCD 屏幕上顯示當(dāng)前的經(jīng)緯度信息顷帖。具體的系統(tǒng)方案圖如下:
1.1北斗 UM220-III 模塊簡(jiǎn)介
(1)接口電路
北斗模塊芯片電路由北斗模塊UM220-III N 和其附加電子器件組成。其中北斗模塊外接4組排針,在芯片與電源之間串聯(lián)電感的作用是起差模濾波作用窟她,防止電流突變對(duì)芯片產(chǎn)生損壞陈症,并聯(lián)電感的作用是提高芯片運(yùn)行的穩(wěn)定性,防止產(chǎn)生噪聲震糖。
模塊輸入端口(UM220-III N 包括:RXD录肯、GPIO、SDA 吊说,SCL 等 如下圖)為防止輸入端不定態(tài)對(duì)模塊造成影響论咏,模塊內(nèi)置上拉電阻至VCC,因此在模塊未加電時(shí)颁井,如果上述端口有數(shù)據(jù)輸入厅贪,會(huì)在模塊VCC上形成串電,又可能造成模塊上電失敗雅宾。
case1:設(shè)計(jì)中使用 nRESET功能
在模塊上電后养涮,將nRESET拉低5 ms以上,即可確保模塊正常啟動(dòng)眉抬。
case2:設(shè)計(jì)中未使用nRESET
在模塊上電之前贯吓,保證模塊已連接輸入端口為高阻態(tài)或低電平,以避免串電蜀变。使用串口1的典型用戶悄谐,需要吧RXD1設(shè)置為高阻態(tài)或低電平,未使用的其他PIN懸空库北。程序流程圖如下:
(2)LCD 液晶顯示器
LCD液晶顯示器數(shù)據(jù)由單片機(jī)p0口進(jìn)行控制爬舰,p2口進(jìn)行指令控制操作。LCD1602是一種專門用來(lái)顯示字母寒瓦,數(shù)字情屹,符號(hào)等的點(diǎn)陣型液晶模塊。1602:顯示的內(nèi)容主要是16*2孵构,即可以顯示兩行屁商,每行16個(gè)字符液晶顯示模塊。相應(yīng)的管教功能颈墅,百度上都是可以查閱的蜡镶,所以小編這里就不贅述了。
(3)UM220-III 通信協(xié)議簡(jiǎn)介
在Unicore 協(xié)議中恤筛,輸入和輸出的語(yǔ)句被稱為消息官还。每條消息均為ASCII 字符組成的字符串。
消息的基本格式為:'(0x24)開始毒坛,后面緊跟著的就是消息名望伦。之后的跟的就是不定數(shù)目的參數(shù)和數(shù)據(jù)林说。消息名與數(shù)據(jù)之間均以逗號(hào)隔開(0x2c)進(jìn)行分割。最后一個(gè)參數(shù)是可選的校驗(yàn)和屯伞,以 '*'(0x2A)與前面的數(shù)據(jù)分割最后腿箩,輸入的消息以 ' \r\n' 結(jié)束。每條消息的總長(zhǎng)度不超過(guò)256個(gè)字節(jié)劣摇,消息名和參數(shù)珠移,校驗(yàn)和中的字母不區(qū)分大小寫。
某些輸入命令的某些參數(shù)可以省略(在命令描述中被標(biāo)記為可選)末融。這些參數(shù)可以為空钧惧,即在兩個(gè)逗號(hào)之間沒(méi)有任何字符。
2 調(diào)試方法
由1.1的原理簡(jiǎn)介可知勾习,此次課題實(shí)現(xiàn)主要由 5 部分組成:系統(tǒng)初始化浓瞪、設(shè)定顯示模式、讀取預(yù)顯示內(nèi)容巧婶、送掃描脈沖乾颁、送顯示數(shù)據(jù)。
這里對(duì)單片機(jī)與模塊的連接做簡(jiǎn)要說(shuō)明艺栈。
UM220/um220-3-n 上帶有兩組 TTL 電平(2.85V)钮孵,一組標(biāo)準(zhǔn)電平 RS232電平。當(dāng)單片機(jī)的RS232電平接口接到UM220模塊上的RS232上眼滤,正常通信。UM220模塊上的RS232接口是DB9 母頭历涝,可以使用公頭的連接線與RS230的接口相連诅需,注意的是通信線需要交叉連接,就像TTL電平中的TXD - - RXD,RXD--TXD 一樣荧库,RS232電平通信中也是有2根通信電纜堰塌,一個(gè)是發(fā)送端(PCXD),一個(gè)是接收端(PCRXD)分衫。若板子上的RS232 的接口是DB9 母頭场刑,那么 2 3針就是 PCRXD 和 PCTXD .第五針就是GND,若沒(méi)有串口線來(lái)連接UM220模塊的話蚪战,可以考慮在DB9下面的2 3 5 針 焊接出3跟線跟單片機(jī)的RS232連接牵现。
若單片機(jī)是3.3V時(shí),可以將單片機(jī)的TTL 接口連接到模塊上的TTL接口邀桑。連接好后就可以編寫程序了瞎疼。
注意,我們使用的 52 單片機(jī)的驅(qū)動(dòng)程序壁畸,使用的是12mhz的晶振贼急,波特率為9600.
3 程序編寫
程序主要是由5部分組成:系統(tǒng)初始化茅茂,設(shè)定顯示模式。讀取預(yù)顯示內(nèi)容太抓,送掃描脈沖空闲,送顯示數(shù)據(jù)。小編只放主程序部分好了:
3.1 定義端口及變量
#include <REG52.H>
#include <stdio.h>
#include <intrins.h>
#include <lcd1602.h>
#include <uart.h>
#include <delay.h>
#include "string.h"
#include <stdlib.h>
unsigned char flag_rec=0; //接收數(shù)據(jù)標(biāo)志
unsigned char num_rec=0; // 計(jì)數(shù)標(biāo)志
//char code TIME_AREA= 8; //時(shí)區(qū)走敌,我們不需要它
unsigned char flag_data; //數(shù)據(jù)緩沖器
//only displaty cmd $GPGGA information
unsigned char JD[16]; //longitude
unsigned char JD_a; //經(jīng)度方向
unsigned char WD[15]; //latitude
unsigned char WD_a; // 緯度方向
unsigned char date[6]; //data
unsigned char time[6]; //data
unsigned char time1[6]; //data
unsigned char speed[5]={'0','0','0','0','0'}; // 速度
unsigned char high[6]; // 高度
unsigned char angle[5]; //方位角
unsigned char use_sat[2]; // 衛(wèi)星計(jì)數(shù)器
unsigned char total_sat[2]; //衛(wèi)星總數(shù)
unsigned char lock; //位置狀態(tài)
//date handing variable
unsigned char seg_count; // 逗號(hào)計(jì)數(shù)器
unsigned char dot_count; //小數(shù)點(diǎn)計(jì)數(shù)器
unsigned char byte_count; // 位計(jì)數(shù)器
unsigned char cmd_number; // 命令模式
unsigned char mode;
unsigned char buf_full;
unsigned char cmd[5]; // 存儲(chǔ)命令模式
//serial disconnect timer
unsigned long int tt=0;
主函數(shù) 系統(tǒng)初始化
//main
void main ()
{
int jd_second,wd_second; // 中間變量
init_uart(); //初始化序列號(hào)
lcd_init() ; // 初始化 lcd1602
delay(200);
LCD_Write_String(0,0,"Please Waiting..."); // "Please Waiting" when it is boot up
delay(200);
delay(200);
delay(200);
delay(200);
delay(200);
delay(200);
delay(200);
delay(200);
delay(200);
delay(200); // 延遲顯示
write_com(0x01); // 清屏
設(shè)置延時(shí)函數(shù),以形成視覺(jué)暫留
while(1)
{
tt++;
if(tt>10000)
{
tt=10000;
write_com(0x01);
LCD_Write_String(3,0,"No Data!");
LCD_Write_String(3,1,"No Data!");
delay(200);
delay(200);
delay(200);
delay(200);
delay(200);
}
···
讀取預(yù)顯示內(nèi)容碴倾,設(shè)置顯示模式,轉(zhuǎn)16進(jìn)制為10進(jìn)制
if(flag_rec==1) // 獲取gps數(shù)據(jù)
{
flag_rec=0; // 清除標(biāo)志符
if (lock==1) // 獲取位置信息
{
//
LCD_Write_String(0,0,"JD :"); // 顯示經(jīng)度
LCD_Write_String(6,0,JD); // 顯示數(shù)據(jù)
LCD_Write_String(9,0,"."); // 進(jìn)制轉(zhuǎn)換
LCD_Write_String(10,0,JD+3);
jd_second=60*atof((char *)(JD+5));
LCD_Write_Char(13,0,jd_second/10+'0'); // 將上一步轉(zhuǎn)換得到浮點(diǎn)數(shù)據(jù)打印在lcd
LCD_Write_Char(14,0,jd_second%10+'0'); // 將上面得到的數(shù)據(jù)分為兩部分悔常,分別打印在LCD 上
LCD_Write_Char(15,0,' '); //填充空間
delay(200); // 保護(hù)lcd
LCD_Write_String(0,1,"WD :"); // 顯示下一行
LCD_Write_String(6,1,WD);
LCD_Write_String(8,1,".");
LCD_Write_String(9,1,WD+2); // 小數(shù)點(diǎn)
wd_second=60*atof((char *)(WD+4));// 將字符串轉(zhuǎn)換成浮點(diǎn)數(shù)
LCD_Write_Char(12,1,wd_second/10+'0');
LCD_Write_Char(13,1,wd_second%10+'0');
LCD_Write_String(14,1," ");
delay(200);
}
}
}
}
串口中斷函數(shù)及模式判斷
判斷的主要依據(jù)就是接收端接受消息與預(yù)結(jié)果匹配影斑,通過(guò)設(shè)置數(shù)組[i,j]和if函數(shù)進(jìn)行判斷匹配(發(fā)送報(bào)文的消息內(nèi)容見(jiàn)1.3的UM220的通信協(xié)議詳解)
//serial interruupt service function
void ser_int (void) interrupt 4
{
unsigned char tmp;
if(RI)
{
tt=0;
RI=0;
tmp=SBUF; // 從緩沖區(qū)接收數(shù)據(jù)
switch(tmp) //if $GPGGA,$GNGSW,$GNRMC,get data then processing it
{
//date start with $
case '$':
cmd_number=0; // 清除命令模式
mode=1; // 選項(xiàng)命令接收模式
byte_count=0; //清除位計(jì)數(shù)器
flag_data=1; // 設(shè)置數(shù)據(jù)標(biāo)志
flag_rec=1; // 設(shè)置數(shù)據(jù)接收標(biāo)志
break;
case ',': //Eg:$GNRMC,134645.000,A,2603.964436,N,11912.410232,E,0.000,15.744,030718,,E,A*0B
seg_count++; // 計(jì)數(shù)器增加
byte_count=0;
break;
case '*':
switch(cmd_number)
{
case 1:
buf_full|=0x01; //00000001
break;
case 2:
buf_full|=0x02; //00000010
break;
case 3:
buf_full|=0x04; //00000100
break;
}
mode=0; //clear mode
break;
default:
// 接受數(shù)據(jù)
if(mode==1)
{
cmd[byte_count]=tmp; // 獲取數(shù)據(jù)和存儲(chǔ)緩沖區(qū)
if(byte_count>=4)
{
if(cmd[0]=='G') // 第一個(gè)字符
{
if(cmd[1]=='N')
{
if(cmd[2]=='G')
{
if(cmd[3]=='G')
{
if(cmd[4]=='A')//判斷$GNGGA
{
cmd_number=1; //數(shù)據(jù)類型
mode=2; //接收日期
seg_count=0; //逗號(hào)計(jì)數(shù)器置0
byte_count=0; //位計(jì)數(shù)器清除
}
}
else if(cmd[3]=='S') //命令模式$GNGSV
{
if(cmd[4]=='V')
{
cmd_number=2;
mode=2; //獲取數(shù)據(jù)
seg_count=0;
byte_count=0;
}
}
}
else if(cmd[2]=='R') //命令模式 $GNRMC
{
if(cmd[3]=='M')
{
if(cmd[4]=='C')
{
cmd_number=3;
mode=2; //存儲(chǔ)數(shù)據(jù)
seg_count=0;
byte_count=0;
}
}
}
}
}
}
}
//日期處理
else if(mode==2)
{
switch (cmd_number) //if receive data
{
case 1: //get and store data,$GPGGA,[],[],[],[],[],[],[],[],[].....
switch(seg_count) // comma 計(jì)數(shù)器
{
case 2: // 2rd逗號(hào)后的緯度
if(byte_count<9)
{
WD[byte_count]=tmp; //獲取緯度
}
break;
case 3: //緯度方向
if(byte_count<1)
{
WD_a=tmp;
}
break;
case 4: //經(jīng)度
if(byte_count<10)
{
JD[byte_count]=tmp; //存儲(chǔ)
}
break;
case 5: //經(jīng)度方向
if(byte_count<1)
{
JD_a=tmp;
}
break;
case 6: //location
if(byte_count<1)
{
lock=tmp;
}
break;
case 7:
if(byte_count<2)
{
use_sat[byte_count]=tmp;
}
break;
case 9: // 高度
if(byte_count<6)
{
high[byte_count]=tmp;
}
break;
}
break;
case 2: //命令模式 $GPGSV
switch(seg_count)
{
case 3: // 衛(wèi)星總數(shù)
if(byte_count<2)
{
total_sat[byte_count]=tmp;
}
break;
}
break;
//命令模式3:無(wú)SUE
case 3: //$GPRMC
switch(seg_count)
{
case 1: //time
if(byte_count<6)
{
time[byte_count]=tmp;
}
break;
case 2: // 位置
if(byte_count<1)
{
if (tmp=='V') {lock=0;}
else
{
lock=1;
}
}
break;
case 3: //lititude
if(byte_count<9)
{
WD[byte_count]=tmp;//我們只需要一次
}
break;
case 4:
if(byte_count<1)
{
WD_a=tmp;
}
break;
case 5: //
if(byte_count<10)
{
JD[byte_count]=tmp; //do not get again
}
break;
case 6: // 直線方向
if(byte_count<1)
{
JD_a=tmp;
}
break;
case 7: // 速度處理
if(byte_count<5)
{
speed[byte_count]=tmp;
}
break;
case 8: // 方向角
if(byte_count<5)
{
angle[byte_count]=tmp;
}
break;
case 9: //other
if(byte_count<6)
{
date[byte_count]=tmp;
}
break;
> }
break;
}
}
byte_count++; // 位計(jì)數(shù)器++
break;
}
}