STM32F10x 學(xué)習(xí)筆記5(USART實(shí)現(xiàn)串口通訊 1)
從前面的介紹可知USART模塊功能非常的強(qiáng)大。這里我只簡單講講如何用USART模塊來實(shí)現(xiàn)標(biāo)準(zhǔn)EIA-232串口通訊。
用過單片機(jī)的人肯定都接觸過串口,設(shè)置串口無非就是設(shè)置波特率、數(shù)據(jù)位、停止位、奇偶校驗(yàn)位。發(fā)送接收也就三種基本方式,輪詢、中斷和DMA。STM32F10x的USART模塊也不過如此。所以我重點(diǎn)講講我在調(diào)試代碼時(shí)犯得各種錯(cuò)誤,那些很容易得到的代碼就不詳細(xì)的講解了。
首先說說我的硬件環(huán)境。還是那塊神舟4號(hào)開發(fā)板,用的是串口2,對(duì)應(yīng)的是USART2。默認(rèn)情況下USART2是連接到IO端口A的,但是我這里需要將USART的管腿重定向到IO端口D上。具體的管腿的關(guān)系參見下表。這個(gè)表是從STM32參考手冊上拷下來的。
初始化USART的代碼很簡單。USART2連接到APB1總線上了,先要打開USART2的時(shí)鐘,然后設(shè)置波特率一類的參數(shù)。
- USART_InitTypeDefUSART_InitStructure;
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
- USART_InitStructure.USART_BaudRate=9600;
- USART_InitStructure.USART_WordLength=USART_WordLength_8b;
- USART_InitStructure.USART_StopBits=USART_StopBits_1;
- USART_InitStructure.USART_Parity=USART_Parity_No;
- USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
- USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
- USART_Init(USART2,&USART_InitStructure);
這樣設(shè)置了還不能使用。因?yàn)槲覀儗SART2重定向了。重定向操作需要寫復(fù)用重映射和調(diào)試I/O配置寄存器(AFIO_MAPR)。GPIO_PinRemapConfig()可以完成這項(xiàng)任務(wù)。
- GPIO_PinRemapConfig(GPIO_Remap_USART2,ENABLE);
光這樣操作還不夠。STM32參考手冊上有這么一段話:
對(duì)寄存器AFIO_EVCR,AFIO_MAPR和AFIO_EXTICRX進(jìn)行讀寫操作前,應(yīng)當(dāng)首先打開AFIO的時(shí)鐘。參考第6.3.7節(jié)APB2外設(shè)時(shí)鐘使能寄存器(RCC_APB2ENR)。
所以需要先打開AFIO的時(shí)鐘。因此,USART2的重定向需要兩步操作:
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
- GPIO_PinRemapConfig(GPIO_Remap_USART2,ENABLE);
我原以為這樣就能工作了,可是結(jié)果還是什么都沒有輸出。沒辦法只能繼續(xù)研究。在讀GPIO的相關(guān)章節(jié)時(shí)看到下圖讓我恍然大悟。
USART2的輸入輸出都是借用PD口管腿,PD口的時(shí)鐘卻還沒給。用到的幾個(gè)IO端口也沒有設(shè)置相應(yīng)的輸入輸出狀態(tài)。在讀到8.1.9復(fù)用功能配置這一小節(jié)時(shí)發(fā)現(xiàn)了如下的表格。
按照上面給出的配置,寫好程序:
- GPIO_InitTypeDefGPIO_InitStructure;
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);
- /*ConfigureUSARTTxasalternatefunctionpush-pull*/
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
- GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
- GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
- GPIO_Init(GPIOD,&GPIO_InitStructure);
- /*ConfigureUSARTRxasinputfloating*/
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
- GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
- GPIO_Init(GPIOD,&GPIO_InitStructure);
再次測試,一切正常。
發(fā)送一個(gè)字符的函數(shù)可以這么寫:
- voidUART_PutChar(USART_TypeDef*USARTx,uint8_tData)
- {
- while(USART_GetFlagStatus(USART2,USART_FLAG_TC)==RESET){};
- USART_SendData(USARTx,Data);
- }
發(fā)送字符串的函數(shù)如下:
- voidUART_PutStr(USART_TypeDef*USARTx,uint8_t*str)
- {
- while(0!=*str)
- {
- UART_PutChar(USARTx,*str);
- str++;
- }
- }
上面串口初始化的代碼可以放到一個(gè)函數(shù)中:
- voidUSART2_init(void)
- {
- GPIO_InitTypeDefGPIO_InitStructure;
- USART_InitTypeDefUSART_InitStructure;
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD|RCC_APB2Periph_AFIO,ENABLE);
- /*ConfigureUSARTTxasalternatefunctionpush-pull*/
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
- GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
- GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
- GPIO_Init(GPIOD,&GPIO_InitStructure);
- /*ConfigureUSARTRxasinputfloating*/
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
- GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
- GPIO_Init(GPIOD,&GPIO_InitStructure);
- GPIO_PinRemapConfig(GPIO_Remap_USART2,ENABLE);
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
- USART_InitStructure.USART_BaudRate=9600;
- USART_InitStructure.USART_WordLength=USART_WordLength_8b;
- USART_InitStructure.USART_StopBits=USART_StopBits_1;
- USART_InitStructure.USART_Parity=USART_Parity_No;
- USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
- USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
- USART_Init(USART2,&USART_InitStructure);
- USART_Cmd(USART2,ENABLE);
- }
今天先寫這么多。接收字符的函數(shù)與發(fā)送字符的函數(shù)差不多,但是這種輪詢方式效率很低,不建議使用。下次寫一篇介紹如何用中斷方式發(fā)送接收串口數(shù)據(jù),中斷方式的效率會(huì)高很多。如果有時(shí)間再寫一篇DMA方式發(fā)送接收數(shù)據(jù)的文章。
評(píng)論