网站客服:zx81024163 |

单片机+北斗模块实现定位

2023-07-30 13:05:06发布    浏览430次    信息编号:66562

友情提醒:凡是以各种理由向你收取费用,均有骗子嫌疑,请提高警惕,不要轻易支付。

单片机+北斗模块实现定位

本文为原创,转载请注明出处。 小编以后可能不会更新简书简书地址了,因为这里的编辑器太难用了,不像CSDN上那么好用,希望各位粉丝多多关注我的CSDN(同名)。

导航是继移动通信之后发展最快的信息产业之一,只要涉及到位置、速度、时间信息领域,只要与斗鱼卫星导航技术有关。 中国北斗卫星导航系统是我国自主研发的全球导航系统。 它是继美国定位系统(GPS)和俄罗斯格洛纳斯卫星导航系统之后第三个成熟的卫星导航系统。 随着北斗导航系统的不断完善,基于北斗导航系统的定位也越来越广泛的应用。 小编结合卫星接收模块UM220-III设计的北斗导航系统接收机。 UM220-III是一款双模接收模块,可以同时接收GPS和北斗信号。 本设计主要完成导航信息接收机的基本设计,实现获取实时位置经纬度、标准时间等相关信息的显示功能。

1 原理介绍

以单片机为核心,读取北斗导航系统模块的标准数据,并在液晶屏上显示当前的经纬度信息。 具体系统方案图如下:

1.1 北斗UM220-III模块介绍

(1)接口电路

北斗模块芯片电路由北斗模块UM220-III N及其附加电子元件组成。 其中,北斗模块外接4组排针。 芯片与电源之间串联电感的作用是滤除差模,防止电流突变损坏芯片。 并联电感的作用是提高芯片工作的稳定性,防止噪声。

模块的输入端口(UM220-III N 包括:RXD、GPIO、SDA、SCL 等如下图所示) 为了防止输入端的不稳定状态对模块造成影响,模块有一个内置上拉电阻到VCC,所以当模块未上电时,如果上述端口有数据输入的话,就会对模块VCC形成串联供电,可能会导致模块无法上电。

case1:在设计中使用函数

模块上电后会拉低5ms以上,保证模块正常启动。

case2:设计中未使用

模块上电前,请确保模块所连接的输入端口处于高阻状态或低电平,以避免串联。 使用串口1的典型用户需要将RXD1设置为高阻状态或低电平,并将其他未使用的引脚悬空。 程序流程图如下:

(2)LCD液晶显示

LCD液晶显示器的数据由单片机的p0口控制,p2口用于命令控制操作。 它是专门用于显示字母、数字、符号等的点阵液晶模块。 1602:显示内容以16*2为主,即可以显示两行,每行16个字符。 相应的学科功能可以在百度上查阅,这里不再赘述。

(3) UM220-III通讯协议简介

在协议中,输入和输出语句称为消息。 每条消息都是一串 ASCII 字符。

消息的基本格式是: KaTeX parse error: Can't use '\r' in math mode at 32: …2,data3,...[*cc]\̲r̲\n All 以 '' (0x24) 开头,接下来是消息名称。 接下来是不定数量的参数和数据。 消息名称和数据以逗号 (0x2c) 分隔。 最后一个参数是可选的校验和,通过“*”(0x2A) 与之前的数据分隔。 最后,输入消息以“\r\n”结尾。 每条消息总长度不超过256字节,消息名称、参数、校验和中的字母不区分大小写。

某些输入命令的某些参数可以省略(在命令说明中标记为可选)。 这些参数可以为空,即两个逗号之间没有任何字符。

2 调试方法

从1.1中原理的简单介绍可以看出,本项目的实现主要由系统初始化、设置显示模式、读取预显示内容、发送扫描脉冲、发送显示数据5部分组成。

这里简单介绍一下单片机和模块的连接。

UM220/um220-3-n有两组TTL电平(2.85V)和一组标准电平RS232电平。 当单片机的RS232电平接口与UM220模块上的RS232连接时,通讯正常。 UM220模块上的RS232接口是DB9母头连接器。 您可以使用公头电缆连接到 RS230 接口。 注意通讯线需要交叉连接,就像TTL电平中的TXD--RXD、RXD-TXD。 RS232电平通信也有两根通信电缆,一根是发送端(PCXD),一根是接收端(PCRXD)。 如果板上的RS232接口是DB9母头,则2 3脚为PCRXD和PCTXD。 第五个引脚是GND。 如果没有串口线连接UM220模块,可以考虑在DB9下面的2 3 5针上焊3针。 连接线和单片机的RS232。

如果单片机是3.3V,可以将单片机的TTL接口连接到模块上的TTL接口。 连接好后就可以编写程序了。

注意,我们使用的52单片机的驱动程序使用的是11.05926晶振,波特率为9600。

#3 编程

该程序主要由5部分组成:系统初始化、设置显示模式。 读取预显示内容,发送扫描脉冲,发送显示数据。 小编只放主程序部分:

定义端口和变量

#include 
#include 
#include 
#include 
#include 
#include 
#include "string.h"
#include 
unsigned char  flag_rec=0;    //接收数据标志
unsigned char num_rec=0;      // 计数标志      
//char code TIME_AREA= 8;		//时区,我们不需要它
unsigned char flag_data;	//date flag
//only displaty cmd $GPGGA information
unsigned char JD[16];		//longitude
unsigned char JD_a;		//经度方向
unsigned char WD[15];		//latitude
unsigned char WD_a;		// 纬度方向
unsigned char date[6];		//date
unsigned char time[6];		//date
unsigned char time1[6];		//date
unsigned char speed[5]={'0','0','0','0','0'};		// 速度
unsigned char high[6];		// 高度
unsigned char angle[5];		//方位角
unsigned char use_sat[2];	// 卫星计数器
unsigned char total_sat[2];	//卫星总数
unsigned char lock;			//位置状态
//date handing variable
unsigned char seg_count;	// 逗号计数器
unsigned char dot_count;	//小数点计数器
unsigned char byte_count;	// 位计数器
unsigned char cmd_number;	// 命令模式
unsigned char mode;			//
unsigned char buf_full;		
unsigned char cmd[5];		// 存储命令模式
//serial disconnect timer
unsigned  long int tt=0;

主要功能系统初始化

//main
void main () 
{	
  int jd_second,wd_second;  // 中间变量
	init_uart();	     //初始化序列号
  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);			// 清屏

设置延迟函数形成视觉暂留

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);
   }

···

读取预显示内容,设置显示格式,十六进制转十进制**

    if(flag_rec==1)             // 获取gps数据
      {
        flag_rec=0;               // 清除标志符
        if (lock==1)              //  获取位置信息
		  	{  
          //
          LCD_Write_String(0,0,"JD  :");    // 显示经度
          LCD_Write_String(6,0,JD);           // 显示数据
          LCD_Write_String(9,0,".");           // 进制转换
          LCD_Write_String(10,0,JD+3);           
          jd_second=60*atof((char *)(JD+5));     
          LCD_Write_Char(13,0,jd_second/10+'0');  // 将上一步转换得到浮点数据打印在lcd
          LCD_Write_Char(14,0,jd_second+'0');  // 将上面得到的数据分为两部分,分别打印在LCD 上
          LCD_Write_Char(15,0,' ');                //填充空间
          delay(200);                         // 保护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);           // 小数点
          wd_second=60*atof((char *)(WD+4)); 
// 将字符串转换成浮点数
          LCD_Write_Char(12,1,wd_second/10+'0');
          LCD_Write_Char(13,1,wd_second+'0');
          LCD_Write_String(14,1,"  ");
          delay(200);
       }
      }
     }
		}

串口中断函数及模式判断

判断的主要依据是接收端收到的报文与预先的结果是否匹配,通过设置数组[i,j]和if函数来判断是否匹配(参见1.3中UM220通信协议的详细解释)为发送消息的消息内容)

//serial interruupt service function
void ser_int (void) interrupt 4
{
 	
 	unsigned char tmp;
	if(RI)
	{
    tt=0;
		RI=0;
		tmp=SBUF;            // 从缓冲区接收数据
		switch(tmp)   //if $GPGGA,$GNGSW,$GNRMC,get data then processing it
		{
      //date start with $
			case '$':
				cmd_number=0;		// 清除命令模式
				mode=1;				// 选项命令接收模式
				byte_count=0;		//清除位计数器
				flag_data=1;     // 设置数据标志
				flag_rec=1;		// 设置数据接收标志
			break;
			case ',':         //Eg:$GNRMC,134645.000,A,2603.964436,N,11912.410232,E,0.000,15.744,030718,,E,A*0B
				seg_count++;		// 计数器增加
				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:
// receive date cmd
				if(mode==1)	
				{
					cmd[byte_count]=tmp;	// 获取数据和存储缓冲区					if(byte_count>=4)          //overlook cmd which less 4 bit
					{			
						if(cmd[0]=='G')           // 第一个字符
						{
							if(cmd[1]=='N')
							{
								if(cmd[2]=='G')
								{
									if(cmd[3]=='G')
									{
										if(cmd[4]=='A')//判断$GNGGA
										{
											cmd_number=1;      //数据类型
											mode=2;            //接收日期
											seg_count=0;       //comma counter clear
											byte_count=0;      //位计数器清除
										}
									}
									else if(cmd[3]=='S')       //命令模式$GNGSV
									{
										if(cmd[4]=='V')
										{
											cmd_number=2;
											mode=2;                //获取数据
											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;         //存储数据
											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 计数器
						{
							case 2:		// 2rd逗号后的纬度
								if(byte_count<9)
								{
									WD[byte_count]=tmp;   //获取纬度
								}
								break;
							case 3:		//纬度方向
								if(byte_count<1)
								{
									WD_a=tmp;
								}
								break;
							case 4:		//经度
								if(byte_count<10)
								{
									JD[byte_count]=tmp; //存储
								}
								break;
							case 5:		//经度方向
								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:		// 卫星总数
								if(byte_count<2)
								{
									total_sat[byte_count]=tmp;
								}
								break;
						}
						break;

//命令模式3:无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++;		// 位计数器++
				break;
		}
	}

4 结果显示

提醒:请联系我时一定说明是从星空网上看到的!