通用同步異步收發(fā)器(USART)提供了一種靈活的方法來與使用工業(yè)標準NR 異步串行數(shù)據(jù)格式的外部設(shè)備之間進行全雙工數(shù)據(jù)交換孵延。 USART利用分數(shù)波特率發(fā)生器提供寬范圍的波特率選擇逛拱,支持同步單向通信和半雙工單線通信。
1、STM32固件庫使用外圍設(shè)備的主要思路
在STM32中嘲玫,外圍設(shè)備的配置思路比較固定僧鲁。首先是使能相關(guān)的時鐘,一方面是設(shè)備本身的時鐘牧氮,另一方面如果設(shè)備通過IO口輸出還需要使能IO口的時鐘琼腔;最后如果對應(yīng)的IO口是復(fù)用功能的IO口,則還必須使能AFIO的時鐘踱葛。
其次是配置GPIO丹莲,GPIO的各種屬性由硬件手冊的AFIO一章詳細規(guī)定,較為簡單尸诽。
接著相關(guān)設(shè)備需要如果需要使用中斷功能甥材,必須先配置中斷優(yōu)先級,后文詳述性含。
然后是配置外圍設(shè)備的相關(guān)屬性洲赵,視具體設(shè)備而定,如果設(shè)備需要使用中斷方式商蕴,必須使能相應(yīng)設(shè)備的中斷叠萍,之后需要使能相關(guān)設(shè)備。
最后如果設(shè)備使用了中斷功能绪商,則還需要填寫相應(yīng)的中斷服務(wù)程序苛谷,在服務(wù)程序中進行相應(yīng)操作。
2格郁、UART的配置步驟(查詢方式)
2.1抄腔、打開時鐘
由于UART的TX和RX和AFIO都掛在APB2橋上,因此采用固件庫函數(shù)RCC_APB2PeriphClockCmd()進行初始化理张。UARTx需要分情況討論赫蛇,如果是UART1,則掛在APB2橋上雾叭,因此采用RCC_APB2PeriphClockCmd()進行初始化悟耘,其余的UART2~5均掛在APB1上。
? ? RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
2.2织狐、GPIO初始化
GPIO的屬性包含在結(jié)構(gòu)體GPIO_InitTypeDef暂幼,其中對于TX引腳,GPIO_Mode字段設(shè)置為GPIO_Mode_AF_PP(復(fù)用推挽輸出)移迫,GPIO_Speed切換速率設(shè)置為GPIO_Speed_50MHz旺嬉;對于RX引腳,GPIO_Mode字段設(shè)置為GPIO_Mode_IN_FLOATING(浮空輸入)厨埋,不需要設(shè)置切換速率邪媳。最后通過GPIO_Init()使能IO口。
以下是GPIO設(shè)置的實例代碼:
? ? GPIO_InitTypeDef GPIO_InitStructure;
? ? //USART1 Tx(PA.09) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
? ? GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
? ? GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
? ? GPIO_Init(GPIOA, &GPIO_InitStructure);
? ? //USART1 Rx(PA.10) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
? ? GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
? ? GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
? ? GPIO_Init(GPIOA, &GPIO_InitStructure);
2.3、配置UART相關(guān)屬性
通過結(jié)構(gòu)體USART_InitTypeDef來確定雨效。UART模式下的字段如下
USART_BaudRate:波特率迅涮,視具體設(shè)備而定
USART_WordLength:字長
USART_StopBits:停止位
USART_Parity:校驗方式
USART_HardwareFlowControl:硬件流控制
USART_Mode:單/雙工
最后設(shè)置。實例代碼為:
//USART1配置
USART_InitTypeDef USART_InitStructure;
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_Tx | USART_Mode_Rx;
? ? USART_Init(USART1, &USART_InitStructure);
? ? USART_Cmd(USART1, ENABLE);
別忘了最后要使用USART_Cmd()來啟動設(shè)備UART1徽龟。
2.4叮姑、重定向print()函數(shù)。
intfputc(intch,FILE *f)
{
? ? USART1->SR;//USART_GetFlagStatus(USART1, USART_FLAG_TC) 解決第一個字符發(fā)送失敗的問題
? ? //一個一個發(fā)送字符USART_SendData(USART1, (unsignedchar) ch);
? ? //等待發(fā)送完成while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
? ? return(ch);
}
最后通過主函數(shù)直接輸出即可据悔。
intmain(void)
{
? ? // USART1 config 9600 8-N-1? ? USART1_Config();
? ? printf("hello world!");
}
3传透、UART的配置步驟(中斷方式)
打開時鐘、GPIO初始化极颓、配置UART相關(guān)屬性旷祸、重定向print()函數(shù) 與上面的相同。
3.1讼昆、中斷優(yōu)先級的配置
這是STM32比較奇怪的地方托享,在只有一個中斷的情況下,仍然需要配置優(yōu)先級浸赫,其作用是使能某條中斷的觸發(fā)通道闰围。STM32的中斷有至多兩個層次,分別是先占優(yōu)先級和從優(yōu)先級既峡,而整個優(yōu)先級設(shè)置參數(shù)的長度為4位羡榴,因此需要首先劃分先占優(yōu)先級位數(shù)和從優(yōu)先級位數(shù),通過NVIC_PriorityGroupConfig()實現(xiàn)运敢;
特定設(shè)備的中斷優(yōu)先級NVIC的屬性包含在結(jié)構(gòu)體NVIC_InitTypeDef中校仑,其中字段NVIC_IRQChannel包含了設(shè)備的中斷向量,保存在啟動代碼中传惠;字段NVIC_IRQChannelPreemptionPriority為主優(yōu)先級迄沫,NVIC_IRQChannelSubPriority為從優(yōu)先級,取值的范圍應(yīng)根據(jù)位數(shù)劃分的情況而定卦方;最后NVIC_IRQChannelCmd字段是是否使能羊瘩,一般定位ENABLE。最后通過NVIC_Init()來使能這一中斷向量盼砍。實例代碼如下:
//配置UART1接收中斷voidNVIC_Configuration(void)
{
? ? NVIC_InitTypeDef NVIC_InitStructure;
? ? /* Configure the NVIC Preemption Priority Bits */?
? ? NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
? ? /* Enable the USARTy Interrupt */? ? NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;? ?
? ? NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0;
? ? NVIC_InitStructure.NVIC_IRQChannelSubPriority =1;
? ? NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
? ? NVIC_Init(&NVIC_InitStructure);
}
3.2尘吗、中斷的服務(wù)程序的設(shè)計
目前使用了UART的兩個中斷USART_IT_RXNE(接收緩存補空中斷)和USART_IT_TXE(發(fā)送緩存空中斷),前一個中斷保證了一旦有數(shù)據(jù)接收到就進入中斷以接收特定長度的數(shù)據(jù)浇坐,后一個中斷表示一旦發(fā)完一個數(shù)據(jù)就進入中斷函數(shù)睬捶,保證連續(xù)發(fā)送一段數(shù)據(jù)。一個設(shè)備的所有中斷都包含在一個中斷服務(wù)程序中近刘,因此必須首先分清楚這次響應(yīng)的是哪一個中斷擒贸,使用USART_GetITStatus()函數(shù)確定臀晃;采用USART_ReceiveData()函數(shù)接收一個字節(jié)數(shù)據(jù),采用USART_SendData()函數(shù)發(fā)送一個字節(jié)數(shù)據(jù)酗宋,當關(guān)閉中斷時采用USART_ITConfig()失能響應(yīng)的中斷积仗。實例程序:
voidUSART1_IRQHandler(void)
{
? ? uint8_t ch;
? ? if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
? ? {? ?
? ? ? ? //ch = USART1->DR;ch = USART_ReceiveData(USART1);//接受數(shù)據(jù)printf("%c", ch );//返回打印? ? }
}
3.3疆拘、接收數(shù)據(jù)函數(shù):
//重定向scanf函數(shù)到USART1intfgetc(FILE *f)
{
? ? ? ? /*等待串口1輸入數(shù)據(jù)*/while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
? ? ? ? return(int)USART_ReceiveData(USART1);
}
4蜕猫、?STM32串口在首次發(fā)送字符的時候,首字符丟失解決辦法
網(wǎng)上關(guān)于發(fā)送字符的代碼大多如下:
USART_SendData(USART1,?(uint8_t)ch);
while(?USART_GetFlagStatus(USART1,?USART_FLAG_TC)?!=?SET);
其實咋一看是說的通的哎迄,但是在仔細看手冊的時候發(fā)現(xiàn)?TC?和?TXE?標志位在復(fù)位的時候被置1?回右,這樣第一次while循環(huán)就是沒有用的。這樣導(dǎo)致了首次第一個字符還沒有被輸出漱挚,就被后面的字符覆蓋掉翔烁,造成實際看到的丟失現(xiàn)象。解決辦法就很簡單:在前面加上一句?USART1->SR;
具體代碼如下:
USART1->SR;
USART_SendData(USART1,?(uint8_t)ch);
while(?USART_GetFlagStatus(USART1,?USART_FLAG_TC)?!=?SET);
下面我來說說原因:?第一句讀取SR寄存器旨涝,第二句寫DR寄存器?剛好清除了TC標志位?蹬屹。第一次while循環(huán)就起作用了。
也可將USART1->SR;替換為USART_GetFlagStatus(USART1,?USART_FLAG_TC)
?本實驗所有程序《STM32串口USART1的查詢和中斷方式程序》
補充:一直有一個疑問是關(guān)于接受和發(fā)送數(shù)據(jù)的問題:對于“hello”這樣的字符串是一個一個接受還是整個接受顯示白华,下面的實驗可以驗證是一個一個進行的慨默。
(stm32 USART串口應(yīng)用)
http://www.makeru.com.cn/live/1392_1164.html?s=45051
基于STM32講解串口操作
http://www.makeru.com.cn/live/1758_490.html?s=45051
通過Z-stack協(xié)議棧實現(xiàn)串口透傳
http://www.makeru.com.cn/live/1758_330.html?s=45051
(stm32直流電機驅(qū)動)
http://www.makeru.com.cn/live/1392_1218.html?s=45051
(零基礎(chǔ)電子產(chǎn)品設(shè)計)