本期对先前串口应用库进行了一些小更新,主要在第二篇文章(https://blog.csdn.net/qq_40831436/article/details/119566869)中,获取串口数据函数:
static uint8_t GetAFraFromUxRxBuff(uint8_t *pbuff,uint8_t *psize,_USARTxRXBUFF *pRxBuff,_FRAMEATTRI *pUxFra)
没有进行地址超出判断,若数据帧的大小大于pbuff的空间大小,将会引起空间溢出风险,虽然说通过将pbuff设置大一些可避免,但在实际使用中由于干扰或者其他因素,有可能导致数据帧出错从而有可能引起空间溢出。
同时,与版本1的串口库函数相比,本次还更新了一些其他小的方面,具体如下:
/*******************************************************
*设计:陈文德
*版本:V1.0
*版本:V1.1版本:5串口全部支持
*版本:V1.2 增加最大长度限制
*版本:V1.3 波特率设置改为宏定义;增加中断使用选择
*版本:V1.4 调试串口使用宏定义
*说明:通过设置USE_USART1..5,可以选择使用哪些串口
通过设置NeedSet_NVICprio可以选择是否进行中断优先级分组,默认分组2
*******************************************************/
源代码如下:
.h文件
/*******************************************************
*设计:陈文德
*版本:V1.0
*版本:V1.1版本:5串口全部支持
*版本:V1.2 增加最大长度限制
*版本:V1.3 波特率设置改为宏定义;增加中断使用选择
*版本:V1.4 调试串口使用宏定义
*说明:通过设置USE_USART1..5,可以选择使用哪些串口
通过设置NeedSet_NVICprio可以选择是否进行中断优先级分组,默认分组2
*******************************************************/
#ifndef __USARTDMA_H
#define __USARTDMA_H
#include "stm32f10x.h"
#include <stdio.h>
/*串口使用情况,置1代表使用此串口*/
#define USE_USART1 1
#define USE_USART2 1
#define USE_USART3 1
#define USE_USART4 1
#define USE_USART5 1
#define USE_IRQ 1 //1-中断函数在.c文件中定义,0-不使用本中断,需自己实现中断函数
#define NeedSet_NVICprio 1 //1:需要设置中断优先级分组,默认分组2 0:不需要设置中断优先级分组
#define DebugUsart USART3
/*串口的波特率定义*/
#define USART1_bps 115200
#define USART2_bps 115200
#define USART3_bps 115200
#define USART4_bps 115200
#define USART5_bps 115200
/*给5个串口编号*/
#define Com_USART1 1
#define Com_USART2 2
#define Com_USART3 3
#define Com_USART4 4
#define Com_USART5 5
#ifdef USE_USART1
/*串口1发送引脚定义*/
#define USART1TX_GPIO_CLK RCC_APB2Periph_GPIOA
#define USART1TX_GPIO_PORT GPIOA
#define USART1TX_GPIO_Pin GPIO_Pin_9
/*串口1接收引脚定义*/
#define USART1RX_GPIO_CLK RCC_APB2Periph_GPIOA
#define USART1RX_GPIO_PORT GPIOA
#define USART1RX_GPIO_Pin GPIO_Pin_10
#define USART1_RxDMA_CHANNEL DMA1_Channel5
#endif
#ifdef USE_USART2
/*串口2发送引脚定义*/
#define USART2TX_GPIO_CLK RCC_APB2Periph_GPIOA
#define USART2TX_GPIO_PORT GPIOA
#define USART2TX_GPIO_Pin GPIO_Pin_2
/*串口2接收引脚定义*/
#define USART2RX_GPIO_CLK RCC_APB2Periph_GPIOA
#define USART2RX_GPIO_PORT GPIOA
#define USART2RX_GPIO_Pin GPIO_Pin_3
#define USART2_RxDMA_CHANNEL DMA1_Channel6
#endif
#ifdef USE_USART3
/*串口3发送引脚定义*/
#define USART3TX_GPIO_CLK RCC_APB2Periph_GPIOB
#define USART3TX_GPIO_PORT GPIOB
#define USART3TX_GPIO_Pin GPIO_Pin_10
/*串口3接收引脚定义*/
#define USART3RX_GPIO_CLK RCC_APB2Periph_GPIOB
#define USART3RX_GPIO_PORT GPIOB
#define USART3RX_GPIO_Pin GPIO_Pin_11
#define USART3_RxDMA_CHANNEL DMA1_Channel3
#endif
#ifdef USE_USART4
/*串口4发送引脚定义*/
#define USART4TX_GPIO_CLK RCC_APB2Periph_GPIOC
#define USART4TX_GPIO_PORT GPIOC
#define USART4TX_GPIO_Pin GPIO_Pin_10
/*串口4接收引脚定义*/
#define USART4RX_GPIO_CLK RCC_APB2Periph_GPIOC
#define USART4RX_GPIO_PORT GPIOC
#define USART4RX_GPIO_Pin GPIO_Pin_11
#define USART4_RxDMA_CHANNEL DMA2_Channel3
#endif
#ifdef USE_USART5
/*串口5发送引脚定义*/
#define USART5TX_GPIO_CLK RCC_APB2Periph_GPIOC
#define USART5TX_GPIO_PORT GPIOC
#define USART5TX_GPIO_Pin GPIO_Pin_12
/*串口5接收引脚定义*/
#define USART5RX_GPIO_CLK RCC_APB2Periph_GPIOD
#define USART5RX_GPIO_PORT GPIOD
#define USART5RX_GPIO_Pin GPIO_Pin_2
#endif
#define UxRXBUFFSIZE 512 //接收缓冲区的大小
/**串口接收缓冲区**/
typedef struct __USARTxRXBUFF
{
uint16_t wp; //当前接收帧在接收缓冲区所处的写地址
uint16_t rp; //当前接收帧在接收缓冲区所处的读地址
uint8_t rxarr[UxRXBUFFSIZE]; //接收缓冲区实体
}_USARTxRXBUFF;
/**帧地址结构体**/
typedef struct __FRAMEADDR
{
uint16_t wpx; //本帧写地址的索引
uint16_t rpx; //本帧读地址的索引
}_FRAMEADDR;
#define FRADDRMAX 10 //最多能记录的帧
/**帧属性结构体**/
typedef struct __FRAMEATTRI
{
_FRAMEADDR fraddr[FRADDRMAX]; //每帧的地址,即通过wpx记录wp, rpx记录rp。队列主体
uint8_t currfra; //当前处理帧。0-(FRADDRMAX-1)
uint8_t nextfra; //下一个帧。0-(FRADDRMAX-1)
}_FRAMEATTRI;
void USARTx_Config(void); //串口初始化配置
void USARTxIDLE_IRQ(uint8_t Com_USARTx); //串口空闲中断处理函数,空闲中断调用
void USART5RXNE_IRQ(void); //串口5接收字节中断处理,串口5专用,串口5接收字节中断调用
void Usart_SendArray( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num); //串口发送函数
void Usart_SendHalfWordArray( USART_TypeDef * pUSARTx, uint16_t *pbuff,uint16_t num);
uint8_t GetAFraFromComx(uint8_t Com_USARTx,uint8_t *pbuff,uint8_t *psize,uint16_t maxrdlen); //从COM1..5口获取一帧数据
uint8_t JudgeUxFraIsNull(uint8_t Com_USARTx); //判断COM1..5口是否还有未处理数据
void ClearUart5Data(void);
#endif /* __USARTDMA_H */
.c文件
/*******************************************************
*设计:陈文德
*版本:V1.0
*版本:V1.1版本:增加USART1..5
*版本:V1.2 增加数据获取最大长度限制
*版本:V1.3 波特率设置改为宏定义;增加中断使用选择
*版本:V1.4 调试串口使用宏定义
*说明:通过设置USE_USART1..5,可以选择使用哪些串口
通过设置NeedSet_NVICprio可以选择是否进行中断优先级分组,默认分组2
*******************************************************/
#include "bsp_usart_dma.h"
#if USE_USART1
_USARTxRXBUFF U1RxBuff; //定义串口接收缓冲区
_FRAMEATTRI g_U1RxFra; //定义帧记录指针缓冲区,非真指针
#endif
#if USE_USART2
_USARTxRXBUFF U2RxBuff; //定义串口接收缓冲区
_FRAMEATTRI g_U2RxFra; //定义帧记录指针缓冲区,非真指针
#endif
#if USE_USART3
_USARTxRXBUFF U3RxBuff; //定义串口接收缓冲区
_FRAMEATTRI g_U3RxFra; //定义帧记录指针缓冲区,非真指针
#endif
#if USE_USART4
_USARTxRXBUFF U4RxBuff; //定义串口接收缓冲区
_FRAMEATTRI g_U4RxFra; //定义帧记录指针缓冲区,非真指针
#endif
#if USE_USART5
_USARTxRXBUFF U5RxBuff; //定义串口接收缓冲区
_FRAMEATTRI g_U5RxFra; //定义帧记录指针缓冲区,非真指针
#endif
/**************************************
*函 数 名: USARTx_Var_Init
*功 能: 串口x相关全局变量初始化
*入口参数: pRxBuff--接收缓冲区
pUxFra--帧记录缓冲区
*返 回 值: 无
**************************************/
static void USARTx_Var_Init(_USARTxRXBUFF *pRxBuff,_FRAMEATTRI *pUxRxFra)
{
pRxBuff->rp = 0;
pRxBuff->wp = 0;
pUxRxFra->currfra = 0;
pUxRxFra->nextfra = 0;
}
/**************************************
*函 数 名: USART_NVIC_Config
*功 能: 串口中断配置
*入口参数: usartx_irqn--中断号
preeprio--抢占优先级
subprio--子优先级
*返 回 值: 无
**************************************/
static void USARTx_NVIC_Config(uint8_t usartx_irqn,uint8_t preeprio,uint8_t subprio)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 配置USART为中断源 */
NVIC_InitStructure.NVIC_IRQChannel = usartx_irqn;
/* 抢断优先级*/
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = preeprio;
/* 子优先级 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = subprio;
/* 使能中断 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
/* 初始化配置NVIC */
NVIC_Init(&NVIC_InitStructure);
}
/**************************************
*函 数 名: USARTx_AFPP_GPIO_Config
*功 能: 复用推挽输出引脚配置
*入口参数: RCC_APB2Periph--APB2时钟
GPIOx--端口
GPIO_Pinx--引脚
*返 回 值: 无
**************************************/
static void USARTx_AFPP_GPIO_Config(uint32_t RCC_APB2Periph,GPIO_TypeDef* GPIOx,uint16_t GPIO_Pinx)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pinx;
GPIO_Init(GPIOx, &GPIO_InitStructure);
}
/**************************************
*函 数 名: USARTx_FloatIN_GPIO_Config
*功 能: 浮空输入引脚配置
*入口参数: RCC_APB2Periph--APB2时钟
GPIOx--端口
GPIO_Pinx--引脚
*返 回 值: 无
**************************************/
static void USARTx_FloatIN_GPIO_Config(uint32_t RCC_APB2Periph,GPIO_TypeDef* GPIOx,uint16_t GPIO_Pinx)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pinx;
GPIO_Init(GPIOx, &GPIO_InitStructure);
}
/**************************************
*函 数 名: USARTx_WorkMode_Config
*功 能: 串口工作模式配置
*入口参数: USARTx--串口
BaudRate--波特率
WordLength--字长
StopBits--停止位
Parity--优先级
*返 回 值: 无
**************************************/
static void USARTx_WorkMode_Config(USART_TypeDef* USARTx,uint32_t BaudRate,uint16_t WordLength,uint16_t StopBits,uint16_t Parity)
{
USART_InitTypeDef USART_InitStructure;
// 配置串口的工作参数
// 配置波特率
USART_InitStructure.USART_BaudRate = BaudRate;
// 配置 针数据字长
USART_InitStructure.USART_WordLength = WordLength;
// 配置停止位
USART_InitStructure.USART_StopBits = StopBits;
// 配置校验位
USART_InitStructure.USART_Parity = Parity ;
// 配置硬件流控制
USART_InitStructure.USART_HardwareFlowControl =
USART_HardwareFlowControl_None;
// 配置工作模式,收发一起
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
// 完成串口的初始化配置
USART_Init(USARTx, &USART_InitStructure);
}
/**************************************
*函 数 名: USARTx_RxDMA_Config
*功 能: 串口x接收DMA配置
*入口参数: USARTx--串口
DMAy_Channelx--DMA通道
RCC_DMAx--时钟
PeriBsAddr--外设地址
MemBsAddr--存储器地址
buffsize--缓冲区大小
prio--DMA优先级
*返 回 值: 无
**************************************/
static void USARTx_RxDMA_Config(USART_TypeDef* USARTx,DMA_Channel_TypeDef* DMAy_Channelx,uint32_t RCC_DMAx,\
uint32_t PeriBsAddr,uint32_t MemBsAddr,uint32_t buffsize,uint32_t prio)
{
DMA_InitTypeDef DMA_InitStructure;
// 开启DMA时钟
RCC_AHBPeriphClockCmd(RCC_DMAx, ENABLE);
DMA_InitStructure.DMA_PeripheralBaseAddr = PeriBsAddr;
DMA_InitStructure.DMA_MemoryBaseAddr = MemBsAddr; //串口接收基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = buffsize; //接收缓冲区的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize =
DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular ; //循环模式
DMA_InitStructure.DMA_Priority = prio;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMAy_Channelx, &DMA_InitStructure);
// 使能DMA
DMA_Cmd (DMAy_Channelx,ENABLE);
USART_DMACmd(USARTx,USART_DMAReq_Rx,ENABLE);
}
/**************************************
*函 数 名: USARTx_Config
*功 能: 串口初始化
*入口参数: 无
*返 回 值: 无
*说 明: 根据USE_USARTx定义初始化串口
**************************************/
void USARTx_Config(void)
{
#if NeedSet_NVICprio
NVIC_SetPriorityGrouping(NVIC_PriorityGroup_2);
#endif
#if USE_USART1
/*串口x使用到的全局变量初始化*/
USARTx_Var_Init(&U1RxBuff,&g_U1RxFra);
/**打开串口时钟**/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
//配置接收发送引脚
USARTx_AFPP_GPIO_Config(USART1TX_GPIO_CLK,USART1TX_GPIO_PORT,USART1TX_GPIO_Pin);
USARTx_FloatIN_GPIO_Config(USART1RX_GPIO_CLK,USART1RX_GPIO_PORT,USART1RX_GPIO_Pin);
//串口工作模式配置
USARTx_WorkMode_Config(USART1,USART1_bps,USART_WordLength_8b,USART_StopBits_1,USART_Parity_No);
//串口中断配置
USARTx_NVIC_Config(USART1_IRQn,1,0);
// 配置串口空闲中断
USART_ClearITPendingBit(USART1,USART_IT_IDLE);
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
// 使能串口
USART_Cmd(USART1, ENABLE);
//串口接收DMA配置
USARTx_RxDMA_Config(USART1,DMA1_Channel5,RCC_AHBPeriph_DMA1,(USART1_BASE+0x04),(uint32_t)U1RxBuff.rxarr,UxRXBUFFSIZE,DMA_Priority_Low);
#endif
#if USE_USART2
/*串口x使用到的全局变量初始化*/
USARTx_Var_Init(&U2RxBuff,&g_U2RxFra);
/**打开串口时钟**/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
//配置接收发送引脚
USARTx_AFPP_GPIO_Config(USART2TX_GPIO_CLK,USART2TX_GPIO_PORT,USART2TX_GPIO_Pin);
USARTx_FloatIN_GPIO_Config(USART2RX_GPIO_CLK,USART2RX_GPIO_PORT,USART2RX_GPIO_Pin);
//串口工作模式配置
USARTx_WorkMode_Config(USART2,USART2_bps,USART_WordLength_8b,USART_StopBits_1,USART_Parity_No);
//串口中断配置
USARTx_NVIC_Config(USART2_IRQn,1,1);
// 配置串口空闲中断
USART_ClearITPendingBit(USART2,USART_IT_IDLE);
USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);
// 使能串口
USART_Cmd(USART2, ENABLE);
//串口接收DMA配置
USARTx_RxDMA_Config(USART2,DMA1_Channel6,RCC_AHBPeriph_DMA1,(USART2_BASE+0x04),(uint32_t)U2RxBuff.rxarr,UxRXBUFFSIZE,DMA_Priority_Low);
#endif
#if USE_USART3
/*串口x使用到的全局变量初始化*/
USARTx_Var_Init(&U3RxBuff,&g_U3RxFra);
/**打开串口时钟**/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
//配置接收发送引脚
USARTx_AFPP_GPIO_Config(USART3TX_GPIO_CLK,USART3TX_GPIO_PORT,USART3TX_GPIO_Pin);
USARTx_FloatIN_GPIO_Config(USART3RX_GPIO_CLK,USART3RX_GPIO_PORT,USART3RX_GPIO_Pin);
//串口工作模式配置
USARTx_WorkMode_Config(USART3,USART3_bps,USART_WordLength_8b,USART_StopBits_1,USART_Parity_No);
//串口中断配置
USARTx_NVIC_Config(USART3_IRQn,1,1);
// 配置串口空闲中断
USART_ClearITPendingBit(USART3,USART_IT_IDLE);
USART_ITConfig(USART3, USART_IT_IDLE, ENABLE);
// 使能串口
USART_Cmd(USART3, ENABLE);
//串口接收DMA配置
USARTx_RxDMA_Config(USART3,DMA1_Channel3,RCC_AHBPeriph_DMA1,(USART3_BASE+0x04),(uint32_t)U3RxBuff.rxarr,UxRXBUFFSIZE,DMA_Priority_Low);
#endif
#if USE_USART4
/*串口x使用到的全局变量初始化*/
USARTx_Var_Init(&U4RxBuff,&g_U4RxFra);
/**打开串口时钟**/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4,ENABLE);
//配置接收发送引脚
USARTx_AFPP_GPIO_Config(USART4TX_GPIO_CLK,USART4TX_GPIO_PORT,USART4TX_GPIO_Pin);
USARTx_FloatIN_GPIO_Config(USART4RX_GPIO_CLK,USART4RX_GPIO_PORT,USART4RX_GPIO_Pin);
//串口工作模式配置
USARTx_WorkMode_Config(UART4,USART4_bps,USART_WordLength_8b,USART_StopBits_1,USART_Parity_No);
//串口中断配置
USARTx_NVIC_Config(UART4_IRQn,1,1);
// 配置串口空闲中断
USART_ClearITPendingBit(UART4,USART_IT_IDLE);
USART_ITConfig(UART4, USART_IT_IDLE, ENABLE);
// 使能串口
USART_Cmd(UART4, ENABLE);
//串口接收DMA配置
USARTx_RxDMA_Config(UART4,DMA2_Channel3,RCC_AHBPeriph_DMA2,(UART4_BASE+0x04),(uint32_t)U4RxBuff.rxarr,UxRXBUFFSIZE,DMA_Priority_Low);
#endif
#if USE_USART5
/*串口x使用到的全局变量初始化*/
USARTx_Var_Init(&U5RxBuff,&g_U5RxFra);
/**打开串口时钟**/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5,ENABLE);
//配置接收发送引脚
USARTx_AFPP_GPIO_Config(USART5TX_GPIO_CLK,USART5TX_GPIO_PORT,USART5TX_GPIO_Pin);
USARTx_FloatIN_GPIO_Config(USART5RX_GPIO_CLK,USART5RX_GPIO_PORT,USART5RX_GPIO_Pin);
//串口工作模式配置
USARTx_WorkMode_Config(UART5,USART5_bps,USART_WordLength_8b,USART_StopBits_1,USART_Parity_No);
//串口中断配置
USARTx_NVIC_Config(UART5_IRQn,0,1);
// 配置串口接收中断
USART_ClearITPendingBit(UART5,USART_IT_RXNE);
USART_ITConfig(UART5, USART_IT_RXNE, ENABLE);
//配置串口空闲中断
USART_ClearITPendingBit(UART5,USART_IT_IDLE);
USART_ITConfig(UART5, USART_IT_IDLE, ENABLE);
// 使能串口
USART_Cmd(UART5, ENABLE);
//串口5无DMA传输
#endif
}
/**************************************
*函 数 名: Usart_SendByte
*功 能: 串口发送一个字节
*入口参数: pUSARTx--USART1..3,UART4/5
ch--要发送的字节
*返 回 值: 无
*说 明:
**************************************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
/* 发送一个字节数据到USART */
USART_SendData(pUSARTx,ch);
/* 等待发送数据寄存器为空 */
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
/**************************************
*函 数 名: Usart_SendArray
*功 能: 串口发送8位数组
*入口参数: pUSARTx--USART1..3,UART4/5
array--要发送的数组指针
num--要发送的数目
*返 回 值: 无
*说 明:
**************************************/
void Usart_SendArray( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
{
uint8_t i;
for(i=0; i<num; i++)
{
/* 发送一个字节数据到USART */
Usart_SendByte(pUSARTx,array[i]);
}
/* 等待发送完成 */
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
}
/**************************************
*函 数 名: Usart_SendString
*功 能: 串口发送字符串
*入口参数: pUSARTx--USART1..3,UART4/5
str--要发送的字符串指针
*返 回 值: 无
*说 明:
**************************************/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
unsigned int k=0;
do
{
Usart_SendByte( pUSARTx, *(str + k) );
k++;
} while(*(str + k)!='\0');
/* 等待发送完成 */
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
{}
}
/***************** 发送一个16位数 **********************/
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
{
uint8_t temp_h, temp_l;
/* 取出高八位 */
temp_h = (ch&0XFF00)>>8;
/* 取出低八位 */
temp_l = ch&0XFF;
/* 发送高八位 */
USART_SendData(pUSARTx,temp_h);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
/* 发送低八位 */
USART_SendData(pUSARTx,temp_l);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
/***************** 发送16位数组 **********************/
void Usart_SendHalfWordArray( USART_TypeDef * pUSARTx, uint16_t *pbuff,uint16_t num)
{
uint16_t i;
for(i=0;i<num;i++)
{
Usart_SendHalfWord(pUSARTx,pbuff[i]);
}
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
}
///重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到串口 */
USART_SendData(DebugUsart, (uint8_t) ch);
/* 等待发送完毕 */
while (USART_GetFlagStatus(DebugUsart, USART_FLAG_TXE) == RESET);
return (ch);
}
///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
/* 等待串口输入数据 */
while (USART_GetFlagStatus(DebugUsart, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(DebugUsart);
}
/**************************************
*函 数 名: USARTxIDLE_IRQ
*功 能: 串口x空闲中断调用函数;仅串口1-4
*入口参数: pUSARTx--USARTx
DMAy_Channelx--串口通道
pRxBuff--串口接收缓冲区
pUxFra--串口接收帧记录缓冲区
*返 回 值: 无
**************************************/
static void USARTx_IDLE_IRQ(USART_TypeDef * pUSARTx,DMA_Channel_TypeDef* DMAy_Channelx,_USARTxRXBUFF *pRxBuff,_FRAMEATTRI *pUxRxFra)
{
uint16_t trnum=0;
//清除空闲中断标志位
pUSARTx->SR;
pUSARTx->DR;
//手册虽然说这个寄存器在DMA循环模式的时候,清0之后会自动恢复为最大接收缓冲区,但加入这一步以防万一
if(DMAy_Channelx->CNDTR == 0)
{
trnum = UxRXBUFFSIZE;
}
else
{
trnum = DMAy_Channelx->CNDTR&0xffff;
}
pRxBuff->wp = UxRXBUFFSIZE-trnum; //得到最新帧的结束地址
pUxRxFra->fraddr[pUxRxFra->nextfra].rpx = pRxBuff->rp; //最新帧的起始地址
pUxRxFra->fraddr[pUxRxFra->nextfra].wpx = pRxBuff->wp; //最新帧的结束地址
pUxRxFra->nextfra = (pUxRxFra->nextfra+1)%FRADDRMAX; //g_Fra.nextfra的值被限制再0,1....(FRADDRMAX-1)
pRxBuff->rp = pRxBuff->wp; //最新帧的起始与结束地址记录完,等待下一次记录
}
#if USE_USART5
/**************************************
*函 数 名: USART5_RXNE_IRQ
*功 能: 串口5接收一个字节
*入口参数: pRxBuff--串口接收缓冲区
*返 回 值: 无
*说 明:
**************************************/
static void USART5_RXNE_IRQ(_USARTxRXBUFF *pRxBuff)
{
pRxBuff->rxarr[pRxBuff->wp] = USART_ReceiveData(UART5);
pRxBuff->wp = (pRxBuff->wp+1)%UxRXBUFFSIZE; //pRxBuff->wp的值被限制再0,1....(UxRXBUFFSIZE-1)
}
/**************************************
*函 数 名: UART5_IDLE_IRQ
*功 能: 串口5空闲中断处理
*入口参数: pRxBuff--串口接收缓冲区
pUxFra--串口接收帧记录缓冲区
*返 回 值: 无
*说 明:
**************************************/
static void UART5_IDLE_IRQ(_USARTxRXBUFF *pRxBuff,_FRAMEATTRI *pUxRxFra)
{
UART5->SR;
UART5->DR;
pUxRxFra->fraddr[pUxRxFra->nextfra].rpx = pRxBuff->rp; //最新帧的起始地址
pUxRxFra->fraddr[pUxRxFra->nextfra].wpx = pRxBuff->wp; //最新帧的结束地址
pUxRxFra->nextfra = (pUxRxFra->nextfra+1)%FRADDRMAX; //g_Fra.nextfra的值被限制再0,1....(FRADDRMAX-1)
pRxBuff->rp = pRxBuff->wp; //最新帧的起始与结束地址记录完,等待下一次记录
}
/**************************************
*函 数 名: USART5RXNE_IRQ
*功 能: 串口5接收字节中断调用函数;串口5专用
*入口参数: 无
*返 回 值: 无
*说 明: 在接收字节中断服务函数中调用
**************************************/
void USART5RXNE_IRQ(void)
{
USART_ClearITPendingBit(UART5,USART_IT_RXNE);
USART5_RXNE_IRQ(&U5RxBuff);
}
void ClearUart5Data(void)
{
U5RxBuff.wp = 0;
U5RxBuff.rp = U5RxBuff.wp;
g_U5RxFra.currfra = g_U5RxFra.nextfra;
}
#endif
/**************************************
*函 数 名: USARTxIDLE_IRQ
*功 能: 串口x空闲中断调用函数;串口1-5
*入口参数: Com_USARTx--定义好的串口通道
*返 回 值: 无
*说 明:串口5除了这个之外还要调用串口接收字节处理
**************************************/
void USARTxIDLE_IRQ(uint8_t Com_USARTx)
{
switch(Com_USARTx)
{
#if USE_USART1
case Com_USART1:
USARTx_IDLE_IRQ(USART1,USART1_RxDMA_CHANNEL,&U1RxBuff,&g_U1RxFra);
break;
#endif
#if USE_USART2
case Com_USART2:
USARTx_IDLE_IRQ(USART2,USART2_RxDMA_CHANNEL,&U2RxBuff,&g_U2RxFra);
break;
#endif
#if USE_USART3
case Com_USART3:
USARTx_IDLE_IRQ(USART3,USART3_RxDMA_CHANNEL,&U3RxBuff,&g_U3RxFra);
break;
#endif
#if USE_USART4
case Com_USART4:
USARTx_IDLE_IRQ(UART4,USART4_RxDMA_CHANNEL,&U4RxBuff,&g_U4RxFra);
break;
#endif
#if USE_USART5
case Com_USART5:
UART5_IDLE_IRQ(&U5RxBuff,&g_U5RxFra);
break;
#endif
default:
break;
}
}
/**************************************
*函 数 名: GetAFraFromUxRxBuff
*功 能: 获取一帧数据
*入口参数: pbuff--获取一帧数据的数组
psize--获取的数目
pRxBuff--串口x缓冲区
pUxFra--串口x帧记录
maxrdlen--最大读取长度
*返 回 值: rtflg--0代表没有获取数据,1代表获取到数据
*说 明: 本函数没有进行地址超出判断,一定要确保你的数据帧的空间小于你定下的 pbuff 的空间
**************************************/
static uint8_t GetAFraFromUxRxBuff(uint8_t *pbuff,uint8_t *psize,_USARTxRXBUFF *pRxBuff,_FRAMEATTRI *pUxFra,uint16_t maxrdlen)
{
uint8_t rtflg=0; //返回值
uint16_t fralen=0; //帧长度
if(pUxFra->currfra != pUxFra->nextfra) //如果为真,说明有未处理的帧
{
/*根据每帧的帧属性(起始与结束地址)在串口接收缓冲区主体中获取一帧数据*/
if(pUxFra->fraddr[pUxFra->currfra].rpx<pUxFra->fraddr[pUxFra->currfra].wpx)
{
//本帧写入的起始地址小于写入的结束地址,直接使用写入结束地址-写入起始地址,计算出本帧的长度
fralen = pUxFra->fraddr[pUxFra->currfra].wpx-pUxFra->fraddr[pUxFra->currfra].rpx;
if(fralen<maxrdlen)
{
//小于最大读取长度,则进行读取
for((*psize)=0;(*psize)<fralen;(*psize)++)
{
//从串口接收缓冲区主体中取出本帧的数据,索引为:pUxFra->fraddr[pUxFra->currfra].rpx+(*psize)
pbuff[(*psize)] = pRxBuff->rxarr[pUxFra->fraddr[pUxFra->currfra].rpx+(*psize)];
}
}
//数据取出之后,本帧的.rpx(本帧起始的写入地址)=本帧的.wpx(本帧写入的结束地址)
pUxFra->fraddr[pUxFra->currfra].rpx=pUxFra->fraddr[pUxFra->currfra].wpx;
}
else
{
fralen = UxRXBUFFSIZE-(pUxFra->fraddr[pUxFra->currfra].rpx);
fralen += pUxFra->fraddr[pUxFra->currfra].wpx;
if(fralen<maxrdlen)
{
//本帧写入的起始地址大于写入的结束地址,说明数据在缓冲区中进行了溢出翻转,分两部分读取
//第一部分为rpx-(UxRXBUFFSIZE-1)的数据,第二部分为0-wpx的数据
for((*psize)=0;pUxFra->fraddr[pUxFra->currfra].rpx<UxRXBUFFSIZE;pUxFra->fraddr[pUxFra->currfra].rpx++)
{
//读取第一部分数据
pbuff[(*psize)] = pRxBuff->rxarr[pUxFra->fraddr[pUxFra->currfra].rpx];
(*psize)++;
}
pUxFra->fraddr[pUxFra->currfra].rpx = 0;
//读取第二部分数据
while(pUxFra->fraddr[pUxFra->currfra].rpx<pUxFra->fraddr[pUxFra->currfra].wpx)
{
pbuff[(*psize)] = pRxBuff->rxarr[pUxFra->fraddr[pUxFra->currfra].rpx];
(*psize)++;
pUxFra->fraddr[pUxFra->currfra].rpx++;
}
}
}
//当前帧数据读取结束,currfra(当前处理的帧+1)----0..(FRADDRMAX-1)
pUxFra->currfra = (pUxFra->currfra+1)%FRADDRMAX;
//读取到数据,返回值赋1
if(fralen<maxrdlen)
{
rtflg = 1;
}
}
return rtflg;
}
/**************************************
*函 数 名: JudgeUxFrameDataNum
*功 能: 判断是否有未处理的数据帧
*入口参数: pUxFra--串口x帧记录
*返 回 值: rtflg--0代表没有数据,1代表有数据需要处理
*说 明:
**************************************/
static uint8_t JudgeUxFrameDataNum(_FRAMEATTRI *pUxFra)
{
uint8_t rtflg=0;
if(pUxFra->currfra != pUxFra->nextfra) //如果为真,说明有未处理的帧
{
rtflg = 1;
}
else
{
rtflg = 0;
}
return rtflg;
}
/**************************************
*函 数 名: GetAFraFromComx
*功 能: 从COM口获取一帧数据
*入口参数: Com_USARTx--定义好的COM口,Com_USART1..5
pbuff--获取一帧数据的数组
psize--获取的数目
maxrdlen--获取的最大长度
*返 回 值: rtflg--0代表没有获取数据,1代表获取到数据
*说 明:
**************************************/
uint8_t GetAFraFromComx(uint8_t Com_USARTx,uint8_t *pbuff,uint8_t *psize,uint16_t maxrdlen)
{
uint8_t rtflg=0; //返回值
switch(Com_USARTx)
{
#if USE_USART1
case Com_USART1:
rtflg = GetAFraFromUxRxBuff(pbuff,psize,&U1RxBuff,&g_U1RxFra,maxrdlen);
break;
#endif
#if USE_USART2
case Com_USART2:
rtflg = GetAFraFromUxRxBuff(pbuff,psize,&U2RxBuff,&g_U2RxFra,maxrdlen);
break;
#endif
#if USE_USART3
case Com_USART3:
rtflg = GetAFraFromUxRxBuff(pbuff,psize,&U3RxBuff,&g_U3RxFra,maxrdlen);
break;
#endif
#if USE_USART4
case Com_USART4:
rtflg = GetAFraFromUxRxBuff(pbuff,psize,&U4RxBuff,&g_U4RxFra,maxrdlen);
break;
#endif
#if USE_USART5
case Com_USART5:
rtflg = GetAFraFromUxRxBuff(pbuff,psize,&U5RxBuff,&g_U5RxFra,maxrdlen);
break;
#endif
default:
break;
}
return rtflg;
}
/**************************************
*函 数 名: JudgeUxFraIsNull
*功 能: 判断当前COM口是否还有未处理的数据
*入口参数: Com_USARTx--定义好的COM口,Com_USART1..5
*返 回 值: rtflg--0代表没有数据,1代表有数据需要处理
*说 明:
**************************************/
uint8_t JudgeUxFraIsNull(uint8_t Com_USARTx)
{
uint8_t rtflg=0; //返回值
switch(Com_USARTx)
{
#if USE_USART1
case Com_USART1:
rtflg = JudgeUxFrameDataNum(&g_U1RxFra);
break;
#endif
#if USE_USART2
case Com_USART2:
rtflg = JudgeUxFrameDataNum(&g_U2RxFra);
break;
#endif
#if USE_USART3
case Com_USART3:
rtflg = JudgeUxFrameDataNum(&g_U3RxFra);
break;
#endif
#if USE_USART4
case Com_USART4:
rtflg = JudgeUxFrameDataNum(&g_U4RxFra);
break;
#endif
#if USE_USART5
case Com_USART5:
rtflg = JudgeUxFrameDataNum(&g_U5RxFra);
break;
#endif
default:
break;
}
return rtflg;
}
#if USE_IRQ
// 串口中断服务函数
#if USE_USART1
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1,USART_IT_IDLE)!=RESET)
{
USARTxIDLE_IRQ(Com_USART1);
}
}
#endif
// 串口中断服务函数
#if USE_USART2
void USART2_IRQHandler(void)
{
if(USART_GetITStatus(USART2,USART_IT_IDLE)!=RESET)
{
USARTxIDLE_IRQ(Com_USART2);
}
}
#endif
// 串口中断服务函数
#if USE_USART3
void USART3_IRQHandler(void)
{
if(USART_GetITStatus(USART3,USART_IT_IDLE)!=RESET)
{
USARTxIDLE_IRQ(Com_USART3);
}
}
#endif
// 串口中断服务函数
#if USE_USART4
void UART4_IRQHandler(void)
{
if(USART_GetITStatus(UART4,USART_IT_IDLE)!=RESET)
{
USARTxIDLE_IRQ(Com_USART4);
}
}
#endif
#if USE_USART5
// 串口中断服务函数
void UART5_IRQHandler(void)
{
if(USART_GetITStatus(UART5,USART_IT_RXNE)!=RESET)
{
USART5RXNE_IRQ();
}
if(USART_GetITStatus(UART5,USART_IT_IDLE)!=RESET)
{
USARTxIDLE_IRQ(Com_USART5);
}
}
#endif
#endif