UART_DMA_DBUS
UART
-
打开UART或者USART-选择Asynchronous
-
Asynchronous - 异步通信
Synchronous - 同步通信
-
打开Parameter Settings选项卡
-
分别配置波特率、数据位长度、校验位、停止位
-
数据方向根据需求配置
-
过采样一般默认16
-
NVIC Setting选项卡中打开串口中断-根据需求自行开启
-
DMA Setting-Add-一般默认即可
-
优先级根据需求调整
-
GPIO Setting-检查IO口是否选择正确
UART基础配置完成
DMA
- DMA配置可以使用HAL库函数直接配置
- 也可以自己仿照HAL库函数进行配置
- 此处采用自己配置的方式配置DMA
DAM_init
void DMA_init(void)
{
//enable the DMA transfer for the receiver request
SET_BIT(huart3.Instance->CR3, USART_CR3_DMAR);
//enalbe idle interrupt
__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
//disable DMA
__HAL_DMA_DISABLE(&hdma_usart3_rx);
while(hdma_usart3_rx.Instance->CR & DMA_SxCR_EN)
{
__HAL_DMA_DISABLE(&hdma_usart3_rx);
}
hdma_usart3_rx.Instance->PAR = (uint32_t) & (USART3->DR);
//memory buffer 1
hdma_usart3_rx.Instance->M0AR = (uint32_t)(sbus_rx_buf[0]);
//memory buffer 2
hdma_usart3_rx.Instance->M1AR = (uint32_t)(sbus_rx_buf[1]);
//data length
hdma_usart3_rx.Instance->NDTR = SBUS_RX_BUF_NUM;
//enable double memory buffer
SET_BIT(hdma_usart3_rx.Instance->CR, DMA_SxCR_DBM);
//enable DMA
__HAL_DMA_ENABLE(&hdma_usart3_rx);
}
注:此处需要更改的关键字如下:
huart3 — 对应串口句柄
hdma_usart3_rx — 对应串口DMA接收句柄
USART3 — 对应串口句柄
sbus_rx_buf[0] — 对应DMA第一缓冲区
sbus_rx_buf[1] — 对应DMA第二缓冲区
DMA_use
void DMA_receive(void)
{
if(huart3.Instance->SR & UART_FLAG_RXNE)
{
__HAL_UART_CLEAR_PEFLAG(&huart3);
}
else if(USART3->SR & UART_FLAG_IDLE)
{
static uint16_t this_time_rx_len = 0;
__HAL_UART_CLEAR_PEFLAG(&huart3);
if ((hdma_usart3_rx.Instance->CR & DMA_SxCR_CT) == RESET)
{
/* Current memory buffer used is Memory 0 */
//disable DMA
__HAL_DMA_DISABLE(&hdma_usart3_rx);
//get receive data length, length = set_data_length - remain_length
this_time_rx_len = SBUS_RX_BUF_NUM - hdma_usart3_rx.Instance->NDTR;
//reset set_data_lenght
hdma_usart3_rx.Instance->NDTR = SBUS_RX_BUF_NUM;
//set memory buffer 1
hdma_usart3_rx.Instance->CR |= DMA_SxCR_CT;
//enable DMA
__HAL_DMA_ENABLE(&hdma_usart3_rx);
if(this_time_rx_len == RC_FRAME_LENGTH)
{
sbus_to_rc(sbus_rx_buf[0], &rc);
}
}
else
{
/* Current memory buffer used is Memory 1 */
//disable DMA
__HAL_DMA_DISABLE(&hdma_usart3_rx);
//get receive data length, length = set_data_length - remain_length
this_time_rx_len = SBUS_RX_BUF_NUM - hdma_usart3_rx.Instance->NDTR;
//reset set_data_lenght
hdma_usart3_rx.Instance->NDTR = SBUS_RX_BUF_NUM;
//set memory buffer 0
DMA1_Stream1->CR &= ~(DMA_SxCR_CT);
//enable DMA
__HAL_DMA_ENABLE(&hdma_usart3_rx);
if(this_time_rx_len == RC_FRAME_LENGTH)
{
sbus_to_rc(sbus_rx_buf[1], &rc);
}
}
}
}
注:此处需要更改的关键字如下:
huart3 — 对应串口句柄
hdma_usart3_rx — 对应串口DMA接收句柄
USART3 — 对应串口句柄
sbus_rx_buf[0] — 对应DMA第一缓冲区
sbus_rx_buf[1] — 对应DMA第二缓冲区
SBUS_RX_BUF_NUM — DMA缓冲区给的空间长度
RC_FRAME_LENGTH — DMA接收到的目标数据长度
sbus_to_rc — 处理DMA接收到的数据的函数
DMA1_Stream1 — 对应的DMA数据流
最后需要在串口回调函数里调用 - DMA_receive()
eg: - 此处以串口3的回调函数为例
void USART3_IRQHandler(void)
{
/* USER CODE BEGIN USART3_IRQn 0 */
DMA_receive();
/* USER CODE END USART3_IRQn 0 */
HAL_UART_IRQHandler(&huart3);
/* USER CODE BEGIN USART3_IRQn 1 */
/* USER CODE END USART3_IRQn 1 */
}
对DMA的理解
DMA_init()
- 使能DMA串口接收
- 使能串口空闲中断
- 先暂时关闭DMA,以便对DMA进行配置
- 配置DMA外设地址 - 此处用于串口接收,所以配置为串口的DR数据寄存器
- 配置DMA第一缓冲区地址
- 配置DMA第二缓冲区地址
- 配置DMA数据长度 - 此处一般配置为实际接收数据的两倍
- 使能双缓冲区配置
- 使能DMA - DMA配置完成后打开DMA
DMA_use
- 如果接收到数据并且串口有空闲中断触发
- 先关闭DMA
- 获取这一次接收到的数据长度
- 重新设定下一次接收的数据长度
- 重新设定下一次接收的缓冲器的地址
- 打开DMA-使能DMA
- 如果这一次接收到的数据长度等于我DMA接收目标数据长度
- 则对DMA接收到的数据进行解析处理 - sbus_to_rc ()
- 下一次就使用另外一个缓冲区进行接收
- 最后在串口中断回调函数里调用就可以
DBUS
在串口前面加一个反相器