找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3286|回复: 0
打印 上一主题 下一主题
收起左侧

用单片机开发可靠的嵌入式软件之数码管

[复制链接]
跳转到指定楼层
楼主
ID:61444 发表于 2014-5-6 17:56 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在许多嵌入式系统中提供某些形式的显示设备用来向用户传递信息。显示器可以有一个简单的指示灯到一个显示复杂图形的液晶显示器。例如:我们常用的显示器件有:LED灯、数码管、点阵屏、LCD屏等。
在此我们来分析一下如何使用7段LED数码管。
1、LED显示器。
发光二极管,或者称为LED,是一个报道体设备。当电流如图1-1所示通过它的时候,可以产生可见的光。LED发光的亮度与通过LED的电流强度成正比。常见的LED灯可以产生红光、黄光、绿光、蓝光。而红色是我们常见的LED灯。

图1-1
2、数码管
数码管是多个LED灯组成的一个显示器件。如图1-2所示。从图中我们可以看出,一个数码管是由A、B、C、D、E、F、G、DP 8个LED灯组成的。其中A-G用来显示数据,DP用来表示小数点,通常我们称这样的数码管为7段式数码管。图1-3表明了这样的数码管与微控制器的连接方式。从图中我们可以看出控制一个数码管需要8个GPIO端口。那么,我们试想一下,如果系统中有多个数码管,那将会非常浪费我们的GPIO端口。那有没有一个节省端口的方法来扩展LED灯呢。图1-4描述了这种方法。

图1-2 图1-3

图1-4
图1-4使用16个端口扩展了8个数码管。我们来看一下怎么使用这8个数码管。从上面的描述我们知道,如果要点亮一个LED灯,只需要在数码管的A引脚和12引脚之间加一个电压就行了,但是那个端口接电源的正极呢?如果A端口需要接电源的正极,那么这个数码管就被称为共阳极数码管,反之,则称为共阴极数码管。图中描述的是共阳极数码管。
3、数码管的动态扫描程序。
接下来我们来看一下怎么使用这个8个数码管。在这里我们使用动态扫描的方法。动态扫描即第一个数码管显示一段时间后第二数码管显示,第二个数码管显示一段时间后第三个数码管显示……依次显示。如果这个扫描的速度足够快的话,我们肉眼就感觉不到是在一个一个显示,而是整体一块显示的。那么这个扫描速度多少合适呢?一般我们的整体扫描时间要不大于20ms。我们这里有8个数码管,那么我们1个数码管的扫描时间设定为2.5ms。
本章我们以显示0-7这8个数字来使用数码管。

软件编写:
#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文件的内容,DispInit()这个函数初始化了数码管所使用的IO端口,并且关闭所有的数码管显示。Timer0Init()这个函数初始化了定时器,设置定时时间为2.5ms。我们这里使用定时器来定时扫描数码管。DispHex(i,i)这个函数设置了再哪个数码管上显示什么数,此函数能够显示十六进制的0-F。DispPoint(i)这个函数实现了显示点,参数为哪个数码管的点。
DISP_N_DIG表明了系统中数码管的数量,这是一个宏定义,需要用户自己修改。

更多详情咨询:曹老师 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文件中的内容。主要实现了数码管的显示,操作。

#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文件中的程序。系统使用定时器0定时2.5ms。当中断到达时中断服务函数调用DispMuxHandler()。在这个函数中把数码管现存中的内容全部显示到数码管上。这个函数首先关闭所有的数码管,然后选择要显示的数码管,把要显示的数据显示到对应的IO口上。我们应用程序只需要改变现存中的内容就可以把数据显示到数码管上。
更多详情咨询:曹老师 QQ:2859780203
                          李工:TEL:18948782707


函数名称函数作用使用者
DispClrScr清屏数码管用户
DispInit数码管显示的初始话用户,上电后必须调用1次
DispMuxHandler把数码管显存中的数据显示到数码管上定时器中断服务函数(用户不能调用)
DispStatClr关闭某一个数码管的显示DispMuxHandler
DispStatSet开启某一个数码管的显示DispMuxHandler
DispHex在某个数码管上显示十六进制数据用户
DispPoint在某个数码管上显示点用户
DispInitPort初始化数码管占用的端口DispInit
DispOutDig选中某一位数码管定时器中断服务函数(用户不能调用)
DispOutSeg选中某一段数码管定时器中断服务函数(用户不能调用)
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表