STM32 串口 首字節(jié)和尾字節(jié)少
使用stm32f10x調(diào)試串口通訊時(shí),發(fā)現(xiàn)一個(gè)出錯(cuò)的現(xiàn)象,硬件復(fù)位重啟之后,發(fā)送測(cè)試數(shù)據(jù)0x01 0x02 0x03 0x04..接收端收到的數(shù)據(jù)為:0x02 0x03 0x04,第一個(gè)數(shù)據(jù)丟失。換成發(fā)送別的數(shù)值的數(shù)據(jù),如0x06 0x0ff,則接收到0x0ff,0x06丟失。錯(cuò)誤依舊。
故障排除過程:
1、剛開始懷疑是接收端的錯(cuò)誤,我是使用電腦串口,運(yùn)行串口輔助調(diào)試工具接收,換成其他軟件后,發(fā)現(xiàn)故障依舊,而且電腦軟件一直是開啟狀態(tài),不像和電腦軟件有關(guān)。
2、使用單步調(diào)試,單步運(yùn)行各個(gè)發(fā)送指令,都正常。能收到0x01 0x02 0x03 0x04的數(shù)據(jù)。間接的排除了不是電腦軟件的問題,而是其他的錯(cuò)誤。
3、單步調(diào)試運(yùn)行雖然正常了,但連續(xù)運(yùn)行時(shí),錯(cuò)誤依舊?,F(xiàn)在有點(diǎn)摸不到頭緒了,單步運(yùn)行正常,看起來編程沒有出錯(cuò),那故障在哪里呢?測(cè)試程序如下
USART_SendData(USART2, 0x01); //A
while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET); //B
USART_SendData(USART2, 0x02); //C
while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
USART_SendData(USART2, 0x03);
while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
USART_SendData(USART2, 0x04);
while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
4、猜測(cè),也許是因?yàn)槟硞€(gè)特殊原因,使第二個(gè)數(shù)據(jù)覆蓋了首個(gè)數(shù)據(jù),使得首個(gè)數(shù)據(jù)丟失。假設(shè):在執(zhí)行B指令時(shí),USART的 TC 狀態(tài)位==SET,那么就會(huì)緊接著執(zhí)行C指令,也就有可能發(fā)生數(shù)據(jù)的覆蓋。于是,在A指令前,加入如下指令:
USART_ClearFlag(USART2,USART_FLAG_TC);
5、加入上一條指令后,運(yùn)行,錯(cuò)誤消失了。說明上一個(gè)假設(shè),應(yīng)該是成立的。
6、查閱stm32f10x參考手冊(cè),找到這樣一句話:
TC:發(fā)送完成
當(dāng)包含有數(shù)據(jù)的一幀發(fā)送完成后,由硬件將該位置位。如果USART_CR1中的TCIE為1,則產(chǎn)生中斷。由軟件序列清除該位(先讀USART_SR,然后寫入U(xiǎn)SART_DR)。TC位也可以通過寫入0來清除,只有在多緩存通訊中才推薦這種清除程序。
0:發(fā)送還未完成;
1:發(fā)送完成。
7、注意到這一句:由軟件序列清除該位(先讀USART_SR,然后寫入U(xiǎn)SART_DR)。 也就是說,要先read USART_SR,然后write USART_DR,才能完成TC狀態(tài)位的清除。而硬件復(fù)位后,串口發(fā)送的首個(gè)數(shù)據(jù)之前沒有read SR的操作,是直接write DR,也就是說,TC沒有被清除掉。 說明第4步的猜測(cè)是對(duì)的。
8、那么,應(yīng)該把指令A(yù)前面加的USART_ClearFlag(USART2,USART_FLAG_TC); 改為USART_GetFlagStatus(USART2, USART_FLAG_TC);,應(yīng)該也能消除錯(cuò)誤。測(cè)試后證實(shí),確實(shí)如此,在發(fā)送首個(gè)數(shù)據(jù)之前,先讀取一下USART_SR,那么就不會(huì)出現(xiàn)首個(gè)數(shù)據(jù)丟失的情況了。
9、總結(jié):硬件復(fù)位后,串口發(fā)送首個(gè)數(shù)據(jù)之前,先讀取一下USART_SR,則能夠保證首個(gè)數(shù)據(jù)發(fā)送時(shí),不出現(xiàn)覆蓋的情況。當(dāng)然,也有別的方法,比如先清除TC狀態(tài)位,或是,在write USART_DR之后,加入一個(gè)小延時(shí),讓數(shù)據(jù)發(fā)送完畢,應(yīng)該也能間接排除這個(gè)錯(cuò)誤。
STM32的USART發(fā)送數(shù)據(jù)時(shí)如何使用TXE和TC標(biāo)志
在USART的發(fā)送端有2個(gè)寄存器,一個(gè)是程序可以看到的USART_DR寄存器(下圖中陰影部分的TDR),另一個(gè)是程序看不到的移位寄存器(下圖中陰影部分Transmit Shift Register)。
對(duì)應(yīng)USART數(shù)據(jù)發(fā)送有兩個(gè)標(biāo)志,一個(gè)是TXE=發(fā)送數(shù)據(jù)寄存器空,另一個(gè)是TC=發(fā)送結(jié)束;對(duì)照下圖,當(dāng)TDR中的數(shù)據(jù)傳送到移位寄存器后,TXE被設(shè)置,此時(shí)移位寄存器開始向TX信號(hào)線按位傳輸數(shù)據(jù),但因?yàn)門DR已經(jīng)變空,程序可以把下一個(gè)要發(fā)送的字節(jié)(操作USART_DR)寫入TDR中,而不必等到移位寄存器中所有位發(fā)送結(jié)束,所有位發(fā)送結(jié)束時(shí)(送出停止位后)硬件會(huì)設(shè)置TC標(biāo)志。
另一方面,在剛剛初始化好USART還沒有發(fā)送任何數(shù)據(jù)時(shí),也會(huì)有TXE標(biāo)志,因?yàn)檫@時(shí)發(fā)送數(shù)據(jù)寄存器是空的。
TXEIE和TCIE的意義很簡(jiǎn)單,TXEIE允許在TXE標(biāo)志為1時(shí)產(chǎn)生中斷,而TCIE允許在TC標(biāo)志為1時(shí)產(chǎn)生中斷。
至于什么時(shí)候使用哪個(gè)標(biāo)志,需要根據(jù)你的需要自己決定。但我認(rèn)為TXE允許程序有更充裕的時(shí)間填寫TDR寄存器,保證發(fā)送的數(shù)據(jù)流不間斷。TC可以讓程序知道發(fā)送結(jié)束的確切時(shí)間,有利于程序控制外部數(shù)據(jù)流的時(shí)序。
評(píng)論