<acronym id="xonnx"></acronym>
      <td id="xonnx"></td>
    1. <pre id="xonnx"></pre>

      1. 專注電子技術學習與研究
        當前位置:單片機教程網 >> MCU設計實例 >> 瀏覽文章

        計數器(狀態機按鍵檢測)程序

        作者:佚名   來源:本站原創   點擊數:  更新時間:2014年02月13日   【字體:

               狀態機是軟件編程中的重要概念,比這個概念更重要的是對它的靈活應用。在一個思路清晰而且高效的程序中,必然有狀態機的身影浮現。例如,一個按鍵命令解析程序就可以被看做狀態機:本來在A狀態下,觸發一個按鍵后切換到了B狀態;再觸發另一個鍵后切換到C狀態,或者返回到A狀態。這就是最簡單的按鍵狀態機的例子。實際的按鍵解析程序會比這更復雜,但這并不影響我們對狀態機的認識。
               進一步看,擊鍵動作本身可以看做一個狀態機。一個擊鍵動作包含按下、抖動、釋放等狀態。其實狀態機的思想不單只是用在按鍵方面,數碼管顯示動態掃描、LED燈亮滅都存在狀態機的思想。使用狀態機思想進行單片機編程,比較通用的方法就是使用switch的選擇性分支語句來進行狀態跳轉。
              通過計數器這個實驗向大家展示狀態機的思想。


        上圖是proteus仿真圖,時間每過1s計數器值自動加1,K1啟動和停止計數器,K2選擇要修改的位,K3當前位加1,K4當前位減1。
        完整代碼如下:
        #include<reg51.h>

        typedef unsigned char UINT8;
        typedef unsigned int  UINT16;
        typedef unsigned long UINT32;
        typedef char          INT8;
        typedef int              INT16;
        typedef long          INT32;

        #define TIMER0_INITIAL_VALUE 5000    //5ms定時
        #define SEG_PORT             P0        //數碼管占用的IO口
        #define KEY_PORT             P1        //按鍵占用的IO口
        #define KEY_MASK             0x0F    //按鍵掩碼
        #define KEY_SEARCH_STATUS     0        //查詢按鍵狀態
        #define KEY_ACK_STATUS         1        //確認按鍵狀態
        #define    KEY_REALEASE_STATUS     2        //釋放按鍵狀態
        #define KEY1                 1        //按鍵1鍵值
        #define KEY2                 2        //按鍵2鍵值
        #define KEY3                 3        //按鍵3鍵值
        #define KEY4                 4        //按鍵4鍵值

        #define HIGH                1
        #define LOW                    0
        #define ON                    1
        #define OFF                    0

        sbit DATA = P0^4;
        sbit CLK = P0^5;

        UINT8 Timer0IRQEvent = 0;    //定時器0中斷事件
        UINT8 Time1SecEvent = 0;    //1s定時事件
        UINT8 TimeCount = 0;        //定時器0計數器,用于計數產生1s定時事件
        UINT8 SegCurPosMark = 0;    //被選中的數碼管
        UINT16 CounterValue = 0;    //計數器
        UINT8 SegCurSel = 0;        //當前選中的數碼管
        UINT8 SegBuf[4] = {0};
        code UINT8 SegCode[10] = {~0x3F,~0x06,~0x5B,~0x4F,~0x66,~0x6D,~0x7D,~0x07,~0x7F,~0x6F};
        code UINT8 SegSelTbl[4] = {0xFE,0xFD,0xFB,0xF7};
        UINT8 bSetTime = 0;            //標志位:是否設置計數值

        void LS164_DATA(unsigned char x)
        {
            if(x)
            {
                DATA = 1;
            }
            else
            {
                DATA = 0;
            }
        }
        void LS164_CLK(unsigned char x)
        {
            if(x)
            {
                CLK = 1;
            }
            else
            {
                CLK = 0;
            }
        }
        /**********************************************************
        *函數名稱:LS164Send
        *輸    入:byte單個字節
        *輸    出:無
        *功    能:74LS164發送單個字節
        ***********************************************************/
        void LS164Send(UINT8 byte)
        {
            UINT8 j;
            for(j=0;j<=7;j++)
            {
                if(byte&(1<<(7-j)))
                {
                    LS164_DATA(HIGH);
                }
                else
                {
                    LS164_DATA(LOW);
                }
                LS164_CLK(LOW);
                LS164_CLK(HIGH);
            }
        }
        /**********************************************************
        *函數名稱:SegRefreshDisplayBuf
        *輸    入:無
        *輸    出:無
        *功    能:數碼管刷新顯示緩存
        ***********************************************************/
        void  SegRefreshDisplayBuf(void)
        {
             SegBuf[0] = CounterValue%10;
             SegBuf[1] = CounterValue/10%10;
             SegBuf[2] = CounterValue/100%10;
             SegBuf[3] = CounterValue/1000%10;       
        }
        /**********************************************************
        *函數名稱:SegDisplay
        *輸    入:無
        *輸    出:無
        *功    能:數碼管顯示數據
        ***********************************************************/
        void SegDisplay(void)
        {
            UINT8 t;
            SEG_PORT = 0x0F;                                    //熄滅所有數碼管
          
            if(bSetTime)                                          //檢查是否設置計數值
            {
                if(SegCurSel == SegCurPosMark)
                {
                    t = SegCode[SegBuf[SegCurSel]] & 0x7F;        //加上小數點
                }
                else
                {
                    t = SegCode[SegBuf[SegCurSel]];               //正常顯示當前數值
                }
            }
            else
            {
                t = SegCode[SegBuf[SegCurSel]];                       //正常顯示當前數值
            }
          
            LS164Send(t);
            SEG_PORT = SegSelTbl[SegCurSel];                       //點亮當前要顯示的數碼管
            if(++SegCurSel >= 4)
            {
                SegCurSel = 0;
            }  
        }
        /**********************************************************
        *函數名稱:TimerInit
        *輸    入:無
        *輸    出:無
        *功    能:定時器初始化
        ***********************************************************/
        void TimerInit(void)
        {
            TH0 = (65536 - TIMER0_INITIAL_VALUE)/256;
            TL0 = (65536 - TIMER0_INITIAL_VALUE)%256;
            TMOD = 0x01;
        }
        /**********************************************************
        *函數名稱:Timer0Start
        *輸    入:無
        *輸    出:無
        *功    能:定時器啟動
        ***********************************************************/
        void Timer0Start(void)
        {
            TR0 = 1;
            ET0 = 1;
        }
        /**********************************************************
        *函數名稱:Timer0Stop
        *輸    入:無
        *輸    出:無
        *功    能:定時器停止
        ***********************************************************/
        void Timer0Stop(void)
        {
            TR0 = 0;
            ET0 = 0;
        }
        /**********************************************************
        *函數名稱:PortInit
        *輸    入:無
        *輸    出:無
        *功    能:I/O初始化
        ***********************************************************/
        void PortInit(void)
        {
            P0 = P1 = P2 = P3 = 0xFF;  
        }
        /**********************************************************
        *函數名稱:KeyRead
        *輸    入:無
        *輸    出:當前按下的按鍵
        *功    能:讀取按鍵值
        ***********************************************************/
        UINT8 KeyRead(void)
        {
            //KeyStatus:靜態變量,保存按鍵狀態
            //keyCurPress:靜態變量,保存當前按鍵的鍵值
            static UINT8 KeyStatus = KEY_SEARCH_STATUS,KeyCurPress = 0;
            UINT8 KeyValue;
            UINT8 i = 0;

            KeyValue = (~KEY_PORT) & KEY_MASK;

            switch(KeyStatus)
            {
                case KEY_SEARCH_STATUS:                       //按鍵查詢狀態
                {
                    if(KeyValue)
                    {
                        KeyStatus = KEY_ACK_STATUS;        //按鍵下一個狀態為確認狀態  
                    }
                    return 0;
                }
                break;
              
                case KEY_ACK_STATUS:                    //按鍵確認狀態
                {
                    if(!KeyValue)
                    {
                        KeyStatus = KEY_SEARCH_STATUS;
                    }
                    else
                    {
                        for(i=0;i<4;i++)
                        {
                            if(KeyValue&(1<<i))
                            {
                                KeyCurPress = KEY1 + i;
                                break;
                            }
                        }
                        KeyStatus = KEY_REALEASE_STATUS;
                    }
                    return 0;
                }
                break;

                case KEY_REALEASE_STATUS:                 //按鍵釋放狀態
                {
                    if(!KeyValue)
                    {
                        KeyStatus = KEY_SEARCH_STATUS;
                        return KeyCurPress;
                    }
                    return 0;
                }
                default:
                    return 0;
                break;
            }
        }
        /**********************************************************
        *函數名稱:main
        *輸    入:無
        *輸    出:無
        *功    能:函數主題
        ***********************************************************/
        void main(void)
        {
            PortInit();
            TimerInit();
            Timer0Start();
            SegRefreshDisplayBuf();
            EA = 1;
            while(1)
            {
                SegRefreshDisplayBuf();
                if(Timer0IRQEvent)
                {
                    Timer0IRQEvent = 0;
                    switch(KeyRead())
                    {
                        case KEY1:
                        {
                            bSetTime = ~bSetTime;
                            SegCurPosMark = 0;  
                        }
                        break;

                        case KEY2:
                        {
                            if(++SegCurPosMark>=4)
                            {
                                SegCurPosMark = 0;
                            }
                        }
                        break;

                        case KEY3:
                        {
                            if(!bSetTime)
                                break;
                            if(CounterValue>=9999)
                                CounterValue = 0;
                            if     (SegCurPosMark == 0)
                                CounterValue += 1;
                            else if(SegCurPosMark == 1)
                                CounterValue += 10;
                            else if(SegCurPosMark == 2)
                                CounterValue += 100;
                            else
                                CounterValue += 1000;
                        }
                        break;

                        case KEY4:
                        {
                            if(!bSetTime)
                                 break;
                            if(CounterValue<=0)
                            CounterValue = 9999;
                            if     (SegCurPosMark == 0)
                                CounterValue -= 1;
                            else if(SegCurPosMark == 1)
                                CounterValue -= 10;
                            else if(SegCurPosMark == 2)
                                CounterValue -= 100;
                            else
                                CounterValue -= 1000;
                        }
                        break;

                        default:
                        break;
                    }
                }
                else if(Time1SecEvent)
                {
                    Time1SecEvent = 0;
                    if(!bSetTime)
                    {
                         if(++CounterValue>=9999)
                        {
                            CounterValue = 0;
                        }
                    }
                }  
            }
        }
        /**********************************************************
        *函數名稱:Timer0IRQ
        *輸    入:無
        *輸    出:無
        *功    能:定時器中斷函數
        ***********************************************************/
        void Timer0IRQ(void) interrupt 1
        {
            TH0 = (65536 - TIMER0_INITIAL_VALUE)/256;
            TL0 = (65536 - TIMER0_INITIAL_VALUE)%256;
            Timer0IRQEvent = 1;

            SegDisplay();

            if(++TimeCount >= 200)
            {
                TimeCount = 0;
                Time1SecEvent = 1;
            }
        }
         

        關閉窗口

        相關文章

        欧美性色欧美精品视频,99热这里只有精品mp4,日韩高清亚洲日韩精品一区二区,2020国自产拍精品高潮