本文是基于STM32G431的LL庫做的,針對裸機(jī)的串口接收和發(fā)送庫。其中UART接收采用DMA+idle中斷+多級緩沖模式。
1. 結(jié)構(gòu)體
先創(chuàng)建幾個(gè)必要的結(jié)構(gòu)體
typedef struct uart_rx {
uint8_t mode;
uint8_t *buf; /* poniter to receive buf */
uint16_t size;
uint32_t wr_index;
uint32_t rd_index;
FlagStatus cplt_flag;
#ifdef UART_RX_MODE_DMA
DMA_TypeDef *dma;
uint32_t dma_channel;
#endif
Queue_TypeDef queue;
} *uart_rx_t;
typedef struct uart_tx {
uint8_t mode;
uint8_t *buf;
uint32_t size;
uint32_t count;
FlagStatus cplt_flag;
#ifdef UART_TX_MODE_DMA
DMA_TypeDef *dma;
uint32_t dma_channel;
#endif
} *uart_tx_t;
typedef struct uart_handle {
USART_TypeDef *periph;
struct uart_tx tx;
struct uart_rx rx;
} *uart_handle_t;
2.初始化
直接上代碼
#ifdef UART2_ENABLE
struct uart_handle huart2;
static uint8_t uart2_recv_buf[UART2_RECV_BUF_SIZE];
#endif
static void dma_set_config(DMA_TypeDef *hdma, uint32_t channel, uint32_t src_address, uint32_t dst_address, uint32_t data_length)
{
if (LL_DMA_GetDataTransferDirection(hdma, channel) == LL_DMA_DIRECTION_PERIPH_TO_MEMORY) {
// LL_DMA_SetM2MDstAddress(hdma, channel, dst_address);
LL_DMA_SetMemoryAddress(hdma, channel, dst_address);
LL_DMA_SetDataLength(hdma, channel, data_length);
LL_DMA_SetPeriphAddress(hdma, channel, src_address);
} else if (LL_DMA_GetDataTransferDirection(hdma, channel) == LL_DMA_DIRECTION_MEMORY_TO_PERIPH) {
// LL_DMA_SetM2MSrcAddress(hdma, channel, src_address);
LL_DMA_SetMemoryAddress(hdma, channel, src_address);
LL_DMA_SetDataLength(hdma, channel, data_length);
LL_DMA_SetPeriphAddress(hdma, channel, dst_address);
} else if (LL_DMA_GetDataTransferDirection(hdma, channel) == LL_DMA_DIRECTION_MEMORY_TO_MEMORY) {
/* TODO: */
} else {
/* TODO: */
}
}
void bsp_uart2_init(uint32_t baudrate)
{
/* USER CODE BEGIN USART2_Init 0 */
/* USER CODE END USART2_Init 0 */
LL_USART_InitTypeDef USART_InitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the peripherals clocks
*/
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2;
PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
Error_Handler();
}
/* Peripheral clock enable */
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART2);
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
/**USART2 GPIO Configuration
PA2 ------> USART2_TX
PA3 ------> USART2_RX
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_2;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_7;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_3;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_7;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USART2 DMA Init */
/* DMA2_Channel1_IRQn interrupt configuration */
// NVIC_SetPriority(DMA2_Channel1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 7, 0));
// NVIC_EnableIRQ(DMA2_Channel1_IRQn);
/* DMA2_Channel2_IRQn interrupt configuration */
NVIC_SetPriority(DMA2_Channel2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 7, 0));
NVIC_EnableIRQ(DMA2_Channel2_IRQn);
/* USART2_RX Init */
LL_DMA_SetPeriphRequest(DMA2, LL_DMA_CHANNEL_1, LL_DMAMUX_REQ_USART2_RX);
LL_DMA_SetDataTransferDirection(DMA2, LL_DMA_CHANNEL_1, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_SetChannelPriorityLevel(DMA2, LL_DMA_CHANNEL_1, LL_DMA_PRIORITY_LOW);
LL_DMA_SetMode(DMA2, LL_DMA_CHANNEL_1, LL_DMA_MODE_CIRCULAR);
LL_DMA_SetPeriphIncMode(DMA2, LL_DMA_CHANNEL_1, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA2, LL_DMA_CHANNEL_1, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA2, LL_DMA_CHANNEL_1, LL_DMA_PDATAALIGN_BYTE);
LL_DMA_SetMemorySize(DMA2, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_BYTE);
/* USART2_TX Init */
LL_DMA_SetPeriphRequest(DMA2, LL_DMA_CHANNEL_2, LL_DMAMUX_REQ_USART2_TX);
LL_DMA_SetDataTransferDirection(DMA2, LL_DMA_CHANNEL_2, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetChannelPriorityLevel(DMA2, LL_DMA_CHANNEL_2, LL_DMA_PRIORITY_LOW);
LL_DMA_SetMode(DMA2, LL_DMA_CHANNEL_2, LL_DMA_MODE_NORMAL);
LL_DMA_SetPeriphIncMode(DMA2, LL_DMA_CHANNEL_2, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA2, LL_DMA_CHANNEL_2, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA2, LL_DMA_CHANNEL_2, LL_DMA_PDATAALIGN_BYTE);
LL_DMA_SetMemorySize(DMA2, LL_DMA_CHANNEL_2, LL_DMA_MDATAALIGN_BYTE);
/* USART2 interrupt Init */
NVIC_SetPriority(USART2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 7, 0));
NVIC_EnableIRQ(USART2_IRQn);
/* USER CODE BEGIN USART2_Init 1 */
/* USER CODE END USART2_Init 1 */
USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1;
USART_InitStruct.BaudRate = baudrate;
USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
USART_InitStruct.Parity = LL_USART_PARITY_NONE;
USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;
LL_USART_Init(USART2, &USART_InitStruct);
LL_USART_SetTXFIFOThreshold(USART2, LL_USART_FIFOTHRESHOLD_1_8);
LL_USART_SetRXFIFOThreshold(USART2, LL_USART_FIFOTHRESHOLD_1_8);
LL_USART_DisableFIFO(USART2);
LL_USART_ConfigAsyncMode(USART2);
/* USER CODE BEGIN WKUPType USART2 */
/* USER CODE END WKUPType USART2 */
/* USER CODE BEGIN USART2_Init 2 */
huart2.periph = USART2;
huart2.rx.mode = UART_RX_MODE_DMA;
huart2.rx.buf = uart2_recv_buf;
huart2.rx.rd_index = 0;
huart2.rx.wr_index = 0;
huart2.rx.size = UART2_RECV_BUF_SIZE;
huart2.rx.cplt_flag = RESET;
huart2.rx.dma = DMA2;
huart2.rx.dma_channel = LL_DMA_CHANNEL_1;
dma_set_config(DMA2, LL_DMA_CHANNEL_1, (uint32_t) & (USART2->RDR), (uint32_t)uart2_recv_buf, UART2_RECV_BUF_SIZE);
/* DMA可以搬運(yùn)數(shù)據(jù)了 */
huart2.tx.mode = UART_TX_MODE_DMA;
huart2.tx.buf = NULL;
huart2.tx.count = 0;
huart2.tx.size = 0;
huart2.tx.cplt_flag = SET; /* 默認(rèn)發(fā)送結(jié)束 */
huart2.tx.dma = DMA2;
huart2.tx.dma_channel = LL_DMA_CHANNEL_2;
QueueCreat(&huart2.rx.queue);
// LL_DMA_EnableIT_TC(DMA2, LL_DMA_CHANNEL_1); /* 使能發(fā)送給完成中斷 */
LL_DMA_EnableChannel(DMA2, LL_DMA_CHANNEL_1); /* 使能DMA指定通道 */
/* 使能串口IDLE中斷 */
LL_USART_EnableDMAReq_RX(USART2);
LL_USART_EnableDMAReq_TX(USART2);
LL_USART_EnableIT_IDLE(USART2);
LL_USART_Enable(USART2);
/* Polling USART2 initialisation */
while ((!(LL_USART_IsActiveFlag_TEACK(USART2))) || (!(LL_USART_IsActiveFlag_REACK(USART2)))) {}
/* USER CODE END USART2_Init 2 */
}
我比較喜歡用cubemx生產(chǎn)初始化代碼,然后添加需要增加的必要初始化。有幾個(gè)重要的點(diǎn)需要注意一下:
1. UART DMA接收設(shè)置了循環(huán)模式,這樣做可以少開一個(gè)DMA接收完成中斷。UART DMA發(fā)送采用正常模式。
2. 使能UART IDLE中斷,這樣做的好處是,UART每次收到一包數(shù)據(jù)之后,會(huì)產(chǎn)生一個(gè)IDLE中斷,通過讀DMA相關(guān)寄存器,可以獲取包數(shù)據(jù)的長度。
3. 中斷接收、
直接貼代碼
int bsp_uart_receive(uart_handle_t huart, uint8_t *pbuf, uint16_t size, uint32_t timeout)
{
int i, retval = -1;
上一篇:stm32系統(tǒng)架構(gòu)及其時(shí)鐘系統(tǒng)
下一篇:重學(xué)STM32---(十)之CAN通信(二)
推薦閱讀最新更新時(shí)間:2025-06-17 12:00




設(shè)計(jì)資源 培訓(xùn) 開發(fā)板 精華推薦
- Microchip 升級數(shù)字信號(hào)控制器(DSC)產(chǎn)品線 推出PWM 分辨率和 ADC 速度業(yè)界領(lǐng)先的新器件
- 意法半導(dǎo)體STM32MP23x:突破成本限制的工業(yè)AI應(yīng)用核心
- 意法半導(dǎo)體推出用于匹配遠(yuǎn)距離無線微控制器STM32WL33的集成的匹配濾波芯片
- ESP32開發(fā)板連接TFT顯示屏ST7789跳坑記
- 如何讓ESP32支持analogWrite函數(shù)
- LGVL配合FreeType為可變字體設(shè)置字重-ESP32篇
- 使用樹莓派進(jìn)行 ESP32 Jtag 調(diào)試
- ESP32怎么在SPIFFS里面存儲(chǔ)html,css,js文件,以及網(wǎng)頁和arduino的通訊
- ESP32 freeRTOS使用測試
- #第八屆立創(chuàng)電賽#語音時(shí)鐘
- 使用 Analog Devices 的 ADP2311 的參考設(shè)計(jì)
- AM2S-0503SH30Z 3.3V 2瓦直流轉(zhuǎn)直流轉(zhuǎn)換器的典型應(yīng)用
- 用電設(shè)備智能監(jiān)控系統(tǒng)畢設(shè)
- 使用 ON Semiconductor 的 FAN7171_F085 的參考設(shè)計(jì)
- LT3460EDC-1 5V 至 36V 升壓轉(zhuǎn)換器的典型應(yīng)用電路
- OM13560: PTN3356評估板
- NCP300LSN20T1 2V 窗口電壓檢測器的典型應(yīng)用
- Recoil 電機(jī)控制器 G431 DRV8350RS
- 【訓(xùn)練營】【物聯(lián)網(wǎng)實(shí)戰(zhàn)】-智能RGB燈-699720A
- CANape 23開啟智能測試新時(shí)代(下)
- 軟件定義汽車電源管理設(shè)計(jì):NXP的PMIC選型攻略解析
- 深度測評時(shí)空壺X1同聲傳譯器:全球最先進(jìn)AI同傳設(shè)備的非凡實(shí)力
- 作為領(lǐng)先的垂直整合制造商(IDM),英飛凌在 300mm氮化鎵生產(chǎn)路線圖方面取得突破
- 鐵威馬F6-424 Max:六盤位擴(kuò)容+國產(chǎn)系統(tǒng)兼容,小白也能玩轉(zhuǎn)NAS
- 開關(guān)電源給鉛酸電池恒流恒壓充電的電流跳動(dòng)問題解析
- 自動(dòng)駕駛中的激光雷達(dá)是否會(huì)傷害攝像頭?
- 觸覺技術(shù)助力企業(yè)在激烈的市場競爭中脫穎而出
- 芯片中的串?dāng)_噪聲有幾類
- 內(nèi)置的溫度傳感器或外部溫度檢測電路來實(shí)現(xiàn)溫度保護(hù)
- 智能電銷機(jī)器人賦能的僅是點(diǎn)對點(diǎn)營銷?
- 國產(chǎn)工業(yè)機(jī)器人跟“四大家族”比為何還有如此大的差異
- 寶馬、戴姆勒等11家車企聯(lián)合,首個(gè)自動(dòng)駕駛標(biāo)準(zhǔn)聯(lián)盟成立
- 超導(dǎo)電硅負(fù)極添加劑已開始在中國生產(chǎn)
- 開源時(shí)代的風(fēng)險(xiǎn)是什么?
- 英特爾執(zhí)行長科再奇開幕演說:大數(shù)據(jù)浪潮來襲
- 聯(lián)發(fā)科推智能電視芯片MT5598 支持HDR與120Hz 4K UHD
- 賽普拉斯為聯(lián)網(wǎng)汽車帶來卓越的車載信息娛樂體驗(yàn)
- Milbeaut影像處理器助攻智能裝置市場
- ST、Cinemo和Valens在CES 2018展上聯(lián)合演示汽車信息娛樂解決方案