萬變不離其宗之UART要點總結

来源:https://www.cnblogs.com/embInn/archive/2020/07/08/13269275.html
-Advertisement-
Play Games

[導讀] 單片機開發串口是應用最為廣泛的通信介面,也是最為簡單的通信介面之一,但是其中的一些要點你是否明瞭呢?來看看本人對串口的一些總結,當然這個總結並不能面面俱到,只是將個人認為具有共性以及相對比較重要的點做了些梳理。 啥是串口? 首先這玩意兒分兩種: **通用非同步收發器(UART)**是用於非同步 ...


[導讀] 單片機開發串口是應用最為廣泛的通信介面,也是最為簡單的通信介面之一,但是其中的一些要點你是否明瞭呢?來看看本人對串口的一些總結,當然這個總結並不能面面俱到,只是將個人認為具有共性以及相對比較重要的點做了些梳理。

啥是串口?

首先這玩意兒分兩種:

  • 通用非同步收發器(UART)是用於非同步串列通信的一種物理層標準,其中數據格式和傳輸速度是可配置的。
  • 通用同步收發器(USART)是一種串列介面設備,可以對其進行編程以進行非同步同步通信。

數據格式

線上空閑、無數據狀態為常高電平,故邏輯低定義為起始位。

  • 起始位:總是1位

  • 數據位:常見的有8位或9位。

  • 校驗位

    • 奇校驗
    • 偶校驗
    • 無校驗
  • 停止位:

    • 1位
    • 2位
  • 波特率:bit rate 就是位/秒的概念,就是1秒傳多少位的概念。常見的波特率有哪些呢?

這裡須註意的要點:

  • 一個有效位元組的傳輸時間怎麼算?

    \[T=位數*\frac{1}{波特率} \]

    比如9600下,1位起始位,8位數據位,奇校驗,1位停止位,則

    \[T=(1+8+1+1)*\frac{1}{9600}=0.00114583秒 \]

    為什麼要理解清楚這個概念呢,因為在應用中需要計算數據吞吐率問題,就比如一個應用是數據採集串口傳輸問題,需要計算採集的位速率需要小於或等於傳輸波特率,否則數據就來不及傳。當然如果說你有足夠大的緩衝區可以臨時存儲,但是如果進來太快,而傳出速度跟不上,多大的緩衝都會滿!

  • 校驗位有用嗎?當你的傳輸介質處於一個有干擾的場景下,校驗位就可以從物理層檢測出錯誤。

  • 理解數據編碼方式有啥意義呢?比如在調試中你可以利用邏輯分析直接去解析收發線上的數據報文。

  • 應用電路設計的時候RX-TX相連,很多初學者容易在這裡踩坑!

  • 常見的傳輸位序為低有效位在前。

  • 對於波特率而言需要註意波特率發生器有可能帶來誤碼問題

啥是UART?

兩邊分別代表兩個通信的設備,單從UART編程的角度講收發不需要物理同步握手,想發就發。圖中箭頭代表數據信息流向。RX表示接收數據,TX表示發送數據。數據總是從發送端傳遞到接收端,這就是為啥RX連接TX,TX連RX的原因。

啥是USART?

同步簡單說,收發不可自如,不可以想發就發,收發需要利用硬體IO口進行握手,RTS/CTS就是用於同步的握手信號:

  • RTS:Ready to send,請求發送,用於在當前傳輸結束時阻止數據發送。
  • CTS:clear to send,清除發送,用於指示 USART 已準備好接收數據。

這個對於普通應用而言並不常見,這裡不做詳細展開,需要用到的時候只需要對應收發時控制握手信號即可。

編程策略

對於不同的單片機,其硬體體系各異,寄存器也差異很大,但是從收發編程策略角度而言,常見有下麵三種方式:

  • 查詢發送/中斷接收模式
  • 收發中斷模式
  • DMA模式

查詢發送/中斷接收模式

這裡以偽代碼方式描述一下:

/*查詢發送位元組*/
void uart_send_byte( uint8 ch )
{
    /*如果當前串口狀態寄存器非空閑,則一直等待*/
    /*註意while迴圈後的分號,表示迴圈體為空操作*/
    while( !UART_IS_IDLE() );
    
    /*此時將發送位元組寫入發送寄存器*/
    UART_TX_REG = ch;    	
}

/*發送一個緩衝區*/
void uart_send_buffer( uint8 *pBuf,uint8 size )
{
    uint8 i = 0;
    /* 異常參數處理*/
    if( pBuf == NULL )
        return;
    
    for( i=0; i<size;i++ )
    {
        send_byte( pBuf[i] );
    }
}

對於接收而言,如採用查詢模式則幾乎是沒有任何應用價值,因為外部數據不知道什麼時候會到來,所以查詢接受就不描述了,這裡描述一下中斷接收。

static uint8 rx_index = 0;
void uart_rx_isr( void )
{
    /* 接收報文處理 */
    rx_buffer[rx_index++] = UART_RX_REG;
}

中斷接收需要考慮的幾個要點:

  • 斷幀:這就取決於協議怎麼制定了,比如應用協議定義的是ASCII碼方式,就可以定義同步頭、同步尾,比如AT指令的解析,做邏輯判斷幀頭、幀尾即可。但是如果傳輸的是16進位數據,比如MODBUS-RTU其斷幀採用的是3.5個位元組時間沒有新的位元組接收到,則認為收到完整的幀了。
  • 如何保證幀的完整性,一般會在報文尾部加校驗,比較常用的校驗模式有CRC校驗演算法。
  • 不同的單片機開發環境對於中斷向量的處理方式略有不同,需要根據各自晶元的特點進行處理。比如51單片機,其發送/接收都共用一個中斷向量號。

收發中斷模式

#define FRAME_SIZE  (128u)
static uint8 tx_buffer[FRAME_SIZE];
static uint8 tx_index  = 0;
static uint8 tx_length = 0;

static uint8 rx_buffer[FRAME_SIZE];
static uint8 rx_index = 0;
static bool  rx_frame_done = false;
void prepare_frame( uint8 * pBuf, uint8 size )
{
     /*將待傳的報文按照協議封裝*/
     /*可能需要處理的事情,比如幀頭、幀尾、校驗等*/
}

bool uart_start_sending( uint8 * pBuf, uint8 size )
{
    if( pBuf == NULL )
        return false;
    
     memcpy( tx_buffer,pBuf,size );
     tx_index  = 0;
     tx_length = size;
    
     /*使能發送中斷,向發送寄存器寫入一個位元組,進入連續發送模式*/
     ENABLE_TX_INT = 1;
     UART_TX_REG   = tx_buffer[tx_index++];
}

void uart_tx_isr( void )
{
    if( tx_index<tx_length )
    {
        UART_TX_REG   = tx_buffer[tx_index++];
    }
    else
    {
        /*發送完畢,關閉發送中斷*/
        DISABLE_TX_INT = 1;
    }
}

void uart_rx_isr( void )
{
    /*處理接收,待接收到完整的幀就設置幀完成標記*/
    /*由於應用各有不同,這裡就無法描述實現了*/
}

還需要考慮的是,對於UART硬體層面的出錯處置,以STM32為例,就可能有下麵的錯誤可能發生:

  • 溢出錯誤
  • 雜訊檢測
  • 幀錯誤
  • 奇偶校驗錯誤

另外不同的單片機其底層硬體實現差異也不較大,比如有的硬體發送緩衝是單位元組的緩衝,有的則具有FIFO,這些在選型編程時都需要綜合考慮。

DMA模式

DMA發送模式而言,大致分這樣幾步:

  • 初始化UART為DMA發送模式,開啟DMA結束中斷,並寫好DMA傳輸結束中斷處理函數
  • 準備待發送報文,幀頭、幀尾、校驗處理
  • 將待發送報文緩衝區首地址賦值給DMA源地址,DMA目標地址設置為UART發送寄存器,設置好發送長度。
  • 啟動DMA傳輸,剩下傳輸完成就會進入傳輸結束中斷處理函數。

DMA接收模式而言,大致分這樣幾步:

  • 初始化UART為DMA接收模式,開啟DMA結束中斷,並寫好DMA傳輸結束中斷處理函數
  • 中斷處理函數中標記接收到幀,對於使用RTOS而言,還可以使用的機制是利用RTOS的事件機制、消息機制進行通知有新的幀接收到了。
  • 對於DMA接收模式而言,對於變長幀的處理較為不利,所以如果想使用DMA接收,制定協議時儘量考慮將幀長度固定,這樣處理會方便些。

總結一下

單片機串口是一個需要好好掌握的內容,這裡總結了一些個人經驗,儘量將一些個人共性的東西總結出來。至於實際實現而言,由於晶元體系差異較多,具體代碼各異。但個人認為處置的思路方法卻是基本一致。所以本文除了描述串口本身的細節而言,想表達的一個額外的觀點是:

  • 對於一些技術點儘量學會將其共性的東西剝離總結出來。
  • 總結、概括、剝離抽象是一個比較好的學習思路,不用對具體的硬體死記,萬變不離其宗。
    文章出自微信公眾號:嵌入式客棧,更多內容,請關註本人公眾號

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.需求示意圖 2.需求描述 原本是為了給做unity3d客戶端開發的同事提供不定時的消息推送,比如商城購買道具後服務端將道具信息推送給客戶端。 本篇文章簡化理解,用“相關部門開展活動,向全市人民徵集社會服務改善意見”為例子。但核心想法一致:單向推送(指這個需求上只需要單向)。所以這個功能並不是聊天 ...
  • 本人製作的這個 “簡易日誌 (SimpleLogger)” 包裡面包含的代碼邏輯,最開始也就是簡單地寫入文本,後來經過實際使用的演化,做了各種優化,添加了一些實用的特性,感覺用著還不錯。正所謂獨樂樂不如眾樂樂,於是將其打包上傳到微軟的包管理庫 NuGet 中,大家可以使用試試,相互交流。 ...
  • 前言 Http我們都已經耳熟能詳了,而關於Http學習的文章網上有很多,各個知識點的講解也可說是深入淺出。然而,學習過後,我們對Http還是一知半解。問題出在了哪? Http是一個客戶機與伺服器之間的通信的協議,真的想學習Http,就必須把客戶機和伺服器也學了,也就是說,必須立體的學習,不然我們永遠 ...
  • 一.背景說明: 之前分享過一個微服務開發框架, “享一個集成.NET Core+Swagger+Consul+Polly+Ocelot+IdentityServer4+Exceptionless+Apollo+SkyWalking的微服務開發框架”,前兩天在Github上收到一個Issues,是想我 ...
  • 本次課程就正式進入開發部分。 首先我們先搭建項目框架,還是和之前漸進式風格保持一致,除必備組件外,儘量使用原生功能以方便大家理解。 開發工具:vs 2019 或以上 資料庫:SQL SERVER 2017 或以上 其他需要用到的我們在項目過程中再提。 一、新建 MVC項目 1、打開VS 2019,C ...
  • 調試腳本所花費的時間常常比編寫代碼還要多。所有編程語言都應該實現的一個特性就是在出現始料未及的情況時,能夠生成跟蹤信息。調試信息可以幫你弄清楚是什麼原因使得程式行為異常。 ...
  • 大家好,我是良許。 我們在平時工作的時候,經常要知道兩個文件之間,以及同個文件不同版本之間有何異同點。在 Windows 下,有 beyond compare 這個好用的工具,而在 Linux 下,也有很多很強大的工具,良許之前也寫過一篇文章介紹: Linux下9種優秀的代碼比對工具推薦 這些比對工 ...
  • [導讀] 前文大致總結了單片機串口的一些值得註意的要點,本文來梳理一下I2C匯流排的一些應用要點。這個題目有點大,對於I2C其實很多地方也沒講清楚,只為了與前文形成系列,如果大家有補充歡迎留言。說了些閑話,進入正題吧。 I2C之前世今生 \(I^2C\)(Inter-Integrated Circui ...
一周排行
    -Advertisement-
    Play Games
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...
  • 目錄前言PostgreSql安裝測試額外Nuget安裝Person.cs模擬運行Navicate連postgresql解決方案Garnet為什麼要選擇Garnet而不是RedisRedis不再開源Windows版的Redis是由微軟維護的Windows Redis版本老舊,後續可能不再更新Garne ...
  • C#TMS系統代碼-聯表報表學習 領導被裁了之後很快就有人上任了,幾乎是無縫銜接,很難讓我不想到這早就決定好了。我的職責沒有任何變化。感受下來這個系統封裝程度很高,我只要會調用方法就行。這個系統交付之後不會有太多問題,更多應該是做小需求,有大的開發任務應該也是第二期的事,嗯?怎麼感覺我變成運維了?而 ...
  • 我在隨筆《EAV模型(實體-屬性-值)的設計和低代碼的處理方案(1)》中介紹了一些基本的EAV模型設計知識和基於Winform場景下低代碼(或者說無代碼)的一些實現思路,在本篇隨筆中,我們來分析一下這種針對通用業務,且只需定義就能構建業務模塊存儲和界面的解決方案,其中的數據查詢處理的操作。 ...
  • 對某個遠程伺服器啟用和設置NTP服務(Windows系統) 打開註冊表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer 將 Enabled 的值設置為 1,這將啟用NTP伺服器功 ...
  • title: Django信號與擴展:深入理解與實踐 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 後端開發 tags: Django 信號 松耦合 觀察者 擴展 安全 性能 第一部分:Django信號基礎 Djan ...
  • 使用xadmin2遇到的問題&解決 環境配置: 使用的模塊版本: 關聯的包 Django 3.2.15 mysqlclient 2.2.4 xadmin 2.0.1 django-crispy-forms >= 1.6.0 django-import-export >= 0.5.1 django-r ...
  • 今天我打算整點兒不一樣的內容,通過之前學習的TransformerMap和LazyMap鏈,想搞點不一樣的,所以我關註了另外一條鏈DefaultedMap鏈,主要調用鏈為: 調用鏈詳細描述: ObjectInputStream.readObject() DefaultedMap.readObject ...
  • 後端應用級開發者該如何擁抱 AI GC?就是在這樣的一個大的浪潮下,我們的傳統的應用級開發者。我們該如何選擇職業或者是如何去快速轉型,跟上這樣的一個行業的一個浪潮? 0 AI金字塔模型 越往上它的整個難度就是職業機會也好,或者說是整個的這個運作也好,它的難度會越大,然後越往下機會就會越多,所以這是一 ...
  • @Autowired是Spring框架提供的註解,@Resource是Java EE 5規範提供的註解。 @Autowired預設按照類型自動裝配,而@Resource預設按照名稱自動裝配。 @Autowired支持@Qualifier註解來指定裝配哪一個具有相同類型的bean,而@Resourc... ...