STM32F103ZET6串口通信


1、電平標准 

  根據通訊使用的電平標准不同,串口通訊可分為TTL標准和RS-232標准,如下表:

  從圖中可以看到,TTL電平標准使用5V表示高電平,使用0V表示低電平。在R232電平標准中,為了增加串口通訊的遠距離傳輸及抗干擾能力,使用的是-15V表示高電平,使用+15V表示低電平。如下圖為RS232TLL電平標准表示同一個信號時的對比。

 

  在電子電路中,一般使用TTL電平進行通訊,而在PC機中則使用RS232電平進行通訊。所以為了使電子設備可以和PC機進行串口通訊,必須對TTL電平和RS232電平的信號進行互相轉換。

2、串口協議

  串口通訊的英文全稱為Serial Communication,這是一種在設備間非常常用的串行通訊方式。

  串口通訊的協議,串口通訊的數據包由發送設備通過自身的TXD接口傳輸到接收設備的RXD接口。在串口通訊的協議中,規定了數據包的內容,該內容由起始位、數據位、校驗位以及停止位組成,通訊雙方的數據包格式要約定一致才能正常收發數據。格式如下圖:

  在數據幀格式中,校驗位可以要也可以不要。

  一般在串口通信中,空閑狀態下,IO口的電平為高電平。

3、串口波特率

  串口通訊一般使用的是異步通訊,異步通訊是沒有時鍾信號的,為了保證兩個設備能夠正常通訊,必須在兩個設備間約定好收發的速率,波特率就是設備的收發速率,波特率表示的是單位時間內收發的bit位,即一個bit的收發時長。比如波特率為9600的設備,那么該設備1S的時間內可以收發9600個bit,發送一個bit的時長位1/9600≈104us。

4、數據幀的起始信號和停止信號  

  串口通訊的一個數據包是從起始信號開始的,直到停止信號結束。數據包的起始信號由一個邏輯0的數據位表示,而數據包的停止信號可由0.5、1、1.5或2個邏輯1的數據位表示。

  有效數據:

  在數據包的起始位之后緊接着的就是要傳輸的主體數據內容,也稱為有效數據,有效數據的長度常被約定位5、6、7或8位。

  數據校驗:

  在有效數據之后,有一個可選的數據校驗位,由於數據通信相對更容易受到外部干擾導致傳輸數據出現偏差,可以在傳輸過程中加上校驗位來解決這個問題,校驗方法有奇校驗、偶校驗、0校驗、1校驗及無校驗。

  奇校驗要求有效數據和校驗位中“1”的個數為奇數,比如一個8位長的有效數據位:01101001,此時總共有4個“1”,為達到奇校驗的效果,校驗位為“1”,最后傳輸的數據將是8位的有效數據加上1位的校驗位總共9位。

  偶校驗與奇校驗要求剛好相反,要求有效數據和校驗位中“1”的個數為偶數,比如數據幀:11001010,此時有效數據“1”的個數位4,所以偶校驗位為“0”。

  0校驗是不管有效數據中的內容是什么,校驗位總為“0”。

  1校驗是不管有效數據中的內容是什么,校驗位總為“1”。

5、UART和USART的區別 

  UART是指通用異步收發器,UASRT是指通用同步/異步收發器。從名稱上可是看出,USART是在UART基礎上增加了同步功能,即USART是UART的增強型。

  STM32的USART一般做異步通信,即UART功能。

6、USART功能概述 

  使用USART雙向通信至少需要三個腳:GND、RX、TX。

  RX:接收數據引腳,通過采樣技術來區別數據和噪音,從而恢復數據。

  TX:發送數據引腳,當發送器被禁止時,輸出引腳恢復到它的IO端口配置。當發送器被激活,並且不發送數據時,TX引腳處於高電平,也就是說USART的空閑狀態的電平時高電平。這里需要注意一點的是,當與設備相連的時候,如果設備斷電,這需要將發送器禁止,使TX口輸出低電平,否者有可能引起IO口電流倒灌。

  TX腳位在單線和智能卡模式里被同時用於數據的發送和接收。

  USART總線在發送或接收前應處於空閑狀態,即高電平。

  一個起始位,起始位為1。

  一個數據字,可以使8位數據或9位數據。發送或接收數據的時候,是先發送或接收低位數據。

  停止位可設置為0.5、1、1.5、2個停止位,發送或接收停止位說明數據幀發送或接收完成。

  使用分數波特率發生器,由12位整數和4位小數組成。

  一個狀態寄存器USART_SR

  數據寄存器USART_DR

  一個波特率寄存器USART_BRR,12位表示波特率的整數,4位表示波特率的小數。

  一個智能卡模式下的保護時間寄存器USART_GTPR

   USART的框圖如下:

7、STM32的USART波特率配置 

  STM32的每個串口都有一個獨立的波特率寄存器USART_BRR,該寄存器由USART分頻器除法因子USARTDIV的整數部分和小數部分組成。bit4~bit15這12位組成了整數部分DIV_Mantissa,bit0~bit3這4個位組成了分數部分DIV_Fraction

  波特率的計數公式 = CLK/(16*USARTDIV)。 

  CLK是USART的時鍾頻率,USART2、USART3、USART4、USART5使用的是APB1總線時鍾,一般是36MHZ(STM32F103系列);而USART1則使用的是APB2總線時鍾,一般是72MHZ(STM32F103系列)。

  可以根據需要的波特率的值換算出USARTDIV的值。比如設置波特率為9600,則USARTDIV為:

    USARTDIV = CLK / (16 * 9600)

  如果CLK = 72MHZ,則:

  USARTDIV = 72000000/(16*9600) = 468.75

  將小數部分換算為16進制:

    DIV_Fraction = 0.75*16 = 12 = 0x0C

  將整數部分轉為16進制:

    DIV_Mantissa = 468 = 0x1D4

  所以波特率寄存器USART_BRR的值為0x1D4C。

  設置波特率時的誤差如下圖:

  注意不要在通信過程中改變波特率寄存器的值。

8、USART中斷請求

  USART中斷請求表:

  

  USART中斷映像圖:

  從中斷映像圖中可以看出,USART的各種中斷事件被連接到同一個中斷向量,也就是說USART產生的中斷都會進入到同一個中斷服務函數內。

  各種中斷事件:

  發送期間:發送完成、清除發送、發送數據。

  接收期間:空閑總線檢測、溢出錯誤、接收數據寄存器非空、校驗錯誤、LIN斷開符號檢測、噪音標志(僅在多緩沖器通信)和幀錯誤(僅在多緩沖器通信)。

  如果設置了對應的使能控制位,這些事件就可以產生各自的中斷,可以在中斷服務函數內通過判斷狀態寄存器的位來區分是哪個中斷。

9、USART寄存器

  只說明一些用到的位。

  USART_SR狀態寄存器:

  Bit7 TXE位:當TDR寄存器中的數據被硬件轉移到移位寄存器的時候,TXE被硬件置位。

  Bit6 TC位:當發送完一幀有效數據的時候,TC就會置位。

  Bit5 RXNE位:當USART的RDR移位寄存器中的數據被轉移到USART_DR寄存器中時,RXNE位被置1,也就是收到數據的時候RXNE位被置1;如果USART_CR1寄存器中的RXNEIE使能,且USART的中斷使能,則產生中斷,就是所謂的接收中斷。RXNE位可以通過對USART_DR寄存器的讀取操作來清除,也可以對USART_SR寄存器的bit5寫0來清除。

   USART_DR數據寄存器:

 

  該寄存器用來發送和接收數據。

  USART_BRR波特比率寄存器:

  該寄存器用來設置USART的波特率。

  USART_CR1控制寄存器:

 

  Bit13 UE位:這個位用來使能和停止USART模塊,這有UE位被置1的時候,USART才能工作。

  Bit12 M位:該位用來定義數據字的長度,當M=0時,數據字的長度為8個bit;當M=1時,數據字的長度為9個bit。

  Bit10 PCE位:該位用來控制是否使用校驗,當PCE=0時,禁止校驗控制;當PCE=1時,使能校驗控制。

  Bit9 PS位:該位用來選擇校驗方式,當PS=0時,使用偶校驗方式;當PS=1時,使用奇校驗。

  Bit8 PEIE位:該位用來控制校驗錯誤中斷,當PEIE=0時,禁止校驗錯誤產生中斷;當PEIE=1時,使能校驗錯誤產生中斷。

  Bit7 TXEIE位:這個是發送緩沖區空中斷使能位,當TXEIE=0時,禁止發送緩沖區空時產生中斷;當TXEIE=1時,使能發送緩沖區空時產生中斷。

  Bit6 TCIE位:這個是發送完成 中斷使能,當TCIE=0時,禁止發送完成產生中斷;當TCIE=1時,使能發送完成產生中斷。

  Bit5 RXNEIE位:這個是接收緩沖區非空中斷使能,當RXNEIE=0時,禁止接收完成時產生中斷;當RXNEIE=1時,使能接收完成時產生中斷。

  Bit4 IDLEIE位:這個是IDLE總線空閑中斷使能位,當IDLEIE=0時,禁止檢測到總線空閑時產生中斷;當IDLEIE=1時,使能檢測到總線空閑時產生中斷。

  Bit3 TE位:這個是發送使能位,當TE=0時,禁止USART發送數據;當TE=1時,使能USART發送數據。

  Bit2 RE位:這個是接收使能位,當RE=0時,禁止USART接收數據;當RE=1時,使能USART接收數據。

  這里主要區分發送緩沖區空和發送完成這兩個點,發送緩沖器空是指USART_DR寄存器的數值被硬件轉移到以為寄存器的時候,也就是說要發送的數值進入移位寄存器的時候,發送緩沖器空這個條件就會成立。而發送完成是指移位寄存器里的數據發送完成。

  當將一個數據寫入USART_DR寄存器的時候,硬件將USART_DR寄存器的值送入移位寄存器,送完之后會置位USART_SR寄存器的bit7 TXE位,而當移位寄存器里的數值發送完成之后會置位USART_SR寄存器的bit6 TC位。

  USART_CR2控制寄存器:

  Bit12~Bit13 STOP位:這個是停止位長度的選擇位,當STOP=00時,使用1個停止位;當STOP=01時,使用0.5個停止位;當STOP=10時,使用2個停止位;當STOP=11時,使用1.5個停止位;

  需要注意的是UART4和UART5不能使用0.5和1.5個停止位。

10、HAL庫操作USART

  在工程之中添加stm32f1xx_hal_uart.c和stm32f1xx_hal_uart.h文件。

  初始化代碼如下:

 1 UART_HandleTypeDef UART_Handler;  2 
 3 uint8_t aRxBuffer;  4 
 5 void USART_Init(void)  6 {  7 
 8     UART_Handler.Instance = USART1;  9     UART_Handler.Init.BaudRate = 9600; 10     UART_Handler.Init.Mode = UART_MODE_TX_RX; 11     UART_Handler.Init.StopBits = UART_STOPBITS_1; 12     UART_Handler.Init.WordLength = UART_WORDLENGTH_8B; 13     UART_Handler.Init.Parity = UART_PARITY_NONE; 14     UART_Handler.Init.HwFlowCtl = UART_HWCONTROL_NONE; 15     HAL_UART_Init(&UART_Handler); 16     
17     //HAL_UART_Receive_IT(&UART_Handler,aRxBuffer,2);
18     __HAL_UART_ENABLE_IT(&UART_Handler, UART_IT_RXNE); 19     
20     HAL_NVIC_SetPriority(USART1_IRQn,2,1); 21  HAL_NVIC_EnableIRQ(USART1_IRQn); 22              
23 }

  使用HAL_UART_Init()函數初始化USART設備。

  從初始化代碼內,可以看到,需要選擇初始化的USART、波特率、USART的模式(接收和發送)、停止位長度的選擇、數據的長度選擇、校驗的選擇、硬件控制流的選擇。還需要設置USART的時鍾和腳位,但是HAL_UART_Init()函數內會調用USART的時鍾和腳位的初始化回調函數,可以在回調函數內設置腳位和時鍾。

  初始化完USART之后,打開USART的接收中斷,由於HAL庫的接收程序比較復雜,這里直接調用宏__HAL_UART_ENABLE_IT(&UART_Handler, UART_IT_RXNE)來打開USART的接收中斷。

  IO和RCC初始化函數如下:

 1 void HAL_UART_MspInit(UART_HandleTypeDef *husart)  2 {  3  GPIO_InitTypeDef GPIO_InitStruct;  4 
 5  __HAL_RCC_GPIOA_CLK_ENABLE();  6  __HAL_RCC_USART1_CLK_ENABLE();  7     
 8     GPIO_InitStruct.Pin = GPIO_PIN_9;  9     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 10     GPIO_InitStruct.Pull = GPIO_NOPULL; 11     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; 12     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 13 
14     GPIO_InitStruct.Pin = GPIO_PIN_10; 15     GPIO_InitStruct.Mode = GPIO_MODE_INPUT; 16     GPIO_InitStruct.Pull = GPIO_NOPULL; 17     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; 18     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 19 
20 }  

  這里注意的是RX腳,既可以設置成浮空輸入模式也可以設置成復用輸入模式,這兩個是一樣的。

  中斷處理函數如下:

 1 void USART1_IRQHandler(void)  2 {  3     //HAL_UART_IRQHandler(&UART_Handler);
 4     
 5     if(__HAL_UART_GET_FLAG(&UART_Handler,UART_FLAG_RXNE))  6  {  7         aRxBuffer = UART_Handler.Instance->DR;  8         HAL_UART_Transmit(&UART_Handler,&aRxBuffer,1,1000);  9  } 10 }

  由於HAL庫的中斷服務處理比較繁瑣,這里直接讀取USART的中斷標志位來處理接收中斷。

  收到數據到,通過讀取USART_DR寄存器的值來獲取接收到的數值,這里將接收到的數據再發送出去。

HAL庫中斷處理函數說明:

  在HAL庫中斷處理中,進入中斷處理函數之后會調用HAL_UART_IRQHandler()函數,在HAL_UART_IRQHandler()函數內判斷是那種類型的中斷,然后去執行響應的操作。比如接收到數據后,會在HAL_UART_IRQHandler()函數內調用UART_Receive_IT()函數。

  這里需要注意一個問題,在UART_Receive_IT()函數中,接收完成后會清除掉接收中斷的使能位,實際在用HAL庫來處理中斷的時候,接收中斷使能位莫名會被清掉。

  在UART_Receive_IT()函數中會調用接收數據的回調函數HAL_UART_RxCpltCallback()來處理數據。

  使用HAL_UART_Receive_IT(&UART_Handler,aRxBuffer,len)函數來接收數據的時候,如果數據長度不為1,則接收到1個數據的時候,不會進入到HAL_UART_RxCpltCallback()函數中,只有收到實際設置的數據長度時,才會進入HAL_UART_RxCpltCallback()函數。通過進入UART_Receive_IT()函數查看代碼的時候,會發現,當接收完實際設置的數據長度時,會清除掉接收中斷的使能位,這里需要小心,防止收到一次數據之后,不能再進入接收中斷。

 添加支持printf()函數的代碼:

 1 //加入以下代碼,支持printf函數,而不需要選擇use MicroLIB 
 2 #pragma import(__use_no_semihosting)             
 3 //標准庫需要的支持函數 
 4 struct __FILE  5 {  6     int handle;  7 
 8 };  9 
10 FILE __stdout; 11 //定義_sys_exit()以避免使用半主機模式 
12 void _sys_exit(int x) 13 { 14     x = x; 15 } 16 //重定義fputc函數 
17 int fputc(int ch, FILE *f) 18 { 19     while(__HAL_UART_GET_FLAG(&UART_Handler,UART_FLAG_TC) == RESET){}; 20       
21     UART_Handler.Instance->DR = (uint8_t) ch; 22     
23     return ch; 24 }

  加上以上代碼后就可以使用printf()函數發送UART數據了,比如printf("hello world!")。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM