STM32串口通信程序模擬超市打印機工作-使用接收中斷、空閒中斷、校驗中斷

項目代碼資料請移步:https://download.csdn.net/download/lishan132/12420086

1 項目簡介

        超市的收銀臺一般都會放置一臺小型打印機,其任務是將顧客的消費金額等信息打印在一張小票上。那麼打印機又是如何知道自己該打印那些內容呢?本文以經典的RS232串口通信來模擬收銀臺電腦與打印機之間的通信工作流程。

  1. 用筆記本電腦模擬收銀臺電腦,串口通信助手爲上位機界面;
  2. 用STM32F103C8T6單片機作爲打印機控制器;
  3. 用PL2303HX模塊完成USB到TTL電平的轉換;
  4. 在串口通信助手發送區輸入打印指令併發送;
  5. 在串口通信助手接收區顯示打印結果及提示信息。

    值得一提的是,超市收銀臺電腦與打印機之間的通信方式不止RS232串口一種,常見的還有USB通信、LPT並口通信、WiFi通信等方式。它們本質上都是一種數據傳輸手段,只不過其工作方式、成本、實現複雜度等有所區別。

       爲了將所學的串口通信知識與實踐相結合,現在通過開發一個實際的項目來掌握串口通信的核心要點及開發流程,實現由理論知識到實際應用的轉變,本文對超市微型打印機的通信部分進行研究設計。設計目標是:

(1)搭建電腦到打印機之間的RS232串口通信電路;

(2)設計串口通信程序,程序運行在打印機控制器STM32F103C8T6中;

(3)通過串口調試助手對通信效果進行演示。

2 設計要求

基礎部分

串口通信的具體設計要求如下:

(1)波特率4800bps,一位起始位,八位有效數據位,一位奇偶校驗位;

(2)使用串口調試助手發送一個數據打印命令“@PrintData12345678900#”;

(3)單片機收到命令後,解析命令,輸出數據“1234567890”,然後給上位機發送“數據已成功打印”。

擴展部分

爲了加深對串口通信知識的理解和運用,本文提出以下擴展要求並進行實現:

(1)每次輸出打印信息及提示信息結束後都進行換行顯示;

(2)系統上電工作時,通過串口通信助手顯示系統正常工作的提示信息;

(3)當打印指令錯誤時,輸出“instruction error”進行提示;

(4)當接收的字符數大於設定的緩衝區大小時,輸出“Overflow error”;

(5)當出現校驗錯誤時,輸出“校驗錯誤,請重新發送命令”。

3 總體設計方案

       使用筆記本電腦與STM32單片機進行數據交互,模擬超市電腦與打印機之間的通信過程。筆記本電腦上安裝有串口調試助手軟件,串口調試助手作爲上位機可以實現人機界面交互的功能,同時也是檢驗串口通信是否正常的工具。

      筆記本電腦一般沒有串口,但至少有一個USB口。單片機的串口是映射到GPIO上的,本文只需要用到接收、發送引腳,也就是2個GPIO,再加上電源和地,一共4個單片機引腳。筆記本的USB口和單片機串口之間不能直接相連,因爲兩者的工作電平邏輯不一致,需要通過一個USB轉TTL模塊進行電平轉換,同時筆記本電腦上需要安裝配套的USB轉串口驅動程序。

 

系統設計方案

4 設計前的思考和準備

思考:

1、串口的參數設置中有一位校驗位,如何實現,又如何體現校驗的作用;

2、如何判斷串口數據傳輸的開始、結束;

3、如何判斷命令是否符合要求,並取出中間的數據部分;

4、能否直接輸出中文。

準備:

  1. 搭建硬件電路連線

        在開發過程中,本文還連接了ST-Link調試器,使用調試器可以讓程序下載更快,同時能進行硬件仿真調試,可以提高開發效率,當然也可以直接使用串口下載程序。項目完成後,實際運行時不需要再連接調試器。

                                                                

硬件連接

      2.安裝USB轉串口驅動程序

        本文用到的USB轉TTL模塊芯片爲PL2303HX,驅動程序可在網上進行下載,雙擊驅動程序按提示完成驅動安裝。其他芯片的驅動安裝方法類似。

安裝USB轉串口驅動

        驅動安裝完成後,插上USB轉TTL模塊,在設備管理器中選擇端口,如果能夠看到識別到的驅動程序和端口號,表示驅動安裝成功。否則,右鍵選擇更新驅動程序,從我的計算機驅動程序中選擇2009年的版本,當出現下圖界面,能分配到一個端口號即表示安裝成功。其它的芯片模塊可能在驅動程序安裝完後就能看到端口號,此時不需要進行驅動程序的更新操作。

驅動安裝成功示意圖

     3.下載串口調試助手軟件、Keil-MDk軟件

      串口調試助手網上非常多,可以自行選擇,但是要注意,一定要知道這款串口助手對中文字符的編碼採用什麼格式,網上資源以GB2313居多,也有部分是採用UTF-8格式的,本文選擇GB2313編碼方式的串口調試助手。

      Keil-MDK軟件是開發嵌入式的IDE,可從網上下載,建議下載5.28版本,破解操作也可從網上參考,本文不贅述。Keil-MDK編程的編碼格式設置一定要與串口調試助手一致,這樣纔不會出現中文亂碼的問題,建議選擇GB2313。

MDK-keil編碼設置

    4.準備一份STM32中文參考手冊,便於開發過程中查詢串口的使用方法以及相關寄存器的設置。

    5.準備一份STM32固件庫手冊,便於開發程序時查詢標準固件庫函數使用方法,加快開發效率。

    6.找到一份STM32工程模板文件,可以直接從固件庫文件中複製,也可以自己創建,省去工程的創建、文件的添加等機械工作。

準備資料

5 本文設計的關鍵點

5.1 校驗位設置

通過查閱STM32中文手冊發現,USART_CR1寄存器中的PCE位可以使能奇偶校驗位的產生,M位可以設置數據字的長度,如下圖所示:

 

USART_CR1寄存器PCE位-決定是否產生校驗位
USART_CR1寄存器M位-決定數據字長度

       M位和PCE位的值兩者共同決定USART幀的格式,一共四種,如下圖所示。根據設計要求,本文設置爲M位爲1,PCE位爲1,即字長爲9,校驗位選擇奇校驗(也可選擇偶校驗)。

 

校驗控制串口幀格式

        通過查閱STM32固件庫手冊,複製串口參數設置代碼示例,並進行修改,下面展示關鍵部分的參數設置。

 

串口初始化參數設置

5.2 串口中斷設置

      串口通信的數據接收、發送程序一般有中斷和查詢(也叫輪詢)兩種方式,相對來說,中斷方式對CUP的資源佔用較少,響應也更及時,本文使用中斷方式接收來自上位機電腦的數據。

      翻閱STM32中文手冊發現,STM32單片機的串口中斷請求事件有以下幾種,當表中事件發生時,只要設置了相應的中斷使能,都會通過嵌套中斷向量(NVIC)的向量表進入到串口中斷服務程序中,可以在服務程序中查詢相應事件的標誌位判斷當前是那一種事件發生。爲了檢測數據的接收、接收完成、奇偶校驗出錯這三種情況,本文設置的三個串口中斷事件,下圖中用紅框標註。

①接收數據就緒可讀表示對方已經發送了一個字節數據,這個數據現在在硬件接收緩衝區中,並且現在可以讀出數據。當第一次發生此事件時代表數據傳輸的開始。

②檢測到空閒線路表示在對方傳輸上一字節數據後,又過了一個字節的傳輸時長,單片機仍然沒有接收到數據,可以代表數據發送的結束,也就是完成了一次數據的傳輸。

③奇偶校驗錯表示按照約定的校驗規則,當前字節的數據發生了錯誤。

STM32串口中斷事件 (注:表中的TXNE標誌應爲RXNE)

 

根據固件庫手冊和庫函數註釋,使能上述三個串口中斷事件的代碼如下:

使能串口中斷事件

 

5.3 串口中斷服務程序

        根據STM32中文手冊,串口中斷事件相應的標誌位在狀態寄存器SR中,在串口中斷服務程序中查詢這幾個標誌位的值就可知道發生了什麼事件。SR寄存器中的三個標誌位介紹如下所示:

 

串口中斷標誌位及清除方法

        從上表看出,標誌位置1時,表示該事件發送,此時單片機可以進行相應操作。但要注意,一定要及時清除標誌位(清0操作),否則程序會一直進入中斷服務程序。對於RXNE位,當讀出DR寄存器中的數據後,硬件自動清0,不用再單獨寫清0的代碼。對於PE位和IDLE爲,需由軟件進行清0,清0操作爲先讀SR寄存器,再讀DR寄存器。串口1軟件清除PE、IDLE標誌位代碼爲:

USART1->SR;  //先讀狀態寄存器

USART1->DR;  //再讀數據寄存器

         串口1的中斷服務程序名爲void USART1_IRQHandler(void),位於stm32f10x_it.c文件中,當然,也可以寫在其他位置,但程序名不要改變,同時要處理好各c文件之間依賴關係。

 串口中斷服務程序

 

6 程序設計

在本文的程序設計中,要注意以下幾個要點。

  1. 有奇偶校驗位時,串口初始化程序中的字長設置爲9,串口調試助手中

的數據位選擇8;

  1. 注意各種標誌位的設置與清除,串口發送完數據後一定要等TXE置位後

再發送下一位數據;

3、主函數、中斷請求函數中不宜寫太多代碼;

4、可以考慮在解析數據前關閉中斷,串口輸出數據後再打開中斷。

整個程序有四個關鍵部分,分別是主函數、串口中斷處理、數據解析、串口輸出,下面分別對它們的流程做簡單介紹。串口輸出和數據解析函數放在附錄中。

6.1 主函數

主函數流程圖

 

主函數程序展示圖

 

6.2 串口中斷處理函數

串口中斷處理函數流程圖

 

接收中斷回調函數

 

空閒中斷回調函數

 

校驗出錯中斷回調函數

6.3 數據解析函數

數據解析函數流程

6.4 串口輸出函數

 

串口輸出函數流程

7 結果演示

     打開串口調試助手,設置好串口參數,按各種情況進行測試,演示效果如下

演示效果圖

 

8 課堂問題解答

 

第19組第一個問題:開始和結束錯誤標誌都設置爲2會不會分不清?

答:因爲指令的開始和結束部分出現錯誤時都表示這是一個錯誤的指令,所以程序中將其錯誤類型都設置爲2,這樣做確實是無法分清到底是指令的開始部分發生了錯誤還是結束部分發送錯誤。如果確實有必要將這兩種錯誤分開,可以考慮在程序中將這兩種情況設置不同的錯誤標誌號。

 

第12組第一個問題:爲啥選奇校驗和偶校驗哪個都對?

答:尚不清楚您說的對是什麼意思,但是不管在串口助手中選哪一種校驗方式,發送指令後單片機都會返回一段信息,可能是成功打印的信息,也可能是錯誤的提示信息。在演示中出現了一個細節可能與您的提問相關,因爲當時發送的是一個錯誤的指令,所以不管選擇奇校驗還是偶校驗方式,單片機返回的信息都是“instruction error”,這是由於程序中必須對數據進行解析,當解析結果爲指令錯誤時,其錯誤碼爲2,也就是輸出“instruction error”。換句話說,當出現多種錯誤時,優先考慮指令是否錯誤。當發送一個正確的指令時,在串口助手中選擇與程序設計中不同的校驗方式,就會輸出“校驗錯誤,請重新發送命令”。

 

第2組第一個問題:自己設定的三個中斷有優先級的考慮嗎?

答:程序中設置有接收中斷、空閒中斷、奇偶校驗出錯中斷,但這三個中斷本質上都屬於串口中斷,只不過這是引起串口中斷的三種不同事件,當任意一件事件發生時,都會進入同一個串口中斷服務函數,可以在中斷服務函數中判斷對應的標誌位是否置1,進而確定是哪一個事件的發生導致進入了串口中斷服務函數。因爲不可能有兩個及以上的事件同時發生,所以這三個中斷事件之間不存在優先級的問題。另外,因爲整個程序只用到了一個串口中斷,不存在其它外設中斷源,所以也可以不用對中斷優先級進行設置。

 

第5組第一個問題:可以詳細講解一下中斷的過程嗎,比如各個中斷的優先級,以及如果在主函數解析時中斷關閉的方式等

答:一個外設(比如定時器、串口)要發生中斷有三個條件,一是使能了外設,可類比爲電路中的幹路總開關;二是打開了中斷使能位,可類比爲支路的第一個開關(有多種事件可觸發串口中斷,可看成是多條支路);三是對應事件的中斷標誌位置1(一般是硬件自動置1),可類比爲支路第二個開關,只有三個開關全部合上,纔會進入中斷服務函數。

當發生中斷時,程序會保存當前的數據和指令執行位置等信息到堆棧,稱爲現場保護。這個堆棧空間是硬件自動開闢的,數據的保存也是自動完成的,不需要在程序中再進行任何操作。保存完畢後,程序會查詢中斷向量表,向量表上保存的是各個中斷的服務程序的起始地址,通過此地址可跳轉到中斷服務中執行中斷服務體內的程序,當離開中斷服務程序時,程序會從堆棧中彈出數據,返回到進入中斷前的指令位置,繼續執行當前程序。

中斷的優先級一般指的是不同中斷源之間的優先級別高低,比如程序中存在定時器中斷和串口中斷,那麼這兩個中斷可能會同時觸發,或者正在串口中斷服務程序中執行時,定時器中斷又被觸發。當發生這些情況時,如果沒有相應的處理機制,系統將會陷入混亂。由此引入的中斷優先級的概念,即將每個中斷源都設置一個優先級別,這樣,遇到上述情況時,就可以根據優先級的高低來決定當前去處理那一部分的程序。如果優先級一樣,或者在程序中沒有設置中斷優先級,那麼系統會根據向量表中默認的優先級進行處理。

STM32中文手冊中的第9章可以查看中斷的相關信息,串口1中斷的默認優先級爲44。

       STM32通過4位數據對優先級進行編程設置,在程序中設置中斷優先級時,有優先級分組、搶佔優先級和響應優先級三個參數設置,系統復位後默認的中斷優先級優先級分組設置爲0,即全部用於響應優先級,不存在搶佔優先級。詳情見STM32固件庫手冊,本文不再贅述。在本文程序的主函數中解析數據時,如果要關閉中斷,只需要關閉上面提到的三個開關中任意一個即可,最簡單的就是直接失能串口外設,其代碼爲:

USART_Cmd(USART1, DISABLE);    /* 失能USART1 */

當輸出數據後,可以再次開啓串口,進行下一次的接收。

第9組第一個問題:如何編寫中斷服務函數

答:進入中斷服務函數後,首先是對標誌位進行判斷,確認中斷事件,然後是標誌位的清除,避免一直進入中斷服務函數。接下來有兩種思路,一是將發生該中斷事件時需要處理的邏輯代碼全部放在該程序中,比如數據的保存、LED等的亮滅等等,執行完畢後退出中斷服務函數;二是設置一個標誌位,然後在主函數的while循環中判斷此外部變量標誌位的值,進而進行相關操作。

 

第21組第一個問題:解析數據時關閉中斷這樣會不會有後續數據的丟失?

答:分兩種情況,如果在解析數據時,又從上位機發送了數據到單片機,那麼這部分數據會丟失,因爲中斷已經關閉,無法進入中斷服務函數,數據根本無法接收,只會在硬件緩衝區一次又一次的被覆蓋。如果在解析數據時沒有新的數據傳輸到單片機,等解析完畢後,中斷再次打開時,纔有數據傳輸過來,那麼對數據是沒有任何影響的。當然,單片機處理數據的數據還是比較快的,如果上一次傳輸的數據比較少,解析數據的時間花費少,中斷可以很快再次打開,那麼是感覺不到什麼影響的,如果一次傳輸大量數據,在下一次傳輸時就可能存在丟失數據的情況,也就是丟包。

 

第4組第一個問題:當數據進入中斷的時候,主函數是在等待嗎?如果是的話中斷函數比較多,怎麼保證當中斷結束時主函數能從原來的位置直接運行?

答:當進入中斷時,主函數的確是處於等待狀態,但第二個問題不需要擔心,每一次進入中斷時,硬件會自動進行現場保護,也就是開闢堆棧空間,保存當前的狀態信息,當然也包括當前指令執行的位置,中斷服務函數結束後,數據從堆棧中彈出,程序回到進入中斷前的現場,繼續執行。整個過程都是硬件自動完成,程序員不用做任何操作。

 

第5組第二個問題:如果傳輸數據中,出現終止符怎麼辦?

答:一般不會在串口助手中發送終止符,字符串終止符(也就是空字符)的Ascii碼爲0x00,在本文程序中,如果出現終止符,後續數據也是能夠接收的,即能夠保存在數組中。但是在單片機的串口發送函數中,遇到空字符就會認爲數據已經結束,後續的數據不會被髮送。遇到這種問題,暫時沒有一個好的解決方案,可以考慮修改串口發送函數,不再以是否爲空字符爲結束標誌,而是確定一個明確的數據長度。

 

第18組第一個問題:程序中字符串的發送是怎麼實現的?

答:程序中的字符串發送沒有用到任何中斷,當然也可以使用中斷,在中斷服務函數中再調用數據發送函數。庫函數void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)可以實現通過串口發送引腳TX,發送1字節數據的功能,第一個參數爲串口號,第二個參數爲發送的數據,因爲STM32中的串口發送數據的字長有8位和9位兩種,所以此參數類型爲uint16_t,即16位。但是一般8位最常用,因爲剛好一個字節,9位的用得較少。發送數據後需要等待當前數據發送完成才能進行下一次的發送,也就是等待發送完成標誌位TC置1,代碼爲:while(USART_GetFlagStatus(USART1,USART_FLAG_TC )==RESET);

   爲了實現字符串的發送,也就是多個字節連續發送,可定義一個函數,如下:

void Send_data(uint8_t *data)

{

while(*data!='\0')

{

  while(USART_GetFlagStatus(USART1,USART_FLAG_TC )==RESET);

  USART_SendData(USART1,*data);

  data++;

}

}

當沒有到達字符串的結束標誌’\0’之前,循環調用數據發送函數,同時指針移到下一位。值得注意的是,如果使用了串口發送功能,那麼最好在串口初始化函數usart1_init()中最後加一句清除發送完成標誌的代碼,如下:

USART_ClearFlag(USART1,USART_FLAG_TC);    //清除發送完成標誌位

 

第2組第二個問題:除了數字還可以發送其他信息嗎?

答:可以的,傳輸的數據在傳輸線上就是一個個的高低電平,在單片機內部就是01...這種的二進制數,將其用不同的譯碼規則翻譯就是不同的信息。一般將其保存到字符數組中,也就是字符類型,符合Ascii碼規則,包含了數字、字母、特殊字符等信息。

 

第24組第一個問題:一次發送數據的上限是多少?

答:理論上是沒有限制的,也就是單片機的串口可以連續工作,一直髮送、接收數據,實際使用時通常在軟件中定義一個緩衝數組,數組的大小就決定了一次發生數據的上限。本程序中定義大小爲100。

 

第5組第三個問題:@printdata12345678900#多次與@printdata12345678901234567890...12345678900#數據傳輸的差別可以說一下麼?

答:@printdata12345678900#多次,例如發送@printdata12345678900#@printdata12345678900#@printdata12345678900#時,按照本文程序的設計思路,依次檢查首尾指令,符合要求,將會正確打印中間數據部分,即打印12345678900#@printdata12345678900#@printdata1234567890

   發送@printdata12345678901234567890...12345678900#時,同樣檢查首尾指令,符合要求,將會正確打印中間數據部分,即打印12345678901234567890...1234567890

 

第24組第二個問題:在stm32端奇偶校驗位要算在數據位中,在PC端奇偶校驗位是否要算在數據位中?

答:這個與PC端串口調試助手開發的源碼有關係,但是大部分軟件都是如果在軟件界面的數據位選擇爲8位,校驗位選擇奇檢驗或偶校驗,那麼調試助手會將接收到的數據的低8位作爲數據位,最高位單獨取出作爲校驗位。所以一般來說,PC端奇偶校驗位不算在數據位中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章