0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

探析STM32上UART丟失的那一字節(jié)數(shù)據(jù)

lcdz66 ? 來(lái)源:雨飛工作室 ? 作者:雨飛工作室 ? 2022-12-19 15:36 ? 次閱讀

串口UART=Universal Asynchronous Receiver / Transmitter,通用異步收發(fā)傳輸器,是工程師最常用的一種串行外設(shè),常見(jiàn)的接口形式有TTL、 RS232、 RS485,但在實(shí)際應(yīng)用中還是會(huì)經(jīng)常遇到各種問(wèn)題,比如:丟失一字節(jié)數(shù)據(jù)。下面就結(jié)合STM32來(lái)講講UART相關(guān)內(nèi)容,談?wù)勅菀讈G失一字節(jié)數(shù)據(jù)的問(wèn)題。

1、UART幾個(gè)標(biāo)志位

STM32上UART狀態(tài)寄存器中的幾個(gè)標(biāo)志位:TXE、TC、RXNE、ORE。這幾個(gè)標(biāo)志位在編程中經(jīng)常使用,數(shù)據(jù)丟失有可能就是對(duì)它們操作不當(dāng)而導(dǎo)致出錯(cuò)。

9edda93c-7f1b-11ed-8abf-dac502259ad0.png ?

TXE=Transmit dataregister empty,發(fā)送數(shù)據(jù)寄存器為空

0:數(shù)據(jù)未傳輸?shù)揭莆患拇嫫鳎?/span>

1:數(shù)據(jù)傳輸?shù)揭莆患拇嫫?/span>

TC=Transmission complete,發(fā)送完 0:傳送未完成;

1:傳送已完成

RXNE=Read dataregister not empty,取數(shù)據(jù)寄存器不為空

0:未接收到數(shù)據(jù);

1:已準(zhǔn)備好讀取接收到的數(shù)據(jù)

ORE=Overrun error,上溢錯(cuò)誤 0:無(wú)上溢錯(cuò)誤;

1:檢測(cè)到上溢錯(cuò)誤

2、UART接收丟失數(shù)據(jù)

UART接收丟失數(shù)據(jù)與軟件和硬件都有可能有關(guān)系,下面說(shuō)幾個(gè)常見(jiàn)丟失數(shù)據(jù)的原因及解決辦法。
問(wèn)題描述 解決辦法
1.接收溢出丟失數(shù)據(jù) 指未及時(shí)取走數(shù)據(jù)導(dǎo)致溢出錯(cuò)誤而丟失數(shù)據(jù),通常是發(fā)生在大量數(shù)據(jù)、以查詢(xún)方式接收數(shù)據(jù)的情況下。MCU啟動(dòng)過(guò)程中、接收數(shù)據(jù)過(guò)多處理不及時(shí)、復(fù)雜系統(tǒng)響應(yīng)不及時(shí)等情況都會(huì)出現(xiàn)數(shù)據(jù)丟失的情況。

(1)及時(shí)清除溢出錯(cuò)誤標(biāo)志;(2)利用通信協(xié)議過(guò)濾因數(shù)據(jù)丟失導(dǎo)致的問(wèn)題

2.接收中斷丟失數(shù)據(jù) 使用UART中斷接收數(shù)據(jù)相比查詢(xún)接收數(shù)據(jù)的方式更常見(jiàn),中斷方式比查詢(xún)方式響應(yīng)更及時(shí),但不合理處理同樣也會(huì)存在數(shù)據(jù)丟失的情況。在數(shù)據(jù)量大時(shí),UART接收中斷函數(shù)耗時(shí)、優(yōu)先級(jí)低等情況下容易丟失數(shù)據(jù)。 (1)中斷函數(shù)里減少不必要的耗時(shí);(2)合理分配中斷優(yōu)先級(jí);(3)使能中斷前清除標(biāo)志位。
3.時(shí)鐘誤差導(dǎo)致丟失數(shù)據(jù) 在通信波特率較高的情況下,如果時(shí)鐘誤差加大,很可能導(dǎo)致數(shù)據(jù)丟失。 (1)使用更高精度晶振;(2)降低通信波特率。
在編程時(shí)需要考慮通信接口方式,在長(zhǎng)距離通信的時(shí)候,需要考慮線路上的延時(shí),如果操作不當(dāng)也會(huì)導(dǎo)致數(shù)據(jù)丟失。

3、串口發(fā)送的幾種寫(xiě)法

串口發(fā)送的幾種寫(xiě)法:一、STM32用USART發(fā)送字符串

	
void UART_Send_Message(u8 *Data)
{
  while(*Data!='')
  {
      USART_SendData(USART1, *Data);
      while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//讀取串口狀態(tài)
      Data++;
  }
}


void main(void)
{
  u8 str_buf[500];
  memset((char *) &str_buf, 0, sizeof(str_buf));
  UART_Send_Message(str_buf);
}
9f147b74-7f1b-11ed-8abf-dac502259ad0.jpg
while(SET == USART_GetFlagStatus(USART1,USART_FLAG_RXNE));

含義是:當(dāng)接收引腳有數(shù)據(jù)時(shí),狀態(tài)寄存器的USART_FLAG_RXNE就會(huì)為1,此時(shí)USART_GetFlagStatus(USART1,USART_FLAG_RXNE)的返回值就為1(SET),若無(wú)數(shù)據(jù)則為RESET。


	
		二、USART_FLAG_TXE和USART_FLAG_TC怎么用這里主要說(shuō)的是在特殊情況下發(fā)送字符軟件代碼的寫(xiě)法:特殊情況指的是:1)調(diào)用發(fā)送字符串函數(shù)“發(fā)送完”本機(jī)立即掉電;2)調(diào)用發(fā)送字符串函數(shù)“發(fā)送完”從機(jī)立即掉電;【上面兩種主要用于芯片對(duì)電源控制的項(xiàng)目中】3)調(diào)用發(fā)送字符串函數(shù)“發(fā)送完”立刻進(jìn)入待機(jī)或停機(jī)。
		主要說(shuō)的是兩個(gè)標(biāo)志位:USART_FLAG_TXE 和 USART_FLAG_TC。USART_FLAG_TXE發(fā)送緩沖區(qū)空標(biāo)志:說(shuō)明可以往數(shù)據(jù)寄存器寫(xiě)入數(shù)據(jù)了,但并不代表數(shù)據(jù)發(fā)送完成了。USART_FLAG_TC發(fā)送完成標(biāo)志:這個(gè)才是代表USART在緩沖區(qū)的數(shù)據(jù)發(fā)送完成了,即從機(jī)接收到了數(shù)據(jù)。這兩個(gè)標(biāo)志的區(qū)別在于:它們分別表示數(shù)據(jù)在發(fā)送過(guò)程中,在兩個(gè)不同的階段中的完成情況。TXE表示數(shù)據(jù)被從發(fā)送緩沖區(qū)中取走,轉(zhuǎn)移到的移位寄存器中,此時(shí)發(fā)送緩沖是空的,可以向其中補(bǔ)充新的數(shù)據(jù)了。而TC則表示最后放入發(fā)送緩沖區(qū)的數(shù)據(jù)已經(jīng)完成了從移位寄存器向發(fā)送信號(hào)線Tx上的轉(zhuǎn)移。所以,判定數(shù)據(jù)最終發(fā)送完成的標(biāo)志是TC,而不是TXE。
		
		
					

4、UART發(fā)送丟失數(shù)據(jù)

UART發(fā)送丟失數(shù)據(jù)很多工程師都遇到過(guò),通常情況下是傳輸未完成的原因。HAL庫(kù)已經(jīng)有幾年了,但還是有很多工程師都使用標(biāo)準(zhǔn)外設(shè)庫(kù),這時(shí)如果自己封裝接口不當(dāng),就會(huì)存在發(fā)送最后一字節(jié)數(shù)據(jù)丟失的問(wèn)題。 1.UART傳輸未完成導(dǎo)致數(shù)據(jù)丟失:如下代碼,只考慮非空,但實(shí)際傳輸并未完成。
void UART_SendByte(uint8_t Data)
{
while(RESET==USART_GetFlagStatus(USART1,USART_FLAG_TXE));  
USART_SendData(USART1, Data);
}
但發(fā)送非空不代表發(fā)送完成,雖然在某些場(chǎng)合更高效,但某些場(chǎng)合就會(huì)導(dǎo)致數(shù)據(jù)丟失。比如:使用此函數(shù)發(fā)送之后進(jìn)入休眠、關(guān)閉接收端設(shè)備電源等情況下。解決辦法:等待發(fā)送完成之后,再次發(fā)送數(shù)據(jù)。
void UART_SendByte(uint8_t Data)
{
while(RESET==USART_GetFlagStatus(USART1,USART_FLAG_TXE));  
USART_SendData(USART1, Data);
while(RESET == USART_GetFlagStatus(USART1, USART_FLAG_TC));
}
如果使用標(biāo)準(zhǔn)外設(shè)庫(kù),要根據(jù)實(shí)際情況封裝函數(shù),比如發(fā)送超時(shí)?;蛘呤褂肏AL封裝的接口,代碼包含判斷傳輸完成:
HAL_StatusTypeDefHAL_UART_Transmit(UART_HandleTypeDef*huart,uint8_t*pData,uint16_tSize,uint32_tTimeout)

2.線路延時(shí)導(dǎo)致數(shù)據(jù)丟失UART通常會(huì)使用232或者485以增加傳輸距離和增強(qiáng)干擾。但是一旦數(shù)據(jù)線路太長(zhǎng)就存在傳輸延時(shí)的情況,特別是485傳輸長(zhǎng)距離,并使用MCU控制傳輸方向的情況下。解決辦法:軟件增加延時(shí)處理;使用通信協(xié)議增加應(yīng)答機(jī)制。 3.其他原因UART應(yīng)用的場(chǎng)景比較多,有些應(yīng)用在復(fù)雜的工廠,干擾較大從而導(dǎo)致數(shù)據(jù)丟失;有些應(yīng)用在溫差較大的環(huán)境,時(shí)鐘偏移較大導(dǎo)致數(shù)據(jù)丟失。解決辦法需要根據(jù)實(shí)際情況,有針對(duì)性解決問(wèn)題。比如:使用更好的通信線,軟件做好容錯(cuò)處理等。 下面講述在不同代碼寫(xiě)法下,得到不同實(shí)驗(yàn)效果【調(diào)試助手接收數(shù)據(jù)】:常見(jiàn)寫(xiě)法一:9f5bf9e0-7f1b-11ed-8abf-dac502259ad0.png ?9f74f774-7f1b-11ed-8abf-dac502259ad0.png這種寫(xiě)法在不是特殊(不掉電、不待機(jī)等)情況下,問(wèn)題不大,USART數(shù)據(jù)會(huì)成功發(fā)送出去。但是在上面說(shuō)的特殊情況下,問(wèn)題就來(lái)了,代碼只將數(shù)據(jù)放到了發(fā)送緩沖區(qū),而沒(méi)有發(fā)送出去就掉電或待機(jī)了,這個(gè)時(shí)候其實(shí)最后兩個(gè)字符是沒(méi)有發(fā)送出去的。2、常見(jiàn)寫(xiě)法二:9f8444ea-7f1b-11ed-8abf-dac502259ad0.png ?9f932b40-7f1b-11ed-8abf-dac502259ad0.png這種寫(xiě)法達(dá)到的效果和上面存在不同的就是倒數(shù)第二個(gè)數(shù)據(jù)發(fā)送出去了,也就是只有最后一個(gè)字符是沒(méi)有發(fā)送出去的。3、常見(jiàn)寫(xiě)法三:9fa14630-7f1b-11ed-8abf-dac502259ad0.png ?9fb6976a-7f1b-11ed-8abf-dac502259ad0.png這種寫(xiě)法達(dá)到的效果和上面兩種寫(xiě)法又不一樣,發(fā)送了10個(gè)字符。4、寫(xiě)法四:9fc86ada-7f1b-11ed-8abf-dac502259ad0.png ?9fe21340-7f1b-11ed-8abf-dac502259ad0.png這種寫(xiě)法按理說(shuō)可以實(shí)現(xiàn)功能,但實(shí)際多次試驗(yàn)結(jié)果卻是第一字節(jié)數(shù)據(jù)丟失了。5、寫(xiě)法五(正確寫(xiě)法):9ff57f48-7f1b-11ed-8abf-dac502259ad0.png ?a0104742-7f1b-11ed-8abf-dac502259ad0.png這種寫(xiě)法是比較完整,為了保守起見(jiàn),在特殊情況下使用該寫(xiě)法。

審核編輯 :李倩


聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5343

    瀏覽量

    120385
  • 數(shù)據(jù)
    +關(guān)注

    關(guān)注

    8

    文章

    7035

    瀏覽量

    89045
  • STM32
    +關(guān)注

    關(guān)注

    2270

    文章

    10900

    瀏覽量

    356089
  • uart
    +關(guān)注

    關(guān)注

    22

    文章

    1235

    瀏覽量

    101404

原文標(biāo)題:探析STM32上UART丟失的那一字節(jié)數(shù)據(jù)

文章出處:【微信號(hào):雨飛工作室,微信公眾號(hào):雨飛工作室】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    如何限制IPD語(yǔ)句中的最大字節(jié)數(shù)?

    當(dāng)數(shù)據(jù)可用時(shí),我正在使用帶有 IP 和 PORT 的擴(kuò)展 IPD 語(yǔ)句。 我的問(wèn)題是,如何限制 IPD 語(yǔ)句中的最大字節(jié)數(shù)? 當(dāng)我嘗試從服務(wù)器作為客戶端檢索數(shù)據(jù)時(shí),響應(yīng)包含大約 20k 的數(shù)
    發(fā)表于 07-17 06:06

    TL16C752D具有64字節(jié)FIFO的雙路UART數(shù)據(jù)

    電子發(fā)燒友網(wǎng)站提供《TL16C752D具有64字節(jié)FIFO的雙路UART數(shù)據(jù)表.pdf》資料免費(fèi)下載
    發(fā)表于 07-10 09:19 ?0次下載
    TL16C752D具有64<b class='flag-5'>字節(jié)</b>FIFO的雙路<b class='flag-5'>UART</b><b class='flag-5'>數(shù)據(jù)</b>表

    如何獲取FIFO中接收的字節(jié)數(shù)?

    我正在嘗試在 UART0 上接收個(gè)字符串,并在最基本的步驟中獲取 RX FIFO 緩沖區(qū)中可用的字節(jié)數(shù)。 我試著使用神奇的公式fifo_len = (READ_PERI_REG
    發(fā)表于 07-10 06:03

    具有128字節(jié)FIFO的TL16C750E UART數(shù)據(jù)

    電子發(fā)燒友網(wǎng)站提供《具有128字節(jié)FIFO的TL16C750E UART數(shù)據(jù)表.pdf》資料免費(fèi)下載
    發(fā)表于 07-08 09:10 ?0次下載
    具有128<b class='flag-5'>字節(jié)</b>FIFO的TL16C750E <b class='flag-5'>UART</b><b class='flag-5'>數(shù)據(jù)</b>表

    使用ESP32的NVS-BLOB存儲(chǔ)12000個(gè)字節(jié)數(shù)據(jù)報(bào)錯(cuò)的原因?

    使用ESP32的NVS-BLOB存儲(chǔ)12000個(gè)字節(jié)數(shù)據(jù),每次完全擦除flash后編程寫(xiě)第次都沒(méi)問(wèn)題,但之后再寫(xiě)就報(bào)錯(cuò)誤ESP_ERR_NVS_NOT_ENOUGH_SPACE (0x1105
    發(fā)表于 06-21 06:53

    ESP32 BLE如何才能接收大于20字節(jié)數(shù)據(jù)

    我使用例程修改功能,發(fā)現(xiàn)在修改MTU加上app 發(fā)送了MTU request (512)后,app 讀特征值數(shù)據(jù)的時(shí)候可以次性讀入42個(gè)字節(jié)數(shù)據(jù),但是app 向 ESP32 寫(xiě)入數(shù)據(jù)
    發(fā)表于 06-20 06:44

    請(qǐng)問(wèn)SPI如何實(shí)現(xiàn)一字節(jié)的收發(fā)?

    通過(guò)SPI方式實(shí)現(xiàn)一字節(jié)的收發(fā),主要是為了適配以下接口:
    發(fā)表于 06-18 07:17

    CC2640R2F BLE如何實(shí)現(xiàn)次連接事件傳輸?shù)?b class='flag-5'>數(shù)據(jù)量為500字節(jié),或者更大?

    您好,我想實(shí)現(xiàn)次連接事件傳輸?shù)?b class='flag-5'>數(shù)據(jù)量為500字節(jié),或者更大。是如何實(shí)現(xiàn)的? MTU設(shè)置成255,應(yīng)該是可以傳輸251字節(jié)數(shù)據(jù)。MAX_NUM_PDU設(shè)置成5,應(yīng)該可以傳送251*5=
    發(fā)表于 05-30 06:12

    STM32L431復(fù)位后第次接收數(shù)據(jù),第一個(gè)字節(jié)丟失的原因?

    if(__HAL_UART_GET_FLAG( hlpuart1, UART_FLAG_IDLE) != RESET) //判斷已經(jīng)接受到一字節(jié)數(shù)據(jù)后的空閑中斷{LPUART_IDLECallBack
    發(fā)表于 05-29 06:14

    如何在AURIX TC375控制器中向DFLASH存儲(chǔ)器寫(xiě)入單字節(jié)數(shù)據(jù)

    我可以使用頁(yè)面地址在 DFLASH 存儲(chǔ)器中寫(xiě)入 8 字節(jié)數(shù)據(jù)。 我需要在任意內(nèi)存地址寫(xiě)入一個(gè)字節(jié)數(shù)據(jù)。 是否可以在任何內(nèi)存地址位置寫(xiě)入單字節(jié)數(shù)據(jù)?
    發(fā)表于 05-27 07:03

    求助,關(guān)于stm32的HAL庫(kù)對(duì)UART采用DMA發(fā)送的地址位標(biāo)志問(wèn)題求解

    stm32 UART多機(jī)通訊可以采用地址喚醒模式,在發(fā)送地址字節(jié)時(shí)設(shè)置USART_DR第9位置1即可,原來(lái)的標(biāo)準(zhǔn)庫(kù)對(duì)這種模式的驅(qū)動(dòng)沒(méi)問(wèn)題,現(xiàn)在最新的HAL驅(qū)動(dòng)庫(kù)對(duì)UART采用DMA發(fā)送
    發(fā)表于 05-09 07:01

    STM32F030F4串口空閑中斷接收不定長(zhǎng)數(shù)據(jù),發(fā)生中斷后不知道如何計(jì)算接收到的字節(jié)數(shù)?

    我用STM32F030F4串口空閑中斷接收不定長(zhǎng)數(shù)據(jù),發(fā)生中斷后不知道怎樣計(jì)算接收到的字節(jié)數(shù)
    發(fā)表于 04-03 07:12

    請(qǐng)問(wèn)cyw20719b2的nvram的存儲(chǔ)空間有多少字節(jié)?

    1)請(qǐng)問(wèn)cyw20719b2的nvram 的存儲(chǔ)空間有多少字節(jié)? 2)用wiced_hal_write_nvram()或wiced_hal_read_nvram()從nvram 寫(xiě)入或讀出一字節(jié)數(shù)據(jù)需要多少時(shí)間
    發(fā)表于 03-01 12:42

    can總線的數(shù)據(jù)幀中數(shù)據(jù)長(zhǎng)度碼和數(shù)據(jù)字節(jié)數(shù)的關(guān)系?

    can總線的數(shù)據(jù)幀中數(shù)據(jù)長(zhǎng)度碼和數(shù)據(jù)字節(jié)數(shù)的關(guān)系? CAN總線是種常用于數(shù)據(jù)通信的協(xié)議,它使用數(shù)據(jù)
    的頭像 發(fā)表于 01-31 11:31 ?2384次閱讀

    M451讓串口接收8個(gè)字節(jié)數(shù)據(jù),為什么每次用串口調(diào)試工具接收到的數(shù)據(jù)都是2次RxData數(shù)據(jù)?

    如下面的段程序,就是讓串口接收8個(gè)字節(jié)數(shù)據(jù),然后把它們通過(guò)串口發(fā)送出去。 uint8_t RxData[8]; uint8_t i = 0; void UART0_IRQHandler(void
    發(fā)表于 01-17 06:44