找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 3793|回復(fù): 0
打印 上一主題 下一主題
收起左側(cè)

用單片機(jī)開發(fā)可靠的嵌入式軟件之?dāng)?shù)碼管

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:61444 發(fā)表于 2014-5-6 17:56 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
在許多嵌入式系統(tǒng)中提供某些形式的顯示設(shè)備用來向用戶傳遞信息。顯示器可以有一個(gè)簡(jiǎn)單的指示燈到一個(gè)顯示復(fù)雜圖形的液晶顯示器。例如:我們常用的顯示器件有:LED燈、數(shù)碼管、點(diǎn)陣屏、LCD屏等。
在此我們來分析一下如何使用7段LED數(shù)碼管。
1、LED顯示器。
發(fā)光二極管,或者稱為L(zhǎng)ED,是一個(gè)報(bào)道體設(shè)備。當(dāng)電流如圖1-1所示通過它的時(shí)候,可以產(chǎn)生可見的光。LED發(fā)光的亮度與通過LED的電流強(qiáng)度成正比。常見的LED燈可以產(chǎn)生紅光、黃光、綠光、藍(lán)光。而紅色是我們常見的LED燈。

圖1-1
2、數(shù)碼管
數(shù)碼管是多個(gè)LED燈組成的一個(gè)顯示器件。如圖1-2所示。從圖中我們可以看出,一個(gè)數(shù)碼管是由A、B、C、D、E、F、G、DP 8個(gè)LED燈組成的。其中A-G用來顯示數(shù)據(jù),DP用來表示小數(shù)點(diǎn),通常我們稱這樣的數(shù)碼管為7段式數(shù)碼管。圖1-3表明了這樣的數(shù)碼管與微控制器的連接方式。從圖中我們可以看出控制一個(gè)數(shù)碼管需要8個(gè)GPIO端口。那么,我們?cè)囅胍幌,如果系統(tǒng)中有多個(gè)數(shù)碼管,那將會(huì)非常浪費(fèi)我們的GPIO端口。那有沒有一個(gè)節(jié)省端口的方法來擴(kuò)展LED燈呢。圖1-4描述了這種方法。

圖1-2 圖1-3

圖1-4
圖1-4使用16個(gè)端口擴(kuò)展了8個(gè)數(shù)碼管。我們來看一下怎么使用這8個(gè)數(shù)碼管。從上面的描述我們知道,如果要點(diǎn)亮一個(gè)LED燈,只需要在數(shù)碼管的A引腳和12引腳之間加一個(gè)電壓就行了,但是那個(gè)端口接電源的正極呢?如果A端口需要接電源的正極,那么這個(gè)數(shù)碼管就被稱為共陽(yáng)極數(shù)碼管,反之,則稱為共陰極數(shù)碼管。圖中描述的是共陽(yáng)極數(shù)碼管。
3、數(shù)碼管的動(dòng)態(tài)掃描程序。
接下來我們來看一下怎么使用這個(gè)8個(gè)數(shù)碼管。在這里我們使用動(dòng)態(tài)掃描的方法。動(dòng)態(tài)掃描即第一個(gè)數(shù)碼管顯示一段時(shí)間后第二數(shù)碼管顯示,第二個(gè)數(shù)碼管顯示一段時(shí)間后第三個(gè)數(shù)碼管顯示……依次顯示。如果這個(gè)掃描的速度足夠快的話,我們?nèi)庋劬透杏X不到是在一個(gè)一個(gè)顯示,而是整體一塊顯示的。那么這個(gè)掃描速度多少合適呢?一般我們的整體掃描時(shí)間要不大于20ms。我們這里有8個(gè)數(shù)碼管,那么我們1個(gè)數(shù)碼管的掃描時(shí)間設(shè)定為2.5ms。
本章我們以顯示0-7這8個(gè)數(shù)字來使用數(shù)碼管。

軟件編寫:
#include "includes.h"

void main(void)
{
    INT8U i;
    DispInit();
    Timer0Init();
   
    for(i=0;i<DISP_N_DIG;i++)
    {
         DispHex(i,i);
         DispPoint(i);
    }
    while(1)
    {
        ;
    }
}
以上是main文件的內(nèi)容,DispInit()這個(gè)函數(shù)初始化了數(shù)碼管所使用的IO端口,并且關(guān)閉所有的數(shù)碼管顯示。Timer0Init()這個(gè)函數(shù)初始化了定時(shí)器,設(shè)置定時(shí)時(shí)間為2.5ms。我們這里使用定時(shí)器來定時(shí)掃描數(shù)碼管。DispHex(i,i)這個(gè)函數(shù)設(shè)置了再哪個(gè)數(shù)碼管上顯示什么數(shù),此函數(shù)能夠顯示十六進(jìn)制的0-F。DispPoint(i)這個(gè)函數(shù)實(shí)現(xiàn)了顯示點(diǎn),參數(shù)為哪個(gè)數(shù)碼管的點(diǎn)。
DISP_N_DIG表明了系統(tǒng)中數(shù)碼管的數(shù)量,這是一個(gè)宏定義,需要用戶自己修改。

更多詳情咨詢:曹老師 QQ:2859780203
                          李工:TEL:18948782707
#include "includes.h"
/*
*********************************************************************************************************
*                                            LOCAL VARIABLES
*********************************************************************************************************/
static INT8U DispDigMsk;          /* Bit mask used to point to next digit to display */
static INT8U DispSegTbl[DISP_N_DIG];  /* Segment pattern table for each digit to display*/
static INT8U DispSegTblIx;               /* Index into DispSegTbl[] for next digit to display */
/*
*********************************************************************************************************
*                             HEXADECIMAL to SEVEN-SEGMENT conversion table
*                                                             a
*                                                           ------
*                                                        f |      | b
*                                                         |  g   |
* Note: The segments are mapped as follows:                       ------
*                                                        e |      | c
*        a    b    c    d    e    f    g    h              |  d   |
*        --   --   --   --   --   --   --   --                     ------ .h
*        B0   B1   B2   B3   B4   B5   B6   B7
*********************************************************************************************************
*/
INT8U code DispHexToSegTbl[] = {      /* HEXADECIMAL to SEVEN-SEGMENT conversion*/
    0xC0,                              /* '0' */
    0xF9,                              /* '1' */
    0xA4,                              /* '2' */
    0xB0,                              /* '3' */
    0x99,                              /* '4' */
    0x92,                              /* '5' */
    0x82,                              /* '6' */
    0xF8,                              /* '7' */
    0x80,                              /* '8' */
    0x90,                              /* '9' */
    0x88,                              /* 'A' */
    0x83,                              /* 'B', Actually displayed as 'b' */
    0xC6,                              /* 'C' */
    0xA1,                              /* 'D', Actually displayed as 'd' */
    0x86,                              /* 'E' */
    0x8E                               /* 'F' */
};

void DispClrScr (void);
void DispInit (void);
void DispStatClr (INT8U dig, INT8U numbit);
void DispStatSet (INT8U dig, INT8U numbit);
void DispOutDig (INT8U msk);
void DispOutSeg (INT8U seg);
void DispInitPort (void);
void DispHex(INT8U dig,INT8U number);
void DispPoint(INT8U dig);

/*$PAGE*/
/*
*********************************************************************************************************
*                                          CLEAR THE DISPLAY
*
* Description: This function is called to clear the display.
* Arguments  : none
* Returns    : none
*********************************************************************************************************
*/
void  DispClrScr (void)
{
    INT8U i;
    for (i = 0;i < DISP_N_DIG;i++)
    {           
        /* Clear the screen by turning OFF all segments */
        DispSegTbl = DISP_CRUSH_SEG;
    }
}

/*$PAGE*/
/*
*********************************************************************************************************
*                                      DISPLAY DRIVER INITIALIZATION
*
* Description : This function initializes the display driver.
* Arguments   : None.
* Returns     : None.
*********************************************************************************************************
*/

void DispInit (void)
{
    DispInitPort();                    /* Initialize I/O ports used in display driver*/
    DispDigMsk   = (1<<(DISP_N_DIG-1));               
    DispSegTblIx = 0;
    DispClrScr();                      /* Clear the Display*/
}

/*$PAGE*/
/*
*********************************************************************************************************
*                                        DISPLAY NEXT SEVEN-SEGMENT DIGIT
*
* Description: This function is called by DispMuxISR() to output the segments and select the next digit
*              to be multiplexed.  DispMuxHandler() is called by DispMuxISR() defined in LED_IA.ASM
* Arguments  : none
* Returns    : none
* Notes      : - You MUST supply the code to clear the interrupt source.  Note that with some
*                microprocessors (i.e. Motorola's MC68HC11), you must clear the interrupt source before
*                enabling interrupts.
*********************************************************************************************************
*/

void  DispMuxHandler (void)
{
DispOutSeg(DISP_CRUSH_SEG);              /*TurnOFFsegmentswhilechanging digits*/
    DispOutDig(DispDigMsk);                   /* Select next digit to display       */
    DispOutSeg(DispSegTbl[DispSegTblIx]);        /* Output digit's seven-segment pattern */
    if (DispSegTblIx == (DISP_N_DIG - 1)) {      /* Adjust index tonextseven-segmentpattern*/
        DispSegTblIx =    0;                     /* Index into first segments pattern*/
        DispDigMsk = (~(1<<(DISP_N_DIG-1)));/*0x80willselectthefirst seven-segment digit  */
    }
    else
    {
        DispSegTblIx++;
        DispDigMsk = ~DispDigMsk;
        DispDigMsk >>= 1;                        /* Select next digit */
        DispDigMsk = ~DispDigMsk;
    }
}

/*$PAGE*/
/*
*********************************************************************************************************
*                                         CLEAR STATUS SEGMENT
*
* Description: This function is called to turn OFF a single segment on the display.
* Arguments  : dig   is the position of the digit where the segment appears (0..DISP_N_DIG-1)
*              bit   is the segment bit to turn OFF (0..7)
* Returns    : none
*********************************************************************************************************
*/

void  DispStatClr (INT8U dig, INT8U numbit)
{
    DispSegTbl[dig] &= ~(1 << numbit);
}

/*
*********************************************************************************************************
*                                           SET STATUS SEGMENT
*
* Description: This function is called to turn ON a single segment on the display.
* Arguments  : dig   is the position of the digit where the segment appears (0..DISP_N_DIG-1)
*              bit   is the segment bit to turn ON (0..7)
* Returns    : none
*********************************************************************************************************
*/

void  DispStatSet (INT8U dig, INT8U numbit)
{
    DispSegTbl[dig] |= 1 << numbit;
}

/*$PAGE*/
/*
*********************************************************************************************************
*                            DISPLAY HEX NUMBER ON SEVEN-SEGMENT DISPLAY
*
* Description: This function is called to display hex number on the seven-segment display.
* Arguments  : dig   is the position of the first digit where the string will appear:
*                        0 for the first  seven-segment digit.
*                        1 for the second seven-segment digit.
*                        .  .   .     .     .      .      .
*                        .  .   .     .     .      .      .
*                        DISP_N_SS - 1 is the last seven-segment digit.
*              number     is the number to display
* Returns    : none
* Notes      : - Not all ASCII characters can be displayed on a seven-segment display.  Consult the
*                ASCII to seven-segment conversion table DispASCIItoSegTbl[].
*********************************************************************************************************
*/

void DispHex(INT8U dig,INT8U number)
{
DispSegTbl[dig] = DispHexToSegTbl[number];
}

void DispPoint(INT8U dig)
{
DispStatClr(dig,7);
}

/*$PAGE*/
/*
*********************************************************************************************************
*                                        I/O PORTS INITIALIZATION
*
* Description: This is called by DispInit() to initialize the output ports used in the LED multiplexing.
* Arguments  : none
* Returns    : none
* Notes      : 74HC573  8 bit latches are used for both the segments and digits outputs.
*********************************************************************************************************
*/

void  DispInitPort (void)
{
    outp(DISP_PORT_SEG, DISP_CRUSH_SEG);              /* Turn OFF segments*/
    outp(DISP_PORT_DIG, DISP_CRUSH_DIG);              /* Turn OFF digits*/
}

/*
*********************************************************************************************************
*                                        DIGIT output
*
* Description: This function outputs the digit selector.
* Arguments  : msk    is the mask used to select the current digit.
* Returns    : none
*********************************************************************************************************
*/

void  DispOutDig (INT8U msk)
{
    outp(DISP_PORT_DIG, msk);
}

/*
*********************************************************************************************************
*                                        SEGMENTS output
*
* Description: This function outputs seven-segment patterns.
* Arguments  : seg    is the seven-segment pattern to output
* Returns    : none
*********************************************************************************************************
*/
void  DispOutSeg (INT8U seg)
{
    outp(DISP_PORT_SEG, seg);
}
以上是smg.c文件中的內(nèi)容。主要實(shí)現(xiàn)了數(shù)碼管的顯示,操作。

#include "includes.h"

//Init timer0 2.5ms
void Timer0Init(void)
{
TMOD |= 0x01;
TH0 = 0xec;
TL0 = 0x77;
TR0 = 1;
TF0 = 0;
EA = 1;
ET0 = 1;
}
void timer0() interrupt 1
{
    EA = 0;
TH0=0xec;
TL0=0x77;
    DispMuxHandler();
    EA = 1;
}
以上是timer.c文件中的程序。系統(tǒng)使用定時(shí)器0定時(shí)2.5ms。當(dāng)中斷到達(dá)時(shí)中斷服務(wù)函數(shù)調(diào)用DispMuxHandler()。在這個(gè)函數(shù)中把數(shù)碼管現(xiàn)存中的內(nèi)容全部顯示到數(shù)碼管上。這個(gè)函數(shù)首先關(guān)閉所有的數(shù)碼管,然后選擇要顯示的數(shù)碼管,把要顯示的數(shù)據(jù)顯示到對(duì)應(yīng)的IO口上。我們應(yīng)用程序只需要改變現(xiàn)存中的內(nèi)容就可以把數(shù)據(jù)顯示到數(shù)碼管上。
更多詳情咨詢:曹老師 QQ:2859780203
                          李工:TEL:18948782707


函數(shù)名稱函數(shù)作用使用者
DispClrScr清屏數(shù)碼管用戶
DispInit數(shù)碼管顯示的初始話用戶,上電后必須調(diào)用1次
DispMuxHandler把數(shù)碼管顯存中的數(shù)據(jù)顯示到數(shù)碼管上定時(shí)器中斷服務(wù)函數(shù)(用戶不能調(diào)用)
DispStatClr關(guān)閉某一個(gè)數(shù)碼管的顯示DispMuxHandler
DispStatSet開啟某一個(gè)數(shù)碼管的顯示DispMuxHandler
DispHex在某個(gè)數(shù)碼管上顯示十六進(jìn)制數(shù)據(jù)用戶
DispPoint在某個(gè)數(shù)碼管上顯示點(diǎn)用戶
DispInitPort初始化數(shù)碼管占用的端口DispInit
DispOutDig選中某一位數(shù)碼管定時(shí)器中斷服務(wù)函數(shù)(用戶不能調(diào)用)
DispOutSeg選中某一段數(shù)碼管定時(shí)器中斷服務(wù)函數(shù)(用戶不能調(diào)用)
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表