本文采用DMA+环形缓冲区对GPS报文进行解析,思路是通过DMA中断接收到GPS报文后,存放到环形缓冲区,然后在主程序中解析GPS报文。解析GPS报文的关键是:将环形缓冲区中的字节转换成字符串,然后在字符串中查找GPS报文头标识(例如:GPGGA)和GPS报文尾部标识(回车换行)。
一、为什么要用DMA接收GPS报文
我们知道,可以用串口接收GPS报文,但是串口有一个缺点,每接收一个字节就会触发接收中断,或者发送一个字节就会触发空中断或者完成中断,造成单片机的CPU频繁产生中断。
DMA有什么好处呢?你需要发送数据时,先把所有要发送的数据填充到发送缓冲区,然后告诉DMA,DMA就会将数据发送出去,发送完毕,触发一次中断告诉你发送完成。你需要接收数据时,DMA设备会将串行数据先存放到DMA内部缓冲区中,当接收完毕,会通知你接收完成,并通知你接收了多少个字节,这个时候,你只需要从DMA设备的接收缓冲区中取出接收的数据即可。
从以上我们可以看到,用DMA接收数据时,接收完毕,DMA产生一次中断;用DMA发送数据时,发送完毕,DMA也只产生一次中断;这样就能大幅度的降低系统响应中断的次数。
STM32F407 DMA通道关系参见如下链接:
https://blog.csdn.net/ba_wang_mao/article/details/104043284
STM32单片机串口空闲中断接收不定长数据
https://blog.csdn.net/qq_20222919/article/details/109090429
STM32单片机串口空闲中断+DMA接收不定长数据,参见如下链接:
STM32F103单片机modbus通信示例
https://blog.csdn.net/qq_20222919/article/details/109110998
二、DMA程序
STM32F407共计6个串口,每个串口都可以配置为DMA方式接收和发送数据。其中:
UARTX_DMA_Tx_Configuration(void) ---> 配置串口DMA接收初始化
UARTX_DMA_Rx_Configuration(void) ---> 配置串口DMA发送初始化
UARTX_DMA_Begin_Send(uint8_t *send_buffer , uint16_t nSendCount) ---> 启动DMA发送
//DMA是高速传输模式,一般是ns级的速度,485是慢速传输,一般是ms级最多是us级的传输
//usart1
// tx 2---7 channel4
// rx 2---5 channel4
//usart2
// tx 1---6 channel4
// rx 1---5 channel4
//usart3
// tx 1---3 channel4
// rx 1---1 channel4
//uart4
// tx 1---4 channel4
// rx 1---2 channel4
//uart5
// tx 1---7 channel4
// rx 1---0 channel4
//usart6
// tx 2---6 channel5
// rx 2---1 channel5
uint8_t USART1_DMA_RX_Buffer[USART1_DMA_RX_BUFFER_MAX_LENGTH];
uint8_t USART1_DMA_TX_Buffer[USART1_DMA_TX_BUFFER_MAX_LENGTH];
uint8_t USART2_DMA_RX_Buffer[USART2_DMA_RX_BUFFER_MAX_LENGTH];
uint8_t USART2_DMA_TX_Buffer[USART2_DMA_TX_BUFFER_MAX_LENGTH];
uint8_t USART3_DMA_RX_Buffer[USART3_DMA_RX_BUFFER_MAX_LENGTH];
uint8_t USART3_DMA_TX_Buffer[USART3_DMA_TX_BUFFER_MAX_LENGTH];
uint8_t UART4_DMA_RX_Buffer[UART4_DMA_RX_BUFFER_MAX_LENGTH];
uint8_t UART4_DMA_TX_Buffer[UART4_DMA_TX_BUFFER_MAX_LENGTH];
uint8_t UART5_DMA_RX_Buffer[UART5_DMA_RX_BUFFER_MAX_LENGTH];
uint8_t UART5_DMA_TX_Buffer[UART5_DMA_TX_BUFFER_MAX_LENGTH];
uint8_t USART6_DMA_RX_Buffer[USART6_DMA_RX_BUFFER_MAX_LENGTH];
uint8_t USART6_DMA_TX_Buffer[USART6_DMA_TX_BUFFER_MAX_LENGTH];
void USART1_DMA_Tx_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 , ENABLE); //DMA2时钟使能
DMA_DeInit(DMA2_Stream7);
while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE); //等待DMA可配置
DMA_InitStructure.DMA_Channel = DMA_Channel_4; //DMA通道配置
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR; //DMA外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)USART1_DMA_TX_Buffer;//发送缓存指针
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; //DMA传输方向:内存--->外设
DMA_InitStructure.DMA_BufferSize = USART1_DMA_TX_BUFFER_MAX_LENGTH; //数据传输字节数量
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_Priority_High
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输
DMA_Init(DMA2_Stream7, &DMA_InitStructure); //初始化DMA Stream
DMA_Cmd(DMA2_Stream7, DISABLE); //开启DMA传输
}
void USART1_DMA_Rx_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 , ENABLE); //DMA2时钟使能
DMA_DeInit(DMA2_Stream5);
while (DMA_GetCmdStatus(DMA2_Stream5) != DISABLE); //等待DMA可配置
DMA_InitStructure.DMA_Channel = DMA_Channel_4; //通道选择
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR; //DMA外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)USART1_DMA_RX_Buffer;//接收缓存指针
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory ; //DMA传输方向:外设到存储器模式:外设--->内存
DMA_InitStructure.DMA_BufferSize = USART1_DMA_RX_BUFFER_MAX_LENGTH; //缓冲大小
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_Priority_VeryHigh
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输
DMA_Init(DMA2_Stream5 , &DMA_InitStructure); //初始化DMA_Stream5
DMA_Cmd(DMA2_Stream5, ENABLE); //开启DMA传输
}
void USART2_DMA_Tx_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1 , ENABLE); //DMA1时钟使能
DMA_DeInit(DMA1_Stream6);
while (DMA_GetCmdStatus(DMA1_Stream6) != DISABLE); //等待DMA可配置
DMA_InitStructure.DMA_Channel = DMA_Channel_4; //DMA通道配置
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR; //DMA外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)USART2_DMA_TX_Buffer;//发送缓存指针
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; //DMA传输方向:内存--->外设
DMA_InitStructure.DMA_BufferSize = USART2_DMA_TX_BUFFER_MAX_LENGTH; //数据传输字节数量
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_Priority_High
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输
DMA_Init(DMA1_Stream6, &DMA_InitStructure); //初始化DMA Stream
DMA_Cmd(DMA1_Stream6, DISABLE); //开启DMA传输
}
void USART2_DMA_Rx_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1 , ENABLE); //DMA1时钟使能
DMA_DeInit(DMA1_Stream5);
while (DMA_GetCmdStatus(DMA1_Stream5) != DISABLE); //等待DMA可配置
DMA_InitStructure.DMA_Channel = DMA_Channel_4; //通道选择
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR; //DMA外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)USART2_DMA_RX_Buffer;//接收缓存指针
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory ; //DMA传输方向:外设到存储器模式:外设--->内存
DMA_InitStructure.DMA_BufferSize = USART2_DMA_RX_BUFFER_MAX_LENGTH; //缓冲大小
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_Priority_VeryHigh
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输
DMA_Init(DMA1_Stream5 , &DMA_InitStructure); //初始化DMA_Stream
DMA_Cmd(DMA1_Stream5, ENABLE); //开启DMA传输
}
void USART3_DMA_Tx_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1 , ENABLE); //DMA2时钟使能
DMA_DeInit(DMA1_Stream3);
while (DMA_GetCmdStatus(DMA1_Stream3) != DISABLE); //等待DMA可配置
DMA_InitStructure.DMA_Channel = DMA_Channel_4; //DMA通道配置
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART3->DR; //DMA外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)USART3_DMA_TX_Buffer;//发送缓存指针
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; //DMA传输方向:内存--->外设
DMA_InitStructure.DMA_BufferSize = USART3_DMA_TX_BUFFER_MAX_LENGTH; //数据传输字节数量
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_Priority_High
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输
DMA_Init(DMA1_Stream3, &DMA_InitStructure); //初始化DMA Stream
DMA_Cmd(DMA1_Stream3, DISABLE); //开启DMA传输
}
void USART3_DMA_Rx_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1 , ENABLE); //DMA2时钟使能
DMA_DeInit(DMA1_Stream1);
while (DMA_GetCmdStatus(DMA1_Stream1) != DISABLE); //等待DMA可配置
DMA_InitStructure.DMA_Channel = DMA_Channel_4; //通道选择
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART3->DR; //DMA外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)USART3_DMA_RX_Buffer;//接收缓存指针
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory ; //DMA传输方向:外设到存储器模式:外设--->内存
DMA_InitStructure.DMA_BufferSize = USART3_DMA_RX_BUFFER_MAX_LENGTH; //缓冲大小
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_Priority_VeryHigh
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输
DMA_Init(DMA1_Stream1 , &DMA_InitStructure); //初始化DMA_Stream
DMA_Cmd(DMA1_Stream1, ENABLE); //开启DMA传输
}
void UART4_DMA_Tx_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1 , ENABLE); //DMA1时钟使能
DMA_DeInit(DMA1_Stream4);
while (DMA_GetCmdStatus(DMA1_Stream4) != DISABLE); //等待DMA可配置
DMA_InitStructure.DMA_Channel = DMA_Channel_4; //DMA通道配置
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&UART4->DR; //DMA外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)UART4_DMA_TX_Buffer; //发送缓存指针
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; //DMA传输方向:内存--->外设
DMA_InitStructure.DMA_BufferSize = UART4_DMA_TX_BUFFER_MAX_LENGTH; //数据传输字节数量
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_Priority_High
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输
DMA_Init(DMA1_Stream4, &DMA_InitStructure); //初始化DMA Stream
DMA_Cmd(DMA1_Stream4, DISABLE); //开启DMA传输
}
void UART4_DMA_Rx_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1 , ENABLE); //DMA1时钟使能
DMA_DeInit(DMA1_Stream2);
while (DMA_GetCmdStatus(DMA1_Stream2) != DISABLE); //等待DMA可配置
DMA_InitStructure.DMA_Channel = DMA_Channel_4; //通道选择
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&UART4->DR; //DMA外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)UART4_DMA_RX_Buffer; //接收缓存指针
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory ; //DMA传输方向:外设到存储器模式:外设--->内存
DMA_InitStructure.DMA_BufferSize = UART4_DMA_RX_BUFFER_MAX_LENGTH; //缓冲大小
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_Priority_VeryHigh
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输
DMA_Init(DMA1_Stream2 , &DMA_InitStructure); //初始化DMA_Stream
DMA_Cmd(DMA1_Stream2, ENABLE); //开启DMA传输
}
void UART5_DMA_Tx_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1 , ENABLE); //DMA1时钟使能
DMA_DeInit(DMA1_Stream7);
while (DMA_GetCmdStatus(DMA1_Stream7) != DISABLE); //等待DMA可配置
DMA_InitStructure.DMA_Channel = DMA_Channel_4; //DMA通道配置
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&UART5->DR; //DMA外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)UART5_DMA_TX_Buffer; //发送缓存指针
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; //DMA传输方向:内存--->外设
DMA_InitStructure.DMA_BufferSize = UART5_DMA_TX_BUFFER_MAX_LENGTH; //数据传输字节数量
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_Priority_High
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输
DMA_Init(DMA1_Stream7, &DMA_InitStructure); //初始化DMA Stream
DMA_Cmd(DMA1_Stream7, DISABLE); //关闭DMA传输
}
void UART5_DMA_Rx_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1 , ENABLE); //DMA1时钟使能
DMA_DeInit(DMA1_Stream0);
while (DMA_GetCmdStatus(DMA1_Stream0) != DISABLE); //等待DMA可配置
DMA_InitStructure.DMA_Channel = DMA_Channel_4; //通道选择
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&UART5->DR; //DMA外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)UART5_DMA_RX_Buffer; //接收缓存指针
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory ; //DMA传输方向:外设到存储器模式:外设--->内存
DMA_InitStructure.DMA_BufferSize = UART5_DMA_RX_BUFFER_MAX_LENGTH; //缓冲大小
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_Priority_VeryHigh
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输
DMA_Init(DMA1_Stream0 , &DMA_InitStructure);
DMA_Cmd(DMA1_Stream0, ENABLE); //开启DMA传输
}
//可以这么认为,USART6如果DMA的TX使用DMA2_Stream6,则USART6如果DMA的RX必须使用DMA2_Stream1
// USART6如果DMA的TX使用DMA2_Stream7,则USART6如果DMA的RX必须使用DMA2_Stream2
void USART6_DMA_Tx_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 , ENABLE); //DMA2时钟使能
DMA_DeInit(DMA2_Stream6);
while (DMA_GetCmdStatus(DMA2_Stream6) != DISABLE); //等待DMA可配置
DMA_InitStructure.DMA_Channel = DMA_Channel_5; //DMA通道配置
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART6->DR; //DMA外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)USART6_DMA_TX_Buffer;//发送缓存指针
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; //DMA传输方向:内存--->外设
DMA_InitStructure.DMA_BufferSize = USART6_DMA_TX_BUFFER_MAX_LENGTH; //数据传输字节数量
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_Priority_High
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输
DMA_Init(DMA2_Stream6 , &DMA_InitStructure); //初始化DMA Stream
DMA_Cmd(DMA2_Stream6 , DISABLE); //开启DMA传输
}
void USART6_DMA_Rx_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 , ENABLE); //DMA2时钟使能
DMA_DeInit(DMA2_Stream1);
while (DMA_GetCmdStatus(DMA2_Stream1) != DISABLE); //等待DMA可配置
DMA_InitStructure.DMA_Channel = DMA_Channel_5; //通道选择
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART6->DR; //DMA外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)USART6_DMA_RX_Buffer;//接收缓存指针
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory ; //DMA传输方向:外设到存储器模式:外设--->内存
DMA_InitStructure.DMA_BufferSize = USART6_DMA_RX_BUFFER_MAX_LENGTH; //缓冲大小
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_Priority_VeryHigh
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输
DMA_Init(DMA2_Stream1 , &DMA_InitStructure); //初始化DMA_Stream5
DMA_Cmd(DMA2_Stream1 , ENABLE); //开启DMA传输
}
void USART1_DMA_Begin_Send(uint8_t *send_buffer , uint16_t nSendCount)
{
if (nSendCount < USART1_DMA_TX_BUFFER_MAX_LENGTH)
{
memcpy(USART1_DMA_TX_Buffer , send_buffer , nSendCount);
DMA_Cmd(DMA2_Stream7 , DISABLE); //关闭DMA传输
while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE); //确保DMA可以被设置
DMA_SetCurrDataCounter(DMA2_Stream7 , nSendCount); //数据传输量
DMA_Cmd(DMA2_Stream7 , ENABLE); //开启DMA传输
}
}
void USART2_DMA_Begin_Send(uint8_t *send_buffer , uint16_t nSendCount)
{
if (nSendCount < USART2_DMA_TX_BUFFER_MAX_LENGTH)
{
memcpy(USART2_DMA_TX_Buffer , send_buffer , nSendCount);
DMA_Cmd(DMA1_Stream6 , DISABLE); //关闭DMA传输
while (DMA_GetCmdStatus(DMA1_Stream6) != DISABLE); //确保DMA可以被设置
DMA_SetCurrDataCounter(DMA1_Stream6 , nSendCount); //数据传输量
DMA_Cmd(DMA1_Stream6 , ENABLE); //开启DMA传输
}
}
void USART3_DMA_Begin_Send(uint8_t *send_buffer , uint16_t nSendCount)
{
if (nSendCount < USART3_DMA_TX_BUFFER_MAX_LENGTH)
{
memcpy(USART3_DMA_TX_Buffer , send_buffer , nSendCount);
DMA_Cmd(DMA1_Stream3 , DISABLE); //关闭DMA传输
while (DMA_GetCmdStatus(DMA1_Stream3) != DISABLE); //确保DMA可以被设置
DMA_SetCurrDataCounter(DMA1_Stream3 , nSendCount); //数据传输量
DMA_Cmd(DMA1_Stream3 , ENABLE); //开启DMA传输
}
}
void UART4_DMA_Begin_Send(uint8_t *send_buffer , uint16_t nSendCount)
{
if (nSendCount < UART4_DMA_TX_BUFFER_MAX_LENGTH)
{
memcpy(UART4_DMA_TX_Buffer , send_buffer , nSendCount);
DMA_Cmd(DMA1_Stream4 , DISABLE); //关闭DMA传输
while (DMA_GetCmdStatus(DMA1_Stream4) != DISABLE); //确保DMA可以被设置
DMA_SetCurrDataCounter(DMA1_Stream4 , nSendCount); //数据传输量
DMA_Cmd(DMA1_Stream4 , ENABLE); //开启DMA传输
}
}
void UART5_DMA_Begin_Send(uint8_t *send_buffer , uint16_t nSendCount)
{
if (nSendCount < UART5_DMA_TX_BUFFER_MAX_LENGTH)
{
memcpy(UART5_DMA_TX_Buffer , send_buffer , nSendCount);
DMA_Cmd(DMA1_Stream7 , DISABLE); //关闭DMA传输
while (DMA_GetCmdStatus(DMA1_Stream7) != DISABLE); //确保DMA可以被设置
DMA_SetCurrDataCounter(DMA1_Stream7 , nSendCount); //数据传输量
DMA_Cmd(DMA1_Stream7 , ENABLE); //开启DMA传输
}
}
void USART6_DMA_Begin_Send(uint8_t *send_buffer , uint16_t nSendCount)
{
if (nSendCount < USART6_DMA_TX_BUFFER_MAX_LENGTH)
{
memcpy(USART6_DMA_TX_Buffer , send_buffer , nSendCount);
DMA_Cmd(DMA2_Stream6 , DISABLE); //关闭DMA传输
while (DMA_GetCmdStatus(DMA2_Stream6) != DISABLE); //确保DMA可以被设置
DMA_SetCurrDataCounter(DMA2_Stream6 , nSendCount); //数据传输量
DMA_Cmd(DMA2_Stream6 , ENABLE); //开启DMA传输
}
}
三、串口初始化程序
不仅要初始化串口,还要初始化DMA接收和DMA发送使能。
void UART4_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
USART_DeInit(UART4);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4 , ENABLE); //for USART2, USART3, UART4 or UART5.
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_UART4);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_UART4);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 38400;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
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);
USART_Cmd(UART4, ENABLE);
USART_ClearFlag(UART4, USART_FLAG_TC);
while (USART_GetFlagStatus(UART4, USART_FLAG_TC) == RESET);
USART_ClearFlag(UART4, USART_FLAG_TC);
USART_ITConfig(UART4, USART_IT_RXNE, DISABLE);
USART_ITConfig(UART4, USART_IT_TXE, DISABLE);
USART_ITConfig(UART4, USART_IT_IDLE, ENABLE);
USART_ITConfig(UART4, USART_IT_TC, ENABLE);
USART_DMACmd(UART4 , USART_DMAReq_Tx,ENABLE);
USART_DMACmd(UART4 , USART_DMAReq_Rx,ENABLE);
}
四、串口中断服务程序
必须使用串口空中断和串口发送完成中断来判断DMA接收完成或DMA发送完成,不能使用串口其它中断。
(1)、ch > 0 表示产生DMA接收中断,并且接收的字节数ch 大于0。
(2)、WriteBufferTo_ringBuffer(GPS_ring , UART4_DMA_RX_Buffer , ch); 将接收到的ch个字节保存到环形缓冲区GPS_ring。
void UART4_IRQHandler(void)
{
int16_t ch;
if (USART_GetITStatus(UART4 , USART_IT_IDLE) != RESET)
{
USART_ClearITPendingBit(UART4 , USART_IT_IDLE); //必须先清除总线空闲中断标识,然后读一下数据寄存器,DMA接收才会正确(先读SR,然后读DR才能清除空闲中断标识)注意:这句必须要,否则不能够清除中断标志位。
ch = USART_ReceiveData(UART4); //必须先清除总线空闲中断标识,然后读一下数据寄存器,DMA接收才会正确(先读SR,然后读DR才能清除空闲中断标识)注意:这句必须要,否则不能够清除中断标志位。
DMA_Cmd(DMA1_Stream2, DISABLE);
DMA_ClearFlag(DMA1_Stream2 , DMA_FLAG_TCIF2 | DMA_FLAG_FEIF2 | DMA_FLAG_DMEIF2 | DMA_FLAG_TEIF2 | DMA_FLAG_HTIF2);
ch = UART4_DMA_RX_BUFFER_MAX_LENGTH - DMA_GetCurrDataCounter(DMA1_Stream2);
if (ch > 0)
{
WriteBufferTo_ringBuffer(GPS_ring , UART4_DMA_RX_Buffer , ch);
}
DMA_SetCurrDataCounter(DMA1_Stream2 , UART4_DMA_RX_BUFFER_MAX_LENGTH);
DMA_Cmd(DMA1_Stream2, ENABLE);
}
else if (USART_GetITStatus(UART4 , USART_IT_TC)!= RESET)
{
USART_ClearITPendingBit(UART4 , USART_IT_TC);
DMA_ClearFlag(DMA1_Stream4 , DMA_FLAG_TCIF4 | DMA_FLAG_FEIF4 | DMA_FLAG_DMEIF4 | DMA_FLAG_TEIF4 | DMA_FLAG_HTIF4);
DMA_SetCurrDataCounter(DMA1_Stream4 , 0);
}
}
五、字符串底层函数
将环形缓冲区中的字节转换成字符串,在字符串中查找GPS报文头标识(例如:GPGGA)和GPS报文尾部标识(回车换行)
void hex_to_string(uint8_t hex_buffer[] , char *string , uint16_t n)
{
uint16_t i;
char *p = string;
for (i = 0 ; i < n ; i++)
*p++ = hex_buffer[i];
*p = '\0';
}
void string_to_hex(char *string , uint8_t hex_buffer[])
{
char *p = string;
uint16_t i = 0;
while (*p != '\0')
hex_buffer[i++] = *p++;
}
uint8_t ASCII_To_Hex(uint8_t number)
{
if (number >= '0' && number <= '9')
return (number - 0x30);
else if (number >= 'a' && number <= 'f')
return ((number - 'a') + 10);
else if (number >= 'A' && number <= 'F')
return ((number - 'A') + 10);
return (0);
}
uint16_t FIND(char *s , char *t)
{
uint16_t i;
uint16_t j;
int16_t end;
end = strlen(s) - strlen(t);
if (end >= 0)
{
for (i = 0 ; i <= end ; i++)
{
for (j = i ; s[j] == t[j-i] ; j++)
{
if (t[j-i+1] == '\0')
return (i+1);
}
}
}
return (0);
}
uint16_t string_FindChar(char *s , char t)
{
char *p = s;
uint16_t i;
for (i = 0 ; *p != '\0'; p++ , i++)
{
if (*p == t)
return (i + 1);
}
return (0);
}
uint16_t string_FindCharS(char *s , char t , uint16_t n)
{
char *p = s;
uint16_t i;
uint16_t j;
for (i = j = 0; (*p != '\0' && i < n); p++ , j++)
{
if (*p == t)
i++;
}
if (i == n)
return (j);
return (0);
}
void LEFT(char* src , char* dest , uint16_t n)
{
char *p = src;
char *q = dest;
uint16_t i = 0;
while (*p!='\0' && i < n)
{
*q++ = *p++;
i++;
}
*q='\0';
}
void RIGHT(char *src , char *dest , uint16_t n)
{
char *p = src;
char *q = dest;
uint16_t len = strlen(src);
if (n > len) n = len;
p += (len - n); // 从右边第n个字符开始
while(*p != '\0')
*(q++) = *(p++);
*q = '\0';
}
void MID(char *src , char *dest , uint16_t n , uint16_t m)
{
char *p = src;
char *q = dest;
uint16_t len = strlen(src);
uint16_t j = m;
uint16_t i = 0;
if (j > len)
j = len;
p += j;
while(*p != '\0' && i < n)
{
*q++ = *p++;
i++;
}
*q='\0';
}
void Reverse(char *s)
{
char c;
int16_t i ;
int16_t j ;
for (i = 0 , j = strlen(s) - 1 ; i < j ; i++ , j--)
{
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
uint8_t Get_Comma_string(char *string , char *str , uint16_t No1 , uint16_t No2)
{
uint16_t comma1;
uint16_t comma2;
if (No1 > 0 && No2 > 0 && No1 < No2)
{
comma1 = string_FindCharS(string , ',' , No1);
comma2 = string_FindCharS(string , ',' , No2);
if (comma1 > 0 && comma2 >0)
{
if (comma2 - comma1 >= 1)
{
MID(string , str , comma2 - comma1 - 1 , comma1);
return (1);//TRUE);
}
}
}
return (0);//FALSE);
}
六、环形缓冲区程序
本环形缓冲区程序支持一次向环形缓冲区写1个字节和多个字节;同时还支持向环形缓冲区读1个字节和读多个字节。
#define MIN(a,b) ( (a) < (b) ) ? (a):(b)
#define RING_MAXLEN (1024)
typedef struct tagring_buf_struct
{
uint8_t *buffer;
uint16_t volatile size;
uint16_t volatile rptr;
uint16_t volatile wptr;
}ring_buf_struct , *ring_buf_struct_ptr;
uint8_t GPS_ring_buffer[RING_MAXLEN];
ring_buf_struct GPS_ring_struct;
ring_buf_struct_ptr GPS_ring;
void ringBufferInit(void)
{
GPS_ring = &GPS_ring_struct;
GPS_ring->size = RING_MAXLEN;
GPS_ring->buffer = GPS_ring_buffer;
memset(GPS_ring->buffer , 0x00 , GPS_ring->size);
GPS_ring->rptr = 0x00;
GPS_ring->wptr = 0x00;
}
BOOL ringBufferEmpty(ring_buf_struct *ring)
{
if (ring->rptr == ring->wptr)
return (TRUE);
return (FALSE);
}
BOOL ringBufferFull(ring_buf_struct *ring)
{
if (ring->rptr == ((ring->wptr + 1) % ring->size))
return (TRUE);
return (FALSE);
}
BOOL WriteCharTo_ringBuffer(ring_buf_struct *ring , uint8_t ch)
{
if (ringBufferFull(ring))
return (FALSE);
ring->buffer[ring->wptr] = ch;
ring->wptr++;
ring->wptr = ring->wptr % ring->size;
return (TRUE);
}
BOOL ReadCharFrom_ringBuffer(ring_buf_struct *ring , uint8_t *ch)
{
if (ringBufferEmpty(ring))
return (FALSE);
*ch = ring->buffer[ring->rptr];
ring->rptr++;
ring->rptr = ring->rptr % ring->size;
return (TRUE);
}
uint16_t ringBufferFilllength(ring_buf_struct *ring)
{
return ((ring->size + ring->wptr - ring->rptr) % ring->size);
}
uint16_t ringBufferFreelength(ring_buf_struct *ring)
{
return (ring->size - ringBufferFilllength(ring) - 1);
}
BOOL WriteBufferTo_ringBuffer(ring_buf_struct *ring , uint8_t *buffer , uint16_t n)
{
uint16_t i;
if (ringBufferFull(ring))
return (FALSE);
if (ringBufferFreelength(ring) < n)
return (FALSE);
i = MIN(n , ring->size - ring->wptr % ring->size); //从ring->wptr开始到缓冲区结尾的空间
memcpy(ring->buffer + (ring->wptr % ring->size) , buffer , i);
if (n > i)
memcpy(ring->buffer , buffer + i , n - i); //从缓冲区开始(0)到ring->rptr之前的n-i个有效空间
ring->wptr = (ring->wptr + n) % ring->size;
return (TRUE);
}
uint16_t ReadBufferFrom_ringBuffer(ring_buf_struct *ring , uint8_t *buffer , uint16_t n)
{
uint16_t i;
uint16_t len;
len = MIN(n , ringBufferFilllength(ring));
i = MIN(len , ring->size - ring->rptr % ring->size );
memcpy(buffer , ring->buffer + (ring->rptr % ring->size) , i);
if (len > i)
memcpy(buffer + i, ring->buffer , len - i);
ring->rptr = (ring->rptr + len) % ring->size;
return (len);
}
七、GPS结构体
enum GPS_MESSAGE_TYPE {
enum_GPS_NULL_MESSAGE = 0 ,
enum_GPS_GPNTR_MESSAGE = 1 ,
enum_GPS_GPRMC_MESSAGE = 2 ,
enum_GPS_GPVTG_MESSAGE = 3 ,
enum_GPS_GPGGA_MESSAGE = 4 ,
enum_GPS_GPTRA_MESSAGE = 5 ,
};
union CONVERT
{
int32_t long_num;
int16_t integer[2];
uint8_t BUF[4];
};
typedef struct tagGPS_STRUCT
{
uint8_t year;
uint8_t month;
uint8_t day;
uint8_t millisecond; //GPS的毫秒不准
double x;
double y;
double z;
int16_t HIGH_AM1;
int16_t HIGH_AM2;
int16_t HDOP;
uint8_t hour;
uint8_t minute;
uint8_t second;
uint16_t Angle;
uint8_t pos_status;
int16_t star_amount;
} GPS_STRUCT;
typedef struct tagGPS_MESSAGE_TYPE
{
int16_t head_pos;
enum GPS_MESSAGE_TYPE enum_message_type;
} GPS_MESSAGE_TYPE_STRUCT;
八、GPS报文解析程序
typedef struct tagCLOCK
{
uint8_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t minute;
uint8_t second;
uint8_t week;
} CLOCK;
char string_GPNTR[20] = "GNNTR";
char string_GPRMC[20] = "GNRMC";
char string_GPGGA[20] = "GNGGA";
char string_GPVTG[20] = "GNVTG";
char string_GPTRA[20] = "GNTRA";
char string_CRLF[20] = "\r\n";
char string_STAR[20] = "*";
char gps_string[512];
GPS_STRUCT GPS;
CLOCK UTC_time;
CLOCK LOCAL_time;
//------------------------------------------------------------------------
//UTC时间转换为任意时区时间,如果是转换为北京时间,设置timezone=8即可。
//utc_time = UTC时间
//timezone = 时区(就北京时区=8)
//------------------------------------------------------------------------
void UTC_to_BJtime(CLOCK *utc_time, int8_t timezone , CLOCK *local_time)
{
int16_t year,month,day,hour;
int16_t lastday = 0; //last day of this month(本月天数)
int16_t lastlastday = 0; //last day of last month(上月天数)
year = utc_time->year; //utc time
month = utc_time->month;
day = utc_time->day;
hour = utc_time->hour + timezone;
//1月大,2月小,3月大,4月小,5月大,6月小,7月大,8月大,9月小,10月大,11月小,12月大
if (month==1 || month==3 || month==5 || month==7 || month==8 || month==10 || month==12)
{
lastday = 31; //本月天数
lastlastday = 30; //这里应该补上上个月的天数
if (month == 3)
{
if ((year%400 == 0) || (year%4 == 0 && year%100 != 0)) //if this is lunar year
lastlastday = 29; //上个月的天数(闰年)
else
lastlastday = 28; //上个月的天数(平年【非闰年】)
}
//if (month == 8)
if (month == 8 || month == 1) //这里应该是8月和1月,因为8月和1月的上一个月(7月和12月)的天数是31天
lastlastday = 31; //上个月的天数
}
else if (month == 4 || month == 6 || month == 9 || month == 11)
{
lastday = 30; //本月天数
lastlastday = 31; //上个月的天数
}
else
{
lastlastday = 31; //上个月的天数
if ((year%400 == 0)||(year%4 == 0 && year%100 != 0))
lastday = 29; //本月天数(闰年)
else
lastday = 28; //本月天数(平年【非闰年】)
}
if (hour >= 24) // 当算出的区时大于或等于24:00时,应减去24:00,日期加一天
{ // if >24, day+1
hour -= 24;
day += 1;
if (day > lastday) // 当算出的日期大于该月最后一天时,应减去该月最后一天的日期
{ // next month, day-lastday of this month
day -= lastday;
month += 1;
if (month > 12) // 当算出的月份大于12时,应减去12,年份加上一年
{ // next year , month-12
month -= 12;
year += 1;
}//if (month > 12)
}//if (day > lastday)
}//if (hour >= 24)
if (hour < 0) // 当算出的区时为负数时,应加上24:00,日期减一天
{ // if <0, day-1
hour += 24;
day -= 1;
if (day < 1) // 当算出的日期为0时,日期变为上一月的最后一天,月份减去一个月
{ // month-1, day=last day of last month
day = lastlastday;
month -= 1;
if (month < 1) // 当算出的月份为0时,月份变为12月,年份减去一年
{ // last year , month=12
month = 12;
year -= 1;
}//if (month < 1)
}//if (day < 1)
}//if (hour < 0)
local_time->year = year;
local_time->month = month;
local_time->day = day;
local_time->hour = hour;
local_time->minute = utc_time->minute;
local_time->second = utc_time->second;
}
//基姆拉尔森计算公式根据日期判断星期几
void CalculateWeekDay(int16_t year , int16_t month , int16_t day)
{
if (month == 1 || month ==2)
{
month +=12;
year--;
}
int16_t iWeek = (day + 2 * month + 3 * (month + 1)/5 + year + year/4 - year/100 + year/400)%7;
switch (iWeek)
{
case 0: break;//printf("星期一\n"); break;
case 1: break;//printf("星期二\n"); break;
case 2: break;//printf("星期三\n"); break;
case 3: break;//printf("星期四\n"); break;
case 4: break;//printf("星期五\n"); break;
case 5: break;//printf("星期六\n"); break;
case 6: break;//printf("星期日\n"); break;
}
}
void GPS_STRING_Init(void)
{
char *p = gps_string;
*p = '\0';
}
void GPS_Init(void)
{
GPS_STRING_Init();
memset(&GPS , 0x00 , sizeof(GPS_STRUCT));
memset(&UTC_time , 0x00 , sizeof(CLOCK));
memset(&LOCAL_time , 0x00 , sizeof(CLOCK));
}
void GPS_strcat(char * string , uint8_t ch)
{
char *p = string;
while (*p != '\0')
p++;
*p++ = ch;
*p = '\0';
}
void Read_GPS_GPRMC_UTC(char *string)
{
uint8_t x1;
uint8_t x2;
char str[100];
char *p;
if (Get_Comma_string(string , str , 1 , 2))
{
p = str;
x1 = *p++;
x2 = *p++;
UTC_time.hour = (x1 - 0x30) * 10 + (x2 - 0x30);
x1 = *p++;
x2 = *p++;
UTC_time.minute = (x1 - 0x30) * 10 + (x2 - 0x30);
x1 = *p++;
x2 = *p++;
UTC_time.second = (x1 - 0x30) * 10 + (x2 - 0x30);
}
}
void Read_GPS_GPRMC_DATE(char *string)
{
uint8_t x9;
uint8_t x10;
char str[100];
char *p;
if (Get_Comma_string(string , str , 9 , 10))
{
p = str;
x9 = *p++;
x10 = *p++;
UTC_time.day = (x9 - 0x30) * 10 + (x10 - 0x30);
x9 = *p++;
x10 = *p++;
UTC_time.month = (x9 - 0x30) * 10 + (x10 - 0x30);
x9 = *p++;
x10 = *p++;
UTC_time.year = (x9 - 0x30) * 10 + (x10 - 0x30);
}
}
void Read_GPS_GPVTG_speed(char *string)
{
char str[100];
float fnum;
union CONVERT Convert;
if (Get_Comma_string(string , str , 7 , 8))
{
fnum = atof(str);
}
}
//
// GPTRA 报文格式
//
//$GPTRA,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>*hh<CR><LF>
//$GPTRA,090807.00,007.23,-00.27,000.00,4,13,0.00,0004*54
//<1> UTC 时间 hhmmss.ss(时分秒格式) 104252.00
//<2> 方向角,hhh.hh 0~360 度 044.56 司南磁偏角
//<3> 俯仰角:-90~90度 ppp.pp -09.74
//<4> 横滚角:-90~90度 rrr.rr 0
///<5> 解状态
//0:无效解;
//1:单点定位解;
//2:伪距差分;
//4:固定解;
//5:浮动解;
//<6> 卫星数
//<7> 差分延迟
//<8> 差分站ID号0000~1023(前导位数不足则补0,如果不是差分定位将为空)
//<9> 校验数据(以*开始)
//==============================================================
void Read_GPS_GPTRA(char *string )
{
char str[100];
float fnum;
if (Get_Comma_string(string , str , 2 , 3))
{
fnum = atof(str);
fnum = fnum * 10;
GPS.Angle = fnum;
}
if (Get_Comma_string(string , str , 5 , 6))
{
GPS.GPTRA_pos_status = atoi(str);
}
if (Get_Comma_string(string , str , 6 , 7))
{
GPS.GPTRA_star_amount = atoi(str);
}
}
void Read_GPS_GPGGA_xyz(char *string)
{
uint8_t x1;
uint8_t x2;
char *p;
char str[100];
int16_t inum;
int32_t lnum1;
int32_t lnum2;
float fnum;
union CONVERT Convert;
if (Get_Comma_string(string , str , 1 , 2))
{
p = str;
x1 = *p++;
x2 = *p++;
UTC_time.hour = (x1 - 0x30) * 10 + (x2 - 0x30);
x1 = *p++;
x2 = *p++;
UTC_time.minute = (x1 - 0x30) * 10 + (x2 - 0x30);
x1 = *p++;
x2 = *p++;
UTC_time.second = (x1 - 0x30) * 10 + (x2 - 0x30);
p++;
x1 = *p++;
x2 = *p++;
GPS.millisecond = (x1 - 0x30) * 10 + (x2 - 0x30);
}
if (Get_Comma_string(string , str , 2 , 3))
{
RTRIM_ZERO(str);
//GPS-X
}
if (Get_Comma_string(string , str , 4 , 5))
{
RTRIM_ZERO(str);
//GPS-Y
}
if (Get_Comma_string(string , str , 6 , 7))
{
GPS.pos_status = atoi(str);
}
if (Get_Comma_string(string , str , 7 , 8))
{
GPS.star_amount = atoi(str);
}
if (Get_Comma_string(string , str , 8 , 9))
{
fnum = atof(str);
fnum = fnum * 100;
inum = fnum;
GPS.HDOP = inum;
}
if (Get_Comma_string(string , str , 9 , 10))
{
RTRIM_ZERO(str);
//GPS-Z
}
if (Get_Comma_string(string , str , 11 , 12))
{
fnum = atof(str);
fnum = fnum * 10000;
Convert.long_num = fnum;
GPS.HIGH_AM1 = Convert.integer[1]; //高位部分
GPS.HIGH_AM2 = Convert.integer[0]; //低位部分
}
}
BOOL GPS_Checksum(char *string , uint16_t head , uint16_t star)
{
char *p1 = string + head - 1;
char *p2;
char ch;
uint8_t checksum = 0x00;
uint8_t sn_lo;
uint8_t sn_hi;
uint8_t sn_lo_hex;
uint8_t sn_hi_hex;
uint8_t sn_hex;
if ((star > head) && strlen(string) >= (star + 2))
{
while (*p1 != '*' && *p1 != '\0')
{
ch = *p1++;
checksum = checksum ^ ch;
}
p2 = p1;
if (*p2 == '*')
{
p2++;
sn_hi = *p2++; // '37' = 7
sn_lo = *p2; // '42' = B
sn_hi_hex = ASCII_To_Hex(sn_hi);
sn_lo_hex = ASCII_To_Hex(sn_lo);
sn_hex = (sn_hi_hex << 0x04) + sn_lo_hex;
if (checksum == sn_hex)
return (TRUE);
}
}//if ((star > head) && strlen(string) >= (star + 2))
return (FALSE);
}
GPS_MESSAGE_TYPE_STRUCT GPS_message_Type(char *string)
{
GPS_MESSAGE_TYPE_STRUCT gps_message_type;
gps_message_type.head_pos = FIND(string , string_GPNTR);
if (gps_message_type.head_pos)
{
gps_message_type.enum_message_type = enum_GPS_GPNTR_MESSAGE;
return (gps_message_type);
}
gps_message_type.head_pos = FIND(string , string_GPRMC);
if (gps_message_type.head_pos)
{
gps_message_type.enum_message_type = enum_GPS_GPRMC_MESSAGE;
return (gps_message_type);
}
gps_message_type.head_pos = FIND(string , string_GPVTG);
if (gps_message_type.head_pos)
{
gps_message_type.enum_message_type = enum_GPS_GPVTG_MESSAGE;
return (gps_message_type);
}
gps_message_type.head_pos = FIND(string , string_GPGGA);
if (gps_message_type.head_pos)
{
gps_message_type.enum_message_type = enum_GPS_GPGGA_MESSAGE;
return (gps_message_type);
}
gps_message_type.head_pos = FIND(string , string_GPTRA);
if (gps_message_type.head_pos)
{
gps_message_type.enum_message_type = enum_GPS_GPTRA_MESSAGE;
return (gps_message_type);
}
gps_message_type.head_pos = 0x00;
gps_message_type.enum_message_type = enum_GPS_NULL_MESSAGE;
return (gps_message_type);
}
void UART4_GPS_Poll(void)
{
uint8_t ch;
BOOL succ_mark = FALSE;
uint16_t star;
GPS_MESSAGE_TYPE_STRUCT gps_message_type;
//从环形缓冲区中取出一个字节
succ_mark = ReadCharFrom_ringBuffer(GPS_ring , &ch);
if (succ_mark)
{
GPS_strcat(gps_string , ch);//从环形缓冲区中取出一个字节,追加到字符串gps_string有尾部,准备解析GPS报文
if (FIND(gps_string , string_CRLF) || strlen(gps_string) >= 255)
{
gps_message_type = GPS_message_Type(gps_string);
switch (gps_message_type.enum_message_type)
{
case enum_GPS_GPRMC_MESSAGE:
star = FIND(gps_string , string_STAR);
if (GPS_Checksum(gps_string , gps_message_type.head_pos , star))
{
Read_GPS_GPRMC_UTC(gps_string + gps_message_type.head_pos - 1);
Read_GPS_GPRMC_DATE(gps_string + gps_message_type.head_pos - 1);
}//if (GPS_Checksum(gps_string , gps_message_type.head_pos , star))
break;
case enum_GPS_GPVTG_MESSAGE:
star = FIND(gps_string , string_STAR);
if (GPS_Checksum(gps_string , gps_message_type.head_pos , star))
{
Read_GPS_GPVTG_speed(gps_string + gps_message_type.head_pos - 1);
}//if (GPS_Checksum(gps_string , gps_message_type.head_pos , star))
break;
case enum_GPS_GPGGA_MESSAGE:
star = FIND(gps_string , string_STAR);
if (GPS_Checksum(gps_string , gps_message_type.head_pos , star))
{
Read_GPS_GPGGA_xyz(gps_string + gps_message_type.head_pos - 1);
}//if (GPS_Checksum(gps_string , gps_message_type.head_pos , star))
break;
case enum_GPS_GPTRA_MESSAGE:
star = FIND(gps_string , string_STAR);
if (GPS_Checksum(gps_string , gps_message_type.head_pos , star))
{
Read_GPS_GPTRA(gps_string + gps_message_type.head_pos - 1);
}//if (GPS_Checksum(gps_string , gps_message_type.head_pos , star))
break;
default:
break;
}//switch (gps_message_type.enum_message_type)
GPS_STRING_Init();
}//if (FIND(gps_string , string_CRLF))
}//if (succ_mark)
}