完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
1.概述
本文实现如下功能:
串口参数结构体 typedef struct{ USART_TypeDef* Uartx; //指向物理串口的结构体 UartIOCfg CfgIO; //串口收发管脚配置结构体 USART_InitTypeDef CfgUart; //串口参数结构体 NVIC_InitTypeDef CfgNvic; //串口中断结构体 UartCfgRx CfgRx; //串口接收DMA配置结构体 UartCfgTx CfgTx; //串口发送DMA配置结构体}SerialTypeDef; 串口IO配置结构体 typedef struct{ GPIO_TypeDef* TxPort; //发送端口 GPIO_TypeDef* RxPort; //接收端口 INT16U TxPin; //发送管脚 INT16U RxPin; //接收管脚}UartIOCfg; 接收DMA配置结构体 typedef struct{ DMA_Stream_TypeDef* DmaStream; //DMA流 INT32U DmaChannel; //通道 INT16U Used; //DMA使用量 FifoTypeDef* Fifo; //流对应使用的FIFO。 INT16U FifoSize; //接收fifo的大小。 NVIC_InitTypeDef CfgNvic; //DMA中断配置结构体}UartCfgRx; 发送DMA配置结构体 typedef struct{ DMA_Stream_TypeDef* DmaStream; //DMA流 INT32U DmaChannel; //通道 FifoTypeDef* Fifo; //流对应使用的FIFO。 INT16U FifoSize; //发送fifo的大小。 INT8U* Buff; //发送的buff INT16U BuffSize; //发送buff的大小 NVIC_InitTypeDef CfgNvic;}UartCfgTx; 3.串口驱动实现 3.1 static局部函数 3.1.1串口IO初始化 /****************************************************** @brief bsp_uart_IOCfg* @note 初始化IO为复用,USART或UART* @param serial 指向串口参数* @retval NONE* @data 2021.07.01* @auth WXL* @his 1.0.0.0 2021.07.01 WXL* create*****************************************************/static void bsp_uart_IOCfg(SerialTypeDef* serial){ GPIO_InitTypeDef GPIO_InitStructure; //IO初始化 RCC_AHB1PeriphClockCmd(1<<( (((INT32U)serial->CfgIO.TxPort)-AHB1PERIPH_BASE) / 0x0400 ),ENABLE); GPIO_InitStructure.GPIO_Pin = (1 << serial->CfgIO.TxPin); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(serial->CfgIO.TxPort , &GPIO_InitStructure); RCC_AHB1PeriphClockCmd(1<<( ( ((INT32U)serial->CfgIO.RxPort)-AHB1PERIPH_BASE) / 0x0400 ),ENABLE); GPIO_InitStructure.GPIO_Pin = (1 << serial->CfgIO.RxPin); GPIO_Init(serial->CfgIO.RxPort , &GPIO_InitStructure); //IO复用 if(serial->Uartx == USART1 || serial->Uartx == USART2 || serial->Uartx == USART3) { GPIO_PinAFConfig(serial->CfgIO.TxPort , serial->CfgIO.TxPin , 7); GPIO_PinAFConfig(serial->CfgIO.RxPort , serial->CfgIO.RxPin , 7); } if(serial->Uartx == UART4 || serial->Uartx == UART5 || serial->Uartx == USART6) { GPIO_PinAFConfig(serial->CfgIO.TxPort , serial->CfgIO.TxPin , 8); GPIO_PinAFConfig(serial->CfgIO.RxPort , serial->CfgIO.RxPin , 8); }} 根据串口参数结构体的内容进行相关收发IO的初始化。注意一下几点:
RCC_AHB1Periph_GPIOA = 1<<( (((INT32U)serial->CfgIO.TxPort)-AHB1PERIPH_BASE) / 0x0400;
3.1.2串口参数初始化 /****************************************************** @brief bsp_usart_UartInit* @note 串口参数初始化* @param serial 指向串口参数* @retval NONE* @data 2021.07.01* @auth WXL* @his 1.0.0.0 2021.07.01 WXL* create*****************************************************/static void bsp_usart_UartInit(SerialTypeDef* serial){ //使能时钟。 if(serial->Uartx == USART1) RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); else if(serial->Uartx == USART2) RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE); else if(serial->Uartx == USART3) RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); else if(serial->Uartx == UART4) RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4,ENABLE); else if(serial->Uartx == UART5) RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5,ENABLE); else if(serial->Uartx == USART6) RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6,ENABLE); USART_Init(serial->Uartx, &serial->CfgUart); USART_Cmd(serial->Uartx, ENABLE);} 根据串口参数结构体中的物理串口进行相应的时钟使能,参数配置。 3.1.3中断初始化 /****************************************************** @brief bsp_usart_NVICCfg* @note 串口中断初始化* @param serial 指向串口参数* @retval NONE* @data 2021.07.01* @auth WXL* @his 1.0.0.0 2021.07.01 WXL* create*****************************************************/static void bsp_usart_NVICCfg(SerialTypeDef* serial){ USART_ITConfig(serial->Uartx, USART_IT_IDLE, ENABLE); NVIC_Init(&serial->CfgNvic); USART_DMACmd(serial->Uartx,USART_DMAReq_Rx,ENABLE); USART_DMACmd(serial->Uartx,USART_DMAReq_Tx,ENABLE);} 3.1.4中断初始化 /****************************************************** @brief bsp_usart_DMACfg* @note 串口DMA配置* @param serial 指向串口参数* @retval 0 成功* 1 申请内存失败* @data 2021.07.01* @auth WXL* @his 1.0.0.0 2021.07.01 WXL* create*****************************************************/static INT8U bsp_usart_DMACfg(SerialTypeDef* serial){ DMA_InitTypeDef DMA_InitStructure; //创建接收FIFO serial->CfgRx.Fifo = func_fifo_Create(serial->CfgRx.FifoSize); if(serial->CfgRx.Fifo == NULL) return 1; serial->CfgRx.Used = 0; //创建发送FIFO serial->CfgTx.Fifo = func_fifo_Create(serial->CfgTx.FifoSize); if(serial->CfgTx.Fifo == NULL) { func_fifo_Free(serial->CfgRx.Fifo); return 1; } //创建发送BUFF serial->CfgTx.Buff = malloc(serial->CfgTx.BuffSize); if(serial->CfgTx.Buff == NULL) { func_fifo_Free(serial->CfgRx.Fifo); func_fifo_Free(serial->CfgTx.Fifo); return 1; } //接收 DMA配置 DMA_Stream_TypeDef* stream = serial->CfgRx.DmaStream; INT32U channle = serial->CfgRx.DmaChannel; if(stream < DMA2_Stream0) RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE); else RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE); DMA_DeInit(stream); while(DMA_GetCmdStatus(stream) != DISABLE) {} DMA_InitStructure.DMA_Channel = channle; DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(serial->Uartx->DR); DMA_InitStructure.DMA_Memory0BaseAddr = (u32)serial->CfgRx.Fifo->Buf; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = serial->CfgRx.FifoSize; 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 = DMA_Priority_Medium; 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(stream, &DMA_InitStructure); DMA_Cmd(stream, ENABLE); NVIC_Init(&serial->CfgRx.CfgNvic); DMA_Cmd(stream, ENABLE); DMA_ITConfig(stream, DMA_IT_TC, ENABLE); //发送 stream = serial->CfgTx.DmaStream; channle = serial->CfgTx.DmaChannel; if(stream < DMA2_Stream0) RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE); else RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE); DMA_DeInit(stream); while(DMA_GetCmdStatus(stream) != DISABLE) {} DMA_InitStructure.DMA_Channel = channle; DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(serial->Uartx->DR); DMA_InitStructure.DMA_Memory0BaseAddr = (u32)serial->CfgTx.Buff; DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_InitStructure.DMA_BufferSize = 0; 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_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; 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(stream, &DMA_InitStructure); DMA_Cmd(stream, ENABLE); NVIC_Init(&serial->CfgTx.CfgNvic); DMA_Cmd(stream, ENABLE); DMA_ITConfig(stream, DMA_IT_TC, ENABLE); return 0;} 串口DMA初始化需要完成如下内容:
/***************************************************** * @brief bsp_uart_rx_callback * @note IDLE中断和DMA完成中断回调函数。 * @param com 端口。 * par 1 DMA完成中断 * 0 IDLE中断。 * @retval NONE * @data 2021.01.20 * @auth WXL * @his 1.0.0.1 2021.01.20 WXL * 新建文件*****************************************************/static void bsp_uart_rx_callback(SerialTypeDef* serial,INT8U par){ INT16U count = 0; INT16U used = 0; //DMA完成中断调用。 if(par == 1) { count = serial->CfgRx.FifoSize - serial->CfgRx.Used;//计算本次接收元素个数。 serial->CfgRx.Used = 0; //DMA为Circular模式,中断中需要清零该变量。 } //IDLE中断调用。 else { //计算本次接收元素个数。 used = serial->CfgRx.FifoSize - DMA_GetCurrDataCounter(serial->CfgRx.DmaStream); count = used - serial->CfgRx.Used; serial->CfgRx.Used = used; } //更新接收FIFO的指针。 func_fifo_PushNoData(serial->CfgRx.Fifo, count);} 在接收DMA完成中断和串口IDLE中断中调用。计算写入量,将FIFO进行相应操作。以上函数均为局部函数,不对外开放。 3.2全局函数 3.2.1设置串口配置参数为默认 /***************************************************** * @brief bsp_uart_ParaSetDefault * @note 设置串口参数未默认IDLE中断和DMA完成中断回调函数。 * @param serial 指向设置的串口 * @retval NONE * @data 2021.01.20 * @auth WXL * @his 1.0.0.1 2021.01.20 WXL * 新建文件*****************************************************/void bsp_uart_ParaSetDefault(SerialTypeDef* serial){ serial->Uartx = USART1; serial->CfgIO.RxPin = 10; serial->CfgIO.RxPort = GPIOA; serial->CfgIO.TxPin = 9; serial->CfgIO.TxPort = GPIOA; serial->CfgUart.USART_BaudRate = 115200; serial->CfgUart.USART_HardwareFlowControl = USART_HardwareFlowControl_None; serial->CfgUart.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; serial->CfgUart.USART_Parity = USART_Parity_No; serial->CfgUart.USART_StopBits = USART_StopBits_1; serial->CfgUart.USART_WordLength = USART_WordLength_8b; serial->CfgNvic.NVIC_IRQChannel = USART1_IRQn; serial->CfgNvic.NVIC_IRQChannelPreemptionPriority = 1; serial->CfgNvic.NVIC_IRQChannelSubPriority = 1; serial->CfgNvic.NVIC_IRQChannelCmd = ENABLE; serial->CfgRx.DmaChannel = DMA_Channel_4; serial->CfgRx.DmaStream = DMA2_Stream5; serial->CfgRx.FifoSize = 200; serial->CfgRx.CfgNvic.NVIC_IRQChannel = DMA2_Stream5_IRQn; serial->CfgRx.CfgNvic.NVIC_IRQChannelPreemptionPriority = 1; serial->CfgRx.CfgNvic.NVIC_IRQChannelSubPriority = 1; serial->CfgRx.CfgNvic.NVIC_IRQChannelCmd = ENABLE; serial->CfgTx.DmaChannel = DMA_Channel_4; serial->CfgTx.DmaStream = DMA2_Stream7; serial->CfgTx.FifoSize = 200; serial->CfgTx.BuffSize = 100; serial->CfgTx.CfgNvic.NVIC_IRQChannel = DMA2_Stream7_IRQn; serial->CfgTx.CfgNvic.NVIC_IRQChannelPreemptionPriority = 1; serial->CfgTx.CfgNvic.NVIC_IRQChannelSubPriority = 1; serial->CfgTx.CfgNvic.NVIC_IRQChannelCmd = ENABLE;} 3.2.2串口初始化 /****************************************************** @brief bsp_uart_init* @note Serial初始化,完成端口IO,中断及DMA的初始化工作* @param serial 指向串口参数* @retval 0 成功* 1 申请内存失败* @data 2021.07.01* @auth WXL* @his 1.0.0.0 2021.07.01 WXL* create*****************************************************/INT8U bsp_uart_init(SerialTypeDef* serial){ if(bsp_usart_DMACfg(serial) == 1) return 1; //IO初始化 bsp_uart_IOCfg(serial); //串口参数初始化 bsp_usart_UartInit(serial); //中断配置初始化 bsp_usart_NVICCfg(serial); return 0;} 3.2.3串口发送函数 /****************************************************** @brief bsp_uart_Transmittx* @note 串口发送数据* @param serial 指向串口参数* @retval 0 成功* 1 DMA繁忙,未发送。* @data 2021.07.01* @auth WXL* @his 1.0.0.0 2021.07.01 WXL* create*****************************************************/INT8U bsp_uart_Transmit(SerialTypeDef* Uartx){ INT8U count = 0; //DMA发送繁忙,不进行操作。 if(DMA_GetCurrDataCounter(Uartx->CfgTx.DmaStream)!= 0) return 1; if(Uartx->CfgTx.Fifo->CntUsed == 0) return 0; if(Uartx->CfgTx.Fifo->CntUsed > Uartx->CfgTx.BuffSize) { count = Uartx->CfgTx.BuffSize; } else count = Uartx->CfgTx.Fifo->CntUsed; //将数据从FIFO中拷贝到DMA的发送缓冲区,重启DMA。 func_fifo_Pull(Uartx->CfgTx.Fifo, count, Uartx->CfgTx.Buff); DMA_Cmd(Uartx->CfgTx.DmaStream,DISABLE); while (DMA_GetCmdStatus(Uartx->CfgTx.DmaStream) != DISABLE) {} DMA_SetCurrDataCounter(Uartx->CfgTx.DmaStream,count); DMA_Cmd(Uartx->CfgTx.DmaStream, ENABLE); return 0;} 3.3中断函数 3.3.1DMA发送中断 /***************************************************** * @brief DMA2_Stream7_IRQHandler * @note DMA2_Stream7的中断函数。 USART1_TX * @param NONE * @retval NONE * @data 2021.01.20 * @auth WXL * @his 1.0.0.1 2021.01.20 WXL * 新建文件*****************************************************/void DMA2_Stream7_IRQHandler(){ if(DMA_GetITStatus(DMA2_Stream7, DMA_IT_TCIF7)) { DMA_ClearFlag(DMA2_Stream5,DMA_FLAG_FEIF7 | DMA_FLAG_DMEIF7 | DMA_FLAG_TEIF7 | DMA_FLAG_HTIF7 | DMA_FLAG_TCIF7); bsp_uart_Transmit(&Serial1); }} 3.3.2DMA接收中断 /***************************************************** * @brief DMA2_Stream5_IRQHandler * @note DMA2_Stream5的中断函数。 USART1_RX * @param NONE * @retval NONE * @data 2021.01.20 * @auth WXL * @his 1.0.0.1 2021.01.20 WXL * 新建文件*****************************************************/void DMA2_Stream5_IRQHandler(void){ if(DMA_GetITStatus(DMA2_Stream5,DMA_IT_TCIF5)) { DMA_ClearFlag(DMA2_Stream5,DMA_FLAG_FEIF5 | DMA_FLAG_DMEIF5 | DMA_FLAG_TEIF5 | DMA_FLAG_HTIF5 | DMA_FLAG_TCIF5); bsp_uart_rx_callback(&Serial1,1); }} 3.3.3串口中断 /***************************************************** * @brief USART1_IRQHandler * @note 串口1中断函数,用于处理接收完成 * @param NONE * @retval NONE * @data 2021.01.20 * @auth WXL * @his 1.0.0.1 2021.01.20 WXL * 新建文件*****************************************************/void USART1_IRQHandler(void){ INT16U data = 0; if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET) { //清除IDLE标志位 data = USART1->SR; data = USART1->DR; bsp_uart_rx_callback(&Serial1,0); }} |
|||
|
|||
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1561 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1501 浏览 1 评论
933 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
665 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1555 浏览 2 评论
1847浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
609浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
503浏览 3评论
507浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
488浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-10 15:35 , Processed in 0.483790 second(s), Total 45, Slave 40 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号