




下載本文檔
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、RI 置 1。51單片機(jī)的串口,是個(gè)全雙工的串口,發(fā)送數(shù)據(jù)的同時(shí),還可以接收數(shù)據(jù)。 當(dāng)串行發(fā)送完畢后,將在標(biāo)志位TI置1,同樣,當(dāng)收到了數(shù)據(jù)后,也會(huì)在 無論RI或TI出現(xiàn)了 1,只要串口中斷處于開放狀態(tài), 單片機(jī)都會(huì)進(jìn)入串口中斷處理程序。在中斷程序中,要區(qū)分出來究竟是發(fā)送引起的中斷,還是接收引起的中斷, 然后分別進(jìn)行處 理。看到過一些書籍和文章,在串口收、發(fā)數(shù)據(jù)的處理方法上,很多人都有不妥之處。接收數(shù)據(jù)時(shí),基本上都是使用中斷方式”,這是正確合理的。1;39.即:每當(dāng)收到一個(gè)新數(shù)據(jù),就在中斷函數(shù)中,把RI清零,并用一個(gè)變量,通知主函數(shù),收到了新數(shù)據(jù)。發(fā)送數(shù)據(jù)時(shí),很多的程序都是使用的查詢方式”,就
2、是執(zhí)行 while(TI =0);這樣的語句來等 待發(fā)送完畢。這時(shí),處理不好的話,就可能帶來問題。看了一些網(wǎng)友編寫的程序,發(fā)現(xiàn)有如下幾條容易出錯(cuò):1.有人在發(fā)送數(shù)據(jù)之前,先關(guān)閉了串口中斷!等待發(fā)送完畢后,再打開串口中斷。也就不會(huì)保存的這樣,在發(fā)送數(shù)據(jù)的等待期間內(nèi),如果收到了數(shù)據(jù),將不能進(jìn)入中斷函數(shù), 這個(gè)新收到的數(shù)據(jù)。這種處理方法,就會(huì)遺漏收到的數(shù)據(jù)。2 有人在發(fā)送數(shù)據(jù)之前,并沒有關(guān)閉串口中斷,當(dāng)TI = 1時(shí),是可以進(jìn)入中斷程序的。但是,卻在中斷函數(shù)中,將TI清零!這樣,在主函數(shù)中的 while(TI =0);,將永遠(yuǎn)等不到發(fā)送結(jié)束的標(biāo)志。3還有人在中斷程序中,并沒有區(qū)分中斷的來源,反而讓發(fā)
3、送引起的中斷,執(zhí)行了接收中斷的程序。對(duì)此,做而論道發(fā)表自己常用的方法: 接收數(shù)據(jù)時(shí),使用 中斷方式”,清除RI后,用一個(gè)變量通知主函數(shù),收到新數(shù)據(jù)。發(fā)送數(shù)據(jù)時(shí),也用中斷方式”,清除TI后,用另一個(gè)變量通知主函數(shù),數(shù)據(jù)發(fā)送完畢。這樣一來,收、發(fā)兩者基本一致,編寫程序也很規(guī)范、易懂。更重要的是,主函數(shù)中,不用在那兒死等發(fā)送完畢,可以有更多的時(shí)間查看其它的標(biāo)志。實(shí)例: 求一個(gè)PC與單片機(jī)串口通信的程序,要求如下:1、如果在電腦上發(fā)送以$開始的字符串,則將整個(gè)字符串原樣返回(字符串長(zhǎng)度不是固定 的)。2、如果接收到1,則將P10置高電平,接收到 0 , P10置低電平。(用來控制一個(gè)LED )】這樣的
4、字符串問題補(bǔ)充:可能會(huì)將【$ABCD,123456,987654ccc,aasdasd,aaaa,sssd,4D(字符串長(zhǎng)度約為 50-150個(gè)字符)傳送給單片機(jī),只能能原樣返回。cpp view plaincopy1.最佳答案:2.下列程序,已經(jīng)調(diào)試成功。3.#include vREG52.H4.sbit LED = P195.6.unsigned char UART_buff;bit New_rec = 0, Send_ed = 1, Money = 0;7./8.9.void main ( void10.SCON = 0x50;/串口方式1,8-n-1,允許接收.11.TMOD = 0x
5、20;/T1 方式212.TH1 = 0xFD; url=/9600b ps11.0592MHz/url13.TL1 = 0xFD;14.TR1 = 1;15.ES = 1;/開中斷.16.EA = 1;17.while(Money = 0);/等著交費(fèi),呵呵,等著接收 $.18.while19.if20.(1) (New_rec = 1) & (Send_ed = 1) /那就發(fā)送./如果收到新數(shù)據(jù)及發(fā)送完畢SBUF = UART_buff;21.22.New_rec = 0;Send_ed = 0;23.24.25./26.void ser_int ( void)interru pt 42
6、8.if (RI = 1) /如果收到.29.RI = 0;/清除標(biāo)志.30.New_rec = 1;31.UART_buff = SBUF;/接收.32.if (UART_buff =1 ) LED = 1;33.if (UART_buff =0 ) LED = 0;34.if (UART_buff =$ ) Money =35.36.else /如果送畢.37.TI = 0;/清除標(biāo)志.38.Send_ed = 1;27.40. 41. /htt p:/bbs.ed nchi 串口接收程序是基于串口中斷的,單片機(jī)的串口每次接收到一字節(jié)數(shù)據(jù)產(chǎn)生一次中斷,然后再讀取某個(gè)寄存器就可以得到串口接收
7、的數(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é)議,來進(jìn)行控制操作,不符合則不進(jìn)行任何操作。簡(jiǎn)而言之就是,單片機(jī)要在一串?dāng)?shù)據(jù)中找到符合一定規(guī)律的幾個(gè)字節(jié)的數(shù)據(jù)。先來說下怎樣定串口協(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ù)求
8、和)。比如0xaa 0x55 + (數(shù)據(jù)部分省略)+校驗(yàn)和(除了 aa 55之外數(shù)據(jù)的和),如果要 是多板卡的話有時(shí)候還要在幀頭后面加一個(gè)板選字節(jié)(相當(dāng)于3字節(jié)幀頭了)。第一次寫串口接收程序的時(shí)候,我首先想到的就是定義一個(gè)全局變量(實(shí)際上最好是 定義局部靜態(tài)變量),初始值設(shè)置為0,然后每進(jìn)一次中斷+1,然后加到串口通信協(xié)議的長(zhǎng)度的時(shí)候再清零。然后判斷幀頭、校驗(yàn)。寫完了之后我自己都覺得不對(duì),一旦數(shù)據(jù)錯(cuò)開了一位,后面就永遠(yuǎn)都接收不到數(shù)了。無奈看了一下前輩們的代碼,跟我的思路差不多,只不過 那個(gè)計(jì)數(shù)值跟接收到的數(shù)據(jù)時(shí)同時(shí)判斷的,而且每次中斷都要判斷, 一旦不對(duì)計(jì)數(shù)的那個(gè)變量就清零。廢話少說,直接上一
9、段代碼讓大家看看就明白了。(通信協(xié)議姑且按照簡(jiǎn)單的aa 55個(gè)字節(jié)數(shù)據(jù) 一個(gè)字節(jié)校驗(yàn),代碼是基于51單片機(jī)的)。接收成功則在中斷程序中把串口接收成功標(biāo)志位置 1。cpp view plaincopy1.2.3.4.5.6.7.8.然后串口中斷部分void ser()interrupt 4static unsigned char count; / 串口接收計(jì)數(shù)的變量RI=0;/手動(dòng)清某個(gè)寄存器,大家都懂的receivecount=SBUF;if (count=0&receivecount=0xaa)/同時(shí)判斷count跟收到的數(shù)據(jù)9.count=1;10.11.12.13.14.15.16.17
10、.18.19.else if (count=1 &receivecount=0x55)count=2;else if (count=2)count+;else if (count=3&receivecount= receive 2)和,或者其他的校驗(yàn)方法,也可能是固定的幀尾/判斷校驗(yàn)和,數(shù)據(jù)多的話是求 /20.21.count=0;22.23.24.25.uartflag =1;ES=0;else/串口接收成功標(biāo)志,為 1時(shí)在主程序中回復(fù),然后清零/關(guān)中斷,回復(fù)完了再ES=1;26.27.28.29.count=0;/判斷不滿足條件就將計(jì)數(shù)值清零switch語句第一次做的串口大概就按照這個(gè)方法
11、寫完了(我后來看過其他的代碼,有人用 寫的,邏輯跟這個(gè)也差不多,不過我還是感覺用if else來寫清晰一些),不過在測(cè)試的時(shí)候發(fā)現(xiàn)了bug,如果數(shù)據(jù)幀發(fā)送一半,然后突然停止,再來重新發(fā),就會(huì)丟失一幀的數(shù)據(jù)。比如先接受到aa 55,然后斷了,再進(jìn)來 aa 55 01 01,就不受控制bug,沒有想到很好的解決辦法,不過這種情況幾率極小, aa的幾率也很小,出問題 aa,于是我把了。后來我也想到一個(gè) bug,如果在多設(shè)備通信中,屬于其他設(shè)備的的幀數(shù)據(jù)最后一位是 aa (或者最后兩位為aa 55,或者最后3位為aa 55板選),下一次通信的數(shù)據(jù)就接收不 到了。當(dāng)時(shí)對(duì)于數(shù)據(jù)突然中斷的所以一直用這個(gè)方法
12、寫也沒有問題。多設(shè)備通信最后一位恰好是 的可能也很小。當(dāng)時(shí)項(xiàng)目里面的控制數(shù)據(jù)跟校驗(yàn)恰好不可能出現(xiàn)if(count=0&receivecount=0xaa)改成了 if(receivecount=0xaa)其他都沒變,解決了,沒有bug 了。不過改天再接著后來我又寫了幾次單片機(jī)程序,才想到了一些解決問題的方法 寫吧,太累了,明天還要上班呢。在后來的項(xiàng)目中,真的遇到了數(shù)據(jù)位跟校驗(yàn)位都可能出現(xiàn)aa的情況。我考慮到每次數(shù)據(jù)都是連續(xù)發(fā)送的(至少我們用labwindows做的上位機(jī)程序是這樣的),成功接收到了一幀數(shù)據(jù)是要有一定時(shí)間回復(fù)的,也就是說如果接收到一半,但是很長(zhǎng)時(shí)間沒接收到數(shù)據(jù), 把計(jì)數(shù)值coun
13、t清零就ok啦。涉及時(shí)間的問題自然要用定時(shí)器來實(shí)現(xiàn)啦。19200,2個(gè)幀頭aa 55,一個(gè)板選,6字節(jié)數(shù)據(jù),一個(gè)這次的通信協(xié)議如下,串口波特率校驗(yàn)字節(jié)(除幀頭外其他數(shù)據(jù)的和)cpp view plaincopy1.全局變量定義2.unsigned char boardAddr; /板選地址,通過檢測(cè)幾個(gè) io引腳,具體怎么得到的就不寫了,很簡(jiǎn)單的3.unsigned char g_DatRev 10=0;/接收緩存4.bit retFlag=O; /為1代表串口接收到了一幀數(shù)據(jù)5.6.7.8串口初始化函數(shù),晶振 22.1184O.9.void init_uart()10.11.SCON = 0
14、x50;/串口方式1允許接收12.TMOD = 0x21;/定時(shí)器1,方式2,8位自動(dòng)重載,同時(shí)配置定時(shí)器0,工作方式113.P CON = 0x80;/波特率加倍14.TH1 = 0xfa;15.TL1 = 0xfa;/寫入串口定時(shí)器初值16.TH0=(65536-2000)/256;/寫入定時(shí)器0初值,串口傳輸一個(gè)字節(jié)時(shí)間為(1/19200)*10,計(jì)算得 0.52ms17.TL0=(65536-2000)%256;/定時(shí)器0定時(shí)大約1ms多18.EA=1;19.ET0=1;/ 波特率:1920022.1184M初值:250(0xfa)20.IE |= 0x90;21.TR1 = 1;22
15、.23.24.串口中斷函數(shù)25.26.void UART_INT( void ) interrupt 427.28.static unsigned charcount; /串口接收計(jì)數(shù)的變量29.30.RI = 0;31.g_DatRevcount = SBUF;32.if (g_DatRevcount=0xaa&count=0)/幀頭J33.34.count=1;35.36.else if (count=1 &g_DatRevcount=0x55)37.38.count=2;39.40.41.else if (count=2&g_DatRev2 = boardAddr)42.43.CK =
16、g_DatRevcount;44.count=3;45.46.47.48.else if (count=3&count=0&count=2& receivecount=0xaa), 這樣就把bug出現(xiàn)的幾率降到了非常小,也只是在前一幀結(jié)尾數(shù)據(jù)恰好為 時(shí)候才出現(xiàn),幾率是多少大家自己算一下吧,呵呵。這樣我自己覺得,進(jìn)到這個(gè)程度,應(yīng)該算可以啦,反正我是很滿意了。aa的那個(gè)bug,因?yàn)閍a 55板選的昨天寫的那種方法改實(shí)際上我還想過其他的方法,比如緩存的數(shù)組采用移位寄存的方式。 字節(jié)的協(xié)議為例。拿前面的cpp view plaincopy1.2.3.4.void ser()interrupt 4 un
17、signed char i;RI=0;5.6.7.8.9.10.11.for (i=0;iv3;i+)receivei=receivei+1;receive3=SBUF;if (reveive0=0xaa&receive1=0x55&receive2=receive3)12.13.14.ret_flag=1;ES = 0;20.21.if (receive(i-9)&0x0f=0xaa&receive(i-8)&0x0f=0x5515.16.17.這段代碼看上去可是簡(jiǎn)單明了,這樣判斷可是不錯(cuò)啊,同時(shí)判斷幀頭跟校驗(yàn)不會(huì)產(chǎn)生前面提到的bug。說實(shí)話當(dāng)時(shí)我剛想出這種方法并寫出來的時(shí)候,馬上就被我給否
18、了。那個(gè)for循環(huán)可真是很占時(shí)間的啊, 延時(shí)函數(shù)都是這樣寫的。 每次都循環(huán)一下,這延時(shí)太長(zhǎng),通信速度太快的話就不能接收到下一字節(jié)數(shù)據(jù)了。最要命的是這個(gè)時(shí)間的長(zhǎng)度是隨著通信協(xié)議幀的字節(jié)數(shù)增加而增加的,如果一次要接收幾十個(gè)字節(jié), 肯定就玩完了。這種方法我一次都沒用過。不過我居然又想出來了這種方法的改良措施,是前兩天剛想出來的,呵呵,還沒有 實(shí)踐過呢。10字節(jié))F面代碼的協(xié)議就按第二段程序(定時(shí)器清零的那個(gè)協(xié)議,一共 全局變量cpp view plaincopy1.2.3.bit ret_flag;unsignedchar receive256=0;unsignedchar boardaddress
19、;4.5.中斷函數(shù)6.7.8.void ser()interrupt 4 9.10.11.12.13.staticunsignedchar i=0;staticunsignedchar total=0;RI=0;14.15.receivei=SBUF;total=total-receivei-7+receivei-1;16.17.18.if (receivei-9=0xaa&receivei-8=0x55&receivei-7=boardaddress&receivei=total19.20.21.ret_flag=1;24.i+;25.26.之所以要定義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í)間。這種方法也是我不久前才想出來的,所以還沒有經(jīng)過實(shí)際的驗(yàn)證。上面的代碼可能會(huì)有邏輯上的錯(cuò)誤,如果真有錯(cuò)誤,有網(wǎng)友看出來的話,請(qǐng)?jiān)谙旅媪粞愿嬖V我。這個(gè)方法也是我原創(chuàng)的哦,別人也肯能會(huì)想到,不過我這個(gè)絕對(duì)不是抄襲別人的。上面的代碼最大的缺點(diǎn)就是變量定義的太多
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年智能快遞柜行業(yè)市場(chǎng)分析報(bào)告
- 高鐵工程勞務(wù)分包合同
- 工業(yè)物聯(lián)網(wǎng)在化工中的應(yīng)用-洞察闡釋
- 2025學(xué)年部編本六年級(jí)下冊(cè)語文教師培訓(xùn)計(jì)劃
- 2025年小學(xué)語文二年級(jí)下冊(cè)課時(shí)安排計(jì)劃
- 環(huán)保設(shè)施電氣安全保障措施
- 動(dòng)態(tài)圖像與視頻的端到端加密技術(shù)研究-洞察闡釋
- 跨國(guó)公司數(shù)字營(yíng)銷與社會(huì)責(zé)任的融合-洞察闡釋
- 大學(xué)教授基礎(chǔ)教育講座觀后感
- 2025-2030全球及中國(guó)數(shù)碼幣行業(yè)市場(chǎng)現(xiàn)狀供需分析及投資評(píng)估規(guī)劃分析研究報(bào)告
- 閩侯縣國(guó)土空間總體規(guī)劃(2021-2035年)
- 烙鐵溫度點(diǎn)檢表
- 國(guó)家開放大學(xué)《建筑測(cè)量》實(shí)驗(yàn)報(bào)告4
- 倉(cāng)庫溫濕度記錄表
- 初中 初二 物理 流體壓強(qiáng)與流速的關(guān)系 教學(xué)設(shè)計(jì)
- 霍蘭德職業(yè)興趣測(cè)試題(卷)完整版
- 飛控板安裝運(yùn)行調(diào)試pix固定翼
- 《中國(guó)古代文學(xué)史:唐宋文學(xué)》PPT課件(完整版)
- 5Why分析法經(jīng)典培訓(xùn)(43頁)
- 2018二建繼續(xù)教育(市政公用工程)試題庫(有答案解析)
- 全面依法治國(guó)(課堂PPT)
評(píng)論
0/150
提交評(píng)論