点亮一个数码管
TF0:只要溢出后,tf0就置1.
只需要知道1和2两种工作模式即可。
使用流程如下:
附上数码管真值表:
完整代码如下:(每秒增加一个显示)
#include <reg52.h>
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
//用数组来存储数码管的真值表,数组将在下一章详细介绍
unsigned char code LedChar[] = {
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
void main()
{
unsigned char cnt = 0; //记录T0中断次数
unsigned char sec = 0; //记录经过的秒数
ENLED = 0; //使能U3,选择数码管DS1
ADDR3 = 1;
ADDR2 = 0;
ADDR1 = 0;
ADDR0 = 0;
TMOD = 0x01; //设置T0为模式1
TH0 = 0xB8; //为T0赋初值0xB800
TL0 = 0x00;
TR0 = 1; //启动T0
while (1)
{
if (TF0 == 1) //判断T0是否溢出
{
TF0 = 0; //T0溢出后,清零中断标志
TH0 = 0xB8; //并重新赋初值
TL0 = 0x00;
cnt++; //计数值自加1
if (cnt >= 50) //判断T0溢出是否达到50次
{
cnt = 0; //达到50次后计数值清零
P0 = LedChar[sec]; //当前秒数对应的真值表中的值送到P0口
sec++; //秒数记录自加1
if (sec >= 16) //当秒数超过0x0F(15)后,重新从0开始
{
sec = 0;
}
}
}
}
}
关于如何算th和tl:
比如当晶振频率为11.0592M的晶振。则每秒可产生机器周期为11.0592/12=0.9216M的机器周期,也就是921600个机器周期。50ms等于0.05秒,所以需要921600*0.05=46080个机器周期;定时器在方式1工作,为16位,最大值为65536,所以需设初值为65536-46080=19456;转为16进制为(4c00),所以高位TH0=0x4c; TL0=0x00;
动态显示多个数码管
10ms内需要刷新同一个数码管。
关于中断 :
完整代码:
/*
*******************************************************************************
* 《手把手教你学51单片机(C语言版)》
* 配套 KST-51 单片机开发板 示例源代码
*
* (c) 版权所有 2014 金沙滩工作室/清华大学出版社 保留所有权利
* 获取更多资料请访问:http://www.kingst.org
*
* 文件名:main.c
* 描 述:第6章 数码管动态显示原理示例(if...else if...语句示例)
* 版本号:v1.0.0
* 备 注:详情见第6章6.4节
*******************************************************************************
*/
#include <reg52.h>
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
unsigned char i = 0; //动态扫描的索引
unsigned int cnt = 0; //记录T0中断次数
unsigned char flagls =0;
unsigned char code LedChar[] = { //数码管显示字符转换表
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[6] = { //数码管显示缓冲区,初值0xFF确保启动时都不亮
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF //缓冲区的作用就是先把该显示的数据存进去,后再取出值,这样可以提高运行速度
};
void main()
{
unsigned long sec = 0; //记录经过的秒数
ENLED = 0; //使能U3,选择控制数码管
ADDR3 = 1; //因为需要动态改变ADDR0-2的值,所以不需要再初始化了
TMOD = 0x01; //设置T0为模式1
TH0 = 0xFC; //为T0赋初值0xFC67,定时1ms
TL0 = 0x67;
TR0 = 1; //启动T0
EA = 1;
ET0 = 1; //开启中断
while (1)
{
if (flagls == 1) //判断T0溢出是否达到1000次 (一秒)
{
flagls = 0;
sec++; //秒计数自加1
//以下代码将sec按十进制位从低到高依次提取并转为数码管显示字符
LedBuff[0] = LedChar[sec%10]; //sec如果等于123456秒 %10就赋值6
LedBuff[1] = LedChar[sec/10%10];
LedBuff[2] = LedChar[sec/100%10];
LedBuff[3] = LedChar[sec/1000%10];
LedBuff[4] = LedChar[sec/10000%10];
LedBuff[5] = LedChar[sec/100000%10];
}
}
}
void InterruptTime0() interrupt 1 //TF自动清零
{
TH0 = 0XFC;
TL0 =0X67;
cnt ++;
if(cnt >= 1000)
{
cnt =0;
flagls = 1;
}
//以下代码完成数码管动态扫描刷新
P0=0xff;//杜绝鬼影现象,即addr没有完全切换时,产生的错误显示。
switch (i)
{
case 0: ADDR2=0; ADDR1=0; ADDR0=0; i++; P0=LedBuff[0]; break;
case 1: ADDR2=0; ADDR1=0; ADDR0=1; i++; P0=LedBuff[1]; break;
case 2: ADDR2=0; ADDR1=1; ADDR0=0; i++; P0=LedBuff[2]; break;
case 3: ADDR2=0; ADDR1=1; ADDR0=1; i++; P0=LedBuff[3]; break;
case 4: ADDR2=1; ADDR1=0; ADDR0=0; i++; P0=LedBuff[4]; break;
case 5: ADDR2=1; ADDR1=0; ADDR0=1; i=0; P0=LedBuff[5]; break;
default: break;
}
}