完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
一、硬软件平台 本次程序实现效果为对GPS信号穿送来的数据进行筛选,并将筛选后的信息通过上位机显示出来,所以此次设计所需硬件包括STM32F407、RS232转TTL、CH340USB转串口模块,注意该模块在使用前,对应的系统需要安装驱动,否则串口调试助手无法识别,另外还包括JLink下载器。 本次代码设计软件为KEIL5并结合F4固件包,上位机系统为WIN7,主机系统为WIN10。 二、算法总体思路设计 由于GPS通过RS232将数据传送给板子,因此使用两个串口资源(串口1和串口2),其中一个用来接收数据,另外一个用来将筛选后的数据发送给上位机。GPS在发送信号时,相邻两次数据的发送之间有明显的时间间隔,所以该间隔可作为判断当前接收的数据是否是一个完整数据的依据。为了保证接收数据的及时性,接收数据时采用串口接收中断,发送数据则作为主程序。因此可得到以下主程序流程图。 三、具体实现步骤 3.1 串口1初始化 本次程序设计通过串口1将筛选后的数据发送给上位机,对应的硬件资源为PA9(USART1-TX)、PA10(USART1-RX)。通过将这两个IO口连接CH340,实现数据传送。串口1波特率设置为38400。 3.2 串口2初始化 串口2用来接收GPS信号,对应硬件资源为PA2(UASRT2-TX)、PA3(USART2-RX),GPS设备接口为RS232,接入单片机时,需要转为TTL电平,注意,在连接板子和RS232转TTL模块的TTL输出端时,RX和TX用反接,否则会接收不到数据。由于GPS信号发送波特率为固定的38400,所以初始化时串口2的波特率也要设置为38400。 串口2使用中断来接收数据,因为初始化时也要配置中断。具体代码如下: void uart2_init(u32 bound){ //GPIO端口设置 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//使能USART1时钟 //串口1对应引脚复用映射 GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_USART2); //GPIOA2复用为USART2 GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_USART2); //GPIOA3复用为USART2 //USART1端口配置 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3; //GPIOA9与GPIOA10 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉 GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9,PA10 //USART1 初始化设置 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_Cmd(USART2, ENABLE); //使能串口2 USART_ClearFlag(USART2, USART_FLAG_TC); USART_ITConfig(USART2, USART_IT_RXNE,ENABLE);//开启相关中断 //Usart2 NVIC 配置 NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;//串口2中断通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级1 NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器 TIM7_Int_Init(99,7199); USART2_RX_STA=0; TIM_Cmd(TIM7,DISABLE); //关闭定时器7 } 3.3 串口2接收中断函数 该中断函数是整个程序的重点所在,主要目的是将接收的字符存入数组内,这里数组名及大小定义为USART2_RX_BUF[NMEA_COUNT_MAX];其中将NMEA_COUNT_MAX设置为600,代表数组最大容量。当有数据发过来时,存入数组,并对该数组进行处理,若没有处理完毕,则不再接收其他数据,这里定义数据接收状态变量vu16 USART2_RX_STA。另外借助10ms定时器(TIM7)中断判断是不是一次连续的数据,如果接收连续2个字符之间的时间差不大于10ms则认为是,如果大于10ms则中断触发,强制标记数据接收完成。 void USART2_IRQHandler(void) //串口2中断服务程序 { GPIO_ResetBits(GPIOA,GPIO_Pin_6); //LED0灯亮 char Buffer; if(SET==USART_GetITStatus(USART2,USART_IT_RXNE)) { USART_ClearFlag(USART2, USART_FLAG_RXNE); Buffer = USART_ReceiveData(USART2);//接收数据 if((USART2_RX_STA&(1<<15))==0)//接收完的一批数据,还没有被处理,则不再接收其他数据 { if(USART2_RX_STA { TIM_SetCounter(TIM7,0);//计数器清空 if(USART2_RX_STA==0) { TIM_Cmd(TIM7,ENABLE);//使能定时器7 } USART2_RX_BUF[USART2_RX_STA++]=Buffer;//记录接收到的值 } else { USART2_RX_STA|=1<<15;//强制标记接收完成 } } } GPIO_SetBits(GPIOA,GPIO_Pin_6);//LED0灯灭 } /*定时器7中断服务函数*/ void TIM7_IRQHandler(void) { if (TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET)//是更新中断 { USART2_RX_STA|=1<<15; //标记接收完成 TIM_ClearITPendingBit(TIM7, TIM_IT_Update ); //清除TIM7更新中断标志 TIM_Cmd(TIM7, DISABLE); //关闭TIM7 } } 3.4数据解析 每次接收的数据都存放在数组里面,每个信息都有属于自己的标识符,例如$GNRMC、!AIVDM等,所以要找到目标信息的位置,直接对数组进行字符串搜索即可。搜索算法如下图所示,返回字符串首字符在数组中的位置。 /*查找字符串*/ u16 FindStr(char *str,char *ptr) { u16 index=0; char *STemp=NULL; char *PTemp=NULL; char *MTemp=NULL; if(0==str||0==ptr) return 0; for(STemp=str;*STemp!=' |