新聞中心

        EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 第26節(jié):在主函數(shù)while循環(huán)中驅(qū)動(dòng)數(shù)碼管的動(dòng)態(tài)掃描程序

        第26節(jié):在主函數(shù)while循環(huán)中驅(qū)動(dòng)數(shù)碼管的動(dòng)態(tài)掃描程序

        作者: 時(shí)間:2016-11-22 來(lái)源:網(wǎng)絡(luò) 收藏
        開(kāi)場(chǎng)白:

        上一節(jié)通過(guò)一個(gè)機(jī)械手自動(dòng)控制程序展示了我在工控常用的編程框架,但是一直沒(méi)涉及到人機(jī)界面,在大多數(shù)的實(shí)際項(xiàng)目中,人機(jī)界面是必不可少的,這一節(jié)開(kāi)始講最常用的人機(jī)界面------動(dòng)態(tài)數(shù)碼管的驅(qū)動(dòng)。

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

        這一節(jié)要教會(huì)大家兩個(gè)知識(shí)點(diǎn):

        第一點(diǎn):數(shù)碼管的動(dòng)態(tài)驅(qū)動(dòng)原理。

        第二點(diǎn):如何通過(guò)編程,讓數(shù)碼管顯示的內(nèi)容轉(zhuǎn)移到幾個(gè)變量接口上,方便以后編寫(xiě)更上一層的窗口程序。

        具體內(nèi)容,請(qǐng)看源代碼講解。

        (1)硬件平臺(tái):基于朱兆祺51單片機(jī)學(xué)習(xí)板。用兩片74HC595動(dòng)態(tài)驅(qū)動(dòng)八位共陰數(shù)碼管。

        (2)實(shí)現(xiàn)功能:

        開(kāi)機(jī)后顯示 8765.4321 的內(nèi)容,注意,其中有一個(gè)小數(shù)點(diǎn)。

        (3)源代碼講解如下:

        #include "REG52.H"

        void initial_myself();

        void initial_peripheral();

        void delay_short(unsigned int uiDelayShort);

        void delay_long(unsigned int uiDelaylong);

        //驅(qū)動(dòng)數(shù)碼管的74HC595

        void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01);

        void display_drive(); //顯示數(shù)碼管字模的驅(qū)動(dòng)函數(shù)

        //驅(qū)動(dòng)LED的74HC595

        void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01);

        sbit beep_dr=P2^7; //蜂鳴器的驅(qū)動(dòng)IO口

        sbit led_dr=P3^5; //作為中途暫停指示燈 亮的時(shí)候表示中途暫停

        sbit dig_hc595_sh_dr=P2^0; //數(shù)碼管的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 ucDigShow8; //第8位數(shù)碼管要顯示的內(nèi)容

        unsigned char ucDigShow7; //第7位數(shù)碼管要顯示的內(nèi)容

        unsigned char ucDigShow6; //第6位數(shù)碼管要顯示的內(nèi)容

        unsigned char ucDigShow5; //第5位數(shù)碼管要顯示的內(nèi)容

        unsigned char ucDigShow4; //第4位數(shù)碼管要顯示的內(nèi)容

        unsigned char ucDigShow3; //第3位數(shù)碼管要顯示的內(nèi)容

        unsigned char ucDigShow2; //第2位數(shù)碼管要顯示的內(nèi)容

        unsigned char ucDigShow1; //第1位數(shù)碼管要顯示的內(nèi)容

        unsigned char ucDigDot8; //數(shù)碼管8的小數(shù)點(diǎn)是否顯示的標(biāo)志

        unsigned char ucDigDot7; //數(shù)碼管7的小數(shù)點(diǎn)是否顯示的標(biāo)志

        unsigned char ucDigDot6; //數(shù)碼管6的小數(shù)點(diǎn)是否顯示的標(biāo)志

        unsigned char ucDigDot5; //數(shù)碼管5的小數(shù)點(diǎn)是否顯示的標(biāo)志

        unsigned char ucDigDot4; //數(shù)碼管4的小數(shù)點(diǎn)是否顯示的標(biāo)志

        unsigned char ucDigDot3; //數(shù)碼管3的小數(shù)點(diǎn)是否顯示的標(biāo)志

        unsigned char ucDigDot2; //數(shù)碼管2的小數(shù)點(diǎn)是否顯示的標(biāo)志

        unsigned char ucDigDot1; //數(shù)碼管1的小數(shù)點(diǎn)是否顯示的標(biāo)志

        unsigned char ucDigShowTemp=0; //臨時(shí)中間變量

        unsigned char ucDisplayDriveStep=1; //動(dòng)態(tài)掃描數(shù)碼管的步驟變量

        unsigned char ucDisplayUpdate=1; //更新顯示標(biāo)志

        //根據(jù)原理圖得出的共陰數(shù)碼管字模表

        code unsigned char dig_table[]=

        {

        0x3f, //0 序號(hào)0

        0x06, //1 序號(hào)1

        0x5b, //2 序號(hào)2

        0x4f, //3 序號(hào)3

        0x66, //4 序號(hào)4

        0x6d, //5 序號(hào)5

        0x7d, //6 序號(hào)6

        0x07, //7 序號(hào)7

        0x7f, //8 序號(hào)8

        0x6f, //9 序號(hào)9

        0x00, //不顯示 序號(hào)10

        };

        void main()

        {

        initial_myself();

        delay_long(100);

        initial_peripheral();

        while(1)

        {

        display_drive(); //顯示數(shù)碼管字模的驅(qū)動(dòng)函數(shù)

        }

        }

        /* 注釋一:

        * 動(dòng)態(tài)驅(qū)動(dòng)數(shù)碼管的原理是,在八位數(shù)碼管中,在任何一個(gè)瞬間,每次只顯示其中一位數(shù)碼管,另外的七個(gè)數(shù)碼管

        * 通過(guò)設(shè)置其公共位com為高電平來(lái)關(guān)閉顯示,只要切換畫(huà)面的速度足夠快,人的視覺(jué)就分辨不出來(lái),感覺(jué)八個(gè)數(shù)碼管

        * 是同時(shí)亮的。以下dig_hc595_drive(xx,yy)函數(shù),其中第一個(gè)形參xx是驅(qū)動(dòng)數(shù)碼管段seg的引腳,第二個(gè)形參yy是驅(qū)動(dòng)

        * 數(shù)碼管公共位com的引腳。

        */

        void display_drive()

        {

        //以下程序,如果加一些數(shù)組和移位的元素,還可以壓縮容量。但是鴻哥追求的不是容量,而是清晰的講解思路

        switch(ucDisplayDriveStep)

        {

        case 1: //顯示第1位

        ucDigShowTemp=dig_table[ucDigShow1];

        if(ucDigDot1==1)

        {

        ucDigShowTemp=ucDigShowTemp|0x80; //顯示小數(shù)點(diǎn)

        }

        dig_hc595_drive(ucDigShowTemp,0xfe);

        break;

        case 2: //顯示第2位

        ucDigShowTemp=dig_table[ucDigShow2];

        if(ucDigDot2==1)

        {

        ucDigShowTemp=ucDigShowTemp|0x80; //顯示小數(shù)點(diǎn)

        }

        dig_hc595_drive(ucDigShowTemp,0xfd);

        break;

        case 3: //顯示第3位

        ucDigShowTemp=dig_table[ucDigShow3];

        if(ucDigDot3==1)

        {

        ucDigShowTemp=ucDigShowTemp|0x80; //顯示小數(shù)點(diǎn)

        }

        dig_hc595_drive(ucDigShowTemp,0xfb);

        break;

        case 4: //顯示第4位

        ucDigShowTemp=dig_table[ucDigShow4];

        if(ucDigDot4==1)

        {

        ucDigShowTemp=ucDigShowTemp|0x80; //顯示小數(shù)點(diǎn)

        }

        dig_hc595_drive(ucDigShowTemp,0xf7);

        break;

        case 5: //顯示第5位

        ucDigShowTemp=dig_table[ucDigShow5];

        if(ucDigDot5==1)

        {

        ucDigShowTemp=ucDigShowTemp|0x80; //顯示小數(shù)點(diǎn)

        }

        dig_hc595_drive(ucDigShowTemp,0xef);

        break;

        case 6: //顯示第6位

        ucDigShowTemp=dig_table[ucDigShow6];

        if(ucDigDot6==1)

        {

        ucDigShowTemp=ucDigShowTemp|0x80; //顯示小數(shù)點(diǎn)

        }

        dig_hc595_drive(ucDigShowTemp,0xdf);

        break;

        case 7: //顯示第7位

        ucDigShowTemp=dig_table[ucDigShow7];

        if(ucDigDot7==1)

        {

        ucDigShowTemp=ucDigShowTemp|0x80; //顯示小數(shù)點(diǎn)

        }

        dig_hc595_drive(ucDigShowTemp,0xbf);

        break;

        case 8: //顯示第8位

        ucDigShowTemp=dig_table[ucDigShow8];

        if(ucDigDot8==1)

        {

        ucDigShowTemp=ucDigShowTemp|0x80; //顯示小數(shù)點(diǎn)

        }

        dig_hc595_drive(ucDigShowTemp,0x7f);

        break;

        }

        ucDisplayDriveStep++;

        if(ucDisplayDriveStep>8) //掃描完8個(gè)數(shù)碼管后,重新從第一個(gè)開(kāi)始掃描

        {

        ucDisplayDriveStep=1;

        }

        /* 注釋二:

        * 如果直接是單片機(jī)的IO口引腳驅(qū)動(dòng)的數(shù)碼管,由于驅(qū)動(dòng)的速度太快,此處應(yīng)該適當(dāng)增加一點(diǎn)delay延時(shí)或者

        * 用計(jì)數(shù)延時(shí)的方式來(lái)延時(shí),目的是在八位數(shù)碼管中切換到每位數(shù)碼管顯示的時(shí)候,都能停留一會(huì)再切換到其它

        * 位的數(shù)碼管界面,這樣可以增加顯示的效果。但是,由于朱兆祺51學(xué)習(xí)板是間接經(jīng)過(guò)74HC595驅(qū)動(dòng)數(shù)碼管的,

        * 在單片機(jī)驅(qū)動(dòng)74HC595的時(shí)候,dig_hc595_drive函數(shù)本身內(nèi)部需要執(zhí)行很多指令,已經(jīng)相當(dāng)于delay延時(shí)了,

        * 因此這里不再需要加delay延時(shí)函數(shù)或者計(jì)數(shù)延時(shí)。

        */

        }

        //數(shù)碼管的74HC595驅(qū)動(dòng)函數(shù)

        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;

        /* 注釋三:

        * 注意,此處的延時(shí)delay_short必須盡可能小,否則動(dòng)態(tài)掃描數(shù)碼管的速度就不夠。

        */

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

        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引腳的上升沿把數(shù)據(jù)送入寄存器

        delay_short(1);

        dig_hc595_sh_dr=1;

        delay_short(1);

        ucTempData=ucTempData<<1;

        }

        dig_hc595_st_dr=0; //ST引腳把兩個(gè)寄存器的數(shù)據(jù)更新輸出到74HC595的輸出引腳上并且鎖存起來(lái)

        delay_short(1);

        dig_hc595_st_dr=1;

        delay_short(1);

        dig_hc595_sh_dr=0; //拉低,抗干擾就增強(qiáng)

        dig_hc595_st_dr=0;

        dig_hc595_ds_dr=0;

        }

        //LED燈的74HC595驅(qū)動(dòng)函數(shù)

        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引腳的上升沿把數(shù)據(jù)送入寄存器

        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引腳的上升沿把數(shù)據(jù)送入寄存器

        delay_short(1);

        hc595_sh_dr=1;

        delay_short(1);

        ucTempData=ucTempData<<1;

        }

        hc595_st_dr=0; //ST引腳把兩個(gè)寄存器的數(shù)據(jù)更新輸出到74HC595的輸出引腳上并且鎖存起來(lái)

        delay_short(1);

        hc595_st_dr=1;

        delay_short(1);

        hc595_sh_dr=0; //拉低,抗干擾就增強(qiáng)

        hc595_st_dr=0;

        hc595_ds_dr=0;

        }

        void delay_short(unsigned int uiDelayShort)

        {

        unsigned int i;

        for(i=0;i

        {

        ; //一個(gè)分號(hào)相當(dāng)于執(zhí)行一條空語(yǔ)句

        }

        }

        void delay_long(unsigned int uiDelayLong)

        {

        unsigned int i;

        unsigned int j;

        for(i=0;i

        {

        for(j=0;j<500;j++) //內(nèi)嵌循環(huán)的空指令數(shù)量

        {

        ; //一個(gè)分號(hào)相當(dāng)于執(zhí)行一條空語(yǔ)句

        }

        }

        }

        void initial_myself() //第一區(qū) 初始化單片機(jī)

        {

        led_dr=0; //關(guān)閉獨(dú)立LED燈

        beep_dr=1; //用PNP三極管控制蜂鳴器,輸出高電平時(shí)不叫。

        hc595_drive(0x00,0x00); //關(guān)閉所有經(jīng)過(guò)另外兩個(gè)74HC595驅(qū)動(dòng)的LED燈

        }

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

        {

        /* 注釋四:

        * 讓數(shù)碼管顯示的內(nèi)容轉(zhuǎn)移到以下幾個(gè)變量接口上,方便以后編寫(xiě)更上一層的窗口程序。

        * 只要更改以下對(duì)應(yīng)變量的內(nèi)容,就可以顯示你想顯示的數(shù)字。初學(xué)者應(yīng)該仔細(xì)看看display_drive等函數(shù),

        * 了解來(lái)龍去脈,就可以知道本驅(qū)動(dòng)程序的框架原理了。

        */

        ucDigShow8=8; //第8位數(shù)碼管要顯示的內(nèi)容

        ucDigShow7=7; //第7位數(shù)碼管要顯示的內(nèi)容

        ucDigShow6=6; //第6位數(shù)碼管要顯示的內(nèi)容

        ucDigShow5=5; //第5位數(shù)碼管要顯示的內(nèi)容

        ucDigShow4=4; //第4位數(shù)碼管要顯示的內(nèi)容

        ucDigShow3=3; //第3位數(shù)碼管要顯示的內(nèi)容

        ucDigShow2=2; //第2位數(shù)碼管要顯示的內(nèi)容

        ucDigShow1=1; //第1位數(shù)碼管要顯示的內(nèi)容

        ucDigDot8=0;

        ucDigDot7=0;

        ucDigDot6=0;

        ucDigDot5=1; //顯示第5位的小數(shù)點(diǎn)

        ucDigDot4=0;

        ucDigDot3=0;

        ucDigDot2=0;

        ucDigDot1=0;

        }

        總結(jié)陳詞:

        把本程序下載到朱兆祺51學(xué)習(xí)板上,發(fā)現(xiàn)顯示的效果還是挺不錯(cuò)的。但是,本程序也有一個(gè)弱點(diǎn),在一些項(xiàng)目中 ,主函數(shù)循環(huán)中的任務(wù)越多,就意味著在某一瞬間,每顯示一位數(shù)碼管停留的時(shí)間就會(huì)越久,一旦超過(guò)某個(gè)值,會(huì)嚴(yán)重影響顯示的效果,有沒(méi)有辦法改善它?當(dāng)然有。欲知詳情,請(qǐng)聽(tīng)下回分解-----在定時(shí)中斷里動(dòng)態(tài)掃描數(shù)碼管的程序。



        評(píng)論


        技術(shù)專(zhuān)區(qū)

        關(guān)閉
        主站蜘蛛池模板: 垫江县| 孝义市| 桐乡市| 延川县| 元谋县| 永吉县| 阿拉尔市| 禄丰县| 故城县| 大冶市| 蓝山县| 临高县| 从江县| 九寨沟县| 贵南县| 滦平县| 锦州市| 定兴县| 平江县| 荆门市| 东乡县| 体育| 天水市| 玛多县| 兖州市| 二连浩特市| 高唐县| 怀来县| 安陆市| 彩票| 云和县| 瑞丽市| 金华市| 平昌县| 页游| 长春市| 繁昌县| 闽侯县| 资溪县| 广东省| 长垣县|