基于STM32F103RC操作
程序混用HAL和LL库
CubeMX配置
配置时钟
串口参数
- 波特率:115200
- 长度:8bit
- 无校验
- 1停止位
设置DMA
- TX:默认内存到外设,以Byte传输,使用DMA2通道5(根据需求可按手册重映射)
- RX:默认外设到内存,需将模式改为循环模式(当收到后续数据可以更新),以Byte传输,使用DMA2通道3(根据需求可按手册重映射)
- 启用串口中断
项目生成
- 将串口更换为LL库
- 设置项目
编码
采用两级缓冲,同时一级缓冲(DMA直接建立通讯的内存数据)须定义为全局变量。
定义(main.h)
/* USER CODE BEGIN ET */
#define UART_TX_LEN 10
#define UART_RX_LEN 10
typedef struct
{
/* L1 buffer */
uint8_t txBuf[UART_TX_LEN];
uint8_t rxBuf[UART_RX_LEN];
_Bool rx_flag;
uint8_t rx_len;
/* L2 buffer */
uint8_t txBuf2[UART_TX_LEN];
uint8_t rxBuf2[UART_RX_LEN];
}UART_Struct_t;
extern UART_Struct_t UART_Struct;
/* USER CODE END ET */
/* USER CODE BEGIN EFP */
void UART_SendBuf(uint16_t len);
/* USER CODE END EFP */
DMA空闲中断接收(stm32f1xx_it.c)
/* USER CODE BEGIN Includes */
#include <string.h>
/* USER CODE END Includes */
/**
* @brie
* f This function handles UART4 global interrupt.
*/
void UART4_IRQHandler(void)
{
/* USER CODE BEGIN UART4_IRQn 0 */
if (LL_USART_IsActiveFlag_IDLE(UART4))
{
LL_DMA_DisableChannel(DMA2, LL_DMA_CHANNEL_3);
uint16_t len = UART_RX_LEN - LL_DMA_GetDataLength(DMA2, LL_DMA_CHANNEL_3) - 1;
if (len <= 0) len = UART_RX_LEN - 1;
UART_Struct.rx_len = len;
memcpy(UART_Struct.rxBuf2, UART_Struct.rxBuf, len);
LL_DMA_SetDataLength(DMA2, LL_DMA_CHANNEL_3, len);
UART_Struct.rx_flag = 1;
LL_DMA_EnableChannel(DMA2, LL_DMA_CHANNEL_3);
LL_USART_ClearFlag_IDLE(UART4);
}
/* USER CODE END UART4_IRQn 0 */
/* USER CODE BEGIN UART4_IRQn 1 */
/* USER CODE END UART4_IRQn 1 */
}
DMA发送(main.c)
/* USER CODE BEGIN Includes */
#include <string.h>
#include <stdio.h>
/* USER CODE END Includes */
/* USER CODE BEGIN PV */
UART_Struct_t UART_Struct;
/* USER CODE END PV */
/* USER CODE BEGIN 0 */
void UART_DMA_Init(void)
{
/* RX DMA Config */
LL_DMA_SetMemoryAddress(DMA2, LL_DMA_CHANNEL_3, (uint32_t)UART_Struct.rxBuf);
LL_DMA_SetPeriphAddress(DMA2, LL_DMA_CHANNEL_3, (uint32_t)(&UART4->DR));
LL_DMA_SetDataLength(DMA2, LL_DMA_CHANNEL_3, UART_RX_LEN);
LL_DMA_EnableChannel(DMA2, LL_DMA_CHANNEL_3);
/* TX DMA Config */
LL_DMA_SetMemoryAddress(DMA2, LL_DMA_CHANNEL_5, (uint32_t)UART_Struct.txBuf);
LL_DMA_SetPeriphAddress(DMA2, LL_DMA_CHANNEL_5, (uint32_t)(&UART4->DR));
LL_DMA_SetDataLength(DMA2, LL_DMA_CHANNEL_5, UART_TX_LEN);
/* UART Enable */
LL_USART_EnableIT_IDLE(UART4);
LL_USART_EnableDMAReq_RX(UART4);
LL_USART_EnableDMAReq_TX(UART4);
}
void UART_SendBuf(uint16_t len)
{
while(!LL_USART_IsActiveFlag_TC(UART4));
LL_DMA_ClearFlag_TC5(DMA2);
LL_DMA_DisableChannel(DMA2, LL_DMA_CHANNEL_5);
memcpy(UART_Struct.txBuf, UART_Struct.txBuf2, len);
LL_DMA_SetDataLength(DMA2, LL_DMA_CHANNEL_5, len);
LL_DMA_EnableChannel(DMA2, LL_DMA_CHANNEL_5);
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_UART4_Init();
/* USER CODE BEGIN 2 */
UART_DMA_Init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
if (UART_Struct.rx_flag)
{
UART_Struct.rx_flag = 0;
UART_Struct.txBuf2[0] = 1;
UART_Struct.txBuf2[1] = 2;
}
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
阻塞式发送(main.c)
int fputc(int ch, FILE *f)
{
while(!LL_USART_IsActiveFlag_TC(UART4));
LL_USART_TransmitData8(UART4, (uint8_t)ch);
}