新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 高手談單片機裸奔的程序框架

        高手談單片機裸奔的程序框架

        作者: 時間:2013-01-09 來源:網絡 收藏


        /*==========================================
        功能:串口接收
        說明:當非0輸出時,收到一幀數據
        放在大循環中執行
        輸出:==0:沒有
        !=0:命令字
        輸入:none
        ==========================================*/
        INT8U ChkRxFrame(void)
        {
        INT8U dat;
        INT8U cnt;
        INT8U sum;
        INT8U ret;
        ret = RX_NULL;
        if (RxBufCnt != 0){
        RxTimer = 0; //清接收計數時間,UARTimeEvent()中對于接收超時做了放棄整幀數據的處理
        //Display();
        cnt = RxCnt;
        dat = RxBuf[RxBufRdIdx]; // Get Char
        if (++RxBufRdIdx == RX_BUFFER_SIZE)
        RxBufRdIdx = 0;
        Cli();
        --RxBufCnt;
        Sei();
        FrameBuf[cnt++] = dat;
        if (cnt >= FRAME_LEN)// 組成一幀
        {
        sum = 0;
        for (cnt = 0;cnt (FRAME_LEN - 1);cnt++)
        sum+= FrameBuf[cnt];
        if (sum == dat)
        ret = FrameBuf[0];
        cnt = 0;
        }
        RxCnt = cnt;
        }
        return ret;
        }
        以上的代碼ChkRxFrame()可以放于串口接收數據處理函數RxProcess() 中,然后放入主循環中執行即可。以上用一個計時變量RxTimer,很微妙的解決了接收幀超時的放棄幀處理,它沒有用任何等待,而且主循環中每次只是接收一個字節數據,時間很短。


        我們開始架構整個系統的框架:
        我們選用一個系統不常用的TIMER來產生系統所需的系統基準節拍,這里我們選用4ms;
        在meg8中我們代碼如下:
        // Timer 0 overflow interrupt service routine
        interrupt [TIM0_OVF] void timer0_ovf_isr(void)
        {
        // Reinitialize Timer 0 value
        TCNT0=0x83;
        // Place your code here
        if ((++Time1ms 0x03) == 0)
        TimeIntFlg = 1;
        }
        然后我們設計一個TimeEvent()函數,來調用一些在以指定的頻率需要循環調用的函數,
        比如每個4ms我們就進行喂狗以及數碼管動態掃描顯示,每隔1s我們就調用led閃爍程序,每隔20ms我們進行鍵盤掃描程序;
        void TimeEvent (void)
        {
        if (TimeIntFlg){
        TimeIntFlg = 0;
        ClearWatchDog();
        display(); // 在4ms事件中,調用LED掃描顯示,以及喂狗
        if (++Time4ms > 5){
        Time4ms = 0;
        TimeEvent20ms();//在20ms事件中,我們處理鍵盤掃描read_keyboard_FUN2()

        if (++Time100ms > 10){
        Time100ms = 0;
        TimeEvent1Hz();// 在1s事件中,我們使工作指示燈閃爍
        }
        }
        UARTimeEvent();//串口的數據接收事件,在4ms事件中處理
        }
        }
        顯然整個思路已經很清晰了,cpu需要處理的循環事件都可以根據其對于時間的要求很方便的加入該函數中。但是我們對這事件有要求:
        執行速度快,簡短,不能有太長的延時等待,其所有事件一次執行時間和必須小于系統的基準時間片4ms(根據需要可以加大系統基準節拍)。所以我們的鍵盤掃描程序,數碼管顯示程序,串口接收程序都如我先前所示。如果逼不得已需要用到較長的延時(如模擬IIc時序中用到的延時)
        我們設計了這樣的延時函數:
        void RunTime250Hz (INT8U delay)//此延時函數的單位為4ms(系統基準節拍)
        {
        while (delay){
        if (TimeIntFlg){
        --delay;
        TimeEvent();
        }
        TxProcess();
        RxProcess();
        }
        }
        我們需要延時的時間=delay*系統記住節拍4ms,此函數就確保了在延時的同時,我們其它事件(鍵盤掃描,led顯示等)也并沒有被耽誤;

        好了這樣我們的主函數main()將很簡短:
        Void main (voie)
        {
        Init_all();
        while (1)
        {
        TimeEvent(); //對于循環事件的處理
        RxProcess();//串口對接收的數據處理
        TxProcess();// 串口發送數據處理

        }
        }
        整體看來我們的系統就成了將近一個萬能的模版了,根據自己所選的cpu,選個定時器,在添加自己的事件函數即可,非常靈活方便實用,一般的單片機能勝任的場合,該模版都能搞定。
        整個系統以全局標志作為主線,形散神不散;系統耗費比較小,只是犧牲了一個Timer而已,在資源缺乏的單片機中,非常適;曾經看過一個網友的模版“單片機實用系統”,其以51為例子寫的,整體思路和這個差不多,不過他寫得更為規范緊湊,非常欣賞;但個人覺得代碼開銷量要大些,用慣了都一樣哦。但是由于本系統以全局標志為驅動事件,所以比較感覺比較凌亂,全局最好都做好注釋,而其要注意一些隱形的函數遞歸情況,千萬不要遞歸的太深哦(有的單片機不支持)。


        上一頁 1 2 3 下一頁

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 灌南县| 广饶县| 齐齐哈尔市| 宜州市| 莆田市| 福贡县| 康平县| 英超| 晋州市| 辛集市| 蓝田县| 库尔勒市| 山丹县| 沅江市| 永安市| 青河县| 申扎县| 河南省| 措美县| 政和县| 临夏市| 含山县| 贵德县| 临江市| 思茅市| 宣化县| 沛县| 恩施市| 肇庆市| 南投县| 彰化县| 望奎县| 沈阳市| 翁牛特旗| 文登市| 武平县| 稷山县| 西盟| 仲巴县| 浑源县| 红河县|