新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 最高效率使用單片機,放棄程序中的延時函數

        最高效率使用單片機,放棄程序中的延時函數

        作者: 時間:2016-11-29 來源:網絡 收藏
        我是PC機底層編程轉過來的,以前從來沒接觸過單片機,五個月前學習AVR,在這里學到很多東西。但也意識到電子工程師們的硬件編程思想與PC機底層編程思想上的很多不同,引發了一些思考。我說一說,供大家參考,只為學習,無意爭論。

        我第一次看到教程里Delay()函數的代碼時我嚇了一跳,竟然讓單片機空轉以實現和外界同步,這怎么可能?
        試想,如果PC機CPU空轉一秒,那么音樂會斷一秒、畫面會停頓一秒、下載文件會斷一秒,這怎么可行?

        本文引用地址:http://www.104case.com/article/201611/323453.htm

        我看到很多單片機程序,它們的單片機99.9%的工作時間都在打空轉,99.9%大家可能感到有些危言聳聽,那就讓我們算一算:

        已內部8M頻的AVR單片機來說,單指令周期僅為1/8 = 0.125us,那一毫秒可以執行多少個單周期指令? 1%0.125*1000 = 8000個

        而我看到論壇里下到的絕大多數程序,兩個延時函數之間代碼的執行時間要遠遠小于8000個指令周期。
        說實話,很多16K以上的程序,把所有延時函數去掉,總體能執行幾毫秒就不錯了。

        換句話說,我說單片機的利用率小于0.01%還是口下留情了。

        要說怎么解決問題,就要先找到問題,我問問大家,程序中,我們為什么延時?

        原因很多,可能是外設速度太慢,也可能是為了躲過人眼視覺停留時間,等等。
        總之就是與外界不同步,而我們想要同步。

        所以說這些延時應該是很有道理的,我不否定這一點,但問題的關鍵這些延時空轉,我們為什么不能把這些時間回收起來做一些別的事呢?
        試想,如果把這99.9%的時間回收,那可以一筆相當巨大的資源。

        有很多人有些特殊方法回收過這些空轉時間,比如說在延時函數中做點事。

        但這些往往都不通用,下面我說一些我的兩種方法:


        1、前后臺模式下延時時間回收的方法:

        前后臺模式就是大家最常用的主程序大循環 + 中斷的模式。

        首先解決外設太慢問題,像串口、鍵盤、LCD、SD卡等IO,這些收發可以建立外部緩沖區。比如串口收發在中斷中完成保存到緩沖區,而主程序操作緩沖區而不直接操縱串口,這已經看到很多人這樣用了。但像矩陣鍵盤的緩沖區,我很少看到有人這么用,在中斷中接收按鍵信息保存到緩沖區。
        還有像LCD,我們一個個往顯存中寫數據是很浪費的,也應該建立緩沖,統一處理。

        建立緩沖區這類方式中間有一些技術難點,比如像串口接收,無法判斷對發是否全部發完,怎么辦?可以設立定時,如果一個字節接收之后1ms之內沒收到下一個,則認為接收完畢。這只是一個思想,具體應用大家掌握。

        可能有人會說,除了外設太慢,還有像視覺停留的問題怎么解決,總不能讓流水燈快到人眼都看不清吧。
        這就我下面要說的問題,這些延時的時間怎么回收?就是全部放到定時中斷中!

        可能又有些人會說,書里、教程都說了,中斷處理東西的時間要盡量短,你這樣整個中斷有太多判斷、很長,時間很長,這不行。

        這是一種教條的思想,把書讀死了。可以在中斷中這樣處理,比如:

        void (*Task)(void);
        ISR
        {
        (*Task)(void);
        }

        中斷里用的內容通過函數指針來調用,這樣可以在主程序根據需要時任意改變要執行的任務,還可以改任務的周期。所用的判斷都是在主程序需中執行,然后改變指針的指向,來確定中斷中下一步的任務。

        這樣,在前后臺系統中主程序將任務分配完,還有很多余力處理很多事。

        比如有很多個鍵盤、LED點陣、數碼管等,它們都需要實時響應,很容造成編程困難、響應遲鈍,其實只要把延時的時間回收,處理這些就非常從容了。

        可能還有人會說,有些項目用不了這么苛刻的時間,你回收的時間用不了,要那么多干嘛?

        其實這時,你就可以用死循環掃描事件,可以實時響應。你的系統跟原來空循環延時比,實時性要高了不知多少倍。


        2、變異的協作式內核

        先說說嵌入式操作系統的內核,簡單的說,它就是個任務調度器,讓多個任務在同一個CPU上同時執行,所謂同時也是相對的,無非就第一個任務執行幾毫秒、第二個任務在執行幾毫秒。。。外表看起來就是同時執行。

        至于可剝奪式內核和協作式內核的區別,大家可以百度一下。

        說道能在單片機上用的嵌入式操作系統,大家會說出一些如uCosII、FreeOS等操作系統。
        還有很多人對這些操作系統十分抗拒、十分反對,他們的理由是什么?

        1、這些操作系統占用大量RAM、ROM
        2、這些實時操作系統所謂的實時是相對非實時操作系統的,跟裸機比實際上是慢了

        這些理由不是沒道理,因為這些商用操作系統都是可剝奪式內核,它們的原則是保證最高優先級任務在可確定的時間內響應。
        它們的有優點是任務切換時間是確定的,不會隨任務的多少而改變。
        有了這些確定性,讓它們在商用產品大放光彩。因為其時間穩定性。

        但它們的缺點也很明顯,中斷級節拍浪費很多時間。任務間同時調用時引發同步問題而引入許多如信號量、郵箱等機制浪費大量RAM、ROM。

        綜上,可剝奪式內核穩定可定量,在越高級的單片機上越有優勢,在8位機上可用,但需要大量裁剪,并不一定合適。

        而協作式內核的核心思想是什么?它不像剝奪式內核保證最高級任務速度最快,而是保證所有任務的平均速度最快!

        正如我前面的說法,我連續兩個延時函數之間的代碼很難超過1ms,甚至很難超過100us,我們可以將其忽略。這樣10個任務,第一個執行完主動放棄單片機控制權,交給第二個任務,第二個任務執行完主動放棄控制權,交給第三個任務。10個任務之間無間隙,每一個任務需要延時時,就主動放棄控制權。

        基于這種思想,我們的就達到了回收空轉延時的目的,而且應為每個任務是執行完后主動放棄,所以不存在剝奪式內核的同步問題,基本不需要郵箱、信號量等機制,對RAM、ROM的要求就非常低了。

        這樣來看,協作式內核非常適合8位機。但可能有太多嵌入式系統的書中對剝奪式內核不分場合的認可,造成很多人誤解。而且uCos等系統的權威,也讓很多RTOS作者爭相效仿,沒用對8位機的場合做合理分析。

        商用系統中沒有協作式內核,而民用的,還少有優秀的協作式內核,都是基于傳統節拍。

        傳統協作式內核需要定時中斷為時鐘基準,也會間歇性打斷任務,造成不必要的損失,這并不是我們想要的。

        我們其實可以僅僅是讓定時器以大分頻系數開著, 而不給其產生中斷的機會。當任務將要放棄使用權時,讀取定時器,作為時鐘基準,然后清零。

        做法一句兩句說不清,而效果是什么?可以做到任務是以不受干擾,與裸機相同的工作狀態,這是傳統協作式內核做不到的,而僅當它需要延時了,才放棄使用權,將延時的時間給其它任務。這正符合我全文的目的 -- 回收空轉延時時間

        這樣的內核體積會非常小,運行方式與裸機無異,僅僅是把空轉延時時間干些其它事。對使用者還沒什么要求,不想以往系統那么復雜。

        可惜市面上并沒有基于這種方式的內核,我已經寫了一個,非常精簡,運行穩定。但作為一個想應用實際的內核,還需要檢驗。我最后檢查一下后,過幾天拿出來大家一起分享。

        PS:好了,我上面兩種方式,均為原創。希望能對大家有幫助~ 第二種中介紹的變異協作式內核思想很簡單,有興趣可以自己寫一個,我過幾天會把我的發上來。



        評論


        技術專區

        關閉
        主站蜘蛛池模板: 合肥市| 泗洪县| 三门峡市| 荥阳市| 桓台县| 滦平县| 丰镇市| 梁平县| 元氏县| 雷州市| 榕江县| 东城区| 宝坻区| 东明县| 洪江市| 平阴县| 阳山县| 云南省| 吐鲁番市| 中超| 榆林市| 金昌市| 松潘县| 韶关市| 三都| 攀枝花市| 横峰县| 海晏县| 汝阳县| 彝良县| 寿光市| 巨鹿县| 潮安县| 湄潭县| 伊宁县| 铁力市| 华阴市| 冀州市| 凤山市| 调兵山市| 贵溪市|