www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁 > 單片機 > 單片機
[導(dǎo)讀]1、C51串口的弊端。C51的串口收發(fā)程序相信大家都很熟悉了,在hello.c里面有很簡單的例程,不知 道大家有沒有注意到hello.c里面有一句很不顯眼的語句"TI = 1;" 當(dāng)你在初始化串口的時候如果你不讓TI = 1的話,相信你看到

1、C51串口的弊端。
C51的串口收發(fā)程序相信大家都很熟悉了,在hello.c里面有很簡單的例程,不知 道大家有沒有注意到hello.c里面有一句很不顯眼的語句"TI = 1;" 當(dāng)你在初始化串口的時候如果你不讓TI = 1的話,相信你看到你的數(shù)據(jù)永遠都發(fā)不出去,debug里運行stop會看到程序?qū)嶋H上是進行到了while(!TI);的語句處進入死循環(huán)了。

深 入一點的看,可以在keil/c51/lib下發(fā)現(xiàn)putchar函數(shù)的原文件,和許多軟件串口驅(qū)動一樣printf()都是反復(fù)調(diào)用putchar() 來實現(xiàn)的,所以putchar函數(shù)是我們進入死循環(huán)的癥結(jié)。putchar函數(shù)很簡單,在其中有一個最小實現(xiàn)方式,我就以這個簡單的例子來解釋。

char putchar(char c){
while(!TI);
TI = 0;
return(SBUF = c);
}

很 顯然,C51中缺省的putchar函數(shù)是靠查詢并等待TI這個標(biāo)志位來實現(xiàn)串口發(fā)送的,也就是說,在putchar函數(shù)中確實發(fā)送了所有的數(shù)據(jù),但是每 發(fā)送一個BYTE前都等待了一段時間。這就不難理解為什么在初始化串口的時候必須把TI置位了,無非是想讓發(fā)第一個數(shù)據(jù)的時候讓putchar函數(shù)能順利 執(zhí)行。

注意,這里有一個問題出現(xiàn)了,我們可以把UART理解為一個獨立的外設(shè),在一次數(shù)據(jù)裝訂后就應(yīng)該交給UART自動完成數(shù)據(jù)收發(fā),也 就是說寶貴的CPU時間應(yīng)該不在這里浪費掉,所以我們可以做出這樣一個結(jié)論C51的putchar函數(shù)其實是有弊端的,它在等待TI置位時大大占用了 CPU時間。

2、刨根問底
為什么C51這么別有用心的設(shè)計這樣一個基礎(chǔ)的函數(shù)來實現(xiàn)收發(fā)呢,為什么必須用TI來支持這個判斷,我在寫程序的時候發(fā)現(xiàn)了一點,其實就是51中UART的一點特性。
51 的UART可以理解為一個自動的串行輸出外設(shè),每對SBUF寫一個數(shù)據(jù)就會觸發(fā)UART的一次串行輸出操作,即在定時器分頻的基礎(chǔ)上逐步移初所有數(shù)據(jù)位 (包括啟始為和結(jié)束位等等),移出速度是靠定時器溢出時間來來度量的,所以對于MCU來說這個時間一般都比較長。因此如果在定時器還沒有溢出的時候再對 SBUF寫數(shù)據(jù)的話會重新引起這個新數(shù)據(jù)的發(fā)送。這樣如果你寫

while(1)
SBUF = 'a';

其實是沒有任何意義的,發(fā)出的肯定是亂碼。
由于以上的原因我們就可以看出TI確實是上次發(fā)送的結(jié)束和下次發(fā)送的開始的結(jié)點。C51也是利用了這樣一個特性來實現(xiàn)自己的函數(shù)。

3 改進的PUTCHAR函數(shù)
緩 沖區(qū)是連接告訴設(shè)備和低速設(shè)備的接口,我們的串口收發(fā)其實就是MCU的高速和UART的低速的協(xié)同工作,所以我們應(yīng)該設(shè)計一個緩沖區(qū)作為數(shù)據(jù)的暫存位置, 當(dāng)設(shè)備發(fā)送數(shù)據(jù)的時候如果UART正在忙于發(fā)上一個數(shù)據(jù)那么就應(yīng)該把數(shù)據(jù)存在BUFF里面,而如果UART不忙了就應(yīng)該把數(shù)據(jù)從BUFF里面順序讀出并發(fā) 送。

這個正好符合隊列的概念,我就設(shè)計了一個循環(huán)隊列來實現(xiàn)這個功能。而在
putchar函數(shù)就應(yīng)該設(shè)計成
void putchar(char c)
{
if(UART不忙)
直接發(fā)送數(shù)據(jù)到SBUF
else
把數(shù)據(jù)寫到BUFF里
}

而中斷函數(shù)則應(yīng)該寫為
ISR(){
……

if(TI){
TI = 0;
if(BUFF里面還有數(shù)據(jù))
取下一個數(shù)據(jù)并發(fā)送;
}

新的問題又出現(xiàn)了,什么是UART忙,他與TI的關(guān)系如何,是不是TI = 0就是UART忙?

前兩個問題先不說,最后一個問題的答案很顯然是“no!”,從最極端的角度來看,上電后UART就是空閑,TI也應(yīng)該等于0!

上面的幾個問題從另一個角度也可以得到答案,這里有一點點哲理的問題,一個物品一般只能完成一件事情,既然TI已經(jīng)作為上次發(fā)送的結(jié)束和下次發(fā)送的開始的結(jié)點那么它應(yīng)該不是作為UART忙的標(biāo)致。

4、最后的設(shè)計概要
從OS的角度來看UART是一種資源,對于我們的程序我們把SBUF看做它的載體,所以對于高速和低速設(shè)備的同步問題我們應(yīng)該引入互斥量來實現(xiàn)對這個資源占用情況的標(biāo)志。所以我設(shè)計的串口驅(qū)動里寫了一個mutex_sbuf來實現(xiàn)這個功能。
后面的事情就簡單了

void putchar(char c)
{
if(mutex_sbuf == 0){
EA = 0
mutex_sbuf = 1;
SBUF = c;
EA = 1
}
else
把數(shù)據(jù)寫到SBUF里面
}

ISR()
{
……

if(TI){
TI = 0;
mutex_sbuf = 0;
if(BUFF里面還有數(shù)據(jù)){
mutex_sbuf = 1;
取下一個數(shù)據(jù)并送;
}
}
}

寫到這里說的差不多了,沒興致了:( 以后我把程序貼上來供大家參考
希望大家能把我的程序優(yōu)化一下,我現(xiàn)在的這個版本的driver是用純C寫的,對ROM的占用太大了。以后我會用ASM來改寫部分代碼。

而且還有一個問題就是C51對于指針的使用很麻煩,程序很容易跑飛,我的代碼還不是足夠的清晰,因為就是指針的亂跑,所以我在必要的函數(shù)里面加了指針類型限定,但是我發(fā)現(xiàn)如果都加限定的話反而也會飛。

過兩天我會放上來希望大家能一起把這個寫好。

寫得不錯,但我不傾向采用中斷發(fā)送。因為如果采 用中斷發(fā)送的話,需要一個發(fā)送緩沖區(qū),緩沖區(qū)設(shè)多大?只設(shè)一個字節(jié)的話,那么調(diào)用putchar的時候是不是先得判斷緩沖區(qū)非空,如果不空則printf 一類的函數(shù)仍然需要等待。緩沖區(qū)設(shè)很大的話,有兩個問題,一是51本來內(nèi)存就小,二仍然是需要判斷緩沖區(qū)空不空??紤]再三,還是用的查詢發(fā)送。到底采用查 詢或中斷發(fā)送,可能要根據(jù)自己的需求來選擇。

另外,KeilC寫的不見得就比asm寫的占空間大;c指針跑飛的原因,大部分是指針越界,比如申請了5字節(jié)內(nèi)存,使用了第6個,把別的變量沖掉了等等,不在于你是否加cast,也就是說與強制類型轉(zhuǎn)換無關(guān),要加強對查表等索引指針的檢查,確保指針不越界。

確實是這樣的,根據(jù)項目需要吧,我現(xiàn)在只是想寫一個模塊出來給大家參考:)
代碼量大是因為我用了循環(huán)隊列,對于buff的操作幾乎是透明的,所以幾乎不用考慮,還有一點因為我用的是RD2的芯片,所以有ERAM,我對內(nèi)存的考慮就稍微少了一些。

如果不用中斷的話就要寫一個scheduler來實現(xiàn),我想以后要寫一個調(diào)度器的實現(xiàn)方式,不過我現(xiàn)在不知道怎么模擬串口收數(shù)據(jù),好象這個問題比較麻煩,斑竹有沒有什么好的想法?
于這個問題我想還是有必要討論一下的,你可能認(rèn)為我對buff的校驗不到位,所以產(chǎn)生了越界,但是我想問為什么有了casting以后就可以不越界了呢

我對C51不是很熟悉,但是我覺得癥結(jié)可能在于函數(shù)嵌套過多,雖然結(jié)構(gòu)明晰了,但是堆棧不夠用了。

另外一個需要注意的是為什么總是跑到IDATA里面,這個我也不解:)
我所有的buff都是在XDATA中的,而且我用了MALLOC函數(shù),但我又用的是compact mode


本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

在電動汽車(EV)領(lǐng)域,牽引逆變器作為關(guān)鍵組件之一,扮演著至關(guān)重要的角色。它不僅影響電動汽車的驅(qū)動性能和效率,還直接關(guān)聯(lián)到整車的安全性和耐用性。本文將詳細介紹在選擇電動汽車牽引逆變器時需要考量的多個方面,包括其保護機制與...

關(guān)鍵字: 逆變器 電動汽車 驅(qū)動

7月3日消息,AMD顯卡戰(zhàn)未來,再添實錘證據(jù)!

關(guān)鍵字: 驅(qū)動 英偉達

在當(dāng)今高速發(fā)展的電子系統(tǒng)領(lǐng)域,信號完整性已然成為確保系統(tǒng)性能與可靠性的關(guān)鍵要素。從驅(qū)動到連接器的信號傳輸路徑宛如一條信息高速公路,而接收端則如同這條公路的終點收費站,其設(shè)置的合理性直接關(guān)乎信號能否準(zhǔn)確無誤地抵達目的地。若...

關(guān)鍵字: 信號 連接器 驅(qū)動

串口全稱是串行接口(Serial Interface),串口通訊指僅用一對傳輸線就能將數(shù)據(jù)以比特位進行傳輸?shù)囊环N通訊方式。盡管串口通訊必按字節(jié)傳輸?shù)牟⑿型ㄐ怕?,但是串口可以在僅用兩根線的情況下完成數(shù)據(jù)傳輸,大大降低了成本...

關(guān)鍵字: 串口 UART

隨著電腦技術(shù)的發(fā)展,一些老的設(shè)備在新電腦上不能被使用,主要原因是不管是臺式電腦,還是筆記本電腦,都很少有串口接口,也就是我們常說的COM口。好在這些設(shè)備都有USB接口,不妨通過接口轉(zhuǎn)換的方式,使我們的設(shè)備在新電腦上重新被...

關(guān)鍵字: 串口 USB

串口:串口是一個泛稱,UART、TTL、RS232、RS485都遵循類似的通信時序協(xié)議,因此都被通稱為串口。串口通訊應(yīng)用是工控人必須掌握的一個技能,幾乎在每一個項目中都會用到,今天我們就來詳細比較一下它們究竟有何區(qū)別。

關(guān)鍵字: 串口 協(xié)議

在復(fù)雜的嵌入式系統(tǒng)或高性能計算環(huán)境中,以太網(wǎng)驅(qū)動的穩(wěn)定性與可靠性至關(guān)重要。然而,有時開發(fā)者會遇到一些難以解釋的現(xiàn)象,比如拔掉一個網(wǎng)口后,另一個原本工作正常的網(wǎng)口突然無法接收數(shù)據(jù)。這種看似不合邏輯的問題,往往隱藏著深層次的...

關(guān)鍵字: 以太網(wǎng) 驅(qū)動

在嵌入式開發(fā)過程中,許多系統(tǒng)通常使用串口驅(qū)動來滿足通信要求,但在實際應(yīng)用中,使用SPI通信方式會更加高效和快捷。

關(guān)鍵字: 串口 驅(qū)動

串口WiFi模塊作為新一代嵌入式WiFi模塊,因其體積小、功耗低的特點,廣泛應(yīng)用于物聯(lián)網(wǎng)、智能家居等領(lǐng)域。

關(guān)鍵字: 串口 WiFi模塊 嵌入式

在現(xiàn)代嵌入式系統(tǒng)設(shè)計中,F(xiàn)PGA(現(xiàn)場可編程門陣列)的靈活性和可重構(gòu)性使其成為許多應(yīng)用的理想選擇。而在FPGA的開發(fā)和部署過程中,如何實現(xiàn)遠程升級和故障恢復(fù)成為了一個重要議題。本文將詳細探討如何通過BPI FLASH實現(xiàn)...

關(guān)鍵字: FPGA 串口 MultiBoot 嵌入式系統(tǒng)
關(guān)閉