Files
CHJ/user/MCU/lhl_uart.c
2026-03-20 21:19:04 +08:00

279 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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 ,开始发送*/
}