單片機(jī)學(xué)習(xí)筆記之51內(nèi)核軟件延時(shí)和串口的巧妙方法
發(fā)布時(shí)間:2020-12-28 11:16:45 點(diǎn)擊次數(shù):254
我不知道每個(gè)人都是如何深造51的。無論如何,我一路輕彈。如今,使用51來開發(fā)產(chǎn)品須要充分利用其內(nèi)部資源。最初,主要的頻率和資源不如32。如何在沒有充分利用的情況下開發(fā)出優(yōu)質(zhì)的產(chǎn)品?然后今天我求學(xué)了兩個(gè)小技巧:擴(kuò)展時(shí)間和串口傳輸中斷
情況就是這樣。在產(chǎn)品開發(fā)中,我相遇了74hc595支配數(shù)碼管。使用過此數(shù)字邏輯芯片的每個(gè)人都知道一個(gè)數(shù)字管是可以的。如果有多個(gè),則須要連續(xù)刷新。然后達(dá)到在不同的位顯示不同的破損代碼(數(shù)字)的效果。這種刷新率還是很特別的。我不知道我的學(xué)說是否正確。無論如何,我知道將50hz的民用電連通到燈泡上,人眼看不到燈泡不停閃爍,然后基于此法則,我只需要確保50hz以上的頻率(在20ms以內(nèi)))即時(shí)刷新顯示,但實(shí)際效果是我延遲了for循環(huán)刷新一次,幾乎看不到閃爍。延遲是軟件的5ms延遲,雖然不可靠,但幾乎是一樣的,我不明白為什么要花5ms才能掃除閃爍,反正只要按照實(shí)際結(jié)果,就出現(xiàn)了疑問5毫秒定期刷新,是否有可能MCU只是刷新數(shù)碼管而沒有做其他工作,這一般而言是不可能的。我在調(diào)試過程中實(shí)現(xiàn)的方法是這樣的:
該程序沒有操作系統(tǒng),只有一般而言的while循環(huán)。循環(huán)中有許多任務(wù),可能需要很長時(shí)間才能運(yùn)轉(zhuǎn)。然后我將復(fù)制更多的刷新函數(shù),并根據(jù)任務(wù)的大體時(shí)間損耗將它們放置在不同的位置,這樣效果十分顯著,最少效果要好得多,然后出現(xiàn)了一個(gè)新疑問。當(dāng)任務(wù)功能長時(shí)間執(zhí)行時(shí),依然會(huì)閃爍。有些朋友可能會(huì)認(rèn)為,然后將刷新顯示功能放在任務(wù)功能中。這確實(shí)是個(gè)好方法,我也在程序中使用了它,但是某些任務(wù)功能對(duì)時(shí)間有嚴(yán)苛的要求,因此它們其實(shí)不能放置在內(nèi)部來擾亂其底層驅(qū)動(dòng)程序。我使用的兩種方法;
1.巧妙使用任務(wù)功能本身的延遲功能
例如,我在項(xiàng)目中使用了DHT11溫度和濕度傳感器。該傳感器(包括DS18B20)是單總線協(xié)商,并且對(duì)時(shí)間要求十分嚴(yán)苛。我檢視了底層驅(qū)動(dòng)程序,發(fā)現(xiàn)并找到了一個(gè)相對(duì)較長的地方:
1.jpg
上圖是DHT11的時(shí)序圖,紅線標(biāo)記的地方是MCU提供給傳感器的實(shí)際信號(hào)。這里的手冊(cè)說它最少要低18ms,所以我在這里寫一篇文章。以下是我修改的代碼:
2.jpg
只需讓這20ms的時(shí)間來做其他事情,即刷新數(shù)字管,當(dāng)然,如果有操作系統(tǒng),則操作系統(tǒng)的延遲調(diào)用機(jī)制將更進(jìn)一步提高效率,在這里,請(qǐng)確保執(zhí)行時(shí)間紅色框中的類似于延遲所需的時(shí)間,并且傳感器數(shù)據(jù)可以正常讀取。我還估算沒有實(shí)際的測試時(shí)間。算是,它不便利展開仿真,也不在公司手中。沒有示波器。
2.使用串口發(fā)送中斷
除了修改延遲時(shí)間外,還有一個(gè)棘手的地方,那就是串行端口發(fā)送一幀數(shù)據(jù),而一幀數(shù)據(jù)相對(duì)較長。等候一個(gè)字節(jié)一個(gè)字節(jié)的發(fā)送需要太多時(shí)間,而且添加起來并不容易。刷新功能,我該怎么做,我忽然想到在發(fā)送中斷之前使用32的串行端口。所以我檢驗(yàn)了寄存器并對(duì)其開展了嘗試,它確實(shí)有效性。這說明以前幾乎沒有使用過串行傳輸中斷,修改之前和之后的代碼如下:
3.jpg
請(qǐng)注意,字節(jié)按字節(jié)數(shù)依次發(fā)送。發(fā)送一個(gè)字節(jié)的函數(shù)原型如下:
4.jpg
修改后的串口中斷功能:
5.jpg
從代碼的構(gòu)造來看,一般的法則是當(dāng)沒有數(shù)據(jù)要發(fā)送時(shí),串行端口中斷是關(guān)閉的。當(dāng)有要發(fā)送的數(shù)據(jù)時(shí),先打算好數(shù)據(jù)并將其存儲(chǔ)在一個(gè)數(shù)組中,然后調(diào)用發(fā)送函數(shù),發(fā)送函數(shù)的內(nèi)容是開啟串口的中斷(ES=1),清除發(fā)送完成標(biāo)記(TI=0),并即將發(fā)送的第一個(gè)數(shù)據(jù)放入寄存器(SBUF=dat[0)]),將模擬的發(fā)送數(shù)據(jù)地址對(duì)準(zhǔn)已發(fā)送的第二個(gè)字節(jié)(因?yàn)榈谝粋€(gè)字節(jié)已發(fā)送)已發(fā)送),然后等候中斷。每次發(fā)送一個(gè)字節(jié)時(shí),串口都會(huì)進(jìn)入中斷功能。在中斷功能中,首先斷定它是否是發(fā)送中斷(51內(nèi)核串行端口的發(fā)送中斷和接收中斷使用相同的中斷向量)。發(fā)送中斷后,請(qǐng)確保清除中斷。標(biāo)記,然后繼續(xù)放置下一個(gè)需要發(fā)送的數(shù)據(jù)(SBUF=WIFI_TX_DATA[TX_CNT++];),然后將需要發(fā)送的數(shù)據(jù)的地址移回。確定是否已發(fā)送所有數(shù)據(jù)發(fā)送,然后在發(fā)送后關(guān)閉串口中斷,這樣可以理想發(fā)送一幀數(shù)據(jù),提高效率!
上面的方法只是一個(gè)簡便的過程。檢測長度是14字節(jié)的固定長度。如果是變長檢測,可以根據(jù)實(shí)際情況開展修改。還有一個(gè)我在這里沒有處置但需要注意的疑問,就是有一種情況需要考慮,當(dāng)尚無發(fā)送一幀數(shù)據(jù)時(shí),需要發(fā)送一個(gè)新的數(shù)據(jù)幀,在這種情況下,您需要修改存儲(chǔ)方法,此處的注意事項(xiàng)是解決方案是將需要發(fā)送的數(shù)據(jù)存儲(chǔ)到相對(duì)較大的數(shù)組,然后在每次發(fā)送時(shí)為該數(shù)組分派兩個(gè)指針,分別是頭指針(p)和尾指針(q)。首先斷定它是否是(p=q),如果是,則驗(yàn)證以前的數(shù)據(jù)早已發(fā)送,現(xiàn)在可以不受阻礙了;如果不等于,則繼續(xù)存儲(chǔ)并同時(shí)回到尾指針q的位置(如果溢出,則回頭看一下循環(huán)數(shù)組的方法)。