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

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > 單片機C程序延時精度研究

          單片機C程序延時精度研究

          作者: 時間:2017-06-04 來源:網(wǎng)絡 收藏
            在單片機應用中,經常會遇到需要短時間延時的情況,一般都是幾十到幾百μs,并且需要很高的精度(比如用單片機驅動DS18B20時,誤差容許的范圍在十幾μs以內,不然很容易出錯);而某些情況下延時時間較長,用計時器往往有點小題大做。另外在特殊情況下,計時器甚至已經全部用于其他方面的定時處理,此時就只能使用軟件定時了[1]。
          1 C語言程序延時
            Keil C51的編程語言常用的有2種: 一種是匯編語言;另一種是C 語言。用匯編語言寫單片機程序時,精確時間延時是相對容易解決的。比如,用的是晶振頻率為12 MHz的AT89C51,打算延時20 μs,51單片機的指令周期是晶振頻率的1/12,即一個機器周期為1 μs;“MOV R0,#X”需要2個機器周期,DJNZ也需要2個機器周期,單循環(huán)延時時間t=2X+3(X為裝入寄存器R0的時間常數(shù))[2]。這樣,存入R0里的數(shù)初始化為8即可,其精度可以達到1 μs。用這種方法,可以非常方便地實現(xiàn)512 μs以下時間的延時。如果需要更長時間,可以使用兩層或更多層的嵌套,當然其精度誤差會隨著嵌套層的增加而成倍增加。
            雖然匯編語言的機器代碼生成效率很高,但可讀性卻并不強,復雜一點的程序就更難讀懂;而C語言在大多數(shù)情況下,其機器代碼生成效率和匯編語言相當,但可讀性和可移植性卻遠遠超過匯編語言,且C 語言還可以嵌入?yún)R編程序來解決高時效性的代碼編寫問題。就開發(fā)周期而言,中大型軟件的編寫使用C 語言的開發(fā)周期通常要比匯編語言短很多,因此研究C語言程序的精確延時性能具有重要的意義[3]。
            C程序中可使用不同類型的變量來進行延時設計。經實驗測試,使用unsigned char類型具有比unsigned int更優(yōu)化的代碼,在使用時應該使用unsigned char作為延時變量。
          2 單層循環(huán)分析
            下面是進行μs級延時的while程序代碼。
            延時函數(shù):
            void delay1(unsigned char i) {
              while(i );}
            主函數(shù):
            void main() {
              while(1) {
                delay1(i);
              }
            }
            使用Keil C51的反匯編功能,延時函數(shù)的匯編代碼如下:
            C:0x00E6AE07MOVR6,0x07
            C:0x00E81FDECR7
            C:0x00E9EEMOVA,R6
            C:0x00EA70FAJNZC:00E6
            C:0x00EC22RET

          圖1 斷點設置位置圖
            通過對i賦值為10,在主程序中圖1所示的位置設置斷點。經過測試,第1次執(zhí)行到斷點處的時間為457 μs,再次執(zhí)行到該處的時間為531 μs,第3次執(zhí)行到斷點處的時間為605 μs,10次while循環(huán)的時間為74 μs,整個測試結果如圖2所示。

          圖2 使用i--方式測試仿真結果圖
            通過對匯編代碼分析,時間延遲t=7X+4(其中X為i的取值)。測試表明,for循環(huán)方式雖然生成的代碼與用while語句不大一樣,但是這兩種方法的效率幾乎相同。C語言中的自減方式有兩種,前面都使用的是i--的方式,能不能使用--i方式來獲得不同的效果呢?將前面的主函數(shù)保持不變,delay1函數(shù)修改為下面的方式:
            void delay1(unsigned char i) {
              while(--i);}
            同樣進行反匯編,得到如下結果:
            C:0x00E3DFFEDJNZR7,
            C:00E3C:0x00E522RET
            比較發(fā)現(xiàn),--i的匯編代碼效率明顯高于i--方式。由于只有1條語句DJNZ,執(zhí)行只需要2個時鐘周期, 1個時鐘周期按1 μs計算,其為2 μs;另外,RET需要2個時鐘周期,能夠達到匯編語言代碼的效率。按前面的測試條件進行測試,第1次執(zhí)行到斷點處的時間為437 μs,再次執(zhí)行到該處的時間為465 μs,第3次執(zhí)行到斷點處的時間為493 μs,10次while循環(huán)的時間為28 μs,整個測試結果如圖3所示。

          圖3 使用--i方式測試仿真結果圖
            調整i的取值,i取8時延時時間為24 μs,i取9時延時時間為26 μs。通過分析得出,10次循環(huán)為28 μs是由于外層循環(huán)造成的,其精度可以達到2 μs。在設計時應該考慮參數(shù)傳遞和RET語句執(zhí)行所需要的時間周期。實驗分析發(fā)現(xiàn),for語句使用--i方式,同樣能夠達到與匯編代碼相同的精度。i取不同值時延時仿真結果如圖4所示。

          圖4 i取不同值時延時仿真結果圖
          3 多重嵌套下的C程序延時
            在某些情況下,延時較長,僅使用單層循環(huán)方式是不能完成的。此時,只能使用多層循環(huán)方式,那么多重循環(huán)條件下,C程序的精度如何呢?下面是一個使用for語句實現(xiàn)1 s延時的函數(shù)。
            延時函數(shù)
            void delay1s(void) {
              for(k=100;k>0;k--) //定時1 s
              for(i=20;i>0;i--)
              for(j=248;j>0;j--);
            }
            主函數(shù)調用延時函數(shù)代碼段:
            while(1) {
              delay1s();
              scond+=1;
            }
            為了直接衡量這段代碼的效果,利用Keil C找出這段代碼產生的匯編代碼:
            C:0x00B37002JNZ
            C:00B7C:0x00B5150CDEC0x0C
            C:0x00B7E50DMOVA,0x0D
            C:0x00B9450CORLA,0x0C
            C:0x00BB70DEJNZC:009B
            C:0x00BDE50BMOVA,0x0B
            C:0x00BF150BDEC0x0B
            C:0x00C17002JNZC:00C5
            C:0x00C3150ADEC0x0A
            C:0x00C5E50BMOVA,0x0B
            C:0x00C7450AORLA,0x0A
            C:0x00C970CAJNZC:0095
            C:0x00CB22RET
            分析匯編代碼,其他匯編代碼使用的不是DJNZ跳轉方式,而是DEC和JNZ語句來實現(xiàn)循環(huán)判斷。1條JNZ指令要花費2個時鐘周期,3條指令就需要6個機器周期,MOV指令和DEC指令各需要1小時鐘周期,1個時鐘周期按1 μs算,其精度最多達到8 μs,最后加上一條LCALL和一條RET語句,所以整個較差[4]。
            利用Keil C的測試工具,在一處設置一個斷點。第1次執(zhí)行到中斷處的時間為0.000 513 s,第2次執(zhí)行到中斷處的時間為1.000 922 s,時間延遲為1.000 409 s,測試結果如圖5所示。對于上面的3種循環(huán)嵌套,循環(huán)次數(shù)為100×20×248=496 000,每次循環(huán)的時間約為2 μs。

          圖5 三重嵌套循環(huán)1 s實現(xiàn)時間測試結果
            為獲取與匯編語言延時的差距,同樣進行1 s的延時,程序代碼段如下:
              LCALL DELY1S
              INC Second
            DELY1S:MOV R5,#100
            D2:MOV R6,#20
            D1:MOV R7,#248
              DJNZ R7,$
              DJNZ R6,D1
              DJNZ R5,D2
              RET
            通過Keil C51測試,其實際延遲時間為0.997 943 s。雖然C語言實現(xiàn)延時方式的匯編代碼復雜度增加,但是與匯編語言實現(xiàn)的方式性能差距并不大。
          4 總結
            匯編語言在實時性方面具有較大的優(yōu)越性,雖然使用Keil C51可以在C語言程序中嵌入?yún)R編代碼,但是復雜度明顯提高。實驗證明,只要合理地運用C語言,在延時編程方面就可以達到與匯編語言相近的精度。為了獲得精確的時間延遲,可通過Keil C工具的仿真功能,調整延遲量,從而得到較理想的結果。
          參考文獻
          [1] InfiniteSpace Studio/isjfk. 51單片機KeilC延時程序的簡單研究[EB/OL]. http://www.icwin.net/ShowArtitle.ASP?art_id=5564cat_id=33.
          [2] 沈舷. 延時程序延時時間的精確計算.電工技術與自動化[J]. 2005,34(6):152-153,157.
          [3] 蹇興亮.單片機定時中斷的精確定時編程方法種種[J].單片機與嵌入式系統(tǒng)應用,2004(8).
          [4] 聶毅.單片機定時器中斷時間誤差的分析及補償[J].微計算機信息,2002,18(4):37-38.


          評論


          相關推薦

          技術專區(qū)

          關閉
          看屁屁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); })();