国产精品久久久久影院,成人午夜福利视频,国产精品久久久久高潮,国产精品 欧美 亚洲 制服,国产精品白浆无码流出

STM32:串口多級緩沖接收

發(fā)布者:幸福之舞最新更新時(shí)間:2025-01-22 來源: jianshu關(guān)鍵字:STM32  串口 手機(jī)看文章 掃描二維碼
隨時(shí)隨地手機(jī)看文章

本文是基于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;

[1] [2]
關(guān)鍵字:STM32  串口 引用地址:STM32:串口多級緩沖接收

上一篇:stm32系統(tǒng)架構(gòu)及其時(shí)鐘系統(tǒng)
下一篇:重學(xué)STM32---(十)之CAN通信(二)

推薦閱讀最新更新時(shí)間:2025-06-17 12:00

STM32串口收發(fā)數(shù)據(jù)使用DMA的原因
STM32串口收發(fā)數(shù)據(jù)使用DMA的原因主要有以下幾點(diǎn): 1.提高數(shù)據(jù)傳輸效率 :DMA(Direct Memory Access)是一種能夠直接從內(nèi)存中讀取或?qū)懭霐?shù)據(jù)的硬件設(shè)備。在嵌入式系統(tǒng)設(shè)計(jì)中,DMA技術(shù)被廣泛應(yīng)用于數(shù)據(jù)傳輸速度較高或需要高效數(shù)據(jù)傳輸?shù)膱龊?。而STM32的串口通信是一種高速數(shù)據(jù)傳輸方式,因此,使用DMA進(jìn)行數(shù)據(jù)收發(fā)能夠提高數(shù)據(jù)傳輸?shù)男屎涂煽啃浴?2.減輕CPU負(fù)擔(dān) :使用DMA進(jìn)行串口數(shù)據(jù)收發(fā)可以減輕CPU的負(fù)擔(dān)。在傳統(tǒng)的數(shù)據(jù)收發(fā)方式中,CPU需要不斷輪詢串口狀態(tài),讀取或?qū)懭霐?shù)據(jù)。這種方式不僅會(huì)占用大量的CPU資源,而且會(huì)降低系統(tǒng)的響應(yīng)速度。而使用DMA后,數(shù)據(jù)傳輸可以在后臺(tái)進(jìn)行,無需CPU干預(yù),從而釋放CP
[單片機(jī)]
STM32串口通信過程詳解
按照數(shù)據(jù)傳送方向分類: 單工:數(shù)據(jù)傳輸只支持?jǐn)?shù)據(jù)在一個(gè)方向上傳輸; 半雙工:允許數(shù)據(jù)在兩個(gè)方向上傳輸。但是,在某一時(shí)刻,只允許數(shù)據(jù)在一個(gè)方向上傳輸,它實(shí)際上是一種切換方向的單工通信;它不需要獨(dú)立的接收端和發(fā)送端,兩者可以合并一起使用一個(gè)端口; 全雙工:允許數(shù)據(jù)同時(shí)在兩個(gè)方向上傳輸。因此,全雙工通信是兩個(gè)單工通信方式的結(jié)合,需要獨(dú)立的接收端和發(fā)送端。 分別如下圖中的a、b、c所示: 按照通信方式分類: 同步通信:帶時(shí)鐘同步信號(hào)傳輸。比如:SPI,IIC通信接口; 異步通信:不帶時(shí)鐘同步信號(hào)。比如:UART(通用異步收發(fā)器),單總線; 在同步通訊中,收發(fā)設(shè)備上方會(huì)使用一根信號(hào)線傳輸信號(hào),在時(shí)鐘信號(hào)的驅(qū)動(dòng)下雙方進(jìn)行協(xié)調(diào),同步數(shù)
[單片機(jī)]
<font color='red'>STM32</font><font color='red'>串口</font>通信過程詳解
STM32串口波特率大小計(jì)算案例
波特率的計(jì)算 STM32下的波特率和串口外設(shè)時(shí)鐘息息相關(guān),USART 1的時(shí)鐘來源于APB2,USART 2-5的時(shí)鐘來源于APB1。在STM32中,有個(gè)波特率寄存器USART_BRR,如下: STM32串口波特率通過USART_BRR進(jìn)行設(shè)置,STM32的波特率寄存器支持分?jǐn)?shù)設(shè)置,以提高精確度。USART_BRR的前4位用于表示小數(shù),后12位用于表示整數(shù)。但是它還不是我們想要設(shè)置的波特率,想要設(shè)置我們串口的波特率大小還需要進(jìn)行計(jì)算。其實(shí)有關(guān)波特率的計(jì)算是下面這一條表達(dá)式: 從上面的表達(dá)式,我們引入了一個(gè)新量USARTDIV,它表示對串口的時(shí)鐘源fck進(jìn)行分頻。假設(shè)我們已知道了波特率和fck時(shí)鐘頻率的大小,那么通過上式便可
[單片機(jī)]
<font color='red'>STM32</font><font color='red'>串口</font>波特率大小計(jì)算案例
STM32CubeIDE 的應(yīng)用: 重定向printf 到stm32串口
一、導(dǎo)入stdio.h庫文件 /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include stdio.h /* USER CODE END Includes */ 二、重寫函數(shù) /* USER CODE BEGIN 4 */ #ifdef __GNUC__ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #define GETCHAR_PROTOTYPE int __io_getcha
[單片機(jī)]
STM32學(xué)習(xí)【2】STM32F103C8T6串口2USART2程序
STM32F103C8T6串口1(PA10/RXD1,PA9/TXD1)用來燒寫程序,串口2(PA3/RXD2,PA2/TXD2)接串口模塊與電腦串口助手通信。IO口PA1接LED+470R電阻+D3V3。 調(diào)試后,能正常運(yùn)行的程序如下: #include stm32f10x.h #include stm32f10x_usart.h #define LED_ON GPIO_ResetBits(GPIOA ,GPIO_Pin_1) #define LED_OFF GPIO_SetBits(GPIOA ,GPIO_Pin_1) void GPIO_Config(void); void USART2_Config(vo
[單片機(jī)]
<font color='red'>STM32</font>學(xué)習(xí)【2】STM32F103C8T6<font color='red'>串口</font>2USART2程序
STM32 HAL庫 串口DMA發(fā)送完成中斷
近期使用STM32驅(qū)動(dòng)MAX3485進(jìn)行485通信,發(fā)現(xiàn)STM32F103C8并不自帶硬件485首發(fā)功能,需要軟件上控制IO高低來驅(qū)動(dòng)MAX3485進(jìn)行485接收、485發(fā)送。 根據(jù)MAX3485手冊可得,進(jìn)行485發(fā)送時(shí)給相應(yīng)引腳高電平。其余時(shí)間為低電平進(jìn)行485接收。因此需要找到串口DMA發(fā)送完成的回調(diào)函數(shù),在發(fā)送完成后將引腳拉低。 在stm32f1xx_hal_uart.c中 /** @defgroup UART_Exported_Functions_Group2 IO operation functions * @brief UART Transmit and Receive functions * @verb
[單片機(jī)]
基于STM32串口環(huán)形隊(duì)列IAP調(diào)試心得
IAP很常見了,我這里主要是記錄一下我所使用的方法,調(diào)試也花了兩天時(shí)間。我所用的型號(hào)是STM32F103C8T6,這個(gè)片子估計(jì)是目前性價(jià)比最高的了,所以平時(shí)也都是用的這個(gè)。這個(gè)IC有64KFlash和20K的RAM,也有小道說有后置隱藏的64K,也就是說其實(shí)是有128K,我一直也沒有測試,有空測測,有大神這樣說,估計(jì)是可以的。這里重點(diǎn)記錄一下我寫的IAP思路和代碼以及細(xì)節(jié)和遇到坑的地方。先大體的概述一下,最后貼上我認(rèn)為重點(diǎn)的代碼。 在概述之前先要解決一個(gè)問題,那就是sram空間和flash空間的問題,sram只有20K,flash有64k。 解決的辦法有很多: 1)最常見的就是自己寫上位機(jī)軟件,通過分包發(fā)送,期間還可以
[單片機(jī)]
基于<font color='red'>STM32</font>的<font color='red'>串口</font>環(huán)形隊(duì)列IAP調(diào)試心得
STM32小白入門(第六天)-------串口通信
今天要講的是串口通信,個(gè)人覺得挺重要的,以后USART、藍(lán)牙通信,485等等都要用到串口,面試官也喜歡問一些串口的問題,比如問你串口參數(shù),數(shù)據(jù)位幾位,波特率多少,還會(huì)問你怎樣設(shè)置串口等等。 一、串口概述 1. 定義 串口通信是一種設(shè)備間非常常用的串行,以比特位的形式發(fā)送或接收數(shù)據(jù),電子工程師經(jīng)常使用這種方式來調(diào)試數(shù)據(jù)。 2. 開發(fā)板硬件用于串口跟PC相連的時(shí)候有以下注意事項(xiàng): A. 使用到usb轉(zhuǎn)串口,所以得安裝驅(qū)動(dòng) B. 跳線帽要進(jìn)行短接 二、程序設(shè)計(jì) 1、設(shè)置引腳功能復(fù)用 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA時(shí)
[單片機(jī)]
小廣播
設(shè)計(jì)資源 培訓(xùn) 開發(fā)板 精華推薦

最新單片機(jī)文章

 
EEWorld訂閱號(hào)

 
EEWorld服務(wù)號(hào)

 
汽車開發(fā)圈

 
機(jī)器人開發(fā)圈

電子工程世界版權(quán)所有 京ICP證060456號(hào) 京ICP備10001474號(hào)-1 電信業(yè)務(wù)審批[2006]字第258號(hào)函 京公網(wǎng)安備 11010802033920號(hào) Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved