開發板芯片:STM32F407ZGT6
PA9-USART1_TX,PA10-USART1_RX;
PF9-LED0,PF10-LED1;
一、串口1配置過程(不使用串口中斷):
1.使能時鍾,包括GPIO時鍾和串口1時鍾使能,注意它們是掛載在不同的時鍾總線上的。
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能端口時鍾 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //使能串口時鍾
2.端口映射到串口1。
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);//端口映射到串口 GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
3.GPIO初始化,注意配置模式時,要設置為復用模式,其他和GPIO基本配置相同
IO_Init。GPIO_Mode = GPIO_Mode_AF; //設置為復用模式 IO_Init。GPIO_OType = GPIO_OType_PP; IO_Init。GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; IO_Init。GPIO_PuPd = GPIO_PuPd_UP; IO_Init。GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &IO_Init);
4.串口1初始化,包括:波特率,發送接收使能,數據位,停止位,奇偶校驗,硬件控制流
UT_Init。USART_BaudRate = 9600; //波特率 UT_Init。USART_HardwareFlowControl = USART_HardwareFlowControl_None; //無硬件控制流 UT_Init。USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //發送接收 UT_Init。USART_Parity = USART_Parity_No; //無奇偶校驗 UT_Init。USART_StopBits = USART_StopBits_1; //停止位1 UT_Init。USART_WordLength = USART_WordLength_8b; //數據位8 USART_Init(USART1, &UT_Init);
5.串口1使能。
USART_Cmd(USART1, ENABLE); //串口使能
二、相關的函數和寄存器介紹
1、數據接收
1.1.狀態寄存器
其中的位5:RXNE就是可以接收完成標志位,當數據接收完成時,RXNE會自動置1,我們可以通過讀取該位的狀態,來判斷是否接收到數據,直接讀取該位的方法是
u8 Receive_Data = 0;
Receive_Flag = USART1->SR & 1 << 5; //若接收到數據則標志位=1
上面的方法就是直接讀取位5的值,接收完成則Receive_Flag=1。
其實我們更喜歡用一個函數來讀取RXNE的狀態:
USART_GetFlagStatus(USART1, USART_IT_RXNE)
該函數不僅可以讀取RXNE的狀態,還可以讀取其他位的狀態,若標志置1,該函數則會返回SET,即1。
我們可以看看該函數是如何實現的呢?
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG) { FlagStatus bitstatus = RESET; /* Check the parameters */ assert_param(IS_USART_ALL_PERIPH(USARTx)); assert_param(IS_USART_FLAG(USART_FLAG)); /* The CTS flag is not available for UART4 and UART5 */ if (USART_FLAG == USART_FLAG_CTS) { assert_param(IS_USART_1236_PERIPH(USARTx)); } if ((USARTx->SR & USART_FLAG) != (uint16_t)RESET) { bitstatus = SET; } else { bitstatus = RESET; } return bitstatus; }
可以看出該函數也是通過讀取寄存器相應的位來返回相應的狀態。
還有另一個函數和這個很相似:
USART_GetITStatus(USART1, USART_IT_RXNE);
這個函數也是讀取RXNE的狀態,不同的是當我們打開了串口中斷,接收到數據時,這個函數才會返回1.
也就是說,無論串口中斷是打開,接受完成后RXNE標志位都會置1,即USART_GetFlagStatus(USART1, USART_IT_RXNE)返回1,如果開啟了中斷,那么USART_GetFlagStatus(USART1, USART_IT_RXNE)和USART_GetITStatus(USART1, USART_IT_RXNE)都會置1。
當RXNE置1,即接收到數據后,我們要及時的讀取接收到的數據,相應的函數是Receive_Data = USART_ReceiveData(USART1);
我們也可以直接讀取USART1->DR寄存器,如Receive_Data = USART1->DR;
1.2.數據寄存器
當讀取完成后,RXNE將自動清零,如果沒有讀取數據,則需要軟件清零,可以使用函數USART_ClearFlag(USART1,USART_IT_RXNE);來進行手動清零,或通過將狀態寄存器位5-RXNE置為0:USART1->SR &= ~(1 << 5);這一點是很重要的。
2.數據發送
將數據進行處理后,我們需要回復一些數據,我們可以通過函數USART_SendData(USART1,data);來向外發送數據,當然我們也可以像讀取數據那樣,將數據寫入DR寄存器來實現 USART1->DR=data。其實我們更多的是通過重定向printf()函數來向外格式化輸出數據,如printf("Receive Succsed: %d \r\n", Data);這個更方便一些。
三、程序實現
那么我們怎么來實現電腦發送0x01來控制LED反轉呢?
1.串口配置函數
void USART1_Config() { GPIO_InitTypeDef IO_Init; USART_InitTypeDef UT_Init; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能端口時鍾 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //使能串口時鍾 GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);//端口映射到串口 GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); IO_Init.GPIO_Mode = GPIO_Mode_AF; //設置為復用模式 IO_Init.GPIO_OType = GPIO_OType_PP; IO_Init.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; IO_Init.GPIO_PuPd = GPIO_PuPd_UP; IO_Init.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &IO_Init); UT_Init.USART_BaudRate = 9600; //波特率 UT_Init.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //無硬件控制流 UT_Init.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //發送接收 UT_Init.USART_Parity = USART_Parity_No; //無奇偶校驗 UT_Init.USART_StopBits = USART_StopBits_1; //停止位1 UT_Init.USART_WordLength = USART_WordLength_8b; //數據位8 USART_Init(USART1, &UT_Init); USART_Cmd(USART1, ENABLE); //串口使能 }
2.主函數
主函數怎么寫呢?其實很簡單,就是對接收的數據進行一下判斷就OK了,如果接收到的數據==0x01,那么LED=!LED,是不是很簡單呢?
int main(void) { LED_Init(); delay_init(168); USART1_Config(); LED0_OFF; LED1_OFF; while(1) { u8 Receive_Data = 0; if(USART_GetITStatus(USART1, USART_IT_RXNE)) //若接收到數據 { Receive_Data = USART_ReceiveData(USART1); //讀取數據后,RXNE標志位自動清零; printf("Receive Succsed: %2x \r\n", Receive_Data); if(Receive_Data == 0x01) LED0 = !LED0; // USART_ClearFlag(USART1,USART_IT_RXNE); //手動清零 } else { LED1 = !LED1; printf("Running....\r\n"); delay_ms(500); } } }
這里使用了串口發送“Running....”和LED1閃爍來指示程序正在運行,這種方法很常用,可以指示程序的運行狀態。
本文章沒有使用串口中斷來進行控制,下一篇文章將會介紹如何使用串口中斷來控制LED。
參考資料:
STM32F4xx中文參考手冊
STM32F4開發指南-庫函數版本_V1.1
USART_百度百科
以上是我學習過程的一些個人理解,有不對或不准確的地方,歡迎各位大神指正。
2017年4月16日21:58:46
歡迎大家關注我的個人博客 http://www.wangchaochao.top/
微信掃碼關注我的公眾號
不定期更新個人學習筆記和技術總結,歡迎大家互相學習交流!