新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 弟30節:數碼管通過閃爍來設置數據

        弟30節:數碼管通過閃爍來設置數據

        作者: 時間:2016-11-22 來源:網絡 收藏
        開場白:
        上一節講了一級菜單,這一節要教會大家兩個知識點:
        第一個:二級菜單的程序的程序框架。
        第二個:繼續加深熟悉鴻哥首次提出的“一二級菜單顯示理論”:凡是人機界面顯示,不管是數碼管還是液晶屏,都可以把顯示的內容分成不同的窗口來顯示,每個顯示的窗口中又可以分成不同的局部顯示。其中窗口就是一級菜單,用ucWd變量表示。局部就是二級菜單,用ucPart來表示。不同的窗口,會有不同的更新顯示變量ucWdXUpdate來對應,表示整屏全部更新顯示。不同的局部,也會有不同的更新顯示變量ucWdXPartYUpdate來對應,表示局部更新顯示。


        具體內容,請看源代碼講解。

        (1)硬件平臺:基于朱兆祺51單片機學習板。加按鍵對應S1鍵,減按鍵對應S5鍵,切換“光標閃爍”按鍵對應S9鍵

        (2)實現功能:
        通過按鍵設置4個不同的參數。
        只有1個窗口。這個窗口顯示4個參數。
        第8,7位數碼管顯示第1個參數。第6,5位數碼管顯示第2個參數。第4,3位數碼管顯示第3個參數。第2,1位數碼管顯示第4個參數。每個參數的范圍是從0到99。
        有三個按鍵。一個是“光標閃爍”按鍵,依次按下此按鍵,每兩位數碼管會依次處于閃爍的狀態,哪兩位數碼管處于閃爍狀態時,此時按加鍵或者減鍵就可以設置當前選中的參數。依次按下“光標閃爍”按鍵,數碼管會在以下5種狀態中循環:只有第8,7位數碼管閃爍---只有第6,5位數碼管閃爍---只有第4,3位數碼管閃爍---只有第2,1位數碼管閃爍---所有的數碼管都不閃爍。

        (3)源代碼講解如下:

        #include "REG52.H"


        #define const_voice_short40 //蜂鳴器短叫的持續時間

        #define const_key_time120 //按鍵去抖動延時的時間
        #define const_key_time220 //按鍵去抖動延時的時間
        #define const_key_time320 //按鍵去抖動延時的時間

        #define const_dpy_time_half200//數碼管閃爍時間的半值
        #define const_dpy_time_all 400//數碼管閃爍時間的全值 一定要比const_dpy_time_half 大

        void initial_myself();
        void initial_peripheral();
        void delay_short(unsigned int uiDelayShort);
        void delay_long(unsigned int uiDelaylong);

        //驅動數碼管的74HC595
        void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01);
        void display_drive(); //顯示數碼管字模的驅動函數

        void display_service(); //顯示的窗口菜單服務程序

        //驅動LED的74HC595
        void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01);

        void T0_time();//定時中斷函數

        void key_service(); //按鍵服務的應用程序
        void key_scan();//按鍵掃描函數 放在定時中斷里


        sbit key_sr1=P0^0; //對應朱兆祺學習板的S1鍵
        sbit key_sr2=P0^1; //對應朱兆祺學習板的S5鍵
        sbit key_sr3=P0^2; //對應朱兆祺學習板的S9鍵

        sbit key_gnd_dr=P0^4; //模擬獨立按鍵的地GND,因此必須一直輸出低電平

        sbit beep_dr=P2^7; //蜂鳴器的驅動IO口
        sbit led_dr=P3^5;//作為中途暫停指示燈 亮的時候表示中途暫停


        sbit dig_hc595_sh_dr=P2^0; //數碼管的74HC595程序
        sbit dig_hc595_st_dr=P2^1;
        sbit dig_hc595_ds_dr=P2^2;

        sbit hc595_sh_dr=P2^3; //LED燈的74HC595程序
        sbit hc595_st_dr=P2^4;
        sbit hc595_ds_dr=P2^5;

        unsigned char ucKeySec=0; //被觸發的按鍵編號

        unsigned intuiKeyTimeCnt1=0; //按鍵去抖動延時計數器
        unsigned char ucKeyLock1=0; //按鍵觸發后自鎖的變量標志

        unsigned intuiKeyTimeCnt2=0; //按鍵去抖動延時計數器
        unsigned char ucKeyLock2=0; //按鍵觸發后自鎖的變量標志

        unsigned intuiKeyTimeCnt3=0; //按鍵去抖動延時計數器
        unsigned char ucKeyLock3=0; //按鍵觸發后自鎖的變量標志

        unsigned intuiVoiceCnt=0;//蜂鳴器鳴叫的持續時間計數器


        unsigned char ucDigShow8;//第8位數碼管要顯示的內容
        unsigned char ucDigShow7;//第7位數碼管要顯示的內容
        unsigned char ucDigShow6;//第6位數碼管要顯示的內容
        unsigned char ucDigShow5;//第5位數碼管要顯示的內容
        unsigned char ucDigShow4;//第4位數碼管要顯示的內容
        unsigned char ucDigShow3;//第3位數碼管要顯示的內容
        unsigned char ucDigShow2;//第2位數碼管要顯示的內容
        unsigned char ucDigShow1;//第1位數碼管要顯示的內容


        unsigned char ucDigDot8;//數碼管8的小數點是否顯示的標志
        unsigned char ucDigDot7;//數碼管7的小數點是否顯示的標志
        unsigned char ucDigDot6;//數碼管6的小數點是否顯示的標志
        unsigned char ucDigDot5;//數碼管5的小數點是否顯示的標志
        unsigned char ucDigDot4;//數碼管4的小數點是否顯示的標志
        unsigned char ucDigDot3;//數碼管3的小數點是否顯示的標志
        unsigned char ucDigDot2;//數碼管2的小數點是否顯示的標志
        unsigned char ucDigDot1;//數碼管1的小數點是否顯示的標志

        unsigned char ucDigShowTemp=0; //臨時中間變量
        unsigned char ucDisplayDriveStep=1;//動態掃描數碼管的步驟變量

        unsigned char ucWd=1;//本程序的核心變量,窗口顯示變量。類似于一級菜單的變量。代表顯示不同的窗口。
        unsigned char ucWd1Update=1; //窗口1更新顯示標志

        unsigned char ucPart=0;//本程序的核心變量,局部顯示變量。類似于二級菜單的變量。代表顯示不同的局部。

        unsigned char ucWd1Part1Update=0;//在窗口1中,局部1的更新顯示標志
        unsigned char ucWd1Part2Update=0; //在窗口1中,局部2的更新顯示標志
        unsigned char ucWd1Part3Update=0; //在窗口1中,局部3的更新顯示標志
        unsigned char ucWd1Part4Update=0; //在窗口1中,局部4的更新顯示標志

        unsigned intuiSetData1=0;//本程序中需要被設置的參數1
        unsigned intuiSetData2=0;//本程序中需要被設置的參數2
        unsigned intuiSetData3=0;//本程序中需要被設置的參數3
        unsigned intuiSetData4=0;//本程序中需要被設置的參數4


        unsigned char ucTemp1=0;//中間過渡變量
        unsigned char ucTemp2=0;//中間過渡變量
        unsigned char ucTemp3=0;//中間過渡變量
        unsigned char ucTemp4=0;//中間過渡變量
        unsigned char ucTemp5=0;//中間過渡變量
        unsigned char ucTemp6=0;//中間過渡變量
        unsigned char ucTemp7=0;//中間過渡變量
        unsigned char ucTemp8=0;//中間過渡變量

        unsigned intuiDpyTimeCnt=0;//數碼管的閃爍計時器,放在定時中斷里不斷累加

        //根據原理圖得出的共陰數碼管字模表
        code unsigned char dig_table[]=
        {
        0x3f,//0 序號0
        0x06,//1 序號1
        0x5b,//2 序號2
        0x4f,//3 序號3
        0x66,//4 序號4
        0x6d,//5 序號5
        0x7d,//6 序號6
        0x07,//7 序號7
        0x7f,//8 序號8
        0x6f,//9 序號9
        0x00,//無 序號10
        0x40,//- 序號11
        0x73,//P 序號12
        };

        void main()
        {
        initial_myself();
        delay_long(100);
        initial_peripheral();
        while(1)
        {
        key_service(); //按鍵服務的應用程序
        display_service(); //顯示的窗口菜單服務程序
        }

        }

        /* 注釋一:
        *鴻哥首次提出的"一二級菜單顯示理論":
        *凡是人機界面顯示,不管是數碼管還是液晶屏,都可以把顯示的內容分成不同的窗口來顯示,
        *每個顯示的窗口中又可以分成不同的局部顯示。其中窗口就是一級菜單,用ucWd變量表示。
        *局部就是二級菜單,用ucPart來表示。不同的窗口,會有不同的更新顯示變量ucWdXUpdate來對應,
        *表示整屏全部更新顯示。不同的局部,也會有不同的更新顯示變量ucWdXPartYUpdate來對應,表示局部更新顯示。
        */


        void display_service() //顯示的窗口菜單服務程序
        {


        switch(ucWd)//本程序的核心變量,窗口顯示變量。類似于一級菜單的變量。代表顯示不同的窗口。
        {
        case 1: //顯示窗口1的數據

        if(ucWd1Part1Update==1)//僅僅參數1局部更新
        {
        ucWd1Part1Update=0; //及時清零標志,避免一直進來掃描

        ucTemp8=uiSetData1/10;//第1個參數
        ucTemp7=uiSetData1%10;
        if(uiSetData1<10)
        {
        ucDigShow8=10;
        }
        else
        {
        ucDigShow8=ucTemp8;
        }
        ucDigShow7=ucTemp7;
        }

        if(ucWd1Part2Update==1)//僅僅參數2局部更新
        {
        ucWd1Part2Update=0;//及時清零標志,避免一直進來掃描

        ucTemp6=uiSetData2/10;//第2個參數
        ucTemp5=uiSetData2%10;
        if(uiSetData2<10)
        {
        ucDigShow6=10;
        }
        else
        {
        ucDigShow6=ucTemp6;
        }
        ucDigShow5=ucTemp5;

        }

        if(ucWd1Part3Update==1)//僅僅參數3局部更新
        {
        ucWd1Part3Update=0;//及時清零標志,避免一直進來掃描

        ucTemp4=uiSetData3/10;//第3個參數
        ucTemp3=uiSetData3%10;
        if(uiSetData3<10)
        {
        ucDigShow4=10;
        }
        else
        {
        ucDigShow4=ucTemp4;
        }
        ucDigShow3=ucTemp3;
        }

        if(ucWd1Part4Update==1)//僅僅參數4局部更新
        {
        ucWd1Part4Update=0; //及時清零標志,避免一直進來掃描

        ucTemp2=uiSetData4/10;//第4個參數
        ucTemp1=uiSetData4%10;

        if(uiSetData4<10)
        {
        ucDigShow2=10;
        }
        else
        {
        ucDigShow2=ucTemp2;
        }
        ucDigShow1=ucTemp1;
        }

        /* 注釋二:
        * 必須注意局部更新和全部更新的編寫順序,局部更新應該寫在全部更新之前,
        * 當局部更新和全部更新同時發生時,這樣就能保證到全部更新的優先響應。
        */

        if(ucWd1Update==1)//窗口1要全部更新顯示
        {
        ucWd1Update=0;//及時清零標志,避免一直進來掃描

        ucTemp8=uiSetData1/10;//第1個參數
        ucTemp7=uiSetData1%10;

        ucTemp6=uiSetData2/10;//第2個參數
        ucTemp5=uiSetData2%10;


        ucTemp4=uiSetData3/10;//第3個參數
        ucTemp3=uiSetData3%10;

        ucTemp2=uiSetData4/10;//第4個參數
        ucTemp1=uiSetData4%10;


        if(uiSetData1<10)
        {
        ucDigShow8=10;
        }
        else
        {
        ucDigShow8=ucTemp8;
        }
        ucDigShow7=ucTemp7;


        if(uiSetData2<10)
        {
        ucDigShow6=10;
        }
        else
        {
        ucDigShow6=ucTemp6;
        }
        ucDigShow5=ucTemp5;

        if(uiSetData3<10)
        {
        ucDigShow4=10;
        }
        else
        {
        ucDigShow4=ucTemp4;
        }
        ucDigShow3=ucTemp3;

        if(uiSetData4<10)
        {
        ucDigShow2=10;
        }
        else
        {
        ucDigShow2=ucTemp2;
        }
        ucDigShow1=ucTemp1;

        }


        //數碼管閃爍
        switch(ucPart)//根據局部變量的值,使對應的參數產生閃爍的動態效果。
        {
        case 0://4個參數都不閃爍

        break;
        case 1://第1個參數閃爍
        if(uiDpyTimeCnt==const_dpy_time_half)
        {
        if(uiSetData1<10) //數碼管顯示內容
        {
        ucDigShow8=10;
        }
        else
        {
        ucDigShow8=ucTemp8;
        }
        ucDigShow7=ucTemp7;
        }
        else if(uiDpyTimeCnt>const_dpy_time_all) //const_dpy_time_all一定要比const_dpy_time_half 大
        {
        uiDpyTimeCnt=0; //及時把閃爍記時器清零

        ucDigShow8=10; //數碼管顯示空,什么都不顯示
        ucDigShow7=10;

        }
        break;
        case 2: //第2個參數閃爍
        if(uiDpyTimeCnt==const_dpy_time_half)
        {
        if(uiSetData2<10) //數碼管顯示內容
        {
        ucDigShow6=10;
        }
        else
        {
        ucDigShow6=ucTemp6;
        }
        ucDigShow5=ucTemp5;
        }
        else if(uiDpyTimeCnt>const_dpy_time_all)//const_dpy_time_all一定要比const_dpy_time_half 大
        {
        uiDpyTimeCnt=0; //及時把閃爍記時器清零

        ucDigShow6=10; //數碼管顯示空,什么都不顯示
        ucDigShow5=10;

        }
        break;
        case 3://第3個參數閃爍
        if(uiDpyTimeCnt==const_dpy_time_half)
        {
        if(uiSetData3<10) //數碼管顯示內容
        {
        ucDigShow4=10;
        }
        else
        {
        ucDigShow4=ucTemp4;
        }
        ucDigShow3=ucTemp3;
        }
        else if(uiDpyTimeCnt>const_dpy_time_all) //const_dpy_time_all一定要比const_dpy_time_half 大
        {
        uiDpyTimeCnt=0; //及時把閃爍記時器清零

        ucDigShow4=10; //數碼管顯示空,什么都不顯示
        ucDigShow3=10;

        }
        break;
        case 4://第4個參數閃爍
        if(uiDpyTimeCnt==const_dpy_time_half)
        {
        if(uiSetData4<10) //數碼管顯示內容
        {
        ucDigShow2=10;
        }
        else
        {
        ucDigShow2=ucTemp2;
        }
        ucDigShow1=ucTemp1;
        }
        else if(uiDpyTimeCnt>const_dpy_time_all) //const_dpy_time_all一定要比const_dpy_time_half 大
        {
        uiDpyTimeCnt=0; //及時把閃爍記時器清零

        ucDigShow2=10; //數碼管顯示空,什么都不顯示
        ucDigShow1=10;

        }
        break;
        }

        break;

        }



        }


        void key_scan()//按鍵掃描函數 放在定時中斷里
        {

        if(key_sr1==1)//IO是高電平,說明按鍵沒有被按下,這時要及時清零一些標志位
        {
        ucKeyLock1=0; //按鍵自鎖標志清零
        uiKeyTimeCnt1=0;//按鍵去抖動延時計數器清零,此行非常巧妙,是我實戰中摸索出來的。
        }
        else if(ucKeyLock1==0)//有按鍵按下,且是第一次被按下
        {
        uiKeyTimeCnt1++; //累加定時中斷次數
        if(uiKeyTimeCnt1>const_key_time1)
        {
        uiKeyTimeCnt1=0;
        ucKeyLock1=1;//自鎖按鍵置位,避免一直觸發
        ucKeySec=1; //觸發1號鍵
        }
        }

        if(key_sr2==1)//IO是高電平,說明按鍵沒有被按下,這時要及時清零一些標志位
        {
        ucKeyLock2=0; //按鍵自鎖標志清零
        uiKeyTimeCnt2=0;//按鍵去抖動延時計數器清零,此行非常巧妙,是我實戰中摸索出來的。
        }
        else if(ucKeyLock2==0)//有按鍵按下,且是第一次被按下
        {
        uiKeyTimeCnt2++; //累加定時中斷次數
        if(uiKeyTimeCnt2>const_key_time2)
        {
        uiKeyTimeCnt2=0;
        ucKeyLock2=1;//自鎖按鍵置位,避免一直觸發
        ucKeySec=2; //觸發2號鍵
        }
        }

        if(key_sr3==1)//IO是高電平,說明按鍵沒有被按下,這時要及時清零一些標志位
        {
        ucKeyLock3=0; //按鍵自鎖標志清零
        uiKeyTimeCnt3=0;//按鍵去抖動延時計數器清零,此行非常巧妙,是我實戰中摸索出來的。
        }
        else if(ucKeyLock3==0)//有按鍵按下,且是第一次被按下
        {
        uiKeyTimeCnt3++; //累加定時中斷次數
        if(uiKeyTimeCnt3>const_key_time3)
        {
        uiKeyTimeCnt3=0;
        ucKeyLock3=1;//自鎖按鍵置位,避免一直觸發
        ucKeySec=3; //觸發3號鍵
        }
        }



        }


        void key_service() //按鍵服務的應用程序
        {
        switch(ucKeySec) //按鍵服務狀態切換
        {
        case 1:// 加按鍵 對應朱兆祺學習板的S1鍵
        switch(ucWd)//在不同的窗口下,設置不同的參數
        {
        case 1:
        switch(ucPart)//在窗口1下,根據不同的局部閃爍位置來設置不同的參數
        {
        case 0:
        break;
        case 1:
        uiSetData1++;
        if(uiSetData1>99) //最大值是99
        {
        uiSetData1=99;
        }
        ucWd1Part1Update=1; //局部更新顯示參數1
        break;
        case 2:
        uiSetData2++;
        if(uiSetData2>99) //最大值是99
        {
        uiSetData2=99;
        }
        ucWd1Part2Update=1; //局部更新顯示參數2
        break;
        case 3:
        uiSetData3++;
        if(uiSetData3>99) //最大值是99
        {
        uiSetData3=99;
        }
        ucWd1Part3Update=1; //局部更新顯示參數3
        break;
        case 4:
        uiSetData4++;
        if(uiSetData4>99) //最大值是99
        {
        uiSetData4=99;
        }
        ucWd1Part4Update=1; //局部更新顯示參數4
        break;
        }
        break;
        }
        uiVoiceCnt=const_voice_short; //按鍵聲音觸發,滴一聲就停。
        ucKeySec=0;//響應按鍵服務處理程序后,按鍵編號清零,避免一致觸發
        break;

        case 2:// 減按鍵 對應朱兆祺學習板的S5鍵
        switch(ucWd)//在不同的窗口下,設置不同的參數
        {
        case 1:
        switch(ucPart)//在窗口1下,根據不同的局部閃爍位置來設置不同的參數
        {
        case 0:
        break;
        case 1:
        uiSetData1--;
        if(uiSetData1>99) //0減去1溢出肯定大于99
        {
        uiSetData1=0;
        }
        ucWd1Part1Update=1; //局部更新顯示參數1
        break;
        case 2:
        uiSetData2--;
        if(uiSetData2>99) //0減去1溢出肯定大于99
        {
        uiSetData2=0;
        }
        ucWd1Part2Update=1; //局部更新顯示參數2
        break;
        case 3:
        uiSetData3--;
        if(uiSetData3>99) //0減去1溢出肯定大于99
        {
        uiSetData3=0;
        }
        ucWd1Part3Update=1; //局部更新顯示參數3
        break;
        case 4:
        uiSetData4--;
        if(uiSetData4>99) //0減去1溢出肯定大于99
        {
        uiSetData4=0;
        }
        ucWd1Part4Update=1; //局部更新顯示參數4
        break;
        }
        break;
        }
        uiVoiceCnt=const_voice_short; //按鍵聲音觸發,滴一聲就停。
        ucKeySec=0;//響應按鍵服務處理程序后,按鍵編號清零,避免一致觸發
        break;

        case 3:// 切換"光標閃爍"按鍵 對應朱兆祺學習板的S9鍵
        switch(ucWd)//在不同的窗口下,設置不同的參數
        {
        case 1://在窗口1下,切換"光標閃爍"
        ucPart++;
        if(ucPart>4)
        {
        ucPart=0;
        }
        ucWd1Update=1;//窗口1全部更新顯示
        break;
        }

        uiVoiceCnt=const_voice_short; //按鍵聲音觸發,滴一聲就停。
        ucKeySec=0;//響應按鍵服務處理程序后,按鍵編號清零,避免一致觸發
        break;


        }
        }


        void display_drive()
        {
        //以下程序,如果加一些數組和移位的元素,還可以壓縮容量。但是鴻哥追求的不是容量,而是清晰的講解思路
        switch(ucDisplayDriveStep)
        {
        case 1://顯示第1位
        ucDigShowTemp=dig_table[ucDigShow1];
        if(ucDigDot1==1)
        {
        ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數點
        }
        dig_hc595_drive(ucDigShowTemp,0xfe);
        break;
        case 2://顯示第2位
        ucDigShowTemp=dig_table[ucDigShow2];
        if(ucDigDot2==1)
        {
        ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數點
        }
        dig_hc595_drive(ucDigShowTemp,0xfd);
        break;
        case 3://顯示第3位
        ucDigShowTemp=dig_table[ucDigShow3];
        if(ucDigDot3==1)
        {
        ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數點
        }
        dig_hc595_drive(ucDigShowTemp,0xfb);
        break;
        case 4://顯示第4位
        ucDigShowTemp=dig_table[ucDigShow4];
        if(ucDigDot4==1)
        {
        ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數點
        }
        dig_hc595_drive(ucDigShowTemp,0xf7);
        break;
        case 5://顯示第5位
        ucDigShowTemp=dig_table[ucDigShow5];
        if(ucDigDot5==1)
        {
        ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數點
        }
        dig_hc595_drive(ucDigShowTemp,0xef);
        break;
        case 6://顯示第6位
        ucDigShowTemp=dig_table[ucDigShow6];
        if(ucDigDot6==1)
        {
        ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數點
        }
        dig_hc595_drive(ucDigShowTemp,0xdf);
        break;
        case 7://顯示第7位
        ucDigShowTemp=dig_table[ucDigShow7];
        if(ucDigDot7==1)
        {
        ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數點
        }
        dig_hc595_drive(ucDigShowTemp,0xbf);
        break;
        case 8://顯示第8位
        ucDigShowTemp=dig_table[ucDigShow8];
        if(ucDigDot8==1)
        {
        ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數點
        }
        dig_hc595_drive(ucDigShowTemp,0x7f);
        break;
        }

        ucDisplayDriveStep++;
        if(ucDisplayDriveStep>8)//掃描完8個數碼管后,重新從第一個開始掃描
        {
        ucDisplayDriveStep=1;
        }



        }


        //數碼管的74HC595驅動函數
        void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01)
        {
        unsigned char i;
        unsigned char ucTempData;
        dig_hc595_sh_dr=0;
        dig_hc595_st_dr=0;

        ucTempData=ucDigStatusTemp16_09;//先送高8位
        for(i=0;i<8;i++)
        {
        if(ucTempData>=0x80)dig_hc595_ds_dr=1;
        else dig_hc595_ds_dr=0;

        dig_hc595_sh_dr=0; //SH引腳的上升沿把數據送入寄存器
        delay_short(1);
        dig_hc595_sh_dr=1;
        delay_short(1);

        ucTempData=ucTempData<<1;
        }

        ucTempData=ucDigStatusTemp08_01;//再先送低8位
        for(i=0;i<8;i++)
        {
        if(ucTempData>=0x80)dig_hc595_ds_dr=1;
        else dig_hc595_ds_dr=0;

        dig_hc595_sh_dr=0; //SH引腳的上升沿把數據送入寄存器
        delay_short(1);
        dig_hc595_sh_dr=1;
        delay_short(1);

        ucTempData=ucTempData<<1;
        }

        dig_hc595_st_dr=0;//ST引腳把兩個寄存器的數據更新輸出到74HC595的輸出引腳上并且鎖存起來
        delay_short(1);
        dig_hc595_st_dr=1;
        delay_short(1);

        dig_hc595_sh_dr=0; //拉低,抗干擾就增強
        dig_hc595_st_dr=0;
        dig_hc595_ds_dr=0;

        }


        //LED燈的74HC595驅動函數
        void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01)
        {
        unsigned char i;
        unsigned char ucTempData;
        hc595_sh_dr=0;
        hc595_st_dr=0;

        ucTempData=ucLedStatusTemp16_09;//先送高8位
        for(i=0;i<8;i++)
        {
        if(ucTempData>=0x80)hc595_ds_dr=1;
        else hc595_ds_dr=0;

        hc595_sh_dr=0; //SH引腳的上升沿把數據送入寄存器
        delay_short(1);
        hc595_sh_dr=1;
        delay_short(1);

        ucTempData=ucTempData<<1;
        }

        ucTempData=ucLedStatusTemp08_01;//再先送低8位
        for(i=0;i<8;i++)
        {
        if(ucTempData>=0x80)hc595_ds_dr=1;
        else hc595_ds_dr=0;

        hc595_sh_dr=0; //SH引腳的上升沿把數據送入寄存器
        delay_short(1);
        hc595_sh_dr=1;
        delay_short(1);

        ucTempData=ucTempData<<1;
        }

        hc595_st_dr=0;//ST引腳把兩個寄存器的數據更新輸出到74HC595的輸出引腳上并且鎖存起來
        delay_short(1);
        hc595_st_dr=1;
        delay_short(1);

        hc595_sh_dr=0; //拉低,抗干擾就增強
        hc595_st_dr=0;
        hc595_ds_dr=0;

        }


        void T0_time() interrupt 1
        {
        TF0=0;//清除中斷標志
        TR0=0; //關中斷

        key_scan(); //按鍵掃描函數

        uiDpyTimeCnt++;//數碼管的閃爍計時器

        if(uiVoiceCnt!=0)
        {
        uiVoiceCnt--; //每次進入定時中斷都自減1,直到等于零為止。才停止鳴叫
        beep_dr=0;//蜂鳴器是PNP三極管控制,低電平就開始鳴叫。
        // beep_dr=1;//蜂鳴器是PNP三極管控制,低電平就開始鳴叫。
        }
        else
        {
        ; //此處多加一個空指令,想維持跟if括號語句的數量對稱,都是兩條指令。不加也可以。
        beep_dr=1;//蜂鳴器是PNP三極管控制,高電平就停止鳴叫。
        // beep_dr=0;//蜂鳴器是PNP三極管控制,高電平就停止鳴叫。
        }

        display_drive();//數碼管字模的驅動函數


        TH0=0xfe; //重裝初始值(65535-500)=65035=0xfe0b
        TL0=0x0b;
        TR0=1;//開中斷
        }


        void delay_short(unsigned int uiDelayShort)
        {
        unsigned int i;
        for(i=0;i {
        ; //一個分號相當于執行一條空語句
        }
        }


        void delay_long(unsigned int uiDelayLong)
        {
        unsigned int i;
        unsigned int j;
        for(i=0;i {
        for(j=0;j<500;j++)//內嵌循環的空指令數量
        {
        ; //一個分號相當于執行一條空語句
        }
        }
        }


        void initial_myself()//第一區 初始化單片機
        {

        /* 注釋三:
        * 矩陣鍵盤也可以做獨立按鍵,前提是把某一根公共輸出線輸出低電平,
        * 模擬獨立按鍵的觸發地,本程序中,把key_gnd_dr輸出低電平。
        * 朱兆祺51學習板的S1就是本程序中用到的一個獨立按鍵。
        */
        key_gnd_dr=0; //模擬獨立按鍵的地GND,因此必須一直輸出低電平

        led_dr=0;//關閉獨立LED燈
        beep_dr=1; //用PNP三極管控制蜂鳴器,輸出高電平時不叫。

        hc595_drive(0x00,0x00);//關閉所有經過另外兩個74HC595驅動的LED燈

        TMOD=0x01;//設置定時器0為工作方式1

        TH0=0xfe; //重裝初始值(65535-500)=65035=0xfe0b
        TL0=0x0b;

        }

        void initial_peripheral() //第二區 初始化外圍
        {


        ucDigDot8=0; //小數點全部不顯示
        ucDigDot7=0;
        ucDigDot6=0;
        ucDigDot5=0;
        ucDigDot4=0;
        ucDigDot3=0;
        ucDigDot2=0;
        ucDigDot1=0;

        EA=1; //開總中斷
        ET0=1; //允許定時中斷
        TR0=1; //啟動定時中斷

        }


        總結陳詞:
        這節講了數碼管通過閃爍來設置數據的基本程序,但是該程序只有一個窗口。實際應用中,有些項目會有幾個窗口,而且每個窗口都要設置幾個參數,這樣的程序該怎么寫?欲知詳情,請聽下回分解-----數碼管通過一二級菜單來設置數據的綜合程序。


        評論


        技術專區

        關閉
        主站蜘蛛池模板: 改则县| 白山市| 霞浦县| 郧西县| 仙游县| 贵德县| 大余县| 疏附县| 湖州市| 介休市| 资源县| 左贡县| 台东县| 泗阳县| 郸城县| 济源市| 分宜县| 马鞍山市| 普宁市| 镇雄县| 宣城市| 淮北市| 武乡县| 辽源市| 额敏县| 随州市| 赤峰市| 元阳县| 阜阳市| 宁晋县| 宜城市| 繁峙县| 东明县| 水城县| 通化市| 新化县| 军事| 绍兴市| 罗田县| 盐边县| 康定县|