版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、搞定單片機(jī)多字節(jié)串口接收工作了一年多,寫(xiě)了不少單片機(jī)串口程序。感覺(jué)串口多字節(jié)接收部分的邏輯相對(duì)于配置寄存器跟串口回復(fù)來(lái)說(shuō),是有點(diǎn)難度的。寄存器配置基本上都是死的,串口回復(fù)多字節(jié)跟回復(fù)一字節(jié)只是多了一個(gè)循環(huán)。串口接收程序是基于串口中斷的,單片機(jī)的串口每次接收到一字節(jié)數(shù)據(jù)產(chǎn)生一次中斷,然后再讀取某個(gè)寄存器就可以得到串口接收的數(shù)據(jù)了。然而在實(shí)際應(yīng)用當(dāng)中,基本上不會(huì)有單字節(jié)接收的情況。一般都是基于一定串口通信協(xié)議的多字節(jié)通信。在422或者485通信中,還可能是一個(gè)主機(jī)(一般是計(jì)算機(jī))帶多個(gè)從機(jī)(相應(yīng)的有單片機(jī)的板卡)。這就要求我們的單片機(jī)能夠在連續(xù)接收到的串口數(shù)據(jù)序列中識(shí)別出符合自己板卡對(duì)應(yīng)的通信協(xié)議
2、,來(lái)進(jìn)行控制操作,不符合則不進(jìn)行任何操作。簡(jiǎn)而言之就是,單片機(jī)要在一串?dāng)?shù)據(jù)中找到符合一定規(guī)律的幾個(gè)字節(jié)的數(shù)據(jù)。先來(lái)說(shuō)下怎樣定串口協(xié)議吧。這個(gè)協(xié)議指的不是串口底層的協(xié)議,而是前面提到的數(shù)據(jù)幀協(xié)議。一般都是有幀頭(23個(gè)字節(jié)吧),數(shù)據(jù)(長(zhǎng)度根據(jù)需要),結(jié)束位(1位,有時(shí)候設(shè)計(jì)成校驗(yàn)字節(jié),最簡(jiǎn)單的校驗(yàn)也就是前面所有數(shù)據(jù)求和)。比如Oxaa0 x55+(數(shù)據(jù)部分省略)+校驗(yàn)和(除了aa55之外數(shù)據(jù)的和),如果要是多板卡的話有時(shí)候還要在幀頭后面加一個(gè)板選字節(jié)(相當(dāng)于3字節(jié)幀頭了)。第一次寫(xiě)串口接收程序的時(shí)候,我首先想到的就是定義一個(gè)全局變量(實(shí)際上最好是定義局部靜態(tài)變量),初始值設(shè)置為0,然后每進(jìn)一次中
3、斷+1,然后加到串口通信協(xié)議的長(zhǎng)度的時(shí)候再清零。然后判斷幀頭、校驗(yàn)。寫(xiě)完了之后我自己都覺(jué)得不對(duì),一旦數(shù)據(jù)錯(cuò)開(kāi)了一位,后面就永遠(yuǎn)都接收不到數(shù)了。無(wú)奈看了一下前輩們的代碼,跟我的思路差不多,只不過(guò)那個(gè)計(jì)數(shù)值跟接收到的數(shù)據(jù)時(shí)同時(shí)判斷的,而且每次中斷都要判斷,一旦不對(duì)計(jì)數(shù)的那個(gè)變量就清零。廢話少說(shuō),直接上一段代碼讓大家看看就明白了。(通信協(xié)議姑且按照簡(jiǎn)單的aa55一個(gè)字節(jié)數(shù)據(jù)一個(gè)字節(jié)校驗(yàn),代碼是基于51單片機(jī)的)。接收成功則在中斷程序中把串口接收成功標(biāo)志位置1。下面是全局變量定義unsignedcharreceive4=0,0,0,0;接收緩存bituart_flag;串口接收成功標(biāo)志然后串口中斷部分
4、voidser()interrupt4staticunsignedcharcount;/串口接收計(jì)數(shù)的變量R|=0;手動(dòng)清某個(gè)寄存器,大家都懂的receivecount=SBUF;if(count=0&receivecount=0 xaa)同時(shí)判斷count跟收到的數(shù)據(jù)count=1;elseif(count=1&receivecount=0 x55)count=2;elseif(count=2)count+;elseif(count=3&receivecount=receive2)/判斷校驗(yàn)和,數(shù)據(jù)多的話是求和,或者其他的校驗(yàn)方法,也可能是固定的幀尾count=0;uart_flag=1;/
5、串口接收成功標(biāo)志,為1時(shí)在主程序中回復(fù),然后清零ES=O;關(guān)中斷,回復(fù)完了再ES=1;elsecount=0;判斷不滿(mǎn)足條件就將計(jì)數(shù)值清零第一次做的串口大概就按照這個(gè)方法寫(xiě)完了(我后來(lái)看過(guò)其他的代碼,有人用switch語(yǔ)句寫(xiě)的,邏輯跟這個(gè)也差不多,不過(guò)我還是感覺(jué)用ifelse來(lái)寫(xiě)清晰一些),不過(guò)在測(cè)試的時(shí)候發(fā)現(xiàn)了bug,如果數(shù)據(jù)幀發(fā)送一半,然后突然停止,再來(lái)重新發(fā),就會(huì)丟失一幀的數(shù)據(jù)。比如先接受到aa55,然后斷了,再進(jìn)來(lái)aa550101,就不受控制了。后來(lái)我也想到一個(gè)bug,如果在多設(shè)備通信中,屬于其他設(shè)備的的幀數(shù)據(jù)最后一位是aa(或者最后兩位為aa55,或者最后3位為aa55板選),下一次
6、通信的數(shù)據(jù)就接收不到了。當(dāng)時(shí)對(duì)于數(shù)據(jù)突然中斷的bug,沒(méi)有想到很好的解決辦法,不過(guò)這種情況幾率極小,所以一直用這個(gè)方法寫(xiě)也沒(méi)有問(wèn)題。多設(shè)備通信最后一位恰好是aa的幾率也很小,出問(wèn)題的可能也很小。當(dāng)時(shí)項(xiàng)目里面的控制數(shù)據(jù)跟校驗(yàn)恰好不可能出現(xiàn)aa,于是我把if(count=0&receivecount=0 xaa)改成了if(receivecount=0 xaa)其他都沒(méi)變,解決了,沒(méi)有bug了。后來(lái)我又寫(xiě)了幾次單片機(jī)程序,才想到了一些解決問(wèn)題的方法定定不過(guò)改天再接著寫(xiě)吧,太累了,明天還要上班呢。在后來(lái)的項(xiàng)目中,真的遇到了數(shù)據(jù)位跟校驗(yàn)位都可能出現(xiàn)aa的情況。我考慮到每次數(shù)據(jù)都是連續(xù)發(fā)送的(至少我們用
7、labwindows做的上位機(jī)程序是這樣的),成功接收到了一幀數(shù)據(jù)是要有一定時(shí)間回復(fù)的,也就是說(shuō)如果接收到一半,但是很長(zhǎng)時(shí)間沒(méi)接收到數(shù)據(jù),把計(jì)數(shù)值count清零就ok啦。涉及時(shí)間的問(wèn)題自然要用定時(shí)器來(lái)實(shí)現(xiàn)啦。這次的通信協(xié)議如下,串口波特率19200,2個(gè)幀頭aa55,一個(gè)板選,6字節(jié)數(shù)據(jù),一個(gè)校驗(yàn)字節(jié)(除幀頭外其他數(shù)據(jù)的和)。全局變量定義unsignedcharboardAddr;/板選地址,通過(guò)檢測(cè)幾個(gè)io引腳,具體怎么得到的就不寫(xiě)了,很簡(jiǎn)單的unsignedcharg_DatRev10=0;接收緩存bitretFlag=0;為1代表串口接收到了一幀數(shù)據(jù)串口初始化函數(shù),晶振22.1184vo
8、idinit_uart()SCON=0 x50;串口方式1允許接收TMOD=0 x21;定時(shí)器1,方式2,8位自動(dòng)重載,同時(shí)配置定時(shí)器0,工作方式1PCON=0 x80;/波特率加倍TH1=0 xfa;TL1=0 xfa;寫(xiě)入串口定時(shí)器初值TH0=(65536-2000)/256;寫(xiě)入定時(shí)器0初值,串口傳輸一個(gè)字節(jié)時(shí)間為(1/19200)*10,計(jì)算得0.52msTL0=(65536-2000)%256;/定時(shí)器0定時(shí)大約1ms多EA=1;ET0=1;波特率:1920022.1184M初值:250(0 xfa)IE|=0 x90;TR1=1;串口中斷函數(shù)voidUART_INT(void)in
9、terruptstaticunsignedcharcount;/串口接收計(jì)數(shù)的變量RI=0;g_DatRevcount=SBUF;/幀頭if(g_DatRevcount=0 xaa&count=0)count=1;elseif(count=1&g_DatRevcount=0 x55)count=2;_CK=g_DatRevcount;elseif(count=3&count=0&count=2&receivecount=Oxaa),這樣就把bug出現(xiàn)的幾率降到了非常小,也只是在前一幀結(jié)尾數(shù)據(jù)恰好為aa55板選的時(shí)候才出現(xiàn),幾率是多少大家自己算一下吧,呵呵。這樣我自己覺(jué)得,昨天寫(xiě)的那種方法改進(jìn)到
10、這個(gè)程度,應(yīng)該算可以啦,反正我是很滿(mǎn)意了。實(shí)際上我還想過(guò)其他的方法,比如緩存的數(shù)組采用移位寄存的方式。拿前面的4個(gè)字節(jié)的協(xié)議為例。voidser()interrupt4unsignedchari;RI=0;for(i=0;i3;i+)receivei=receivei+1;receive3=SBUF;if(reveiveO=Oxaa&receive1=0 x55&receive2=receive3)ret_flag=1;ES=0;這段代碼看上去可是簡(jiǎn)單明了,這樣判斷可是不錯(cuò)啊,同時(shí)判斷幀頭跟校驗(yàn)不會(huì)產(chǎn)生前面提到的bug。說(shuō)實(shí)話當(dāng)時(shí)我剛想出這種方法并寫(xiě)出來(lái)的時(shí)候,馬上就被我給否了。那個(gè)for循環(huán)
11、可真是很占時(shí)間的啊,延時(shí)函數(shù)都是這樣寫(xiě)的。每次都循環(huán)一下,這延時(shí)太長(zhǎng),通信速度太快的話就不能接收到下一字節(jié)數(shù)據(jù)了。最要命的是這個(gè)時(shí)間的長(zhǎng)度是隨著通信協(xié)議幀的字節(jié)數(shù)增加而增加的,如果一次要接收幾十個(gè)字節(jié),肯定就玩完了。這種方法我一次都沒(méi)用過(guò)。不過(guò)我居然又想出來(lái)了這種方法的改良措施,是前兩天剛想出來(lái)的,呵呵,還沒(méi)有實(shí)踐過(guò)呢。下面代碼的協(xié)議就按第二段程序(定時(shí)器清零的那個(gè)協(xié)議,一共10字節(jié))全局變量bitret_flag;unsignedcharreceive256=0;unsignedcharboardaddress;中斷函數(shù)voidser()interrupt4staticunsignedcha
12、ri=0;staticunsignedchartotal=0;RI=0;receivei=SBUF;total=total-receivei-7+receivei-1;if(receivei-9=0 xaa&receivei-8=0 x55&receivei-7=boardaddress&receivei=total)ret_flag=1;ES=0;i+;之所以要定義256個(gè)長(zhǎng)度的數(shù)組,就是為了能夠讓數(shù)組首尾相接。因?yàn)?-1=255,255+1=0。而且我在計(jì)算校驗(yàn)的時(shí)候也改進(jìn)了算法,不會(huì)因?yàn)閿?shù)據(jù)長(zhǎng)度的增加而增加計(jì)算校驗(yàn)值的時(shí)間。這種方法也是我不久前才想出來(lái)的,所以還沒(méi)有經(jīng)過(guò)實(shí)際的驗(yàn)證。上面的
13、代碼可能會(huì)有邏輯上的錯(cuò)誤,如果真有錯(cuò)誤,有網(wǎng)友看出來(lái)的話,請(qǐng)?jiān)谙旅媪粞愿嬖V我。這個(gè)方法也是我原創(chuàng)的哦,別人也肯能會(huì)想到,不過(guò)我這個(gè)絕對(duì)不是抄襲別人的。上面的代碼最大的缺點(diǎn)就是變量定義的太多了,太占ram資源了,編譯的時(shí)候可能會(huì)出現(xiàn)錯(cuò)誤,畢竟51單片機(jī)才128字節(jié)的ram(有的資源也很豐富的,比如c8051系列的),這一下子就是256字節(jié)的變量。不過(guò)對(duì)于資源多一些的單片機(jī),這樣寫(xiě)還是可以的。要是能有4bit在一起的數(shù)據(jù)類(lèi)型就好了,呵呵,verilog代碼里面是可以的,C語(yǔ)言里貌似不行啊。要想能在例如51單片機(jī)上運(yùn)行,只能按照下面的折中方式了,也就是把i相關(guān)的量都與一個(gè)0 x0f全局變量bitret_flag;unsignedcharreceive16=0;可以考慮在定義時(shí)加上idata,畢竟還可能是32或者64長(zhǎng)度的數(shù)組呢unsignedcharidatareceive16=0;unsignedcharboardaddress;中斷函數(shù)voidser()interrupt4staticunsignedchari=0;staticunsignedchartotal=0;RI=0;receivei&0 x0f=SBUF;total=total-receive(i-7)&0 x0f+recei
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024年醫(yī)生年終考核個(gè)人工作總結(jié)
- 第20課 正面戰(zhàn)場(chǎng)的抗戰(zhàn)(解析版)
- 寒假自習(xí)課 25春初中道德與法治八年級(jí)下冊(cè)教學(xué)課件 第四單元第七課 第1課時(shí) 自由平等的真諦
- 《游戲的基本理論》課件
- 新媒體風(fēng)云模板
- 2024企業(yè)主要負(fù)責(zé)人安全培訓(xùn)考試題加解析答案
- 乒乓球比賽作文300字集合九篇
- 2023年-2024年員工三級(jí)安全培訓(xùn)考試題含答案(能力提升)
- 2024企業(yè)主要負(fù)責(zé)人安全培訓(xùn)考試題及答案往年題考
- 七年級(jí)下《國(guó)寶大熊貓》蘇教版-課件
- 中小企業(yè)內(nèi)部控制與風(fēng)險(xiǎn)管理(第二版)項(xiàng)目一:內(nèi)部控制與風(fēng)險(xiǎn)管理基礎(chǔ)
- 駕駛艙資源管理緒論課件
- 聲藝 EPM8操作手冊(cè)
- 西北農(nóng)林科技大學(xué)專(zhuān)業(yè)學(xué)位研究生課程案例庫(kù)建設(shè)項(xiàng)目申請(qǐng)書(shū)(MBA)
- 外墻保溫、真石漆施工技術(shù)交底
- 車(chē)床日常點(diǎn)檢表
- 配網(wǎng)工程施工監(jiān)理管理要點(diǎn)~.docx
- 國(guó)內(nèi)No.7信令方式技術(shù)規(guī)范----綜合業(yè)務(wù)數(shù)字網(wǎng)用戶(hù)部分(ISUP)
- 尾礦庫(kù)在線監(jiān)測(cè)方案)
- 房屋安全簡(jiǎn)易鑒定表.docx
- FSSC運(yùn)營(yíng)管理制度(培訓(xùn)管理辦法)
評(píng)論
0/150
提交評(píng)論