本章中主要講解的是串口異步通訊,異步通訊中由於沒有時鍾信號, 所以兩個通訊設備之間需要約定好波特率,即每個碼元的長度,以便對信號進行解碼 。
串口通訊的一個數據包從起始信號開始,直到停止信號結束。數據包的起始信號由一
個邏輯 0 的數據位表示,而數據包的停止信號可由 0.5、 1、 1.5 或 2 個邏輯 1 的數據位表示,
只要雙方約定一致即可。
STM32 芯片具有多個 USART 外設用於串口通訊,它是 Universal Synchronous
Asynchronous Receiver and Transmitter 的縮寫,即通用同步異步收發器可以靈活地與外部設
備進行全雙工數據交換。有別於 USART,它還有具有 UART 外設(Universal Asynchronous
Receiver and Transmitter),它是在 USART 基礎上裁剪掉了同步通信功能,只有異步通信。
簡單區分同步和異步就是看通信時需不需要對外提供時鍾輸出,我們平時用的串口通信基
本都是 UART。
STM32 的 USART 輸出的是 TTL 電平信號,若需要 RS-232 標准的信號可使用
MAX3232 芯片進行轉換。
①功能引腳
TX:發送數據輸出引腳。
RX:接收數據輸入引腳。
SW_RX:數據接收引腳,只用於單線和智能卡模式,屬於內部引腳,沒有具體外部引
腳。
nRTS:請求以發送(Request To Send), n 表示低電平有效。如果使能 RTS 流控制,當
USART 接收器准備好接收新數據時就會將 nRTS 變成低電平;當接收寄存器已滿時,
nRTS 將被設置為高電平。該引腳只適用於硬件流控制。
nCTS:清除以發送(Clear To Send), n 表示低電平有效。如果使能 CTS 流控制,發送
器在發送下一幀數據之前會檢測 nCTS 引腳,如果為低電平,表示可以發送數據,如果為
高電平則在發送完當前數據幀之后停止發送。該引腳只適用於硬件流控制。
SCLK:發送器時鍾輸出引腳。這個引腳僅適用於同步模式。
USART 引腳在 STM32F429IGT6 芯片具體發布見表 20-3。
應用型編程,先會使用,有需要再去解析內部實現:
int main(void) { /*初始化USART 配置模式為 115200 8-N-1,中斷接收*/ Debug_USART_Config(); /* 發送一個字符串 */ Usart_SendString( DEBUG_USART,"這是一個串口中斷接收回顯實驗\n"); printf("這是一個串口中斷接收回顯實驗\n"); while(1) { } }
void Debug_USART_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_AHB1PeriphClockCmd(DEBUG_USART_RX_GPIO_CLK|DEBUG_USART_TX_GPIO_CLK,ENABLE); /* 使能 USART 時鍾 */ RCC_APB2PeriphClockCmd(DEBUG_USART_CLK, ENABLE); /* GPIO初始化 */ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /* 配置Tx引腳為復用功能 */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_PIN ; GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure); /* 配置Rx引腳為復用功能 */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_PIN; GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure); /* 連接 PXx 到 USARTx_Tx*/ GPIO_PinAFConfig(DEBUG_USART_RX_GPIO_PORT,DEBUG_USART_RX_SOURCE,DEBUG_USART_RX_AF); /* 連接 PXx 到 USARTx__Rx*/ GPIO_PinAFConfig(DEBUG_USART_TX_GPIO_PORT,DEBUG_USART_TX_SOURCE,DEBUG_USART_TX_AF); /* 配置串DEBUG_USART 模式 */ /* 波特率設置:DEBUG_USART_BAUDRATE */ USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE; /* 字長(數據位+校驗位):8 */ USART_InitStructure.USART_WordLength = USART_WordLength_8b; /* 停止位:1個停止位 */ USART_InitStructure.USART_StopBits = USART_StopBits_1; /* 校驗位選擇:不使用校驗 */ USART_InitStructure.USART_Parity = USART_Parity_No; /* 硬件流控制:不使用硬件流 */ USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; /* USART模式控制:同時使能接收和發送 */ USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; /* 完成USART初始化配置 */ USART_Init(DEBUG_USART, &USART_InitStructure); /* 嵌套向量中斷控制器NVIC配置 */ NVIC_Configuration(); /* 使能串口接收中斷 */ USART_ITConfig(DEBUG_USART, USART_IT_RXNE, ENABLE); /* 使能串口 */ USART_Cmd(DEBUG_USART, ENABLE); }
從上面的紅色部分我們可以知道,和往常一樣,開啟時鍾是第一步,尤其注意的是引腳復用調用的函數,注意是GPIO_Pinsource而不是GPIO_Pin.
在編寫程序的時候,首先參考官方固件庫,然后謹記編程要點,比如什么時鍾應該開啟,引腳功能如何配置,是否有復用模式,中斷是否需要配置。這需要我們熟悉外設掛載在哪個總線上,已及總線的最高時鍾,這些都知道以后,固件庫編程是很快速的。至於固件庫的具體實現,也是很有參考價值的,但是如果你手上還有很多需要學習的東西,可以暫時不管固件庫底層如何實現,先完成基本設計,再慢慢深入。這是一個長期累積的過程。
串口調試助手,不勾選發送模式,默認是以字符的方式發送。
編程時需要用到的固件庫函數
要使用printf重定向,需要重寫fputc函數,並且在keil中勾選使用微庫。
NOTE:
STM32默認就是小端模式:
The processor can access data words in memory in little-endian format or big-endian
format. It always accesses code in little-endian format.
Note:
Little-endian is the default memory format for ARM processors.
在發送一個字節8位模式時,是從高位開始向低位傳輸的:
但是,要是我們想要發送一個16位的數據,是先發送高8位呢還是低8位?通過參考歷程可以看出,是先發送的高8位,再發送低8位。
那么為什么要先發送高8位再發送底八位呢?
例如一個16位數據0x1234;在寄存器中是高位在前,低位在后的(stm32默認小端模式)。
二進制 0001 0010 0011 0100;
要想把這一串二進制以8位一次的方式發送,如果我們先發送低8位,再發送高8位,最后出來將會是0x3412,所以,我們應該先發送高位再發送低位。
重要寄存器,解釋為什么發送接收庫函數要那么去寫:
//接收庫函數
//發送庫函數
首先,這是中斷服務函數調用的,首先調用接收函數,能進接收中斷,所以肯定有數據發來單片機接收到了,此時把DR寄存器的值得低9位(在我們的歷程中使用的8位,到底是9位還是8位要看M的設置),這個值返回出來,確實應該是接收函數。但是,為什么像DR中寫入數據,就是發送了?剛開始我也不理解,但是參看參考手冊之后,發現,寫數據倒DR寄存器中會硬件觸發標志,這樣,內核可以知道你是接收還是發送。
發送端:
7. 在 USART_DR 寄存器中寫入要發送的數據(該操作將清零 TXE 位)。為每個要在單緩
沖區模式下發送的數據重復這一步驟。
8. 向 USART_DR 寄存器寫入最后一個數據后,等待至 TC=1。這表明最后一個幀的傳送已
完成。禁止 USART 或進入暫停模式時需要此步驟,以避免損壞最后一次發送。
接收端:
這樣,讀DR寄存器,會產生一些硬件標志置位,所以內核可以知道是否接收完成,向DR寄存器寫數據,也會產生一些硬件標志位,這樣內核就知道是否發送發送完成。
嵌入式開發,離不開和芯片手冊折騰,但是這又是必備技能,而且這里STMF4還是中文參考手冊,更多時候,我們開發是英文手冊,更加困難,所以,軟件程序員,必須熟練運用英語和數學。