[導(dǎo)讀]本文介紹如何使用帶FIFO的串口來減少接收中斷次數(shù),通過一種自定義通訊協(xié)議格式,給出幀打包方法;之后介紹一種特殊的串口數(shù)據(jù)發(fā)送方法,可在避免使用串口發(fā)送中斷的情況下,提高系統(tǒng)的響應(yīng)速度。一種可1.簡介串口由于使用簡單,價格低廉,配合RS485芯片可以實(shí)現(xiàn)長距離、抗干擾能力強(qiáng)的局域...
單片機(jī)、ARM、嵌入式等硬件、軟件設(shè)計經(jīng)驗(yàn)的分享,并提供一定的技術(shù)支持。我已加入“維權(quán)騎士”(rightknights.com)的版權(quán)保護(hù)計劃" data-from="0">本文介紹如何使用帶FIFO的串口來減少接收中斷次數(shù),通過一種自定義通訊協(xié)議格式,給出幀打包方法;之后介紹一種特殊的串口數(shù)據(jù)發(fā)送方法,可在避免使用串口發(fā)送中斷的情況下,提高系統(tǒng)的響應(yīng)速度。一種可1. 簡介
串口由于使用簡單,價格低廉,配合RS485芯片可以實(shí)現(xiàn)長距離、抗干擾能力強(qiáng)的局域網(wǎng)絡(luò)而被廣泛使用。隨著產(chǎn)品功能的增多,需要處理的任務(wù)也越來越復(fù)雜,系統(tǒng)任務(wù)也越來越需要及時響應(yīng)。絕大多數(shù)的現(xiàn)代單片機(jī)(ARM7、Cortex-M3)串口都帶有一定數(shù)量的硬件FIFO,本文將介紹如何使用硬件FIFO來減少接收中斷次數(shù),提高發(fā)送效率。在此之前,先來列舉一下傳統(tǒng)串口數(shù)據(jù)收發(fā)的不足之處:(1)每接收一個字節(jié)數(shù)據(jù),產(chǎn)生一次接收中斷。不能有效的利用串口硬件FIFO,減少中斷次數(shù)。(2)應(yīng)答數(shù)據(jù)采用等待發(fā)送的方法。由于串行數(shù)據(jù)傳輸?shù)臅r間遠(yuǎn)遠(yuǎn)跟不上CPU的處理時間,等待串口發(fā)送完當(dāng)前字節(jié)再發(fā)送下一字節(jié)會造成CPU資源浪費(fèi),不利于系統(tǒng)整體響應(yīng)(在1200bps下,發(fā)送一字節(jié)大約需要10ms,如果一次發(fā)送幾十個字節(jié)數(shù)據(jù),CPU會長時間處于等待狀態(tài))。(3)應(yīng)答數(shù)據(jù)采用中斷發(fā)送。增加一個中斷源,增加系統(tǒng)的中斷次數(shù),這會影響系統(tǒng)整體穩(wěn)定性(從可靠性角度考慮,中斷事件應(yīng)越少越好)。(4)針對上述的不足之處,將結(jié)合一個常用自定義通訊協(xié)議,提供一個完整的解決方案。2.串口FIFO
串口FIFO可以理解為串口專用的緩存,該緩存采用先進(jìn)先出方式。數(shù)據(jù)接收FIFO和數(shù)據(jù)發(fā)送FIFO通常是獨(dú)立的兩個硬件。串口接收的數(shù)據(jù),先放入接收FIFO中,當(dāng)FIFO中的數(shù)據(jù)達(dá)到觸發(fā)值(通常觸發(fā)值為1、2、4、8、14字節(jié))或者FIFO中的數(shù)據(jù)雖然沒有達(dá)到設(shè)定值但是一段時間(通常為3.5個字符傳輸時間)沒有再接收到數(shù)據(jù),則通知CPU產(chǎn)生接收中斷;發(fā)送的數(shù)據(jù)要先寫入發(fā)送FIFO,只要發(fā)送FIFO未空,硬件會自動發(fā)送FIFO中的數(shù)據(jù)。寫入發(fā)送FIFO的字節(jié)個數(shù)受FIFO最大深度影響,通常一次寫入最多允許16字節(jié)。上述列舉的數(shù)據(jù)跟具體的硬件有關(guān),CPU類型不同,特性也不盡相同,使用前應(yīng)參考相應(yīng)的數(shù)據(jù)手冊。3.數(shù)據(jù)接收與打包
FIFO可以緩存串口接收到的數(shù)據(jù),因此我們可以利用FIFO來減少中斷次數(shù)。以NXP的lpc1778芯片為例,接收FIFO的觸發(fā)級別可以設(shè)置為1、2、4、8、14字節(jié),推薦使用8字節(jié)或者14字節(jié),這也是PC串口接收FIFO的默認(rèn)值。這樣,當(dāng)接收到大量數(shù)據(jù)時,每8個字節(jié)或者14個字節(jié)才會產(chǎn)生一次中斷(最后一次接收除外),相比接收一個字節(jié)即產(chǎn)生一個中斷,這種方法串口接收中斷次數(shù)大大減少。將接收FIFO設(shè)置為8或者14字節(jié)也十分簡單,還是以lpc1778為例,只需要設(shè)置UART FIFO控制寄存器UnFCR即可。接收的數(shù)據(jù)要符合通訊協(xié)議規(guī)定,數(shù)據(jù)與協(xié)議是密不可分的。通常我們需要將接收到的數(shù)據(jù)根據(jù)協(xié)議打包成一幀,然后交由上層處理。下面介紹一個自定義的協(xié)議幀格式,并給出一個通用打包成幀的方法。自定義協(xié)議格式如圖3-1所示。- 幀首:通常是3~5個0xFF或者0xEE
- 地址號:要進(jìn)行通訊的設(shè)備的地址編號,1字節(jié)
- 命令號:對應(yīng)不同的功能,1字節(jié)
- 長度:數(shù)據(jù)區(qū)域的字節(jié)個數(shù),1字節(jié)
- 數(shù)據(jù):與具體的命令號有關(guān),數(shù)據(jù)區(qū)長度可以為0,整個幀的長度不應(yīng)超過256字節(jié)
- 校驗(yàn):異或和校驗(yàn)(1字節(jié))或者CRC16校驗(yàn)(2字節(jié)),本例使用CRC16校驗(yàn)
下面介紹如何將接收到的數(shù)據(jù)按照圖3-1所示的格式打包成一幀。3.1 定義數(shù)據(jù)結(jié)構(gòu)
typedef?struct?
{??
????uint8_t?*?dst_buf;??????????????????//指向接收緩存??
????uint8_t?sfd;????????????????????????//幀首標(biāo)志,為0xFF或者0xEE??
????uint8_t?sfd_flag;???????????????????//找到幀首,一般是3~5個FF或EE??
????uint8_t?sfd_count;??????????????????//幀首的個數(shù),一般3~5個??
????uint8_t?received_len;???????????????//已經(jīng)接收的字節(jié)數(shù)??
????uint8_t?find_fram_flag;?????????????//找到完整幀后,置1??
????uint8_t?frame_len;??????????????????//本幀數(shù)據(jù)總長度,這個區(qū)域是可選的??
}find_frame_struct;3.2 初始化數(shù)據(jù)結(jié)構(gòu),一般放在串口初始化中
/**?
*?@brief????初始化尋找?guī)臄?shù)據(jù)結(jié)構(gòu)?
*?@param????p_fine_frame:指向打包幀數(shù)據(jù)結(jié)構(gòu)體變量?
*?@param????dst_buf:指向幀緩沖區(qū)?
*?@param????sfd:幀首標(biāo)志,一般為0xFF或者0xEE?
*/??
void?init_find_frame_struct(find_frame_struct?*?p_find_frame,uint8_t?*dst_buf,uint8_t?sfd)??
{??
????p_find_frame->dst_buf=dst_buf;??
????p_find_frame->sfd=sfd;??
????p_find_frame->find_fram_flag=0;??
????p_find_frame->frame_len=10;???????
????p_find_frame->received_len=0;??
????p_find_frame->sfd_count=0;??
????p_find_frame->sfd_flag=0;??
}?3.3 數(shù)據(jù)打包程序
/**?
*?@brief????尋找一幀數(shù)據(jù)??返回處理的數(shù)據(jù)個數(shù)?
*?@param????p_find_frame:指向打包幀數(shù)據(jù)結(jié)構(gòu)體變量?
*?@param????src_buf:指向串口接收的原始數(shù)據(jù)?
*?@param????data_len:src_buf本次串口接收到的原始數(shù)據(jù)個數(shù)?
*?@param????sum_len:幀緩存的最大長度?
*?@return???本次處理的數(shù)據(jù)個數(shù)?
*/??
uint32_t?find_one_frame(find_frame_struct?*?p_find_frame,const?uint8_t?*?src_buf,uint32_t?data_len,uint32_t?sum_len)??
{??
????uint32_t?src_len=0;??
????while(data_len--)??
????{??
????????if(p_find_frame?->sfd_flag==0)????????????????????????
????????{???//沒有找到起始幀首??
????????????if(src_buf[src_len ]==p_find_frame?->sfd)??
????????????{??
????????????????p_find_frame?->dst_buf[p_find_frame?->received_len ]=p_find_frame?->sfd;??
????????????????if( p_find_frame?->sfd_count==5)??????????
????????????????{??
????????????????????p_find_frame?->sfd_flag=1;??
????????????????????p_find_frame?->sfd_count=0;??
????????????????????p_find_frame?->frame_len=10;??
????????????????}??
????????????}??
????????????else??
????????????{??
????????????????p_find_frame?->sfd_count=0;???
????????????????p_find_frame?->received_len=0;???
????????????}??
????????}??
????????else???
????????{???//是否是"長度"字節(jié)??Y->獲取這幀的數(shù)據(jù)長度??
????????????if(7==p_find_frame?->received_len)????????????????
????????????{??
????????????????p_find_frame->frame_len=src_buf[src_len] 5 1 1 1 2;?//幀首 地址號 命令號 數(shù)據(jù)長度 校驗(yàn)???????
????????????????if(p_find_frame->frame_len>=sum_len)??
????????????????{???//這里處理方法根據(jù)具體應(yīng)用不一定相同??
????????????????????MY_DEBUGF(SLAVE_DEBUG,("數(shù)據(jù)長度超出緩存!\n"));??
????????????????????p_find_frame->frame_len=?sum_len;???????
????????????????}??
????????????}??
??????????????
????????????p_find_frame?->dst_buf[p_find_frame->received_len ]=src_buf[src_len ];????????????????
????????????if(p_find_frame?->received_len==p_find_frame?->frame_len)??????????????????
????????????{??
????????????????p_find_frame?->received_len=0;??????????????//一幀完成????
????????????????p_find_frame?->sfd_flag=0;??
????????????????p_find_frame?->find_fram_flag=1;???????????????????
????????????????return?src_len;??
????????????}??
????????}??
????}??
????p_find_frame?->find_fram_flag=0;??
????return?src_len;??
}?使用例子:定義數(shù)據(jù)結(jié)構(gòu)體變量:find_frame_struct?slave_find_frame_srt;定義接收數(shù)據(jù)緩沖區(qū):#define?SLAVE_REC_DATA_LEN??128
uint8_t?slave_rec_buf[SLAVE_REC_DATA_LEN];在串口初始化中調(diào)用結(jié)構(gòu)體變量初始化函數(shù):init_find_frame_struct(
本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
串口作為單片機(jī)開發(fā)的一個常用的外設(shè),應(yīng)用范圍非常廣。大部分時候,串口需要接收處理的數(shù)據(jù)長度是不定的。那么怎么才能判斷一幀數(shù)據(jù)是否結(jié)束呢,今天就以STM32單片機(jī)為例,介紹幾種接收不定長數(shù)據(jù)的方法。
關(guān)鍵字:
單片機(jī)
串口
STM32
單片機(jī)誕生于1971年,經(jīng)歷了SCM、MCU、SoC三大階段。單片機(jī)由以前的1位、4位、8位、16位,發(fā)展到現(xiàn)在的32位甚至64位。當(dāng)前國內(nèi)MCU廠商已有上百家,對標(biāo)進(jìn)口芯片的情況非常嚴(yán)重,導(dǎo)致國內(nèi)MCU產(chǎn)品將陷入同質(zhì)化...
關(guān)鍵字:
單片機(jī)
MCU
市場
(微控制單元 MCU(Microcontroller Unit),又稱單片機(jī),是把中央處理器(CentralProcess Unit; CPU)的頻率與規(guī)格做適當(dāng)縮減,并將內(nèi)存(memory)、計數(shù)器(Timer)、US...
關(guān)鍵字:
單片機(jī)
芯片
CPU
在疫情的影響下,出門后、用餐前使用酒精消毒已成了人們的日常,而酒精噴霧機(jī)也因此變得十分熱銷。為了避免交叉感染的風(fēng)險,自動酒精噴霧器也就應(yīng)運(yùn)而生。不同于傳統(tǒng)手動噴霧器不美觀、手部接觸不衛(wèi)生的bug,此款自動感應(yīng)酒精噴霧器使...
關(guān)鍵字:
芯嶺技術(shù)
方案開發(fā)
解決方案
單片機(jī)
在實(shí)際的單片機(jī)控制系統(tǒng)中,有時候會使用數(shù)字邏輯芯片對單片機(jī)和受控元件進(jìn)行隔離,以保護(hù)單片機(jī),或者令單片機(jī)更好地對后級進(jìn)行控制。
關(guān)鍵字:
單片機(jī)
數(shù)字邏輯芯片
受控元件
MH32F103AVET6使用高性能的32位內(nèi)核,內(nèi)置了多達(dá)2個高級定時器、10個通用定時器、2個基本定時器、3個12位的ADC、2個12位的DAC,還包含標(biāo)準(zhǔn)和先進(jìn)的通信接口包括:3個SPI接口、2個I2S接口、2個I...
關(guān)鍵字:
單片機(jī)
MCU
最近由于換季,天氣突然的轉(zhuǎn)涼,大家也是直呼好冷。天冷了自然是要注意防寒保暖。一個能夠當(dāng)充電寶用的暖手寶會是你最好的陪伴。暖手寶是一種非常便捷易用的發(fā)熱工具,并且體形小巧,可以隨身攜帶并輕易握在手中,也可以放置在身上的其它...
關(guān)鍵字:
芯嶺技術(shù)
方案開發(fā)
解決方案
單片機(jī)
XL32F003 系列微控制器采用高性能的 32 位 ARM?Cortex?- M0+ 內(nèi)核,寬電壓工作范圍的MCU。嵌入高達(dá)64 Kbytes flash和8 Kbytes SRAM存儲器,最高工作頻率32 MHz。包...
關(guān)鍵字:
單片機(jī)
MCU
電動洗鼻器是一種全新的鼻腔清潔工具,一般是通過水壓將生理鹽水送進(jìn)鼻腔,借助于生理鹽水的殺菌作用及水流的沖擊力,將鼻腔內(nèi)已聚集的致病菌及污洉排出,從而使鼻腔恢復(fù)正常的生理環(huán)境,恢復(fù)鼻腔的自我排毒功能,達(dá)到保護(hù)鼻腔的目的。讓...
關(guān)鍵字:
芯嶺技術(shù)
方案開發(fā)
解決方案
單片機(jī)
大家好,我是小舒,今天我?guī)砹艘粋€開源項(xiàng)目。學(xué)習(xí)單片機(jī)的小伙伴,對J-link一定不會陌生。J-link可以使用JATA和SWD接口進(jìn)行在線Debug和程序的燒錄,曾經(jīng)一段時間,某寶上J-Link鋪天蓋地,各種各樣,價格...
關(guān)鍵字:
開源項(xiàng)目
J-link
單片機(jī)
51單片機(jī)是對兼容英特爾8051指令系統(tǒng)的單片機(jī)的統(tǒng)稱。51單片機(jī)廣泛應(yīng)用于家用電器、汽車、工業(yè)測控、通信設(shè)備中。因?yàn)?1單片機(jī)的指令系統(tǒng)、內(nèi)部結(jié)構(gòu)相對簡單,所以國內(nèi)許多高校用其進(jìn)行單片機(jī)入門教學(xué)。
關(guān)鍵字:
51
單片機(jī)
51單片機(jī)論壇
單片機(jī)又稱單片微控制器,它不是完成某一個邏輯功能的芯片,而是把一個計算機(jī)系統(tǒng)集成到一個芯片上。相當(dāng)于一個微型的計算機(jī),和計算機(jī)相比,單片機(jī)只缺少了I/O設(shè)備。概括的講:一塊芯片就成了一臺計算機(jī)。它的體積小、質(zhì)量輕、價格便...
關(guān)鍵字:
單片機(jī)
微控制器
芯片
前幾天直播間不小心給物聯(lián)網(wǎng)開發(fā)板通入了12V電源。原本開發(fā)板的供電要求是5V。不小心將拾音磁流體的適配器12V插了進(jìn)去。瞬間板子出現(xiàn)燒焦的味道,馬上斷電。當(dāng)時并沒有發(fā)現(xiàn)是哪里出現(xiàn)發(fā)熱,首先害怕是WiFi模塊燒壞,因?yàn)檫@個...
關(guān)鍵字:
單片機(jī)
物聯(lián)網(wǎng)
從事計算機(jī)和或電子行業(yè)相關(guān)領(lǐng)域工作的朋友,一般都聽說過單片機(jī)和嵌入式。但是要問單片機(jī)和嵌入式兩者之間有什么聯(lián)系,大多數(shù)人都不能很好的解釋清楚。想要弄清楚嵌入式和單片機(jī)有什么聯(lián)系,首先就要弄明白什么是嵌入式,什么是單片機(jī)。...
關(guān)鍵字:
嵌入式
單片機(jī)
自從芯片漲價潮以來,國產(chǎn)芯片,尤其是單片機(jī)類芯片猶如雨后春筍般發(fā)展起來,其中也不乏一些優(yōu)秀的產(chǎn)品。今天來盤點(diǎn)一下一些有特點(diǎn)的單片機(jī)。這里所說的單片機(jī),是指通用型的MCU,像ESP32等SOC芯片就不在本次討論范圍內(nèi)了。而...
關(guān)鍵字:
芯片
單片機(jī)
很多RTOS之所以可以用于資源很少的單片機(jī),是因?yàn)樗鼈兛梢耘渲?,一般可以使用宏定義來選擇需要的功能,而裁剪掉不必要的功能,以減少對硬件的資源占用。
關(guān)鍵字:
RTOS
單片機(jī)
C語言是一門面向過程的、抽象化的通用程序設(shè)計語言,廣泛應(yīng)用于底層開發(fā)。C語言能以簡易的方式編譯、處理低級存儲器。C語言是僅產(chǎn)生少量的機(jī)器語言以及不需要任何運(yùn)行環(huán)境支持便能運(yùn)行的高效率程序設(shè)計語言。盡管C語言提供了許多低級...
關(guān)鍵字:
C語言
單片機(jī)
單片機(jī)(Single-Chip Microcomputer)是一種集成電路芯片,是采用超大規(guī)模集成電路技術(shù)把具有數(shù)據(jù)處理能力的中央處理器CPU、隨機(jī)存儲器RAM、只讀存儲器ROM、多種I/O口和中斷系統(tǒng)、定時器/計數(shù)器等...
關(guān)鍵字:
單片機(jī)
寄存器
從二十世紀(jì)九十年代開始,單片機(jī)技術(shù)就已經(jīng)發(fā)展起來,隨著時代的進(jìn)步與科技的發(fā)展,目前該技術(shù)的實(shí)踐應(yīng)用日漸成熟,單片機(jī)被廣泛應(yīng)用于各個領(lǐng)域。
關(guān)鍵字:
單片機(jī)
電子產(chǎn)品