<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 關(guān)于單片機(jī)上for循環(huán)中運(yùn)用ACC的隱蔽錯(cuò)誤

          關(guān)于單片機(jī)上for循環(huán)中運(yùn)用ACC的隱蔽錯(cuò)誤

          作者: 時(shí)間:2016-11-22 來源:網(wǎng)絡(luò) 收藏
          最近寫了幾個(gè)程序,一個(gè)是用51單片機(jī)讀取模數(shù)傳感器adc0832的電壓值,一個(gè)是讀取ds1302的時(shí)間值,結(jié)果都出現(xiàn)了讀數(shù)一直為0的情況。我調(diào)試了近一個(gè)星期,修改了一個(gè)我認(rèn)為不可能會(huì)錯(cuò)的句子,程序運(yùn)行成功了,這才發(fā)現(xiàn)了一個(gè)極其隱蔽的錯(cuò)誤。(我用的是xp系統(tǒng),用keil4軟件編譯)

          先上代碼:第一個(gè)為錯(cuò)誤代碼,第二個(gè)為正確代碼。這是用來向ds1302芯片寫入命令或數(shù)據(jù)的函數(shù)。實(shí)現(xiàn)把8位的數(shù)據(jù)dat一位一位地寫入ds1302的io口。其中ACC0為ACC的第0位。

          本文引用地址:http://www.ex-cimer.com/article/201611/319881.htm

          認(rèn)真對(duì)比這兩個(gè)代碼,可能會(huì)覺得沒區(qū)別,而且這兩個(gè)代碼都可以通過編譯(加上reg52.h和一些宏定義)。我也是一直認(rèn)為for()這里邊沒有錯(cuò)誤,結(jié)果。。。試著修改時(shí)鐘信號(hào),增加延時(shí)之類的,調(diào)了好久還是錯(cuò),嚴(yán)重打擊我的自信心。這兩個(gè)代碼的區(qū)別就只有for(i=0;i<8;i++)和for(i=8;i>0;i--)了。學(xué)過c語言的人都知道,這兩個(gè)句子都是實(shí)現(xiàn)一個(gè)8次的循環(huán),功能一模一樣。怎么會(huì)因?yàn)檫@個(gè)句子的區(qū)別就導(dǎo)致單片機(jī)控制的錯(cuò)誤呢?神奇!

          接著我試著把錯(cuò)誤程序中的ACC改為51芯片的寄存器B,燒錄進(jìn)單片機(jī),程序運(yùn)行成功,跟“for(i=8;i>0;i--),ACC版”一樣,lcd在很囂張地顯示著正確的時(shí)間( for(i=0;i<8;i++),ACC版lcd的時(shí)間顯示為0)。附:

          這樣就知道原因了,使用for(i=0;i<8;i++)的運(yùn)算中可能有累加器ACC參與了,導(dǎo)致修改了ACC的值,使寫入的命令出現(xiàn)錯(cuò)誤。但為什么for(i=8;i>0;i--)就沒有ACC的參與呢?一個(gè)大大的問號(hào)。基于我調(diào)試了一個(gè)星期的程序,皆因?yàn)檫@一個(gè)神奇的錯(cuò)誤,我實(shí)在不甘心,決定研究到底。于是,分別查看了這三個(gè)程序代碼用 keil4 編譯后得到的 匯編代碼。(學(xué)過匯編就是爽啊,哈)

          對(duì)比后,可以發(fā)現(xiàn),出錯(cuò)的原因是for(i=0;i<8;i++)ACC版中,用ACC接收了實(shí)參(存儲(chǔ)的為要寫入的指令),然后在 for 循環(huán)前要給變量 “ i " 賦值時(shí),要用到ACC清零,再把ACC中的零賦給 R7 ("i"的值存儲(chǔ)在R7)。這樣的話,原來存儲(chǔ)在ACC中的寫入指令就被清零,自然會(huì)導(dǎo)致控制出現(xiàn)錯(cuò)誤,最終沒法讀取ds1302芯片的時(shí)間,故顯示為零。

          而在for(i=8;i>0;i--)ACC版中,也用ACC接收了實(shí)參的值,但在 for 循環(huán)前,給變量“ i ” 賦值時(shí),賦值為8,不需要用到ACC,所以ACC一直是存儲(chǔ)著實(shí)參中的指令,沒有被清零,所以能夠順利地向ds1302發(fā)送指令,從而能夠讀取到時(shí)間。

          總結(jié):

          因?yàn)橛胒or(i=0;i0;i--)類的指令多了 CLR A 和 INC R7 兩條指令,CJNE 指令又比較DJNZ指令多了一個(gè)字節(jié)的程序代碼存儲(chǔ)空間,在頻率為12M的51單片機(jī)上體現(xiàn)為執(zhí)行同樣功能的程序,要多用2us,代碼空間花多一字節(jié)。所以前者是毫無優(yōu)勢(shì)的,以后應(yīng)養(yǎng)成用

          for(i=n;i>0;i--)的習(xí)慣。

          請(qǐng)不要反駁我用了這么長的時(shí)間去研究,只能使單片機(jī)執(zhí)行快2us,而說我鉆牛角尖,只是因?yàn)?,這個(gè)錯(cuò)誤導(dǎo)致我整個(gè)程序無法正常運(yùn)行,這不是一件小事。

          至于為什么要用到累加器ACC來接收實(shí)參,是因?yàn)楹竺娴某绦蛞岩粋€(gè)8位的實(shí)參一位一位地輸出到一個(gè)io口,自定義一個(gè)變量的話,按位尋址好像比較麻煩,要經(jīng)過一系列 位運(yùn)算 ,或者用bit定義8個(gè)位(有好的方法請(qǐng)告訴我,哈),而且我寫不出來。而用ACC的話,可以很輕易地操作ACC的任意一位,如ACC0,ACC7。在網(wǎng)上查了一下,好像還有一種方法是定義 一種叫 位域 的東東,我看的c語言的書都沒介紹,所以還不是很了解。

          /************************************************************/

          剛剛想了一下,不用ACC 的方法,作一個(gè)位運(yùn)算dat &0x01,修改如下:

          想到了這個(gè)方法后,覺得自己好白癡,以后都不用ACC了。



          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();