生产实习设计报告
设计题目:基于GPS模块的定位装置
生产组长:王海昕
设计组长:孙振邦
小组成员:王洪振、唐政亮、帖小龙、宋劲草、宋晓林
苏刚、孙晓龙、史俊、赵若曦
实习日期:2012年8月27日-9月15日
一、概述
本设计基于STM32F107开发板,结合iTrax03-02 型GPS 接收机,实现GPS模块与STM32的通信;通过GPS模块实现定位,STM32对GPS模块传入的数据进行读取和处理,将得到定位信息在OLED显示。
该定位装置还有如下附加功能:SD卡数据存储功能,定位状态显示(卫星颗数等);可通过RS232串口传输坐标和时间至PC机,并通过上位机软件实现路径计算和网络地图定位。
二、总体设计
1.总体系统结构
2.功能实现
⑴.经纬度测定,海拔高度测定
⑵.速度计算与方向指示
⑶.SD卡定时存储信息
⑷.上位机制作及路径计算
3.人员分工
孙振邦、王海昕完成源程序的编写,以及代码的修改、编译、下载、调试等工作;
宋劲草、宋晓林、苏刚负责GPS数据编码转换编程;
王洪振、帖小龙、唐政亮负责串口数据传输、SD卡定时存储设置;
史俊、赵若曦、孙晓龙负责上位机界面设计和各项功能的验证。
三、关键模块设计
⑴.GPS模块
iTrax03-02 型GPS 接收机是根据芬兰FASTRAX公司的GPS模块进行了电平转换、通信接口等电路设计后生产的一款GPS(OEM)接收机产品。该产品通过底板上9pin排线与计算机串口直接通信,定位后即可输出载体的经纬度信息、时间信息、速度信息等。
(2)GPS定位数据格式解析
数据形式:$GPGGA,hhmmss.dd,xxmm.dddd, OLED使用的控制器为SSD1305,可通过写入不同的命令字来设置对比度、显示开关、电荷泵、页地址等。 OLED被配置为使用I2C的方式。I2C的地址二进制位为0111100X,16进制为0x78(写地址),0x79(读地址)。OLED的Reset平时应该拉高,在初始化的时候,应该有一个从低电平到高电平的跳变。 使用的MCU端口为 PB6 CLK I2C PB7 SDA I2C PE6 RESET (低有效) (3)距离计算功能 公式、原理什么的 (4).串行通信模块 RS232的电平转换芯片为MAX232CE。外部接口为DB9。有两个LED指示灯,TXD用来显示接受到数据,RXD用来显示正在发送数据。对外接口为DB9接口,定义为:2RXD,3TXD,5GND。因此,基板可以通过串口线直接连接到PC机,和PC机进行通信。 使用的MCU端口为: PD5 UART2_TX(Remap) PD6 UART2_RX(remap) 四、测试结果 1.开机上电后在数据有效的情况下进入定位信息显示模式; 2.进入定位信息显示模式后,OLED显示出当前位置经度、纬度、海拔高度、移动速度、移动方向、卫星显示颗数 3.设定中断时间后,数据会自动存储至SD卡; 4.通过RS232串口与PC通讯后可以通过上位机软件打开该位置的谷歌地图显示,并且计算路径长度。 附录一 定位测试数据 保存数据如下: $GPGSV,3,1,10,01,35,047,32,04,30,244,24,08,12,207,27,09,06,318,12*71 $GPGSV,3,2,10,11,20,063,36,17,54,320,39,20,54,099,23,27,10,309,26*7F $GPGSV,3,3,10,28,78,225,29,32,34,062,26*75 $GPRMC,071738.50,A,3609.4075,N,12029.3426,E,0.00,302.3,090912,5.8,W,A*15 $GPGGA,071738.50,3609.4075,N,12029.3426,E,1,05,2.0,115.0,M,5.5,M,,*50 $PFST,FOM,6*63 $GPGSA,A,3,01,08,11,17,28,,,,,,,,2.9,2.0,2.1*3D $GPGSV,3,1,10,01,35,047,32,04,30,244,24,08,12,207,27,09,06,318,12*71 $GPGSV,3,2,10,11,20,063,36,17,54,320,39,20,54,099,23,27,10,309,26*7F $GPGSV,3,3,10,28,78,225,29,32,34,062,26*75 $GPRMC,071739.50,A,3609.4075,N,12029.3428,E,0.00,302.3,090912,5.8,W,A*1A $GPGGA,071739.50,3609.4075,N,12029.3428,E,1,07,2.0,115.0,M,5.5,M,,*5D $PFST,FOM,24*53 $GPGSA,A,3,01,04,08,11,17,27,28,,,,,,2.9,2.0,2.1*3C $GPGSV,3,1,10,01,35,047,31,04,30,244,24,08,12,207,27,09,06,318,12*72 $GPGSV,3,2,10,11,20,063,36,17,54,320,38,20,54,099,23,27,10,309,25*7D $GPGSV,3,3,10,28,78,225,27,32,34,062,26*7B $GPRMC,071740.50,A,3609.4074,N,12029.3429,E,0.00,302.3,090912,5.8,W,A*14 $GPGGA,071740.50,3609.4074,N,12029.3429,E,1,07,1.8,115.0,M,5.5,M,,*58 $PFST,FOM,20*57 $GPGSA,A,3,01,04,08,11,17,27,28,,,,,,2.7,1.8,2.0*38 $GPGSV,3,1,10,01,35,047,31,04,30,244,24,08,12,207,27,09,06,318,12*72 $GPGSV,3,2,10,11,20,063,36,17,54,320,38,20,54,099,23,27,10,308,25*7C $GPGSV,3,3,10,28,78,225,27,32,34,062,26*7B $GPRMC,071741.50,A,3609.4074,N,12029.3431,E,0.00,302.3,090912,5.8,W,A*1C 附录二 关键程序代码 Main.c: #include "includes.h" #include "led.h" #include GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; void USART1_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE); // 定义UART1 TX (PA.09)脚为复用推挽输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //IO口的第九脚 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //IO口复用推挽输出 GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化串口1输出IO口 // 定义 USART1 Rx (PA.10)为悬空输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //IO口的第十脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//IO口悬空输入 GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化串口1输入IO口 //串口参数配置 USART_InitStructure.USART_BaudRate = 4800; //设置波特率为115200 USART_InitStructure.USART_WordLength = USART_WordLength_8b; //设置数据位为8位 USART_InitStructure.USART_StopBits = USART_StopBits_1; //设置停止位为1位 USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //没有硬件流控 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //发送与接收 //完成串口COM1的时钟配置、GPIO配置,根据上述参数初始化并使能 USART_Init(USART1, &USART_InitStructure); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //使能串口1接收中断 USART_Cmd(USART1, ENABLE); NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } int main(void) { delay_init(72); GUI_Init(); GUI_SetBkColor(GUI_BLUE); GUI_Clear(); USART1_Init(); while(1) { gps_display(); } } GPS.c: #include "includes.h" //GPS数据存储数组// unsigned char JD[11]; //经度 unsigned char JD_a; //经度方向 unsigned char WD[10]; //纬度 unsigned char WD_a; //纬度方向 unsigned char time[10]; //时间 unsigned char speed[6] = {0}; //速度 unsigned char speed2[6] = {0}; //速度 unsigned char high[6]; //高度 unsigned char haiba[6]; //海拔 unsigned char angle[6]; //方位角 unsigned char use_sat[3]; //使用的卫星数 unsigned char total_sat[3]; //天空中总卫星数 unsigned char lock; //定位状态 //串口中断需要的变量 unsigned char seg_count; //逗号计数器 unsigned char dot_count; //小数点计数器 unsigned char byte_count; //位数计数器 unsigned char cmd_number; //命令类型 unsigned char mode; //0:结束模式,1:命令模式,2:数据模式 unsigned char buf_full; //1:整句接收完成,相应数据有效。0:缓存数据无效。 unsigned char cmd[5]; //命令类型存储数组 unsigned char USART_END; unsigned char newflag = 0; // 经纬度转换用// double d; double f; unsigned char d_d; double D_D; unsigned char time_8; //时区转换 void gps_deal(void) { u8 tmp = 0; if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //如果是接收中断 tmp = USART_ReceiveData(USART1); switch(tmp) { case '$': cmd_number = 0; //命令类型清空 mode = 1; //接收命令模式 byte_count = 0; //接收位数清空 break; case ',': seg_count++; //逗号计数加1 byte_count = 0; break; case '*': switch(cmd_number) { case 1: newflag |= 0x01; //GGA break; case 2: newflag |= 0x02; //GSV break; case 3: newflag |= 0x04; //RMC break; } mode = 0; break; default: if(mode == 1) { //命令种类判断 cmd[byte_count] = tmp; //接收字符放入类型缓存 if(byte_count >= 4) //如果类型数据接收完毕,判断类型 { if(cmd[0] == 'G') { if(cmd[1] == 'P') { if(cmd[2] == 'G') { if(cmd[3] == 'G') { if(cmd[4] == 'A') { cmd_number = 1; mode = 2; seg_count = 0; byte_count = 0; } } else if(cmd[3] == 'S') { if(cmd[4] == 'V') { cmd_number = 2; mode = 2; seg_count = 0; byte_count = 0; } } } else if(cmd[2] == 'R') { 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) { case 1: //类型1数据接收。GPGGA switch(seg_count) { case 2: //纬度处理 if(byte_count < 11) { WD[byte_count] = tmp; WD[byte_count+1] = '\\0'; //解决输出位数过多 } break; case 3: //纬度方向处理 if(byte_count < 1) { WD_a = tmp; } break; case 4: //经度处理 if(byte_count < 11) { JD[byte_count] = tmp; JD[byte_count+1] = '\\0'; } break; case 5: //经度方向处理 if(byte_count < 1) { JD_a = tmp; } break; case 7: //定位使用的卫星数 if(byte_count < 2) { use_sat[byte_count] = tmp; use_sat[byte_count+1] = '\\0'; } break; case 9: //高度处理 if(byte_count < 6) { high[byte_count] = tmp; } break; case 11: //海拔处理 if(byte_count < 6) { haiba[byte_count] = tmp; } break; } break; case 2: //类型2数据接收。GPGSV switch(seg_count) { case 3: //天空中的卫星总数 if(byte_count < 2) { total_sat[byte_count] = tmp; total_sat[byte_count+1] = '\\0'; } break; } break; case 3: //类型3数据接收。GPRMC switch(seg_count) { case 1: if(byte_count < 10) { //时间处理 time[byte_count] = tmp; } break; case 2: //定位判断 if(byte_count < 1) { lock = tmp; } break; case 7: //速度处理 if(byte_count < 5) { speed2[byte_count] = tmp; // spd_wei=byte_count; } break; case 8: //方位角处理 if(byte_count < 5) { angle[byte_count] = tmp; } break; } break; } } byte_count++; //接收数位加1 break; } } //时区转换 void TIME_AREA(void) { time_8 = (time[0] - 0x30) * 10 + (time[1] - 0x30) + 8; if(time_8 > 23) { time_8 = time_8 - 24 ; } time[0] = (time_8 / 10) + 0x30; time[1] = ((time_8 - (time_8 / 10) * 10) / 1) + 0x30; } //经纬度转换 double JWD_AREA(char *jwd) { d = atof(jwd) / 100.0; //将JD[]转换为double d_d = d / 1; f = (d - d_d) / 60.0 * 100; D_D = d_d + f; return D_D; } void gps_display(void) { LED0=!LED0; if(newflag == 0x07) { newflag = 0; GUI_SetColor(GUI_GREEN); GUI_SetFont(&GUI_Font8x16); GUI_DispStringAt("status",20,20); GUI_DispCharAt(lock,140,20); TIME_AREA(); GUI_DispStringAt("time",20,40); GUI_DispStringAt(time,140,40); GUI_DispStringAt("Longitude ",20,60); JWD_AREA(JD); //经度转换 GUI_DispFloat(D_D,10) ; GUI_DispCharAt(JD_a,120,60); GUI_DispStringAt("Latitude ",20,80); JWD_AREA(WD); //纬度转换 GUI_DispFloat(D_D,10) ; GUI_DispCharAt(WD_a,120,80); GUI_DispStringAt("use_sat",20,100); GUI_DispStringAt(use_sat,140,100); GUI_DispStringAt("total_sat",20,120); GUI_DispStringAt(total_sat,140,120); GUI_DispStringAt("Elevation",20,140); GUI_DispStringAt(high,140,140); GUI_DispStringAt("high",20,160); GUI_DispStringAt(haiba,140,160); GUI_DispStringAt("Speed",20,180); GUI_DispStringAt(speed2,140,180); GUI_DispStringAt("Direction",20,200); GUI_DispStringAt(angle,140,200); GUI_DispStringAt("OUC AUTOMATION GPS",40,280); } } // printf("状态 :%c\\r\\n", lock); //串口输出调试 // TIME_AREA(); // printf("时间 :%c%c时%c%c分%c%c%c%c%c秒\\r\\n", time[0], time[1], time[2], time[3], time[4], time[5], time[6], time[7], time[8]); //串口输出调试 // JWD_AREA(JD); //经度转换 // printf("经度 :%f%c\\r\\n", D_D, JD_a); //串口输出调试jd // JWD_AREA(WD); //纬度转换 // printf("纬度 :%f%c\\r\\n", D_D, WD_a); //串口输出调试wd // printf("卫星 :%s颗\\r\\n", use_sat); //串口输出调试 // printf("卫星 :%s颗\\r\\n", total_sat); //串口输出调试 // printf("高度 :%sm\\r\\n", haiba); //串口输出调试 // printf("海拔 :%sm\\r\\n", high); //串口输出调试 // printf("速度 :%s节\\r\\n", speed2); //串口输出调试 // printf("方位 :%s度\\r\\n", angle); //串口输出调试 // printf("状态 :%c\\r\\n", lock); //串口输出调试 // TIME_AREA(); // printf("时间 :%c%c时%c%c分%c%c%c%c%c秒\\r\\n", time[0], time[1], time[2], time[3], time[4], time[5], time[6], time[7], time[8]); //串口输出调试 // JWD_AREA(JD); //经度转换 // printf("经度 :%f%c\\r\\n", D_D, JD_a); //串口输出调试jd // JWD_AREA(WD); //纬度转换 // printf("纬度 :%f%c\\r\\n", D_D, WD_a); //串口输出调试wd // printf("卫星 :%s颗\\r\\n", use_sat); //串口输出调试 // printf("卫星 :%s颗\\r\\n", total_sat); //串口输出调试 // printf("高度 :%sm\\r\\n", haiba); //串口输出调试 // printf("海拔 :%sm\\r\\n", high); //串口输出调试 // printf("速度 :%s节\\r\\n", speed2); //串口输出调试 // printf("方位 :%s度\\r\\n", angle); //串口输出调试
⑵.OLED显示模块名称 说明 $GPGGA GGA消息协议头 hhmmss.dd UTC时间 xxmm.dddd 纬度信息,度、分格式 纬度半球N(北半球)或S(南半球) yyymm.dddd 经度信息,度、分格式 纬度半球E(东经)或E(西经) V 判断是否已定位,定位为1,未定位为0 ss 使用的解算卫星的数量一般0-12颗 d.d HDOP水平精度因子 h.h 海拔高度 M 单位米 g.g WGS-84地表面与水平面的差值 M 单位米 a.a 空 xxxx 空 hh 校验及固定包尾