324 lines
14 KiB
C
324 lines
14 KiB
C
#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 ,开始发送*/
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|