日本a√视频在线,久久青青亚洲国产,亚洲一区欧美二区,免费g片在线观看网站

        <style id="k3y6c"><u id="k3y6c"></u></style>
        <s id="k3y6c"></s>
        <mark id="k3y6c"></mark>
          
          

          <mark id="k3y6c"></mark>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 基于 STM32F4 的串口通信驅(qū)動(dòng)實(shí)現(xiàn)詳解(環(huán)形緩沖區(qū)版)

          基于 STM32F4 的串口通信驅(qū)動(dòng)實(shí)現(xiàn)詳解(環(huán)形緩沖區(qū)版)

          作者:嵌入式芯視野 時(shí)間:2025-07-09 來源:今日頭條 收藏

          在嵌入式系統(tǒng)開發(fā)中,串口通信(UART)是最常用的基礎(chǔ)通信方式之一。為了解決串口數(shù)據(jù)讀寫的不連續(xù)性問題,通常會(huì)配合環(huán)形緩沖區(qū)使用,以實(shí)現(xiàn)高效、穩(wěn)定的數(shù)據(jù)收發(fā)緩存管理。

          本文介紹一個(gè)基于 STM32F4 系列 MCU 編寫的,采用中斷方式配合發(fā)送/接收緩沖區(qū),并封裝為控制臺(tái)接口,便于在系統(tǒng)中調(diào)用。

          一、串口緩沖區(qū)定義與初始化

          串口收發(fā)數(shù)據(jù)通常不直接讀寫寄存器,而是通過緩沖機(jī)制管理數(shù)據(jù)流。本例中使用了兩個(gè)環(huán)形緩沖區(qū) rxbuf 和 txbuf,分別用于接收和發(fā)送:

          static unsigned char rxbuf[TTY_RXBUF_SIZE];  // 接收緩沖區(qū)static unsigned char txbuf[TTY_TXBUF_SIZE];  // 發(fā)送緩沖區(qū)static ring_buf_t rbsend, rbrecv;            // 緩沖區(qū)控制結(jié)構(gòu)體

          并在串口初始化時(shí)調(diào)用 ring_buf_init() 對緩沖區(qū)進(jìn)行初始化。

          二、串口初始化函數(shù) uart_init

          static void uart_init(int baudrate)

          該函數(shù)用于初始化 USART1,并完成如下步驟:

          1. 初始化收發(fā)緩沖區(qū)控制結(jié)構(gòu)體。

          2. 打開 GPIOA 和 USART1 時(shí)鐘。

          3. 配置 USART1 的引腳復(fù)用功能(PA9 → TX,PA10 → RX)。

          4. 配置 GPIO 模式(復(fù)用模式,無上下拉)。

          5. 配置串口參數(shù)(波特率等)。

          6. 配置 NVIC 中斷優(yōu)先級并使能 USART1 中斷。

          通過將底層串口配置封裝在 uart_init() 中,使得后續(xù)調(diào)用更加簡潔。


          三、串口寫函數(shù) uart_write

          static unsigned int uart_write(const void *buf, unsigned int len)

          此函數(shù)負(fù)責(zé)將要發(fā)送的數(shù)據(jù)寫入發(fā)送緩沖區(qū),并開啟發(fā)送中斷:

          • 通過 ring_buf_put() 將數(shù)據(jù)寫入 rbsend。

          • 開啟 USART_IT_TXE 發(fā)送中斷。

          • 返回實(shí)際寫入字節(jié)數(shù)。

          由于發(fā)送在中斷中進(jìn)行,所以只需觸發(fā)中斷即可自動(dòng)依次發(fā)送緩沖區(qū)數(shù)據(jù)。


          四、串口讀函數(shù) uart_read

          static unsigned int uart_read(void *buf, unsigned int len)

          用于從接收緩沖區(qū)讀取數(shù)據(jù):

          • 通過 ring_buf_get() 從 rbrecv 中取出數(shù)據(jù)放入 buf。

          • 返回實(shí)際讀取長度。

          適用于非阻塞方式的讀取調(diào)用。


          五、緩沖區(qū)狀態(tài)查詢函數(shù)

          代碼中定義了以下緩沖區(qū)狀態(tài)查詢接口:

          static bool tx_isfull(void);   // 判斷發(fā)送緩沖區(qū)是否滿bool tx_isempty(void);         // 判斷發(fā)送緩沖區(qū)是否為空bool rx_isempty(void);         // 判斷接收緩沖區(qū)是否為空

          這些函數(shù)用于上層邏輯判斷是否可以繼續(xù)發(fā)送、是否有接收數(shù)據(jù)等,提升串口使用靈活性。


          六、TTY 接口結(jié)構(gòu)體封裝

          串口驅(qū)動(dòng)最終以一個(gè)結(jié)構(gòu)體 tty_t 形式暴露接口:

          const tty_t tty = {
              uart_init,
              uart_write,
              uart_read,
              tx_isfull,
              tx_isempty,
              rx_isempty
          };

          這種方式便于統(tǒng)一管理串口控制接口,適合在大型項(xiàng)目中引入“控制臺(tái)抽象層”統(tǒng)一管理多個(gè)串口。


          七、串口中斷處理函數(shù) USART1_IRQHandler

          這是串口驅(qū)動(dòng)的核心部分,負(fù)責(zé)響應(yīng) USART1 的收發(fā)中斷:

          void USART1_IRQHandler(void)

          主要包含以下處理邏輯:

          1. 接收中斷 RXNE:

          2. 從接收寄存器讀取數(shù)據(jù)。

          3. 存入接收緩沖區(qū) rbrecv。

          4. 發(fā)送中斷 TXE:

          5. 從發(fā)送緩沖區(qū) rbsend 中取出下一個(gè)字節(jié)發(fā)送。

          6. 若無數(shù)據(jù)可發(fā),關(guān)閉發(fā)送中斷。

          7. 溢出錯(cuò)誤中斷 ORE_RX:

          8. 讀取一次數(shù)據(jù)清除溢出標(biāo)志位。

          通過中斷方式處理串口收發(fā),不僅避免了阻塞操作,還能在高速數(shù)據(jù)傳輸中保持系統(tǒng)響應(yīng)性。


          八、總結(jié)

          本驅(qū)動(dòng)模塊實(shí)現(xiàn)了一個(gè)完整的串口通信功能,具備如下特點(diǎn):

          • 支持發(fā)送與接收雙緩沖。

          • 使用中斷驅(qū)動(dòng)方式收發(fā)數(shù)據(jù)。

          • 提供狀態(tài)判斷接口,便于上層調(diào)用。

          • 封裝為 tty_t 控制臺(tái)結(jié)構(gòu),支持模塊化應(yīng)用。

          其設(shè)計(jì)適用于嵌入式系統(tǒng)中多個(gè)串口同時(shí)工作的場景,也適合作為 CLI 控制臺(tái)、調(diào)試口或上位機(jī)通信口的底層驅(qū)動(dòng)支撐。結(jié)合環(huán)形緩沖區(qū),可有效避免數(shù)據(jù)丟失或阻塞,是一種常用、穩(wěn)定的串口通信實(shí)現(xiàn)方式。

          開源代碼:

          #include "stm32f4xx.h"#include "ringbuffer.h"#include "tty.h"#include "public.h"   #include <string.h>#if (TTY_RXBUF_SIZE & (TTY_RXBUF_SIZE - 1)) != 0 
              #error "TTY_RXBUF_SIZE must be power of 2!"#endif#if (TTY_TXBUF_SIZE & (TTY_TXBUF_SIZE - 1)) != 0 
              #error "TTY_RXBUF_SIZE must be power of 2!"#endifstatic unsigned char rxbuf[TTY_RXBUF_SIZE];         /*接收緩沖區(qū) */static unsigned char txbuf[TTY_TXBUF_SIZE];         /*發(fā)送緩沖區(qū) */static ring_buf_t rbsend, rbrecv;                   /*收發(fā)緩沖區(qū)管理*//*
           * @brief     串口初始化
           * @param[in]   baudrate - 波特率
           * @return      none
           */static void uart_init(int baudrate){
              ring_buf_init(&rbsend, txbuf, sizeof(txbuf));/*初始化環(huán)形緩沖區(qū) */
              ring_buf_init(&rbrecv, rxbuf, sizeof(rxbuf)); 
              
              RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA , ENABLE);
              
          GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
          GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);  
              
              gpio_conf(GPIOA, GPIO_Mode_AF, GPIO_PuPd_NOPULL, 
                        GPIO_Pin_9 | GPIO_Pin_10);
              
              RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
              uart_conf(USART1, baudrate);                    /*串口配置*/
              
              nvic_conf(USART1_IRQn, 1, 1);
              
          }/*
           * @brief     向串口發(fā)送緩沖區(qū)內(nèi)寫入數(shù)據(jù)并啟動(dòng)發(fā)送
           * @param[in]   buf       -  數(shù)據(jù)緩存
           * @param[in]   len       -  數(shù)據(jù)長度
           * @return      實(shí)際寫入長度(如果此時(shí)緩沖區(qū)滿,則返回len)
           */static unsigned int uart_write(const void *buf, unsigned int len){   
              unsigned int ret;
              ret = ring_buf_put(&rbsend, (unsigned char *)buf, len);  
              USART_ITConfig(USART1, USART_IT_TXE, ENABLE);    return ret; 
          }/*
           * @brief     讀取串口接收緩沖區(qū)的數(shù)據(jù)
           * @param[in]   buf       -  數(shù)據(jù)緩存
           * @param[in]   len       -  數(shù)據(jù)長度
           * @return      (實(shí)際讀取長度)如果接收緩沖區(qū)的有效數(shù)據(jù)大于len則返回len否則返回緩沖
           *              區(qū)有效數(shù)據(jù)的長度
           */static unsigned int uart_read(void *buf, unsigned int len){    return ring_buf_get(&rbrecv, (unsigned char *)buf, len);
          }/*發(fā)送緩沖區(qū)滿*/static bool tx_isfull(void){    return ring_buf_len(&rbsend) == TTY_TXBUF_SIZE;
          }/*發(fā)送緩沖區(qū)空*/bool tx_isempty(void){    return ring_buf_len(&rbsend) == 0;
          }/*接收緩沖區(qū)空*/bool rx_isempty(void){    return ring_buf_len(&rbrecv) == 0;
          }/*控制臺(tái)接口定義 -------------------------------------------------------------*/const tty_t tty = {
              uart_init,
              uart_write,
              uart_read,
              tx_isfull,
              tx_isempty,
              rx_isempty
          };/*
           * @brief     串口1收發(fā)中斷
           * @param[in]   none
           * @return      none
           */void USART1_IRQHandler(void){     
              unsigned char data;    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
                  data = USART_ReceiveData(USART1);
                  ring_buf_put(&rbrecv, &data, 1);           /*將數(shù)據(jù)放入接收緩沖區(qū)*/             
              }    if (USART_GetITStatus(USART1, USART_IT_TXE) != RESET) {        if (ring_buf_get(&rbsend, &data, 1))      /*從緩沖區(qū)中取出數(shù)據(jù)---*/
                      USART_SendData(USART1, data);            
                  else{
                      USART_ITConfig(USART1, USART_IT_TXE, DISABLE);    
                  }
              }    if (USART_GetITStatus(USART1, USART_IT_ORE_RX) != RESET) {
                  data = USART_ReceiveData(USART1);        
              }
          }



          關(guān)鍵詞: 串口通信驅(qū)動(dòng)

          評論


          技術(shù)專區(qū)

          關(guān)閉