#include "../main/SystemInclude.h" DMA_HandleTypeDef DMA_Handle_UartRx , DMA_Handle_UartTx ; /*********************************************************************************************************************************************/ /*初始化*/ /*********************************************************************************************************************************************/ 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); } 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中断服务函数(Interrupt Service Routine, ISR) * @note 此函数在UART0中断触发时自动调用(接收到数据) * @warning 中断处理应尽量简短,避免长时间阻塞其他中断 */ 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中断服务函数(Interrupt Service Routine, ISR) * @note 此函数在UART1中断触发时自动调用(接收到数据) * @warning 中断处理应尽量简短,避免长时间阻塞其他中断 */ 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 方式*/ /*********************************************************************************************************************************************/ /* 基础定时器中断回调函数 与DMA_UART_AnyLength_Rx_Init 联合使用 */ void Btimer_irq_callback(void) { comState.state.ReceivedData = 1 ;//接收完成标志位 } //接收-------------------------------------------------------------------- /* UART DMA不定长接收初始化 DMA_CHANNEL 使用两个通道作为串口DMA收发使用,RX TX共用一个,Btime0使用一个, 两个串口物理接口都使用这两个DMA通道,使用宏 DMA_USE_UART_CHOOSE 切换UART0或者UART1来使用这两个DMA通道 */ 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 ,开始接收*/ } //获取不定长接收实际长度 void Get_UART_Rx_ActualLength(void) { /* 缓冲区数据长度计算,获取当前帧长度*/ comState.RxLenth = LHL_DMA_GetDestAddress(DMA_CHANNEL_UART_Rx) - (u32)&comState.RxdData ; } //发送-------------------------------------------------------------------- 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 ,开始发送*/ }