通信接口背景知識
設備之間通信的方式
一般情況下,設備之間的通信方式可以分成並行通信和串行通信兩種。它們的區別是:
串行通信的分類
1、按照數據傳送方向,分為:
單工:數據傳輸只支持數據在一個方向上傳輸;
半雙工:允許數據在兩個方向上傳輸。但是,在某一時刻,只允許數據在一個方向上傳輸,它實際上是一種切換方向的單工通信;它不需要獨立的接收端和發送端,兩者可以合並一起使用一個端口。
全雙工:允許數據同時在兩個方向上傳輸。因此,全雙工通信是兩個單工通信方式的結合,需要獨立的接收端和發送端。
2、按照通信方式,分為:
- 同步通信:帶時鍾同步信號傳輸。比如:SPI,IIC通信接口。
- 異步通信:不帶時鍾同步信號。比如:UART(通用異步收發器),單總線。
在同步通訊中,收發設備上方會使用一根信號線傳輸信號,在時鍾信號的驅動下雙方進行協調,同步數據。例如,通訊中通常雙方會統一規定在時鍾信號的上升沿或者下降沿對數據線進行采樣。
在異步通訊中不使用時鍾信號進行數據同步,它們直接在數據信號中穿插一些用於同步的信號位,或者將主題數據進行打包,以數據幀的格式傳輸數據。通訊中還需要雙方規約好數據的傳輸速率(也就是波特率)等,以便更好地同步。常用的波特率有4800bps、9600bps、115200bps等。
在同步通訊中,數據信號所傳輸的內容絕大部分是有效數據,而異步通訊中會則會包含數據幀的各種標識符,所以同步通訊效率高,但是同步通訊雙方的時鍾允許誤差小,稍稍時鍾出錯就可能導致數據錯亂,異步通訊雙方的時鍾允許誤差較大。
常見的串行通信接口
STM32串口通信基礎
STM32的串口通信接口有兩種,分別是:UART(通用異步收發器)、USART(通用同步異步收發器)。而對於大容量STM32F10x系列芯片,分別有3個USART和2個UART。
UART引腳連接方法
RXD:數據輸入引腳,數據接受;
TXD:數據發送引腳,數據發送。

對於兩個芯片之間的連接,兩個芯片GND共地,同時TXD和RXD交叉連接。這里的交叉連接的意思就是,芯片1的RxD連接芯片2的TXD,芯片2的RXD連接芯片1的TXD。這樣,兩個芯片之間就可以進行TTL電平通信了。
若是芯片與PC機(或上位機)相連,除了共地之外,就不能這樣直接交叉連接了。盡管PC機和芯片都有TXD和RXD引腳,但是通常PC機(或上位機)通常使用的都是RS232接口(通常為DB9封裝),因此不能直接交叉連接。RS232接口是9針(或引腳),通常是TxD和RxD經過電平轉換得到的。故,要想使得芯片與PC機的RS232接口直接通信,需要也將芯片的輸入輸出端口也電平轉換成rs232類型,再交叉連接。
經過電平轉換后,芯片串口和rs232的電平標准是不一樣的:
單片機的電平標准(TTL電平):+5V表示1,0V表示0;
Rs232的電平標准:+15/+13 V表示1,-15/-13表示0。
RS-232通訊協議標准串口的設備間通訊結構圖如下:
所以單片機串口與PC串口通信就應該遵循下面的連接方式:在單片機串口與上位機給出的rs232口之間,通過電平轉換電路(如下面圖中的Max232芯片) 實現TTL電平與RS232電平之間的轉換。
具體要了解RS232串口的,可以查看鏈接RS232串口簡介。
STM32的UART特點
全雙工異步通信;
分數波特率發生器系統,提供精確的波特率。發送和接受共用的可編程波特率,最高可達4.5Mbits/s;
可編程的數據字長度(8位或者9位);
可配置的停止位(支持1或者2位停止位);
可配置的使用DMA多緩沖器通信;
單獨的發送器和接收器使能位;
檢測標志:① 接受緩沖器 ②發送緩沖器空 ③傳輸結束標志;
多個帶標志的中斷源,觸發中斷;
其他:校驗控制,四個錯誤檢測標志。
串口通信過程
STM32中UART參數
串口通訊的數據包由發送設備通過自身的TXD接口傳輸到接收設備的RXD接口,通訊雙方的數據包格式要規約一致才能正常收發數據。STM32中串口異步通信需要定義的參數:起始位、數據位(8位或者9位)、奇偶校驗位(第9位)、停止位(1,15,2位)、波特率設置。
UART串口通信的數據包以幀為單位,常用的幀結構為:1位起始位+8位數據位+1位奇偶校驗位(可選)+1位停止位。如下圖所示:
奇偶校驗位分為奇校驗和偶校驗兩種,是一種簡單的數據誤碼校驗方法。奇校驗是指每幀數據中,包括數據位和奇偶校驗位的全部9個位中1的個數必須為奇數;偶校驗是指每幀數據中,包括數據位和奇偶校驗位的全部9個位中1的個數必須為偶數。
校驗方法除了奇校驗(odd)、偶校驗(even)之外,還可以有:0 校驗(space)、1 校驗(mark)以及無校驗(noparity)。 0/1校驗:不管有效數據中的內容是什么,校驗位總為0或者1。
UART(USART)框圖
這個框圖分成上、中、下三個部分。本文大概地講述一下各個部分的內容,具體的可以看《STM32中文參考手冊》中的描述。
框圖的上部分,數據從RX進入到接收移位寄存器,后進入到接收數據寄存器,最終供CPU或者DMA來進行讀取;數據從CPU或者DMA傳遞過來,進入發送數據寄存器,后進入發送移位寄存器,最終通過TX發送出去。
然而,UART的發送和接收都需要波特率來進行控制的,波特率是怎樣控制的呢?
這就到了框圖的下部分,在接收移位寄存器、發送移位寄存器都還有一個進入的箭頭,分別連接到接收器控制、發送器控制。而這兩者連接的又是接收器時鍾、發送器時鍾。也就是說,異步通信盡管沒有時鍾同步信號,但是在串口內部,是提供了時鍾信號來進行控制的。而接收器時鍾和發送器時鍾有是由什么控制的呢?
可以看到,接收器時鍾和發送器時鍾又被連接到同一個控制單元,也就是說它們共用一個波特率發生器。同時也可以看到接收器時鍾(發生器時鍾)的計算方法、USRRTDIV的計算方法。
這里需要知道一個知識點:
UART1的時鍾:PCLK2(高速);
UART2、UART3、UART4的時鍾:PCLK1(低速)。
原文:https://blog.csdn.net/qq_38410730/article/details/79887200
vc++6.0使用串口控件例程
打開VC++6.0,建立一個基於對話框的MFC應用程序SCommTest;
選擇Project菜單下Add To Project子菜單中的 Components and Controls…選項,在彈出的對話框中雙擊Registered ActiveX Controls項(稍等一會,這個過程較慢),則所有注冊過的ActiveX控件出現在列表框中。 選擇Microsoft Communications Control, version 6.0,,單擊Insert按鈕將它插入到我們的Project中來,接受缺省的選項。(如果你在控件列表中看不到Microsoft Communications Control, version 6.0,那可能是你在安裝VC6時沒有把ActiveX一項選上,重新安裝VC6,選上ActiveX就可以了),
這時在ClassView視窗中就可以看到CMSComm類了,(注意:此類在ClassWizard中看不到,重構clw文件也一樣),並且在控件工具欄Controls中出現了電話圖標(如圖1所示),現在要做的是用鼠標將此圖標拖到對話框中,程序運行后,這個圖標是看不到的。
打開ClassWizard->Member Viariables選項卡,選擇CSCommTestDlg類,為IDC_MSCOMM1添加控制變量:m_ctrlComm,這時你可以看一看,在對話框頭文件中自動加入了//{{AFX_INCLUDES() #include "mscomm.h" //}}AFX_INCLUDES 。
向主對話框中添加兩個編輯框,一個用於接收顯示數據ID為IDC_EDIT_RXDATA,另一個用於輸入發送數據,ID為IDC_EDIT_TXDATA,再添加一個按鈕,功能是按一次就把發送編輯框中的內容發送一次,將其ID設為IDC_BUTTON_MANUALSEND。別忘記了將接收編輯框的Properties->Styles中把Miltiline和Vertical Scroll屬性選上,發送編輯框若你想輸入多行文字,也可選上Miltiline。
再打開ClassWizard->Member Viariables選項卡,選擇CSCommTestDlg類,為IDC_EDIT_RXDATA添加CString變量m_strRXData,為IDC_EDIT_TXDATA添加CString變量m_strTXData。說明: m_strRXData和m_strTXData分別用來放入接收和發送的字符數據。
打開ClassWizard->Message Maps,選擇類CSCommTestDlg,選擇IDC_MSCOMM1,雙擊消息OnComm,將彈出的對話框中將函數名改為OnComm。
這個函數是用來處理串口消息事件的,如每當串口接收到數據,就會產生一個串口接收數據緩沖區中有字符的消息事件,我們剛才添加的函數就會執行,我們在OnComm()函數加入相應的處理代碼就能實現自已想要的功能了。請你在函數中加入如下代碼:
void CSCommTestDlg::OnComm() { // TODO: Add your control notification handler code here VARIANT variant_inp; COleSafeArray safearray_inp; LONG len,k; BYTE rxdata[2048]; //設置BYTE數組 An 8-bit integerthat is not signed. CString strtemp; if(m_ctrlComm.GetCommEvent()==2) //事件值為2表示接收緩沖區內有字符 { ////////以下你可以根據自己的通信協議加入處理代碼 variant_inp=m_ctrlComm.GetInput(); //讀緩沖區 safearray_inp=variant_inp; //VARIANT型變量轉換為ColeSafeArray型變量 len="safearray"_inp.GetOneDimSize(); //得到有效數據長度 for(k=0;k<len;k++) safearray_inp.GetElement(&k,rxdata+k);//轉換為BYTE型數組 for(k=0;k<len;k++) { BYTE bt=*(char*)(rxdata+k); //字符型 strtemp.Format("%c",bt); //將字符送入臨時變量strtemp存放 m_strRXData+=strtemp; //加入接收編輯框對應字符串 } } UpdateData(FALSE); //更新編輯框內容 }
到目前為止還不能在接收編輯框中看到數據,因為我們還沒有打開串口,但運行程序不應該有任何錯誤,不然,你肯定哪兒沒看仔細,因為我是打開VC6對照着做一步寫一行的,運行試試。沒錯吧?那么做下一步:
你可以在你需要的時候打開串口,例如在程序中做一個開始按鈕,在該按鈕的處理函數中打開串口。現在我們在主對話框的CSCommTestDlg::OnInitDialog()打開串口,加入如下代碼:
// TODO: Add extra initialization here if(m_ctrlComm.GetPortOpen()) m_ctrlComm.SetPortOpen(FALSE); m_ctrlComm.SetCommPort(4); //選擇com4 if( !m_ctrlComm.GetPortOpen()) m_ctrlComm.SetPortOpen(TRUE);//打開串口 else AfxMessageBox("cannot open serial port"); m_ctrlComm.SetSettings("115200,n,8,1"); //波特率9600,無校驗,8個數據位,1個停止位 m_ctrlComm.SetInputMode(1); //1:表示以二進制方式檢取數據 m_ctrlComm.SetRThreshold(1); //參數1表示每當串口接收緩沖區中有多於或等於1個字符時將引發一個接收數據的OnComm事件 m_ctrlComm.SetInputLen(0); //設置當前接收區數據長度為0 m_ctrlComm.GetInput();//先預讀緩沖區以清除殘留數據
現在你可以試試程序了,將串口線接好后,打開串口調試助手,並將串口設在com2,選上自動發送,也可以等會手動發送。再執行你編寫的程序,接收框里應該有數據顯示了。
先為發送按鈕添加一個單擊消息即BN_CLICKED處理函數,打開ClassWizard->Message Maps,選擇類CSCommTestDlg,選擇IDC_BUTTON_MANUALSEND,雙擊BN_CLICKED添加OnButtonManualsend()函數,並在函數中添加如下代碼:
void CSCommTestDlg::OnButtonManualsend() { // TODO: Add your control notification handler code here UpdateData(TRUE); //讀取編輯框內容 m_ctrlComm.SetOutput(COleVariant(m_strTXData));//發送數據 }
運行程序,在發送編輯框中隨意輸入點什么,單擊發送按鈕,啊!看看,在另一端的串口調試助手(或別的調試工具)接收框里出現了什么。
如果你真是初次涉獵串口編程,又一次成功,那該說聲謝謝我了,因為我第一次做串口程序時可費勁了,那時網上的資料也不好找。開開玩笑,謝謝你的支持,有什么好東西別忘了給我寄一份。
說明:
由於用到VC控件,在沒有安裝VC的計算機上運行時要從VC中把mscomm32.ocx、msvcrt.dll、mfc42.dll拷到Windows目錄下的System子目錄中(win2000為System32)並再進行注冊設置。


