#include "../main/SystemInclude.h" DMA_HandleTypeDef DMA_Handle_UartRx , DMA_Handle_UartTx ; /*********************************************************************************************************************************************/ /*初始化*/ /*********************************************************************************************************************************************/ /**------------------------------------------------------------------------ * @brief 初始化 UART0,配置引脚和通信参数 * @param baudrate_bps: 波特率,单位 bps,如 115200 * @note 使用 P0.1 作为 RX(复用 SIN0),P0.2 作为 TX(复用 SOUT0), * 数据格式:8位数据、1位停止位、无校验。 * @example UART0_Init(115200); **/ void UART0_Init(uint32_t baudrate_bps) { GPIO_InitTypeDef GPIO_InitStructure; UART_InitTypeDef UART_InitStructure; /* 1. 设置 UART GPIO复用引脚 */ GPIO_InitStructure.Pin = GPIO_PIN_1; GPIO_InitStructure.Mode = GPIO_MODE_INPUT; GPIO_InitStructure.Current = GPIO_CURRENT_4mA; GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.SchmittTrigger = ENABLE; GPIO_InitStructure.Alternate = GPIO0_1_AF_SIN0; LHL_GPIO_Init(pGPIO0, &GPIO_InitStructure); // P0.1 -> SIN0(UART_RX) GPIO_InitStructure.Pin = GPIO_PIN_2; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Current = GPIO_CURRENT_4mA; GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.SchmittTrigger = DISABLE; GPIO_InitStructure.Alternate = GPIO0_2_AF_SOUT0; LHL_GPIO_Init(pGPIO0, &GPIO_InitStructure); // P0.2 -> SOUT0(UART_TX) /* 2. 设置UART参数 */ UART_InitStructure.UART_BaudRate = baudrate_bps; // 硬件最高波特率需小于时钟频率/16 UART_InitStructure.UART_WordLength = UART_WordLength_8b; // 数字位数:8 UART_InitStructure.UART_StopBits = UART_StopBits_1; // 停止位数:1 UART_InitStructure.UART_Parity = UART_Parity_None; // 校验位:无 LHL_UART_Init(pUART0, &UART_InitStructure); //pUART0->IER_DLH = 0x1; /* UART_IT_EDSSI 调制解调器状态中断 UART_IT_ELSI 接收线路状态中断 UART_IT_ETBEI 发送中断 UART_IT_ERBFI 接收中断 */ // LHL_UART_ITConfig( pUART0 ,UART_IT_EDSSI|UART_IT_ELSI|UART_IT_ETBEI|UART_IT_ERBFI , ENABLE); // NVIC_SetPriority(UART0_IRQn,1); // NVIC_EnableIRQ(UART0_IRQn); } /**------------------------------------------------------------------------ * @brief 初始化 UART1,配置引脚和通信参数 * @param baudrate_bps: 波特率,单位 bps,如 115200 * @note 使用 P1.0 作为 RX(复用 SIN1),P1.1 作为 TX(复用 SOUT1), * 数据格式:8位数据、1位停止位、无校验。 * @example UART1_Init(115200); **/ void UART1_Init(uint32_t baudrate_bps) { GPIO_InitTypeDef GPIO_InitStructure; UART_InitTypeDef UART_InitStructure; /* 1. 设置 UART GPIO复用引脚 */ GPIO_InitStructure.Pin = GPIO_PIN_0; GPIO_InitStructure.Mode = GPIO_MODE_INPUT; GPIO_InitStructure.Current = GPIO_CURRENT_4mA; GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.SchmittTrigger = ENABLE; GPIO_InitStructure.Alternate = GPIO1_0_AF_SIN1; LHL_GPIO_Init(pGPIO1, &GPIO_InitStructure); // P0.1 -> SIN0(UART_RX) GPIO_InitStructure.Pin = GPIO_PIN_1; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Current = GPIO_CURRENT_4mA; GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.SchmittTrigger = DISABLE; GPIO_InitStructure.Alternate = GPIO1_1_AF_SOUT1; LHL_GPIO_Init(pGPIO1, &GPIO_InitStructure); // P0.2 -> SOUT0(UART_TX) /* 2. 设置UART参数 */ UART_InitStructure.UART_BaudRate = baudrate_bps; // 硬件最高波特率需小于时钟频率/16 UART_InitStructure.UART_WordLength = UART_WordLength_8b; // 数字位数:8 UART_InitStructure.UART_StopBits = UART_StopBits_1; // 停止位数:1 UART_InitStructure.UART_Parity = UART_Parity_None; // 校验位:无 LHL_UART_Init(pUART1, &UART_InitStructure); /* UART_IT_EDSSI 调制解调器状态中断 UART_IT_ELSI 接收线路状态中断 UART_IT_ETBEI 发送中断 UART_IT_ERBFI 接收中断 */ // LHL_UART_ITConfig( pUART1 ,UART_IT_EDSSI|UART_IT_ELSI|UART_IT_ETBEI|UART_IT_ERBFI , ENABLE); // NVIC_SetPriority(UART1_IRQn,1); // NVIC_EnableIRQ(UART1_IRQn); } /*********************************************************************************************************************************************/ /*中断方式*/ /*********************************************************************************************************************************************/ /**------------------------------------------------------------------------ * @brief UART0 中断服务函数 * @note 当前仅预留框架,未实现具体处理逻辑。 * 可根据需要在此处添加接收/发送中断处理代码。 **/ void UART0_IRQHandler(void) { /* 收发数据,读写RBR_THR_DLL寄存器: * - 读取时:作为接收缓冲寄存器(RBR),存储UART接收到的数据 * - 写入时:作为发送保持寄存器(THR),用于发送数据 */ // if (LHL_UART_GetFlag(pUART0, UART_FLAG_DR) == SET) // 判断接收中断 // if ((LHL_UART_GetFlag(pUART0, UART_FLAG_THRE) == SET) && \ // (LHL_UART_GetPending(pUART0, UART_IT_ETBEI) == SET)) // 判断发送中断 if (LHL_UART_GetPending(pUART0, UART_IT_RXNE) == SET) // 判断接收中断 { // uart_buffer[index++] = LHL_UART_ReceiveData(pUART0); // 放入缓存 } if (LHL_UART_GetPending(pUART0, UART_IT_TXE) == SET) { // if(index) // 如果缓存还有数据 // { // LHL_UART_SendData(pUART0, uart_buffer[--index]); // } // else // { // LHL_UART_SendData(pUART0, 0x00); // Send NULL // LHL_UART_ITConfig(pUART0, UART_IT_ETBEI, DISABLE); // 关闭发送中断 // } } } /**------------------------------------------------------------------------ * @brief UART1 中断服务函数 * @note 当前仅预留框架,未实现具体处理逻辑。 * 可根据需要在此处添加接收/发送中断处理代码。 **/ void UART1_IRQHandler(void) { if (LHL_UART_GetPending(pUART1, UART_IT_RXNE) == SET) // 判断接收中断 { // uart_buffer[index++] = LHL_UART_ReceiveData(pUART0); // 放入缓存 } if (LHL_UART_GetPending(pUART1, UART_IT_TXE) == SET) { } } /*********************************************************************************************************************************************/ /*DMA 方式*/ /*********************************************************************************************************************************************/ /**------------------------------------------------------------------------ * @brief 基础定时器中断回调函数(与 DMA_UART_AnyLength_Rx_Init 配合使用) * @note 当 DMA 接收超时(空闲帧)时调用,设置接收完成标志, * 停止基础定时器和 DMA 通道,并清除相关标志。 **/ void Btimer_irq_callback(void) { comState.state.ReceivedData = 1 ; //接收完成标志位 StopBtimer0(); //FY LHL_DMA_Stop(&DMA_Handle_UartRx); //FY 关闭DMA接收数据 LHL_DMA_Stop(&DMA_Handle_UartTx); //FY 关闭DMA接收数据 //LHL_DMA_ClearPending(&DMA_Handle_UartRx); //LHL_DMA_ClearPending(&DMA_Handle_UartTx); } //接收-------------------------------------------------------------------- /**------------------------------------------------------------------------ * @brief UART DMA 不定长接收初始化 * @param baudrate_bps: 波特率,用于计算空闲帧超时时间 * @note 使用 DMA 通道 UART_Rx 搬运数据,通过基础定时器监控空闲帧间隔。 * 超时时间由宏 IDLE_FRAME_INTERVAL 和系统时钟计算。 * 配置了两个 TCD 描述符用于控制基础定时器的启动/停止。 * 初始化后自动启动 DMA 接收。 * @example DMA_UART_AnyLength_Rx_Init(115200); **/ void DMA_UART_AnyLength_Rx_Init( uint32_t baudrate_bps) { DMA_HandleTypeDef DMA_Handle_BTime; DMA_InitTypeDef DMA_InitStructure[TCD_COUNT]; /* 分散聚合模式的多个初始化结构体参数 */ static DMA_DES_N_TypeDef TCD_Quene[TCD_COUNT] __ALIGN(32);/* DMA TCD描述符必须32位对齐*/ static uint8_t BTimerCTRLValue[2]; /* 定时器配置参数 */ uint16_t IdleFrameValue; /* 1 配置DMAUX 请求源UART0 RX,触发MA0 */ DMA_DMAMUX_CFG(DMA_CHANNEL_UART_Rx,REQUEST_SOURCE_UART_RX);//将DMAMUX链接到串口接收通道(DMA通道0) LHL_DMA_Stop(&DMA_Handle_UartRx); DMA_Handle_UartRx.Channel = DMA_CHANNEL_UART_Rx; //配置DMA0,请求源来自DMAMUX UART_RX,用于搬运UART RX数据 DMA_Handle_UartRx.Request = DMA_HARDWARE_REQUEST; DMA_Handle_UartRx.Mode = DMA_CHAINING_MODE; DMA_Handle_UartRx.Init.Direction = DMA_PERIPH_TO_MEMORY; // 外设->内存 DMA_Handle_UartRx.Init.Src_Address = (uint32_t)(&DMA_UART->RBR_THR_DLL); DMA_Handle_UartRx.Init.Dest_Address = (uint32_t)comState.RxdData; // 串口数据缓存区 DMA_Handle_UartRx.Init.Data_Width = DMA_DATA_WIDTH_1B; DMA_Handle_UartRx.Init.Data_Size = 1; DMA_Handle_UartRx.Init.Repetition = RXD_MAX_DATA; DMA_Handle_UartRx.Init.Trans_Mode = DMA_SINGLE_TRANSMISSION; DMA_Handle_UartRx.Init.Chaining = (DMA_CHAINING_t)DMA_CHANNEL_BtimCfg ;//理论上应该写TO_DMA_CHANNEL_x (x=01/2/3/NONE) 不过这样写简便,以适应DMA_CHANNEL_BtimCfg 改变的情况 if (LHL_DMA_Init(&DMA_Handle_UartRx) != LHL_OK) { while(1); } /*1 初始化BTIM TImer Base,用于串口空闲帧超时监控 新增ADC使用DMA序列采样流程 */ /*2 计算空闲间隔:超时时间为IDEL_FRAME_INTERVAL个数据位 */ /*3 配置BTIMER CTRL寄存器参数,DMA1负责写入 */ /*4 开启BTIM1中断:产生中断表示串口接收到一帧数据,且空闲时间超过空闲间隔设定 */ BTimerCTRLValue[0] = 0; BTimerCTRLValue[1] = BTIM_TCTRL_TEN_Msk | BTIM_TCTRL_TIE_Msk; IdleFrameValue = (uint16_t)(SystemCoreClock * IDLE_FRAME_INTERVAL / baudrate_bps) - 1; BTIM0_Init(IdleFrameValue); Btimer_register_irq_callback(BTIMER_0,Btimer_irq_callback); //注册中断函数,用于进入空闲帧判断 DMA_Handle_BTime.Channel = DMA_CHANNEL_BtimCfg; //配置DMA通道1,由DMA0触发,用于搬运BTIM设置参数 DMA_Handle_BTime.Request = DMA_HARDWARE_REQUEST; DMA_Handle_BTime.Mode = DMA_SCATTER_GATHER_MODE; // 分散-聚合模式 DMA_Handle_BTime.TCD_Count = TCD_COUNT; // TCD描述符数量 DMA_Handle_BTime.TCD_List = TCD_Quene; // TCD描述符链表 DMA_Handle_BTime.TCD_Init = DMA_InitStructure; // TCD初始化队列 DMA_InitStructure[0].Direction = DMA_MEMORY_TO_PERIPH; // TCD0用于复位BTIM寄存器 DMA_InitStructure[0].Src_Address = (uint32_t)&BTimerCTRLValue[0]; DMA_InitStructure[0].Dest_Address = (uint32_t)(&BTIM->TCTRL_0); DMA_InitStructure[0].Data_Width = DMA_DATA_WIDTH_1B; DMA_InitStructure[0].Data_Size = 1; DMA_InitStructure[0].Repetition = 1; DMA_InitStructure[0].Trans_Mode = DMA_CYCLIC_TRANSMISSION; DMA_InitStructure[0].TCD_Address = (int32_t)&TCD_Quene[1]; DMA_InitStructure[0].Auto_Start = DISABLE; DMA_InitStructure[0].INT_Major = DISABLE; DMA_InitStructure[0].INT_Half = DISABLE; DMA_InitStructure[0].Chaining = TO_DMA_CHANNEL_NONE; DMA_InitStructure[1].Direction = DMA_MEMORY_TO_PERIPH; // TCD1用于重启BTIM寄存器 DMA_InitStructure[1].Src_Address = (uint32_t)&BTimerCTRLValue[1]; DMA_InitStructure[1].Dest_Address = (uint32_t)(&BTIM->TCTRL_0); DMA_InitStructure[1].Data_Width = DMA_DATA_WIDTH_1B; DMA_InitStructure[1].Data_Size = 1; DMA_InitStructure[1].Repetition = 1; DMA_InitStructure[1].Trans_Mode = DMA_CYCLIC_TRANSMISSION; DMA_InitStructure[1].TCD_Address = (int32_t)&TCD_Quene[0]; DMA_InitStructure[1].Auto_Start = ENABLE; DMA_InitStructure[1].INT_Major = DISABLE; DMA_InitStructure[1].INT_Half = DISABLE; DMA_InitStructure[1].Chaining = TO_DMA_CHANNEL_NONE; if (LHL_DMA_Init(&DMA_Handle_BTime) != LHL_OK) { while(1); } /*DMA 配置完成开始接收*/ LHL_DMA_Start(&DMA_Handle_UartRx); /* 显式启动DMA0 ,开始接收*/ } /**------------------------------------------------------------------------ * @brief 获取 DMA 接收的实际数据长度 * @note 根据当前 DMA 目的地址与缓冲区起始地址的差值计算已接收字节数, * 结果存入 comState.RxLenth 中。 * @example Get_UART_Rx_ActualLength(); **/ void Get_UART_Rx_ActualLength(void) { /* 缓冲区数据长度计算,获取当前帧长度*/ comState.RxLenth = LHL_DMA_GetDestAddress(DMA_CHANNEL_UART_Rx) - (u32)&comState.RxdData ; } //发送-------------------------------------------------------------------- /**------------------------------------------------------------------------ * @brief UART DMA 发送初始化 * @note 使用 DMA 通道 UART_Tx 将 comState.TxdData 中的数据发送出去, * 发送长度由 comState.TxLenth 决定,单次模式。 * 使能发送完成中断,并自动启动 DMA。 * @example DMA_UART_Tx_Init(); **/ void DMA_UART_Tx_Init(void) { DMA_DMAMUX_CFG(DMA_CHANNEL_UART_Tx,REQUEST_SOURCE_UART_TX);//将DMAMUX链接到串口接收通道(DMA通道0) /* 3.4 配置DMA通道1,负责缓存区数据搬运到UART0 TX数据 */ DMA_Handle_UartTx.Channel = DMA_CHANNEL_UART_Tx; DMA_Handle_UartTx.Mode = DMA_DIRECT_MODE; DMA_Handle_UartTx.Request = DMA_HARDWARE_REQUEST; DMA_Handle_UartTx.Init.Direction = DMA_MEMORY_TO_PERIPH; // 内存->外设 DMA_Handle_UartTx.Init.Src_Address = (uint32_t)&comState.TxdData; // 源:缓存区 DMA_Handle_UartTx.Init.Dest_Address = (uint32_t)(&DMA_UART->RBR_THR_DLL); // 目的:UART TX寄存器 DMA_Handle_UartTx.Init.Data_Width = DMA_DATA_WIDTH_1B; DMA_Handle_UartTx.Init.Data_Size = 1; DMA_Handle_UartTx.Init.Repetition = comState.TxLenth ; DMA_Handle_UartTx.Init.Trans_Mode = DMA_SINGLE_TRANSMISSION; // 单次模式 if (LHL_DMA_Init(&DMA_Handle_UartTx) != LHL_OK) { while(1); // DMA Init Error } // /* 使能DMA中断 */ LHL_DMA_ITConfig(&DMA_Handle_UartTx, DMA_IT_MAJOR, ENABLE); // 配置DMA1主中断 // NVIC_EnableIRQ(DMA1_CH0_IRQn); //DMA_CHANNEL_UART_Tx LHL_DMA_Start(&DMA_Handle_UartTx); /* 显式启动DMA0 ,开始发送*/ }