上一篇说了使用合宙官方调试软件接受模块发来的数据,现在尝试使用STM32获取定位数据并且把数据通过串口发送到电脑。
stm32与模块通讯使用的是串口,所设整个设计思路为,stm32通过串口接收模块发来的数据,然后再筛选出定位坐标,再将坐标通过串口发送到电脑。
stm32与模块通讯采用stm32的串口2,与电脑通讯采用串口1.
-
- void uart1_init(u32 bound){
- //GPIO端口设置
- GPIO_InitTypeDef GPIO_InitStructure;
- USART_InitTypeDef USART_InitStructure;
- NVIC_InitTypeDef NVIC_InitStructure;
-
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
-
- //USART1_TX GPIOA.9
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
- GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
-
- //USART1_RX GPIOA.10初始化
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOAtiNG;//浮空输入
- GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
- //Usart1 NVIC 配置
- NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
- NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
-
- //USART 初始化设置
- USART_InitStructure.USART_BaudRate = bound;//串口波特率
- 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(USART1, &USART_InitStructure); //初始化串口1
- USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
- USART_Cmd(USART1, ENABLE); //使能串口1
- }
- void uart2_init(uint32_t bound)
- {
- //GPIO端口设置
- GPIO_InitTypeDef GPIO_InitStructure;
- USART_InitTypeDef USART_InitStructure;
- NVIC_InitTypeDef NVIC_InitStructure;
-
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2|RCC_APB2Periph_GPIOA, ENABLE); //使能USART2,GPIOA时钟
-
- //USART2_TX GPIOA.2
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA2
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
- GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
-
- //USART2_RX GPIOA3初始化
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
- GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
- //Usart2 NVIC 配置
- NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //子优先级3
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
- NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
-
- //USART 初始化设置
- USART_InitStructure.USART_BaudRate = bound;//串口波特率
- 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(USART2, &USART_InitStructure); //初始化串口2
- USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断
- USART_Cmd(USART2, ENABLE);
- }
复制代码
2个串口初始化完成,模块连接的是串口2,引脚为USART2_RX GPIOA3,USART2_TX GPIOA.2
,接下来就是再串口2的接收中断筛选数据。这里我们就要知道NMEA协议,协议格式可以通过合宙官网资料去了解GK9701输入输出格式文档。
这里我们重点关注$--RMC之后的内容,
从样例数据以及解释中我们可以发现 ,N ,E,前面的数据就是我们需要的定位坐标。
现在我们就是要在串口2中的接受中断中找到$GNRMC语句,然后根据逗号 ','去定位到N,E前的数据,因为数据中每一个数据名都是以逗号隔开的,所以在第3个逗号后就是纬度数据,在第5个逗号后就是经度数据。有了这些信息我们呢就可以写代码了
- void USART2_IRQHandler(void)
- {
- uint8_t res;
- static uint8_t k = 0; ///判断逗号的个数
- static uint8_t flag = 0; ///数据有效性
- if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
- {
- res =(uint8_t) USART2->DR;
- USART1->DR = res;
- // 将收到的数据发送到串口1,可注释
- if(USART_RX_BUF[0] == '
- 然后下载程序到开发板,这里我使用的是正点原子的开发板,然后连接定位模块。
- 打开串口调试助手,注意模块上电后要等一会儿才有有有效数据,另外模块放置与户外。
-
- 通过串口我们收到了模块的 原始数据,同时还有解析后的数据。这样我们一个单片机获取定位数据的一个简单的列子就完成了,我们还可以再细化获取更多我们想要的数据,具体体参考合宙官网提供的资料,找到我们需要的数据在那个数据帧里,然后再去通过逗号定位得到我们想要的数据。
- 参考资料:[url=https://blog.csdn.net/m0_65088451/article/details/123549470]基于stm32的GPS解析数据[/url]
- || res == '
- 然后下载程序到开发板,这里我使用的是正点原子的开发板,然后连接定位模块。
- 打开串口调试助手,注意模块上电后要等一会儿才有有有效数据,另外模块放置与户外。
- 通过串口我们收到了模块的 原始数据,同时还有解析后的数据。这样我们一个单片机获取定位数据的一个简单的列子就完成了,我们还可以再细化获取更多我们想要的数据,具体体参考合宙官网提供的资料,找到我们需要的数据在那个数据帧里,然后再去通过逗号定位得到我们想要的数据。
- 参考资料:[url=https://blog.csdn.net/m0_65088451/article/details/123549470]基于stm32的GPS解析数据[/url]
- )
- {
- if(res == '
- 然后下载程序到开发板,这里我使用的是正点原子的开发板,然后连接定位模块。
- 打开串口调试助手,注意模块上电后要等一会儿才有有有效数据,另外模块放置与户外。
- 通过串口我们收到了模块的 原始数据,同时还有解析后的数据。这样我们一个单片机获取定位数据的一个简单的列子就完成了,我们还可以再细化获取更多我们想要的数据,具体体参考合宙官网提供的资料,找到我们需要的数据在那个数据帧里,然后再去通过逗号定位得到我们想要的数据。
- 参考资料:[url=https://blog.csdn.net/m0_65088451/article/details/123549470]基于stm32的GPS解析数据[/url]
- )
- USART_RX_STA = 0;
- USART_RX_BUF[USART_RX_STA++] = res;
- }
- // 判断是不是$GNRMC,是则通过逗号去定位接受到那个名字的数据了
- if(USART_RX_BUF[4] == 'M' && USART_RX_BUF[5] == 'C')
- {
- if(res==',')
- k++;
- switch(k)
- {
- case 2:
- if(res=='A'&&res!=',')
- flag=1;
- else
- flag=0;
- break;
- case 3: //定位到第三个逗号,说明后面再接受到的是定位信息
- if(flag==1&&res!=','&&res!='.')
- { longitude*=10; // 数据类型 uint32_t,
- longitude+=res-48; // 48为字符'0',
- }
- break;
- case 5:
- //定位到第5个逗号,说明后面再接受到的是定位信息
- if(flag==1&&res!=','&&res!='.')
- { latitude*=10;
- latitude+=res-48;
- }
- break;
- }
- if(res==0x0A)
- {
- //
- $GNRMC数据接收完毕,清空接收数组和
- memset(USART_RX_BUF,0x00,USART_REC_LEN);
- USART_RX_STA=0;
- k=0;
- flag = 0;
- //打印定位信息到电脑,
- printf("longitude: %frn",(float)longitude/10000000);
- printf("latitude: %frn",(float)latitude/10000000);
- longitude=0;
- latitude=0;
-
- }
- }
-
- }
- }
复制代码
然后下载程序到开发板,这里我使用的是正点原子的开发板,然后连接定位模块。
打开串口调试助手,注意模块上电后要等一会儿才有有有效数据,另外模块放置与户外。
通过串口我们收到了模块的 原始数据,同时还有解析后的数据。这样我们一个单片机获取定位数据的一个简单的列子就完成了,我们还可以再细化获取更多我们想要的数据,具体体参考合宙官网提供的资料,找到我们需要的数据在那个数据帧里,然后再去通过逗号定位得到我们想要的数据。
参考资料:基于stm32的GPS解析数据
|