完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
在中移物联网实习过程中,使用的是公司自己开发的麒麟做开发板,在调试GPS模块时,我参考了stm32MINI板的相关例程,写出了以下程序。因为该GPS模块传输速率很快,我们能需要用到DMA来读取数据流。但例程提供的是串口2的程序,板子固定好串口二由sim80c模块使用,所以我后来改成了串口三,然后被联调的同事告知串口3也被占用,我只能再次改成串口4.以下提供源码:
//uart4.c #include "delay.h" #include "usart4.h" #include "stdarg.h" #include "stdio.h" #include "string.h" #include "stm32f10x.h" //串口发送缓存区 __align(8) u8 USART4_TX_BUF[USART4_MAX_SEND_LEN]; //发送缓冲,最大USART4_MAX_SEND_LEN字节 #ifdef USART4_RX_EN //如果使能了接收 //串口接收缓存区 u8 USART4_RX_BUF[USART4_MAX_RECV_LEN]; //接收缓冲,最大USART4_MAX_RECV_LEN个字节. //通过判断接收连续2个字符之间的时间差不大于10ms来决定是不是一次连续的数据. //如果2个字符接收间隔超过10ms,则认为不是1次连续数据.也就是超过10ms没有接收到 //任何数据,则表示此次接收完毕. //接收到的数据状态 //[15]:0,没有接收到数据;1,接收到了一批数据. //[14:0]:接收到的数据长度 u16 USART4_RX_STA=0; void UART4_IRQHandler(void) { u8 res; if(USART_GetITStatus(UART4, USART_IT_RXNE) != RESET)//接收到数据 { res =USART_ReceiveData(UART4); if(USART4_RX_STA TIM_SetCounter(TIM4,0);//计数器清空 if(USART4_RX_STA==0)TIM4_Set(1); //使能定时器4的中断 USART4_RX_BUF[USART4_RX_STA++]=res; //记录接收到的值 }else { USART4_RX_STA|=1<<15; //强制标记接收完成 } } } //初始化IO 串口4 //pclk1:PCLK1时钟频率(Mhz) //bound:波特率 void USART4_Init(u32 bound) { NVIC_InitTypeDef NVIC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); // GPIOc时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4,ENABLE); USART_DeInit(UART4); //复位串口4 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOC, &GPIO_InitStructure); // GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入 GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化 USART_InitStructure.USART_BaudRate = bound;//一般设置为9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式 USART_InitStructure.USART_StopBits = USART_StopBits_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; //收发模式 USART_Init(UART4, &USART_InitStructure); //初始化串口 //波特率设置 // USART2->BRR=(pclk1*1000000)/(bound);// 波特率设置 //USART2->CR1|=0X200C; //1位停止,无校验位. USART_DMACmd(UART4,USART_DMAReq_Tx,ENABLE); //使能串口4的DMA发送 UART_DMA_Config(DMA2_Channel3,(u32)&UART4->DR,(u32)USART4_TX_BUF);// USART_Cmd(UART4, ENABLE); //使能串口 #ifdef USART4_RX_EN //如果使能了接收 //使能接收中断 USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);//开启中断 NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器 TIM4_Init(99,7199); //10ms中断 USART4_RX_STA=0; //清零 TIM4_Set(0); //关闭定时器4 #endif } //确保一次发送数据不超过USART2_MAX_SEND_LEN字节 void u4_printf(char* fmt,...) { va_list ap; va_start(ap,fmt); sprintf((char*)USART4_TX_BUF,fmt,ap); va_end(ap); while(DMA_GetCurrDataCounter(DMA2_Channel3)!=0); // UART_DMA_Enable(DMA2_Channel3,strlen((const char*)USART4_TX_BUF)); //通过dma发送出去 } //定时器4中断服务程序 void TIM4_IRQHandler(void) { if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)//是更新中断 { USART4_RX_STA|=1<<15; //标记接收完成 TIM_ClearITPendingBit(TIM4, TIM_IT_Update ); //清除TIMx更新中断标志 TIM4_Set(0); //关闭TIM4 } } //设置TIM4的开关 //sta:0,关闭;1,开启; void TIM4_Set(u8 sta) { if(sta) { TIM_SetCounter(TIM4,0);//计数器清空 TIM_Cmd(TIM4, ENABLE); //使能TIMx }else TIM_Cmd(TIM4, DISABLE);//关闭定时器4 } //通用定时器中断初始化 //这里始终选择为APB1的2倍,而APB1为36M //arr:自动重装值。 //psc:时钟预分频数 void TIM4_Init(u16 arr,u16 psc) { NVIC_InitTypeDef NVIC_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //时钟使能//TIM4时钟使能 //定时器TIM3初始化 TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位 TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE ); //使能指定的TIM4中断,允许更新中断 NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器 } #endif ///////////////////////////////////////USART2 DMA发送配置部分////////////////////////////////// //DMA1的各通道配置 //这里的传输形式是固定的,这点要根据不同的情况来修改 //从存储器->外设模式/8位数据宽度/存储器增量模式 //DMA_CHx:DMA通道CHx //cpar:外设地址 //cmar:存储器地址 void UART_DMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar) { DMA_InitTypeDef DMA_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输 DMA_DeInit(DMA_CHx); //将DMA的通道1寄存器重设为缺省值 DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA外设ADC基地址 DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA内存基地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //数据传输方向,从内存读取发送到外设 DMA_InitStructure.DMA_BufferSize = 0; //DMA通道的DMA缓存的大小 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据宽度为8位 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常缓存模式 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输 DMA_Init(DMA_CHx, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器 } //开启一次DMA传输 void UART_DMA_Enable(DMA_Channel_TypeDef*DMA_CHx,u8 len) { DMA_Cmd(DMA_CHx, DISABLE ); //关闭 指示的通道 DMA_SetCurrDataCounter(DMA_CHx,len);//DMA通道的DMA缓存的大小 DMA_Cmd(DMA_CHx, ENABLE); //开启DMA传输 } //usart4.h #ifndef __USART4_H #define __USART4_H #include "sys.h" ////////////////////////////////////////////////////////////////////////////////// //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //ALIENTEK STM32开发板 //串口2驱动代码 //正点原子@ALIENTEK //技术论坛:www.openedv.com //修改日期:2014/3/29 //版本:V1.0 //版权所有,盗版必究。 //Copyright(C) 广州市星翼电子科技有限公司 2009-2019 //All rights reserved ////////////////////////////////////////////////////////////////////////////////// #define USART4_MAX_RECV_LEN 200 //最大接收缓存字节数 #define USART4_MAX_SEND_LEN 200 //最大发送缓存字节数 #define USART4_RX_EN 1 //0,不接收;1,接收. extern u8 USART4_RX_BUF[USART4_MAX_RECV_LEN]; //接收缓冲,最大USART2_MAX_RECV_LEN字节 extern u8 USART4_TX_BUF[USART4_MAX_SEND_LEN]; //发送缓冲,最大USART2_MAX_SEND_LEN字节 extern u16 USART4_RX_STA; //接收数据状态 void USART4_Init(u32 bound); //串口2初始化 void TIM4_Set(u8 sta); void TIM4_Init(u16 arr,u16 psc); void UART_DMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar); void UART_DMA_Enable(DMA_Channel_TypeDef*DMA_CHx,u8 len); void u4_printf(char* fmt, ...); #endif //gps.h #ifndef __GPS_H #define __GPS_H #include "sys.h" ////////////////////////////////////////////////////////////////////////////////// //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //ALIENTEK STM32开发板 //ATK-NEO-6M GPS模块驱动代码 //正点原子@ALIENTEK //技术论坛:www.openedv.com //修改日期:2014/3/30 //版本:V2.0 //版权所有,盗版必究。 //Copyright(C) 广州市星翼电子科技有限公司 2009-2019 //All rights reserved //******************************************************************************** //V2.0 修改说明 20140330 //1,添加Ublox_Cfg_Cfg_Save函数 //2,添加Ublox_Cfg_Msg函数 //3,添加Ublox_Cfg_Prt函数. ////////////////////////////////////////////////////////////////////////////////// //GPS NMEA-0183协议重要参数结构体定义 //卫星信息 __packed typedef struct { u8 num; //卫星编号 u8 eledeg; //卫星仰角 u16 azideg; //卫星方位角 u8 sn; //信噪比 }nmea_slmsg; //UTC时间信息 __packed typedef struct { u16 year; //年份 u8 month; //月份 u8 date; //日期 u8 hour; //小时 u8 min; //分钟 u8 sec; //秒钟 }nmea_utc_time; //NMEA 0183 协议解析后数据存放结构体 __packed typedef struct { u8 svnum; //可见卫星数 nmea_slmsg slmsg[12]; //最多12颗卫星 nmea_utc_time utc; //UTC时间 u32 latitude; //纬度 分扩大100000倍,实际要除以100000 u8 nshemi; //北纬/南纬,N:北纬;S:南纬 u32 longitude; //经度 分扩大100000倍,实际要除以100000 u8 ewhemi; //东经/西经,E:东经;W:西经 u8 gpssta; //GPS状态:0,未定位;1,非差分定位;2,差分定位;6,正在估算. u8 posslnum; //用于定位的卫星数,0~12. u8 possl[12]; //用于定位的卫星编号 u8 fixmode; //定位类型:1,没有定位;2,2D定位;3,3D定位 u16 pdop; //位置精度因子 0~500,对应实际值0~50.0 u16 hdop; //水平精度因子 0~500,对应实际值0~50.0 u16 vdop; //垂直精度因子 0~500,对应实际值0~50.0 int altitude; //海拔高度,放大了10倍,实际除以10.单位:0.1m u16 speed; //地面速率,放大了1000倍,实际除以10.单位:0.001公里/小时 }nmea_msg; //////////////////////////////////////////////////////////////////////////////////////////////////// //UBLOX NEO-6M 配置(清除,保存,加载等)结构体 __packed typedef struct { u16 header; //cfg header,固定为0X62B5(小端模式) u16 id; //CFG CFG ID:0X0906 (小端模式) u16 dlength; //数据长度 12/13 u32 clearmask; //子区域清除掩码(1有效) u32 savemask; //子区域保存掩码 u32 loadmask; //子区域加载掩码 u8 devicemask; //目标器件选择掩码 b0:BK RAM;b1:FLASH;b2,EEPROM;b4,SPI FLASH u8 cka; //校验CK_A u8 ckb; //校验CK_B }_ublox_cfg_cfg; //UBLOX NEO-6M 消息设置结构体 __packed typedef struct { u16 header; //cfg header,固定为0X62B5(小端模式) u16 id; //CFG MSG ID:0X0106 (小端模式) u16 dlength; //数据长度 8 u8 msgclass; //消息类型(F0 代表NMEA消息格式) u8 msgid; //消息 ID //00,GPGGA;01,GPGLL;02,GPGSA; //03,GPGSV;04,GPRMC;05,GPVTG; //06,GPGRS;07,GPGST;08,GPZDA; //09,GPGBS;0A,GPDTM;0D,GPGNS; u8 iicset; //IIC消输出设置 0,关闭;1,使能. u8 uart1set; //UART1输出设置 0,关闭;1,使能. u8 uart2set; //UART2输出设置 0,关闭;1,使能. u8 u***set; //USB输出设置 0,关闭;1,使能. u8 spiset; //SPI输出设置 0,关闭;1,使能. u8 ncset; //未知输出设置 默认为1即可. u8 cka; //校验CK_A u8 ckb; //校验CK_B }_ublox_cfg_msg; //UBLOX NEO-6M UART端口设置结构体 __packed typedef struct { u16 header; //cfg header,固定为0X62B5(小端模式) u16 id; //CFG PRT ID:0X0006 (小端模式) u16 dlength; //数据长度 20 u8 portid; //端口号,0=IIC;1=UART1;2=UART2;3=USB;4=SPI; u8 reserved; //保留,设置为0 u16 txready; //TX Ready引脚设置,默认为0 u32 mode; //串口工作模式设置,奇偶校验,停止位,字节长度等的设置. u32 baudrate; //波特率设置 u16 inprotomask; //输入协议激活屏蔽位 默认设置为0X07 0X00即可. u16 outprotomask; //输出协议激活屏蔽位 默认设置为0X07 0X00即可. u16 reserved4; //保留,设置为0 u16 reserved5; //保留,设置为0 u8 cka; //校验CK_A u8 ckb; //校验CK_B }_ublox_cfg_prt; //UBLOX NEO-6M 时钟脉冲配置结构体 __packed typedef struct { u16 header; //cfg header,固定为0X62B5(小端模式) u16 id; //CFG TP ID:0X0706 (小端模式) u16 dlength; //数据长度 u32 interval; //时钟脉冲间隔,单位为us u32 length; //脉冲宽度,单位为us signed char status; //时钟脉冲配置:1,高电平有效;0,关闭;-1,低电平有效. u8 timeref; //参考时间:0,UTC时间;1,GPS时间;2,当地时间. u8 flags; //时间脉冲设置标志 u8 reserved; //保留 signed short antdelay; //天线延时 signed short rfdelay; //RF延时 signed int userdelay; //用户延时 u8 cka; //校验CK_A u8 ckb; //校验CK_B }_ublox_cfg_tp; //UBLOX NEO-6M 刷新速率配置结构体 __packed typedef struct { u16 header; //cfg header,固定为0X62B5(小端模式) u16 id; //CFG RATE ID:0X0806 (小端模式) u16 dlength; //数据长度 u16 measrate; //测量时间间隔,单位为ms,最少不能小于200ms(5Hz) u16 navrate; //导航速率(周期),固定为1 u16 timeref; //参考时间:0=UTC Time;1=GPS Time; u8 cka; //校验CK_A u8 ckb; //校验CK_B }_ublox_cfg_rate; extern nmea_msg gpsx; //GPS信息 int NMEA_Str2num(u8 *buf,u8*dx); void GPS_Analysis(nmea_msg *gpsx,u8 *buf); void NMEA_GPGSV_Analysis(nmea_msg *gpsx,u8 *buf); void NMEA_GPGGA_Analysis(nmea_msg *gpsx,u8 *buf); void NMEA_GPGSA_Analysis(nmea_msg *gpsx,u8 *buf); void NMEA_GPGSA_Analysis(nmea_msg *gpsx,u8 *buf); void NMEA_GPRMC_Analysis(nmea_msg *gpsx,u8 *buf); void NMEA_GPVTG_Analysis(nmea_msg *gpsx,u8 *buf); u8 Ublox_Cfg_Cfg_Save(void); u8 Ublox_Cfg_Msg(u8 msgid,u8 uart1set); u8 Ublox_Cfg_Prt(u32 baudrate); u8 Ublox_Cfg_Tp(u32 interval,u32 length,signed char status); u8 Ublox_Cfg_Rate(u16 measrate,u8 reftime); float get_longtitude(void); float get_latitude(void); void gps_config(void); #endif //gps.c #include "gps.h" #include "led.h" #include "delay.h" #include "usart4.h" #include "stdio.h" #include "stdarg.h" #include "string.h" #include "math.h" ////////////////////////////////////////////////////////////////////////////////// //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //ALIENTEK STM32开发板 //ATK-NEO-6M GPS模块驱动代码 //正点原子@ALIENTEK //技术论坛:www.openedv.com //修改日期:2014/3/30 //版本:V2.0 //版权所有,盗版必究。 //Copyright(C) 广州市星翼电子科技有限公司 2009-2019 //All rights reserved //******************************************************************************** //V2.0 修改说明 20140330 //1,添加Ublox_Cfg_Cfg_Save函数 //2,添加Ublox_Cfg_Msg函数 //3,添加Ublox_Cfg_Prt函数. ////////////////////////////////////////////////////////////////////////////////// nmea_msg gpsx; //GPS信息 __align(4) u8 dtbuf[50]; //打印缓存器 //从buf里面得到第cx个逗号所在的位置 //返回值:0~0XFE,代表逗号所在位置的偏移. // 0XFF,代表不存在第cx个逗号 u8 NMEA_Comma_Pos(u8 *buf,u8 cx) { u8 *p=buf; while(cx) { if(*buf=='*'||*buf<' '||*buf>'z')return 0XFF;//遇到'*'或者非法字符,则不存在第cx个逗号 if(*buf==',')cx--; buf++; } return buf-p; } //m^n函数 //返回值:m^n次方. u32 NMEA_Pow(u8 m,u8 n) { u32 result=1; while(n--)result*=m; return result; } //str转换为数字,以','或者'*'结束 //buf:数字存储区 //dx:小数点位数,返回给调用函数 //返回值:转换后的数值 int NMEA_Str2num(u8 *buf,u8*dx) { u8 *p=buf; u32 ires=0,fres=0; u8 ilen=0,flen=0,i; u8 mask=0; int res; while(1) //得到整数和小数的长度 { if(*p=='-'){mask|=0X02;p++;}//是负数 if(*p==','||(*p=='*'))break;//遇到结束了 if(*p=='.'){mask|=0X01;p++;}//遇到小数点了 else if(*p>'9'||(*p<'0')) //有非法字符 { ilen=0; flen=0; break; } if(mask&0X01)flen++; else ilen++; p++; } if(mask&0X02)buf++; //去掉负号 for(i=0;i ires+=NMEA_Pow(10,ilen-1-i)*(buf-'0'); } if(flen>5)flen=5; //最多取5位小数 *dx=flen; //小数点位数 for(i=0;i fres+=NMEA_Pow(10,flen-1-i)*(buf[ilen+1+i]-'0'); } res=ires*NMEA_Pow(10,flen)+fres; if(mask&0X02)res=-res; return res; } //分析GPGSV信息 //gpsx:nmea信息结构体 //buf:接收到的GPS数据缓冲区首地址 void NMEA_GPGSV_Analysis(nmea_msg *gpsx,u8 *buf) { u8 *p,*p1,dx; u8 len,i,j,slx=0; u8 posx; p=buf; p1=(u8*)strstr((const char *)p,"$GPGSV"); len=p1[7]-'0'; //得到GPGSV的条数 posx=NMEA_Comma_Pos(p1,3); //得到可见卫星总数 if(posx!=0XFF)gpsx->svnum=NMEA_Str2num(p1+posx,&dx); for(i=0;i p1=(u8*)strstr((const char *)p,"$GPGSV"); for(j=0;j<4;j++) { posx=NMEA_Comma_Pos(p1,4+j*4); if(posx!=0XFF)gpsx->slmsg[slx].num=NMEA_Str2num(p1+posx,&dx); //得到卫星编号 else break; posx=NMEA_Comma_Pos(p1,5+j*4); if(posx!=0XFF)gpsx->slmsg[slx].eledeg=NMEA_Str2num(p1+posx,&dx);//得到卫星仰角 else break; posx=NMEA_Comma_Pos(p1,6+j*4); if(posx!=0XFF)gpsx->slmsg[slx].azideg=NMEA_Str2num(p1+posx,&dx);//得到卫星方位角 else break; posx=NMEA_Comma_Pos(p1,7+j*4); if(posx!=0XFF)gpsx->slmsg[slx].sn=NMEA_Str2num(p1+posx,&dx); //得到卫星信噪比 else break; slx++; } p=p1+1;//切换到下一个GPGSV信息 } } //分析GPGGA信息 //gpsx:nmea信息结构体 //buf:接收到的GPS数据缓冲区首地址 void NMEA_GPGGA_Analysis(nmea_msg *gpsx,u8 *buf) { u8 *p1,dx; u8 posx; p1=(u8*)strstr((const char *)buf,"$GPGGA"); posx=NMEA_Comma_Pos(p1,6); //得到GPS状态 if(posx!=0XFF)gpsx->gpssta=NMEA_Str2num(p1+posx,&dx); posx=NMEA_Comma_Pos(p1,7); //得到用于定位的卫星数 if(posx!=0XFF)gpsx->posslnum=NMEA_Str2num(p1+posx,&dx); posx=NMEA_Comma_Pos(p1,9); //得到海拔高度 if(posx!=0XFF)gpsx->altitude=NMEA_Str2num(p1+posx,&dx); } //分析GPGSA信息 //gpsx:nmea信息结构体 //buf:接收到的GPS数据缓冲区首地址 void NMEA_GPGSA_Analysis(nmea_msg *gpsx,u8 *buf) { u8 *p1,dx; u8 posx; u8 i; p1=(u8*)strstr((const char *)buf,"$GPGSA"); posx=NMEA_Comma_Pos(p1,2); //得到定位类型 if(posx!=0XFF)gpsx->fixmode=NMEA_Str2num(p1+posx,&dx); for(i=0;i<12;i++) //得到定位卫星编号 { posx=NMEA_Comma_Pos(p1,3+i); if(posx!=0XFF)gpsx->possl=NMEA_Str2num(p1+posx,&dx); else break; } posx=NMEA_Comma_Pos(p1,15); //得到PDOP位置精度因子 if(posx!=0XFF)gpsx->pdop=NMEA_Str2num(p1+posx,&dx); posx=NMEA_Comma_Pos(p1,16); //得到HDOP位置精度因子 if(posx!=0XFF)gpsx->hdop=NMEA_Str2num(p1+posx,&dx); posx=NMEA_Comma_Pos(p1,17); //得到VDOP位置精度因子 if(posx!=0XFF)gpsx->vdop=NMEA_Str2num(p1+posx,&dx); } //分析GPRMC信息 //gpsx:nmea信息结构体 //buf:接收到的GPS数据缓冲区首地址 void NMEA_GPRMC_Analysis(nmea_msg *gpsx,u8 *buf) { u8 *p1,dx; u8 posx; u32 temp; float rs; p1=(u8*)strstr((const char *)buf,"GPRMC");//"$GPRMC",经常有&和GPRMC分开的情况,故只判断GPRMC. posx=NMEA_Comma_Pos(p1,1); //得到UTC时间 if(posx!=0XFF) { temp=NMEA_Str2num(p1+posx,&dx)/NMEA_Pow(10,dx); //得到UTC时间,去掉ms gpsx->utc.hour=temp/10000; gpsx->utc.min=(temp/100)%100; gpsx->utc.sec=temp%100; } posx=NMEA_Comma_Pos(p1,3); //得到纬度 if(posx!=0XFF) { temp=NMEA_Str2num(p1+posx,&dx); gpsx->latitude=temp/NMEA_Pow(10,dx+2); //得到° rs=temp%NMEA_Pow(10,dx+2); //得到' gpsx->latitude=gpsx->latitude*NMEA_Pow(10,5)+(rs*NMEA_Pow(10,5-dx))/60;//转换为° } posx=NMEA_Comma_Pos(p1,4); //南纬还是北纬 if(posx!=0XFF)gpsx->nshemi=*(p1+posx); posx=NMEA_Comma_Pos(p1,5); //得到经度 if(posx!=0XFF) { temp=NMEA_Str2num(p1+posx,&dx); gpsx->longitude=temp/NMEA_Pow(10,dx+2); //得到° rs=temp%NMEA_Pow(10,dx+2); //得到' gpsx->longitude=gpsx->longitude*NMEA_Pow(10,5)+(rs*NMEA_Pow(10,5-dx))/60;//转换为° } posx=NMEA_Comma_Pos(p1,6); //东经还是西经 if(posx!=0XFF)gpsx->ewhemi=*(p1+posx); posx=NMEA_Comma_Pos(p1,9); //得到UTC日期 if(posx!=0XFF) { temp=NMEA_Str2num(p1+posx,&dx); //得到UTC日期 gpsx->utc.date=temp/10000; gpsx->utc.month=(temp/100)%100; gpsx->utc.year=2000+temp%100; } } //分析GPVTG信息 //gpsx:nmea信息结构体 //buf:接收到的GPS数据缓冲区首地址 void NMEA_GPVTG_Analysis(nmea_msg *gpsx,u8 *buf) { u8 *p1,dx; u8 posx; p1=(u8*)strstr((const char *)buf,"$GPVTG"); posx=NMEA_Comma_Pos(p1,7); //得到地面速率 if(posx!=0XFF) { gpsx->speed=NMEA_Str2num(p1+posx,&dx); if(dx<3)gpsx->speed*=NMEA_Pow(10,3-dx); //确保扩大1000倍 } } //提取NMEA-0183信息 //gpsx:nmea信息结构体 //buf:接收到的GPS数据缓冲区首地址 void GPS_Analysis(nmea_msg *gpsx,u8 *buf) { NMEA_GPGSV_Analysis(gpsx,buf); //GPGSV解析 NMEA_GPGGA_Analysis(gpsx,buf); //GPGGA解析 NMEA_GPGSA_Analysis(gpsx,buf); //GPGSA解析 NMEA_GPRMC_Analysis(gpsx,buf); //GPRMC解析 NMEA_GPVTG_Analysis(gpsx,buf); //GPVTG解析 } //GPS校验和计算 //buf:数据缓存区首地址 //len:数据长度 //cka,ckb:两个校验结果. void Ublox_CheckSum(u8 *buf,u16 len,u8* cka,u8*ckb) { u16 i; *cka=0;*ckb=0; for(i=0;i *cka=*cka+buf; *ckb=*ckb+*cka; } } /////////////////////////////////////////UBLOX 配置代码///////////////////////////////////// //检查CFG配置执行情况 //返回值:0,ACK成功 // 1,接收超时错误 // 2,没有找到同步字符 // 3,接收到NACK应答 u8 Ublox_Cfg_Ack_Check(void) { u16 len=0,i; u8 rval=0; while((USART4_RX_STA&0X8000)==0 && len<100)//等待接收到应答 { len++; delay_ms(5); } if(len<250) //超时错误. { len=USART4_RX_STA&0X7FFF; //此次接收到的数据长度 for(i=0;i if(i==len)rval=2; //没有找到同步字符 else if(USART4_RX_BUF[i+3]==0X00)rval=3;//接收到NACK应答 else rval=0; //接收到ACK应答 }else rval=1; //接收超时错误 USART4_RX_STA=0; //清除接收 return rval; } //配置保存 //将当前配置保存在外部EEPROM里面 //返回值:0,执行成功;1,执行失败. u8 Ublox_Cfg_Cfg_Save(void) { u8 i; _ublox_cfg_cfg *cfg_cfg=(_ublox_cfg_cfg *)USART4_TX_BUF; cfg_cfg->header=0X62B5; //cfg header cfg_cfg->id=0X0906; //cfg cfg id cfg_cfg->dlength=13; //数据区长度为13个字节. cfg_cfg->clearmask=0; //清除掩码为0 cfg_cfg->savemask=0XFFFF; //保存掩码为0XFFFF cfg_cfg->loadmask=0; //加载掩码为0 cfg_cfg->devicemask=4; //保存在EEPROM里面 Ublox_CheckSum((u8*)(&cfg_cfg->id),sizeof(_ublox_cfg_cfg)-4,&cfg_cfg->cka,&cfg_cfg->ckb); while(DMA2_Channel3->CNDTR!=0); //等待通道7传输完成 UART_DMA_Enable(DMA2_Channel3,sizeof(_ublox_cfg_cfg)); //通过dma发送出去 for(i=0;i<6;i++)if(Ublox_Cfg_Ack_Check()==0)break; //EEPROM写入需要比较久时间,所以连续判断多次 return i==6?1:0; } //配置NMEA输出信息格式 //msgid:要操作的NMEA消息条目,具体见下面的参数表 // 00,GPGGA;01,GPGLL;02,GPGSA; // 03,GPGSV;04,GPRMC;05,GPVTG; // 06,GPGRS;07,GPGST;08,GPZDA; // 09,GPGBS;0A,GPDTM;0D,GPGNS; //uart1set:0,输出关闭;1,输出开启. //返回值:0,执行成功;其他,执行失败. u8 Ublox_Cfg_Msg(u8 msgid,u8 uart1set) { _ublox_cfg_msg *cfg_msg=(_ublox_cfg_msg *)USART4_TX_BUF; cfg_msg->header=0X62B5; //cfg header cfg_msg->id=0X0106; //cfg msg id cfg_msg->dlength=8; //数据区长度为8个字节. cfg_msg->msgclass=0XF0; //NMEA消息 cfg_msg->msgid=msgid; //要操作的NMEA消息条目 cfg_msg->iicset=1; //默认开启 cfg_msg->uart1set=uart1set; //开关设置 cfg_msg->uart2set=1; //默认开启 cfg_msg->u***set=1; //默认开启 cfg_msg->spiset=1; //默认开启 cfg_msg->ncset=1; //默认开启 Ublox_CheckSum((u8*)(&cfg_msg->id),sizeof(_ublox_cfg_msg)-4,&cfg_msg->cka,&cfg_msg->ckb); while(DMA2_Channel3->CNDTR!=0); //等待通道7传输完成 UART_DMA_Enable(DMA2_Channel3,sizeof(_ublox_cfg_msg)); //通过dma发送出去 return Ublox_Cfg_Ack_Check(); } //配置NMEA输出信息格式 //baudrate:波特率,4800/9600/19200/38400/57600/115200/230400 //返回值:0,执行成功;其他,执行失败(这里不会返回0了) u8 Ublox_Cfg_Prt(u32 baudrate) { _ublox_cfg_prt *cfg_prt=(_ublox_cfg_prt *)USART4_TX_BUF; cfg_prt->header=0X62B5; //cfg header cfg_prt->id=0X0006; //cfg prt id cfg_prt->dlength=20; //数据区长度为20个字节. cfg_prt->portid=1; //操作串口1 cfg_prt->reserved=0; //保留字节,设置为0 cfg_prt->txready=0; //TX Ready设置为0 cfg_prt->mode=0X08D0; //8位,1个停止位,无校验位 cfg_prt->baudrate=baudrate; //波特率设置 cfg_prt->inprotomask=0X0007;//0+1+2 cfg_prt->outprotomask=0X0007;//0+1+2 cfg_prt->reserved4=0; //保留字节,设置为0 cfg_prt->reserved5=0; //保留字节,设置为0 Ublox_CheckSum((u8*)(&cfg_prt->id),sizeof(_ublox_cfg_prt)-4,&cfg_prt->cka,&cfg_prt->ckb); while(DMA2_Channel3->CNDTR!=0); //等待通道7传输完成 UART_DMA_Enable(DMA2_Channel3,sizeof(_ublox_cfg_prt)); //通过dma发送出去 delay_ms(200); //等待发送完成 USART4_Init( baudrate); //重新初始化串口2 return Ublox_Cfg_Ack_Check();//这里不会反回0,因为UBLOX发回来的应答在串口重新初始化的时候已经被丢弃了. } //配置UBLOX NEO-6的时钟脉冲输出 //interval:脉冲间隔(us) //length:脉冲宽度(us) //status:脉冲配置:1,高电平有效;0,关闭;-1,低电平有效. //返回值:0,发送成功;其他,发送失败. u8 Ublox_Cfg_Tp(u32 interval,u32 length,signed char status) { _ublox_cfg_tp *cfg_tp=(_ublox_cfg_tp *)USART4_TX_BUF; cfg_tp->header=0X62B5; //cfg header cfg_tp->id=0X0706; //cfg tp id cfg_tp->dlength=20; //数据区长度为20个字节. cfg_tp->interval=interval; //脉冲间隔,us cfg_tp->length=length; //脉冲宽度,us cfg_tp->status=status; //时钟脉冲配置 cfg_tp->timeref=0; //参考UTC 时间 cfg_tp->flags=0; //flags为0 cfg_tp->reserved=0; //保留位为0 cfg_tp->antdelay=820; //天线延时为820ns cfg_tp->rfdelay=0; //RF延时为0ns cfg_tp->userdelay=0; //用户延时为0ns Ublox_CheckSum((u8*)(&cfg_tp->id),sizeof(_ublox_cfg_tp)-4,&cfg_tp->cka,&cfg_tp->ckb); while(DMA2_Channel3->CNDTR!=0); //等待通道7传输完成 UART_DMA_Enable(DMA2_Channel3,sizeof(_ublox_cfg_tp)); //通过dma发送出去 return Ublox_Cfg_Ack_Check(); } //配置UBLOX NEO-6的更新速率 //measrate:测量时间间隔,单位为ms,最少不能小于200ms(5Hz) //reftime:参考时间,0=UTC Time;1=GPS Time(一般设置为1) //返回值:0,发送成功;其他,发送失败. u8 Ublox_Cfg_Rate(u16 measrate,u8 reftime) { _ublox_cfg_rate *cfg_rate=(_ublox_cfg_rate *)USART4_TX_BUF; if(measrate<200)return 1; //小于200ms,直接退出 cfg_rate->header=0X62B5; //cfg header cfg_rate->id=0X0806; //cfg rate id cfg_rate->dlength=6; //数据区长度为6个字节. cfg_rate->measrate=measrate;//脉冲间隔,us cfg_rate->navrate=1; //导航速率(周期),固定为1 cfg_rate->timeref=reftime; //参考时间为GPS时间 Ublox_CheckSum((u8*)(&cfg_rate->id),sizeof(_ublox_cfg_rate)-4,&cfg_rate->cka,&cfg_rate->ckb); while(DMA2_Channel3->CNDTR!=0); //等待通道7传输完成 UART_DMA_Enable(DMA2_Channel3,sizeof(_ublox_cfg_rate));//通过dma发送出去 return Ublox_Cfg_Ack_Check(); } void gps_config() { u8 key=0XFF; if(Ublox_Cfg_Rate(1000,1)!=0) //设置定位信息更新速度为1000ms,顺便判断GPS模块是否在位. { printf("正在配置......n"); while((Ublox_Cfg_Rate(1000,1)!=0)&&key) //持续判断,直到可以检查到NEO-6M,且数据保存成功 { USART4_Init(9600); //初始化串口2波特率为9600(EEPROM没有保存数据的时候,波特率为9600.) Ublox_Cfg_Prt(38400); //重新设置模块的波特率为38400 USART4_Init(38400); //初始化串口2波特率为38400 Ublox_Cfg_Tp(1000000,100000,1); //设置PPS为1秒钟输出1次,脉冲宽度为100ms key=Ublox_Cfg_Cfg_Save(); //保存配置 } printf("配置成功!!!n"); } } float get_longtitude() // { float tp; tp=gpsx.longitude; sprintf((char *)dtbuf,"Longitude:%.5f %1c ",tp/=100000,gpsx.ewhemi); //得到经度字符串 return tp; } float get_latitude() // { float tp; tp=gpsx.latitude; sprintf((char *)dtbuf,"Latitude:%.5f %1c ",tp/=100000,gpsx.nshemi); //得到经度字符串 return tp; } //main.c #include "led.h" #include "delay.h" #include "sys.h" #include "usart.h" #include "usart4.h" #include "gps.h" #include "string.h" #include "key.h" #include "adc.h" //ALIENTEK Mini STM32开发板扩展实验12 //ATK-NEO-6M GPS模块实验-库函数版本 //技术支持:www.openedv.com //广州市星翼电子科技有限公司 u8 USART1_TX_BUF[USART4_MAX_RECV_LEN]; //串口1,发送缓存区 const u8*fixmode_tbl[4]={"Fail","Fail"," 2D "," 3D "}; //fix mode字符串 //显示GPS定位信息 /*void Gps_Msg_Show(void) { float tp; POINT_COLOR=BLUE; tp=gpsx.longitude; sprintf((char *)dtbuf,"Longitude:%.5f %1c ",tp/=100000,gpsx.ewhemi); //得到经度字符串 printf("Longitude:%.5f %1c ",tp,gpsx.ewhemi); tp=gpsx.latitude; sprintf((char *)dtbuf,"Latitude:%.5f %1c ",tp/=100000,gpsx.nshemi); //得到纬度字符串 printf("Latitude:%.5f %1c ",tp,gpsx.nshemi); tp=gpsx.altitude; sprintf((char *)dtbuf,"Altitude:%.1fm ",tp/=10); //得到高度字符串 tp=gpsx.speed; sprintf((char *)dtbuf,"Speed:%.3fkm/h ",tp/=1000); //得到速度字符串 if(gpsx.fixmode<=3) //定位状态 { sprintf((char *)dtbuf,"Fix Mode:%s",fixmode_tbl[gpsx.fixmode]); } sprintf((char *)dtbuf,"Valid satellite:%02d",gpsx.posslnum); //用于定位的卫星数 sprintf((char *)dtbuf,"Visible satellite:%02d",gpsx.svnum%100); //可见卫星数 sprintf((char *)dtbuf,"UTC Date:%04d/%02d/%02d ",gpsx.utc.year,gpsx.utc.month,gpsx.utc.date); //显示UTC日期 printf("UTC Date:%04d/%02d/%02d n",gpsx.utc.year,gpsx.utc.month,gpsx.utc.date); sprintf((char *)dtbuf,"UTC Time:%02d:%02d:%02d ",gpsx.utc.hour,gpsx.utc.min,gpsx.utc.sec); //显示UTC时间 printf("UTC Time:%02d:%02d:%02d n",gpsx.utc.hour,gpsx.utc.min,gpsx.utc.sec); printf("BeiJing Time:%02d:%02d:%02d n",gpsx.utc.hour+8,gpsx.utc.min,gpsx.utc.sec); } */ int main(void) { u16 i,rxlen; float temperature,longtitude,latitude; u8 upload=0; delay_init(); //延时函数初始化 uart_init(38400); //串口初始化为9600 USART4_Init(38400); //初始化串口3 LED_Init(); //初始化与LED连接的硬件接口 KEY_Init(); //初始化与LED连接的硬件接口 Adc_Init(); //ADC初始化 //gps_config(); //配置gps delay_ms(500); while(1) { delay_ms(1); if(USART4_RX_STA&0X8000) //接收到一次数据了 { rxlen=USART4_RX_STA&0X7FFF; //得到数据长度 for(i=0;i USART4_RX_STA=0; //启动下一次接收 USART1_TX_BUF=0; //自动添加结束符 GPS_Analysis(&gpsx,(u8*)USART1_TX_BUF);//分析字符串 if(upload)printf("rn%srn",USART1_TX_BUF);//发送接收到的数据到串口1 } longtitude = get_longtitude(); //经度 printf("Longitude:%.5f %1c ",longtitude,gpsx.ewhemi); latitude = get_latitude(); //纬度 printf("Latitude:%.5f %1c ",latitude,gpsx.nshemi); printf("UTC Time:%02d:%02d:%02d n",gpsx.utc.hour+8,gpsx.utc.min,gpsx.utc.sec); delay_ms(1000); } } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1777 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1621 浏览 1 评论
1080 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
728 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1678 浏览 2 评论
1938浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
731浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
570浏览 3评论
595浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
554浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 03:47 , Processed in 1.162666 second(s), Total 46, Slave 40 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号