基于51单片机GPS定位系统经纬度GSM短信上报设计

1、设计需求及目标

本系统由STC89C52单片机电路+GPS模块电路+GSM模块SIM800A+指示灯电路+电源电路组成。

1、系统上电后,系统向特定手机号码发送短信,短信内容为系统的当前经纬度信息。40s左右发一次。

2、如果需要立刻发送经纬度信息,直接按板载按键即可立刻发送经纬度数据,不用等待40s。

3、短信发送及初始化有状态指示灯指示。

4、GSM模块是SIM800A,该模块和SIM900A电路程序完全兼容外观外形一模一样

2、设计思路及方案

 本系统具体框图如下图所示:

 硬件电路如图:

3、部分代码

#include <reg52.h> 
#include <intrins.h>
#include <stdio.h>
#include "delay.h"

/**The UART1 stage1**/
#define STAGE_SOHE  0x01
#define STAGE_TYPE  0x02
#define STAGE_NONE  0x03
#define STAGE_DATA  0x04

#define INIT 0xFF
#define TRUE 0x00
#define FALSE 0x01

sbit LED = P1^0;//指示灯
sbit key =P2^0;//按键

unsigned char Lin0_No[13]="N:000.000000";//显示北纬
unsigned char Lin1_Ea[12]="E:000.000000";//显示东经

unsigned long xdata time_20ms=0;

unsigned char xdata	devide_flag;		        //GPS数据逗号分隔符
unsigned char xdata	speed_end;			//收速度数据结束标志
unsigned char xdata	dir_end;			//收方向角数据结束标志
unsigned char xdata  sysmode_GPS=FALSE;                    //gps有效无效标志
unsigned char xdata ew_flag;                        //东西标志
unsigned char xdata ns_flag;                        //南北标志

unsigned char xdata	gps_infor_weijing[17];    //暂存经纬度 格式是以度分秒的是形式
unsigned char xdata	gps_infor_speed[4];       //暂存速率
unsigned char xdata	gps_infor_time[6];        //时间暂存
unsigned char xdata	gps_infor_date[6];        //日期暂存
unsigned char xdata	gps_infor_dir[3];         //方向暂存

unsigned char xdata recv1_step=STAGE_SOHE;                       //串口接收指令步骤
unsigned char xdata uart1_r_buf;                       //串口的缓存
unsigned char xdata rev1_buf_busy;                    //串口接收忙碌标志
unsigned char xdata temp1_buf[85];                   //串口接收数组
unsigned int  xdata record1=0;   					//串口接收计数
unsigned char i ;

unsigned char dealGpsMes=FALSE;   //gps定时处理标志

unsigned char reportTime = 0;//短信上报时间 计数

void Init_Timer0(void);//函数声明
void gpsDealfun(void);
void uartSendStr(unsigned char *s,unsigned char length);
void UART_Init(void);
void uartSendByte(unsigned char dat);


void main (void)
{
	Init_Timer0();        //定时器0初始化
	
	UART_Init();	  //串口初始化

	LED = 0;		   //打开led
	key = 1;
	for(i=0;i<50;i++)	 //延时有助于稳定
	{DelayMs(100);}	
	uartSendStr("aAT+CMGF=1\r\n",12);	//初始化gsm模块

	for(i=0;i<7;i++)	 //延时有助于稳定
	{DelayMs(100);}
	uartSendStr("AT+CSCS=\"GSM\"\r\n",15);

	for(i=0;i<7;i++)	    //延时有助于稳定
	{DelayMs(100);}
	LED =1;

	while(1)         //主循环
	{
		if(dealGpsMes==TRUE)   //gps信息处理
		{
			dealGpsMes=FALSE;  //清除标志
			gpsDealfun();	   //gps信息处理函数
		}
		
		if((reportTime >= 20)||(key == 0))		//2s计数一次
		{
			reportTime = 0;
			LED=0;		//打开led
			uartSendStr("AT+CMGF=1\r\n",11);  //设置字符集
			for(i=0;i<5;i++)
			{DelayMs(100);}
			uartSendStr("AT+CSCS=\"GSM\"\r\n",15); //设置
			for(i=0;i<5;i++)
			{DelayMs(100);}
			uartSendStr("AT+CMGS=\"+8618105140357\"\r\n",26); //可以修改电话号码
//			uartSendStr("AT+CMGS=\"+8617686988225\"\r\n",26); //可以修改电话号码
			for(i=0;i<3;i++)
			{DelayMs(100);} 
			uartSendStr(Lin0_No,13);//发送短信内容 在gps数据处理情况	
			uartSendStr(Lin1_Ea,12);		
						
			for(i=0;i<2;i++)
			{DelayMs(100);}
			uartSendByte(0x1a);        	//发送
			for(i=0;i<40;i++)
			{DelayMs(100);}

			LED =1;	  //关闭led
		}
		DelayMs(5);	
	}
}

void gpsDealfun(void)
{
	unsigned char num=0;
	unsigned long Mid_Du;       //中间变量 暂存经纬度的整数部分 即度
	unsigned long Mid_Fen;      //中间变量 暂存经纬度的小数部分 即分  gps原始数据是度分秒格式
	unsigned long Mid_Vale;     ////中间变量 暂存经纬度 并将其扩大了10000000倍

	if(sysmode_GPS==TRUE)		//检测gps是否有效数据
	{
		sysmode_GPS=FALSE;			//清除有效位

        Mid_Du=(gps_infor_weijing[0]-0x30)*10000000+(gps_infor_weijing[1]-0x30)*1000000;    //处理纬度 暂存整数部分扩大10000000
        
        Mid_Fen=(gps_infor_weijing[2]-0x30)*10000000+(gps_infor_weijing[3]-0x30)*1000000+
          (gps_infor_weijing[4]-0x30)*100000+(gps_infor_weijing[5]-0x30)*10000+
            (gps_infor_weijing[6]-0x30)*1000+(gps_infor_weijing[7]-0x30)*100;        //处理纬度 暂存小数部分扩大10000000       
        Mid_Fen=Mid_Fen/60;                                                     //分秒换算为小数位
        Mid_Vale=Mid_Du+Mid_Fen;        //最终纬度 格式为000.00000000 非度分秒格式
        Lin0_No[0]='N';
		Lin0_No[1]='N';                  
		Lin0_No[2]=':';                  
		Lin0_No[3]='0';                  
        Lin0_No[4]=Mid_Vale/10000000+0x30;                  //将处理后的纬度填入字符串 并打印显示
        Lin0_No[5]=(Mid_Vale/1000000)%10+0x30;
        Lin0_No[6]='.';
        Lin0_No[7]=(Mid_Vale/100000)%10+0x30;
        Lin0_No[8]=(Mid_Vale/10000)%10+0x30;
        Lin0_No[9]=(Mid_Vale/1000)%10+0x30;
        Lin0_No[10]=(Mid_Vale/100)%10+0x30;
        Lin0_No[11]=(Mid_Vale/10)%10+0x30;
        Lin0_No[12]=Mid_Vale%10+0x30;
        
        Mid_Du=(gps_infor_weijing[8]-0x30)*100000000+(gps_infor_weijing[9]-0x30)*10000000+(gps_infor_weijing[10]-0x30)*1000000; //处理经度 暂存整数部分扩大10000000
        
        Mid_Fen=(gps_infor_weijing[11]-0x30)*10000000+(gps_infor_weijing[12]-0x30)*1000000+
          (gps_infor_weijing[13]-0x30)*100000+(gps_infor_weijing[14]-0x30)*10000+
            (gps_infor_weijing[15]-0x30)*1000+(gps_infor_weijing[16]-0x30)*100; //处理经度 暂存小数部分扩大10000000       
        Mid_Fen=Mid_Fen/60;                                                //分秒换算为小数位
        Mid_Vale=Mid_Du+Mid_Fen;                                          //最终经度 格式为000.00000000 非度分秒格式
        Lin1_Ea[0]='E';                  
		Lin1_Ea[1]=':';     
        Lin1_Ea[2]=Mid_Vale/100000000+0x30;                            //将处理后的经度填入字符串 并打印显示
        Lin1_Ea[3]=(Mid_Vale/10000000)%10+0x30;
        Lin1_Ea[4]=(Mid_Vale/1000000)%10+0x30;
        Lin1_Ea[5]='.';
        Lin1_Ea[6]=(Mid_Vale/100000)%10+0x30;
        Lin1_Ea[7]=(Mid_Vale/10000)%10+0x30;
        Lin1_Ea[8]=(Mid_Vale/1000)%10+0x30;
        Lin1_Ea[9]=(Mid_Vale/100)%10+0x30;
        Lin1_Ea[10]=(Mid_Vale/10)%10+0x30;
        Lin1_Ea[11]=Mid_Vale%10+0x30;
       
	}
	else
	{
        Lin1_Ea[0]='G';               //无gps信号情况下 打印正在连接
		Lin1_Ea[1]='P';                  
		Lin1_Ea[2]='S';                  
        Lin1_Ea[3]=' ';                  /*将处理后的纬度填入字符串 并打印显示*/
        Lin1_Ea[4]='L';
        Lin1_Ea[5]='I';
        Lin1_Ea[6]='N';
        Lin1_Ea[7]='K';
        Lin1_Ea[8]='I';
        Lin1_Ea[9]='N';
        Lin1_Ea[10]='G';
        Lin1_Ea[11]='.';Lin1_Ea[12]='.';Lin1_Ea[13]='.';
		for(i=0;i<14;i++)
		{
			Lin0_No[i]=Lin1_Ea[i];
		}
	}
//	DelayMs(10);
//	SendStr(Lin0_No,12);
//	DelayMs(10);
//	SendStr(Lin1_Ea,12);
}


void Init_Timer0(void)
{
	TMOD |= 0x01;	  //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响		     
	TH0 = 0x0B8;	  //11.0592M 20ms
	TL0 = 0x00;
	EA=1;            //总中断打开
	ET0=1;           //定时器中断打开
	TR0=1;           //定时器开关打开
}

void Timer0_isr(void) interrupt 1 
{
	TH0 = 0x0B8;	  //11.0592M 20ms
	TL0 = 0x00;
	time_20ms++;
	if(time_20ms%100==0)	//2s左右处理一次
	{
		dealGpsMes=TRUE;	
		reportTime++;
	}
}

void UART_Init(void)
{
    SCON  = 0x50;		        // SCON: 模式 1, 8-bit UART, 使能接收  
    TMOD |= 0x20;               // TMOD: timer 1, mode 2, 8-bit 重装
    TH1   = 0xFD;               // TH1:  重装值 9600 波特率 晶振 11.0592MHz  
    TR1   = 1;                  // TR1:  timer 1 打开                         
    EA    = 1;                  //打开总中断
    ES    = 1;                  //打开串口中断
}

void uartSendByte(unsigned char dat)
{
	unsigned char time_out;
	time_out=0x00;
	SBUF = dat;			  //将数据放入SBUF中
	while((!TI)&&(time_out<100))  //检测是否发送出去
	{time_out++;DelayUs2x(10);}	//未发送出去 进行短暂延时
	TI = 0;						//清除ti标志
}

void uartSendStr(unsigned char *s,unsigned char length)
{
	unsigned char NUM;
	NUM=0x00;
	while(NUM<length)	//发送长度对比
	{
		uartSendByte(*s);  //放松单字节数据
		s++;		  //指针++
		NUM++;		  //下一个++
  	 }
}

void UART_SER (void) interrupt 4 //串行中断服务程序
{
    if(RI)                        //判断是接收中断产生
    {
	  RI=0;                      //标志位清零
	  uart1_r_buf=SBUF;                      //提取buf中的值
	  rev1_buf_busy=0x00;                         //判别 放置break问题
	  switch(recv1_step)
	  {
	  case STAGE_SOHE: if(uart1_r_buf == '$')     //判断接收到了$  具体原因参考GPS标准协议NMEA0183
	  {
	    rev1_buf_busy=0x01;
	    if(uart1_r_buf == '$')              //再次查看接收的是否是$
	    {
	      recv1_step=STAGE_TYPE;            //跳转到下一步
	      record1=0;                        //计数清零
	    }
	    else
	    {
	      recv1_step=STAGE_SOHE;        //恢复初始化
	      record1=0;
	    }
	  }
	  break;
	  case STAGE_TYPE: if(rev1_buf_busy == 0x00)
	  {

	    rev1_buf_busy=0x01;
	    temp1_buf[record1]=uart1_r_buf;
	    record1++;
	    if(record1 == 0x05)
	    {                                                 //查看$GPRMC开头的命令行
	      if((temp1_buf[0] == 'G') && (temp1_buf[1] == 'P') && (temp1_buf[2] == 'R') && (temp1_buf[3] == 'M') && (temp1_buf[4] == 'C'))
	      {
	        recv1_step=STAGE_NONE;    //跳转到下一步
	        record1=0;
	      } 
	      else
	      {
	        recv1_step=STAGE_SOHE;//恢复初始化
	        record1=0;
	      }
	    }
	  }
	  break;
	  case STAGE_NONE: if(rev1_buf_busy == 0x00)//接收命令格式:$GPRMC,054347.00,A,3202.04770,N,11846.23632,E,0.000,0.00,221013,,,A*67
	  {
	    rev1_buf_busy=0x01;
	    record1++;
	    if((record1 > 0x01) && (record1 < 0x08))                                                                                    
	    {
	      gps_infor_time[record1-2]=uart1_r_buf;			//时间存储						
	    }
	    if((uart1_r_buf == ',') && (record1 > 0x07) && (record1 < 0x010))   //||((uart1_r_buf == ',') && (record1==0x02))
	    {
	      record1=0xcc;
	    }
	    if(record1 ==  0xcd)
	    {
	      record1=0;
	      devide_flag=2;
	      speed_end=0x00;
	      dir_end=0x00;
	      if(uart1_r_buf == 'A')  //gps收到数据 且有效
	      { 
	        recv1_step=STAGE_DATA;    //跳转到下一步
	      }
	      else
	      {
	        sysmode_GPS=FALSE;
	        recv1_step=STAGE_SOHE;    //无效恢复初始化
	        record1=0;
	      }
	    }
	  }
	  break;
	  case STAGE_DATA:  if(rev1_buf_busy == 0x00)
	  {
	    rev1_buf_busy=0x01;
	    record1++;
	    if(uart1_r_buf == ',')    //判断逗号
	    { 
	      devide_flag++;      //逗号次数记录
	      record1=0;
	    }
	    if(devide_flag == 3)
	    {
	      if((record1 > 0) && (record1 < 5))
	      {
	        gps_infor_weijing[record1-1]=uart1_r_buf;	    //存储经纬度 此处为纬度							
	      }
	      if((record1 > 5) && (record1 < 10))             //跳过小数点的存储
	      {
	        gps_infor_weijing[record1-2]=uart1_r_buf;	   //存储经纬度 此处为纬度															
	      }
	    }
	    if(devide_flag == 4)
	    {
	      if(record1 > 0)
	      {
	        ns_flag=uart1_r_buf;            //接收纬度NS标志
	      }
	    }
	    if(devide_flag == 5)
	    {
	      if((record1 > 0) && (record1 < 6))
	      {
	        gps_infor_weijing[record1+7]=uart1_r_buf;	  //存储经纬度 此处为纬度										
	      }
	      if((record1 > 6) && (record1 < 11))                //跳过小数点的存储
	      {
	        gps_infor_weijing[record1+6]=uart1_r_buf;       //存储经纬度 此处为经度																			
	      }
	    }
	    if(devide_flag == 6)
	    {
	      if(record1 > 0)
	      {
	        ew_flag=uart1_r_buf;            //经度度 EW标志
	      }
	    }
	    if(devide_flag == 7)
	    {
	      if(speed_end == 0x00)
	      {
	        if((record1 > 0) && (uart1_r_buf != '.'))
	        {
	          gps_infor_speed[record1-1]=uart1_r_buf;   //接收速率
	        }
	        else if(uart1_r_buf == '.')
	        {
	          record1--;
	          speed_end=0xff;
	        }
	      }
	      else if(speed_end == 0xff)
	      {
	        speed_end=0xfe;
	        gps_infor_speed[record1-1]=uart1_r_buf;
	        gps_infor_speed[3]=gps_infor_speed[record1-1];
	        gps_infor_speed[2]=gps_infor_speed[record1-2];
	        if(record1 > 2)
	        {
	          gps_infor_speed[1]=gps_infor_speed[record1-3];
	        }
	        else
	        {
	          gps_infor_speed[1]=0x30;
	        }
	        if(record1 > 3)
	        {
	          gps_infor_speed[0]=gps_infor_speed[record1-4];
	        }
	        else
	        {
	          gps_infor_speed[0]=0x30;
	        }
	      }
	    }
	    if(devide_flag == 8)
	    {
	      if(dir_end == 0x00)
	      {
	        if((record1 > 0) && (uart1_r_buf != '.'))
	        {
	          gps_infor_dir[record1-1]=uart1_r_buf;   //存储方向
	        }
	        else if(uart1_r_buf == '.')
	        {
	          record1--;
	          dir_end=0xff;
	        }
	      }
	      else if(dir_end == 0xff)
	      {
	        dir_end=0xfe;
	        if(record1 == 2)
	        {
	          gps_infor_dir[2]=gps_infor_dir[record1-2];
	          gps_infor_dir[1]=0x30;
	          gps_infor_dir[0]=0x30;
	        }
	        if(record1 == 3)
	        {
	          gps_infor_dir[2]=gps_infor_dir[record1-2];
	          gps_infor_dir[1]=gps_infor_dir[record1-3];
	          gps_infor_dir[0]=0x30;
	        }
	      }
	    }
	    if(devide_flag == 9)
	    {
	      if((record1 > 0) && (record1 < 7))
	      {
	        gps_infor_date[record1-1]=uart1_r_buf;
	      }
	    }
	    if(uart1_r_buf == 0x0d)
	    {
	      recv1_step=STAGE_SOHE;    //接收完成 并信号确定 
	      record1=0;                //恢复初始化状态 为下一次准备
	      devide_flag=0;
	      sysmode_GPS=TRUE;         //置位 GPS 信号为正确
	    }
	  }
	  break;
	  }
	}
   if(TI)  //如果是发送标志位,清零
	TI=0;
}

完整资料:https://market.m.taobao.com/app/idleFish-F2e/widle-taobao-rax/page-detail?wh_weex=true&wx_navbar_transparent=true&id=614260612227&ut_sk=1.WUpxx7gpwUoDAMmnnrBIzAno_12431167_1585544024566.Copy.detail.614260612227.1828622527&forceFlush=1

发布了30 篇原创文章 · 获赞 12 · 访问量 1998

猜你喜欢

转载自blog.csdn.net/weixin_41017942/article/details/105196718