目的
让数码管在指定位置显示指定数字
一,STC单片机模块
二,数码管
2.1 数码管位置
2.2 生活中用到的数目管
红绿灯
LED数码管在生活中随处可见,洗衣机、电饭煲、热水器、微波炉、冰箱、这些最基本的家用电器上基本都用到了这种7段LED数码管(段
为LED灯的个数)。
2.3 数码管的分类
按显示段数分:分为七段、八段、九段、十四段和十六段
七段:七段数码管由7个LED构成
八段:八段数码管比七段多了一个小数点
九段:九段数码管由9个LED构成
十四段:十四段数码管由14个LED构成
十六段:十六段数码管由16个LED构成
按显示位数分:分为1位、2位、3位及多位数码管(大于1位),
我们的板子上是8段4位。
2.4 数码管电路图
单个数码管的电路图设计如下
内部接线图如下两种
第一种:共阴极(8个LED的负极接一起)
第二种:共阳极(8个LED的正极接一起)
可以看到,这个‘8’有A、B、C、D、E、F、G和DP8个LED构成。我们在程序上只需要将对应位置的LED点亮就可以了。ABCDEFG‘DP’8个位置刚好对应上一个byte的8个Bit位。要注意这里是与byte的低位对齐。
比如:
数字‘0’就是A、B、C、D、E、F位置的LED亮起。0011 1111 ,十六进制0x3F;
数字‘1’就是B、C 两个位置LED亮起。二进制0000 0110 ,十六进制0x06;
数字‘2’就是A、B、G、E、D位置的LED亮起、
……
以此类推,我们可以用HEX罗列出数码管能展示的所有可供我们认识的字符,要显示对应的字符,则P0值如下表
数码管显示 | 点亮位置的LED | 十六进制 (P0值) | 二进制 | |||||||
高 | 低 | |||||||||
DP | G | F | E | D | C | B | A | |||
0 | ABCDEF | 0x3F | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 |
1 | BC | 0x06 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
2 | ABGED | 0x5B | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 |
3 | ABCDG | 0x4F | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 |
4 | FGBC | 0x66 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 |
5 | AFGCD | 0x6D | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 1 |
6 | AFEDCG | 0x7D | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 1 |
7 | ABC | 0x07 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
8 | ABCDEFG | 0x7F | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
9 | GFABCD | 0x6F | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 1 |
A | ABCEFG | 0x77 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 1 |
C | AFED | 0x39 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 1 |
E | AFEDG | 0x79 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 1 |
F | AFEG | 0x71 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 1 |
H | BCEFG | 0x76 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 0 |
J | BCDE | 0x1E | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 |
L | FED | 0x38 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 |
p | ABGFE | 0x73 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | 1 |
q | ABGFC | 0x67 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 1 |
U | BCDEF | 0x3E | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 0 |
. | 'DP' | 0x80 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
b | FEGDC | 0x7C | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 0 |
d | BCDEG | 0x5E | 0 | 1 | 0 | 1 | 1 | 1 | 1 | 0 |
u | CDE | 0x1C | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 |
这里我们在程序中用两个数组表示;
/*数码管可显示值*/
unsigned int ShuMaGuan_EnableDisplayValue[]={0,1,2,3,4,5,6,7,8,9,'A','C','E','F','H','J','L','P','q','U','.','b','d','u'};
/*数码管显示值对应的HEX*/
unsigned int ShuMaGuan_EnableDisplayHEX[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,
0x77,0x39,0x79,0x71,0x76,0x1E,0x38,0x73,0x67,0x3E,0x80,0x7C,0x5E,0x1C};
/*** 函 数:获取可显值对应的HEX* 参 数:数码管显示的值* 返 回 值:数码管显示时对应的HEX*/
unsigned int ShuMaGuan_GetEnableDisplayValueOfHEX(unsigned int Value)
{unsigned int index=0;for(index=0;index<24;index++)//遍历显示值的数组{if(ShuMaGuan_EnableDisplayValue[index]==Value)//找到对应值的索引{break;}}return ShuMaGuan_EnableDisplayHEX[index];
}
/*** 函 数:设置数码管要显示的值* 参 数:显示值* 返 回 值:无*/
void ShuMaGuan_SetDisplayValue(unsigned int Value)
{/*将要显示的值 复制给P0*/P0=ShuMaGuan_GetEnableDisplayValueOfHEX(Value);
}
数码管中的8个LED的一端已经通过上面P0设置成功,另一端我们也要设置接通LED才会连接到电路中导通。所以我们还需要了解74HC138译码器。
2.5 74HC138 译码器
译码器的作用:简单理解就是尽量让程序设置少的针脚通断去控制逻辑电路通断和数据传输。
假如在这里不用译码器,我们全部用单一导线和开关将LED的两端与电源正负极接通。那么线路就比较多,引脚也较多,我们程序中要控制的就增加。
在74HC138译码器上,有三个引脚P22、P23、P24,每个引脚都可以有通断(0、1)那么我们用三位的二进制就可以满足8个位置上通断。
C | B | A | |
P24 | P23 | P22 | |
LED1 | 1 | 1 | 1 |
LED2 | 1 | 1 | 0 |
LED3 | 1 | 0 | 1 |
LED4 | 1 | 0 | 0 |
LED5 | 0 | 1 | 1 |
LED6 | 0 | 1 | 0 |
LED7 | 0 | 0 | 1 |
LED8 | 0 | 0 | 0 |
我们程序想让那个位置上的LED亮起,就设置对应值就导通了!
/*** 函 数:设置要显示的数码管 位置* 参 数:位置(左起1-8)* 返 回 值:无*/
void ShuMaGuan_SetDisplayLocation(unsigned int Location)
{switch(Location) //位码输出{case 1:P2_4=1;P2_3=1;P2_2=1;break;case 2:P2_4=1;P2_3=1;P2_2=0;break;case 3:P2_4=1;P2_3=0;P2_2=1;break;case 4:P2_4=1;P2_3=0;P2_2=0;break;case 5:P2_4=0;P2_3=1;P2_2=1;break;case 6:P2_4=0;P2_3=1;P2_2=0;break;case 7:P2_4=0;P2_3=0;P2_2=1;break;case 8:P2_4=0;P2_3=0;P2_2=0;break;}
}
有了上面两步,我们在主函数就只需要设置在数码管的哪个位置显示什么值就好。
/*** 函 数:数码管展示* 参 数:Location 显示的位置,Value 显示的值* 返 回 值:无*/
void ShuMaGuan_Display(unsigned int Location,unsigned int Value)
{/*显示位置*/ShuMaGuan_SetDisplayLocation(Location);/*显示值*/ShuMaGuan_SetDisplayValue(Value);
}
三,创建Keil项目
详细参考:51单片机STC89C52RC——创建Keil项目-CSDN博客
四,代码
main.c 如下
#include <REGX52.H>
#include "ShuMaGuan.h"
/*** 函 数:主函数* 参 数:无* 返 回 值:无*/
void main()
{/*在数码管的第一个位置显示2*/ShuMaGuan_Display(1,2);while(1){}
}
ShuMaGuan.h如下
#ifndef __SHUMAGUAN_H_
#defind __SHUMAGUAN_H_
void ShuMaGuan_Display(unsigned int Location,unsigned int Value);
#endif
ShuMaGuan.c如下
#include <REGX52.H>
/*数码管可显示值*/
unsigned int ShuMaGuan_EnableDisplayValue[]={0,1,2,3,4,5,6,7,8,9,'A','C','E','F','H','J','L','P','q','U','.','b','d','u'};
/*数码管显示值对应的HEX*/
unsigned int ShuMaGuan_EnableDisplayHEX[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,
0x77,0x39,0x79,0x71,0x76,0x1E,0x38,0x73,0x67,0x3E,0x80,0x7C,0x5E,0x1C};
/*** 函 数:获取可显值对应的HEX* 参 数:数码管显示的值* 返 回 值:数码管显示时对应的HEX*/
unsigned int ShuMaGuan_GetEnableDisplayValueOfHEX(unsigned int Value)
{unsigned int index=0;for(index=0;index<24;index++)//遍历显示值的数组{if(ShuMaGuan_EnableDisplayValue[index]==Value)//找到对应值的索引{break;}}return ShuMaGuan_EnableDisplayHEX[index];
}
/*** 函 数:设置数码管要显示的值* 参 数:显示值* 返 回 值:无*/
void ShuMaGuan_SetDisplayValue(unsigned int Value)
{/*将要显示的值 复制给P0*/P0=ShuMaGuan_GetEnableDisplayValueOfHEX(Value);
}
/*** 函 数:设置要显示的数码管 位置* 参 数:位置(左起1-8)* 返 回 值:无*/
void ShuMaGuan_SetDisplayLocation(unsigned int Location)
{switch(Location) //位码输出{case 1:P2_4=1;P2_3=1;P2_2=1;break;case 2:P2_4=1;P2_3=1;P2_2=0;break;case 3:P2_4=1;P2_3=0;P2_2=1;break;case 4:P2_4=1;P2_3=0;P2_2=0;break;case 5:P2_4=0;P2_3=1;P2_2=1;break;case 6:P2_4=0;P2_3=1;P2_2=0;break;case 7:P2_4=0;P2_3=0;P2_2=1;break;case 8:P2_4=0;P2_3=0;P2_2=0;break;}
}
/*** 函 数:数码管展示* 参 数:Location 显示的位置,Value 显示的值* 返 回 值:无*/
void ShuMaGuan_Display(unsigned int Location,unsigned int Value)
{/*显示位置*/ShuMaGuan_SetDisplayLocation(Location);/*显示值*/ShuMaGuan_SetDisplayValue(Value);
}
五,代码编译、下载到51单片机
代码编译请参考
《51单片机STC89C52RC——代码编译-CSDN博客》
代码下载请参考
《51单片机STC89C52RC——STCAI-ISP代码下载-CSDN博客》