例程下载:https://github.com/xiaoengineer/lanqiano
首先得说说什么是数码管
数码管其实就是一堆发光二极管,将这些发光二极管封装在一起,每一个发光二极管做成字符的一个段,就组成了所谓的七段LED字符显示器。根据内部连接的不同,LED显示有共阴和共阳之分。共阴的适用于高电平驱动,共阳的适用于低电平驱动。由于集成电路的高电平输出电流小,而低电平输出电流相对比较大,所以集成电路直接驱动LED时,较多采用低电平的驱动方式。
知道了这些就可以控制数码管了:首先控制位选,指定数字是在哪一位数码管上显示,禁止位选使能,之后是段选,控制数码管显示什么,禁止段选使能。这样就完成任务了。
下面是静态显示,控制一个数字
#include
typedef unsigned int u16;
typedef unsigned char u8;
void close()
{
P2 = (P2 & 0X1F) | 0XA0;
P0 = 0XAF;
P2 = 0x1f; //关闭蜂鸣器,继电器
}
void main()
{
close();
P2 = (P2 & 0X1F) | 0XC0; //这个是位选使能,是不是感觉和普通的
//开发板不一样?那是由于开发板的设计决定的
//这样做是可以保证我可以修改我想要的位而保证
//其他位不变
P0 = 0X01; //位选,选第一个位
P2 = P2 & 0X1F; //禁止使能
P2 = (P2 & 0X1F) | 0XE0; //这个是段选,也不太一样,理由同上
P0 = 0xC0; //段选,显示一个数
P2 = 0X1F;
while(1);
}
下面这个是动态显示,何为动态显示?动态显示就是利用人眼的视觉暂留(这个仿真的不太好),闪动地播放数字。
先说一下共阳的段位表(0~F)
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
我将以两种方式来实现0 ~9999的数字显示(使用定时器)
方式一:
#include
typedef unsigned int u16;
typedef unsigned char u8;
u8 seg_ment[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80,
0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E}; //定义段位
u8 seg_bit[] = {0x80, 0x40, 0x20, 0x10}; //定义位选
u16 count, sec_flag;
void close()
{
P2 = (P2 & 0X1F) | 0XA0;
P0 = 0XAF;
P2 = P2 & 0X1F;
}
void delay(u8 ms)
{
u8 i, j;
for(i = ms; i > 0; i --)
for(j = 114; j > 0; j --);
}
void led_show(u16 number)
{
/*这种处理数字的方法很简单,C语言课上老师应该都讲过*/
u16 kilobit = number / 1000;
u16 hundreds_place = number % 1000 / 100;
u16 decade = number % 1000 % 100 / 10;
u16 unit = number - (kilobit * 1000 + hundreds_place * 100 + decade * 10);
/*下面是显示函数*/
/*显示个位*/
P2 = (P2 & 0X1F) | 0XC0;
P0 = seg_bit[0];
P2 = P2 & 0X1f;
P2 = (P2 & 0X1F) | 0XE0;
P0 = seg_ment[unit];
P2 = P2 & 0X1f;
delay(10);
/*显示十位*/
P2 = (P2 & 0X1F) | 0XC0;
P0 = seg_bit[1];
P2 = P2 & 0X1f;
P2 = (P2 & 0X1f) | 0XE0;
P0 = seg_ment[decade];
P2 = P2 & 0X1f;
delay(10);
/*显示百位*/
P2 = (P2 & 0X1f) | 0XC0;
P0 = seg_bit[2];
P2 = P2 & 0X1f;
P2 = (P2 & 0X1F) | 0XE0;
P0 = seg_ment[hundreds_place];
P2 = P2 & 0x1f;
delay(10);
/*显示千位*/
P2 = (P2 & 0X1F) | 0XC0;
P0 = seg_bit[3];
P2 = P2 & 0X1f;
P2 = (P2 & 0X1F) | 0XE0;
P0 = seg_ment[kilobit];
P2 = P2 & 0X1f;
delay(10);
}
void Timer0Init(void) //100微秒@12.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x9C; //设置定时初值
TH0 = 0xFF; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA = 1;
ET0 =1;
}
void main()
{
u16 sec;
close();
Timer0Init();
while(1)
{
if(sec_flag)
{
sec_flag = 0;
if(sec < 9999)
{
sec ++;
led_show(sec);
}
else
sec = 0;
}
}
}
void interruptTimer0() interrupt 1
{
TL0 = 0x9C; //设置定时初值
TH0 = 0xFF; //设置定时初值
count ++;
if(count > 100)
{
count = 0;
sec_flag = 1;
}
}
方法二:
#include
typedef unsigned int u16;
typedef unsigned char u8;
u8 seg_ment[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80,
0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E}; //定义段位
u8 led_buff[] = {0xff, 0xff, 0xff, 0xff};//确保在上电的时候不亮
u16 count, sec_flag;
void close()
{
P2 = (P2 & 0X1F) | 0XA0;
P0 = 0XAF;
P2 = P2 & 0X1F;
}
void delay(u8 ms)
{
u8 i, j;
for(i = ms; i > 0; i --)
for(j = 114; j > 0; j --);
}
void Timer0Init(void) //100微秒@12.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x9C; //设置定时初值
TH0 = 0xFF; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA =1;
ET0 =1;
}
/*这个函数使用来显示的*/
void led_scan()
{
static u8 index = 0; //这个静态变量使用来自动移位的
P2 = (P2 & 0x1f) | 0xe0;
P0 = 0XFF; //这个是消影
P2 = P2 & 0X1F;
delay(5);
P2 = (P2 & 0X1F) | 0XC0;
P0 = 0X80 >> index; //这个就实现了自动移位
P2 = 0x1f;
P2 = (P2 &0x1f) | 0xe0;
P0 = led_buff[index];
P2 = P2 & 0X1F;
if(index < 3)
index ++;
else
index = 0;
}
/*这个函数是用来处理数据的,用了缓存的思想*/
void show_number(u16 dat)
{
char i;
u8 buf[4];
for(i = 0; i < 4; i ++)
{
buf[i] = dat % 10;
dat = dat / 10; //将数字是各个位分离出来并存入缓存
}
for(i = 3; i > 0; i --)
{
if(buf[i] == 0) //如果临时缓存区里代表高位的没有数字
led_buff[i] = 0xff; //那么就为0xff,否则就可以正式填入数据
else
break;
}
for(; i >= 0; i --)
{
led_buff[i] = seg_ment[buf[i]];
}
}
void main()
{
u16 sec;
close();
Timer0Init();
while(1)
{
if(sec_flag)
{
sec_flag = 0;
if(sec < 9999)
{
sec ++;
show_number(sec);
led_scan();
}
else
sec = 0;
}
}
}
void T0_interrput() interrupt 1
{
TL0 = 0x9C; //设置定时初值
TH0 = 0xFF; //设置定时初值
count ++;
if(count > 100)
{
count = 0;
sec_flag = 1;
}
}
两种方法各有好处,以自己而定。