1.系统上电后数码管显示0,按下S4用定时器以间隔500ms在数码管上依次显示0-F,重复,按下S5用定时器以间隔1s显示0-F,按下S6用定时器以间隔2S显示0-F
#include<STC15F2K60S2.H>
unsigned int tt=0;
unsigned char tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0X88,0X83,0XC6,0XA1,0X86,0X8E};
unsigned char num=0;
unsigned char key;
void Delayms(int ms);
void Timer0Init(void);
void KEY_Scan(void);
void main(void)
{
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; //初始化程序
P2=0XC0;P0=0X01;P2=0XFF;P0=0XFF; //数码管初始化程序,打开第一个数码管
//配置定时器0
Timer0Init();
ET0=1;
EA=1;
P0=0XC0; //上电后显示0
while(1)
{
KEY_Scan();
P0=tab[num];
}
}
void Timer0Init(void) //5毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x00; //设置定时初值
TH0 = 0x28; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
void KEY_Scan(void)
{
if(P33==0) //S4
{
Delayms(5);
if(P33==0)
{
key=4;
}
while(!P33);
}
else if(P32==0) //S5
{
Delayms(5);
if(P32==0)
{
key=5;
}
while(!P32);
}
else if(P31==0) //S6
{
Delayms(5);
if(P31==0)
{
key=6;
}
while(!P31);
}
}
void Delayms(int ms)
{
int i,j;
for(i=0;i<ms;i++)
for(j=845;j>0;j--);
}
void Timer0(void) interrupt 1
{
if(key==4) //S4按下时间隔500ms显示
{
if(tt>100)tt=0; //避免超出范围
tt++;
if(tt==100)
{
tt=0;
num++;
if(num==16)num=0;
}
}
else if(key==5) //S5按下时间隔1s显示
{
if(tt>200)tt=0; //避免超出范围
tt++;
if(tt==200)
{
tt=0;
num++;
if(num==16)num=0;
}
}
else if(key==6) //S6按下时间隔2s显示
{
if(tt>400)tt=0; //避免超出范围
tt++;
if(tt==400)
{
tt=0;
num++;
if(num==16)num=0;
}
}
}
程序的大致思路是:初始化数码管打开第一个数码管后,由于我们要用到定时器0,故我们要初始化配置定时器0(利用下载器进行配置),然后由于用到了三个独立按键,我们编写判断是哪一个按键的函数,用key来区分按下不同按键所导致的结果,传递到定时器0中断函数中设置key不同情况的对应结果。
注:
1.tt变量需要用int型,因为char型的范围是0~255,400>255超出了范围程序会卡死。
2.由上面的定时器0中断函数可以看到,有三个地方设置了超出范围即归0,一开始尝试的时候没有判断是否超出范围,导致按完S6后,再按S4、S5时以及按完S5再按S4时因为超出范围程序可能会出现卡死。
3.选择按键方式的跳线帽跳在右边两针。
2.独立按键S4,S5使用外部中断分别控制数码管显示0-9正计时和倒计时
#include<STC15F2K60S2.H>
unsigned char tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};
unsigned char seg;
char num=0;
void Delayms(int ms);
void main(void)
{
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; //初始化程序
P2=0XC0;P0=0X01;P2=0XFF;P0=0XFF; //数码管初始化程序,打开第一个数码管
EX0=1; //打开中断0
EX1=1; //打开中断1
IT0=0; //上升沿下降沿均可触发
IT1=0; //上升沿下降沿均可触发
EA=1; //打开总中断
while(1)
{
if(seg==0)
{
P0=tab[num];
num--;
if(num==-1)num=9;
Delayms(1000);
}
else if(seg==1)
{
P0=tab[num];
num++;
if(num==10)num=0;
Delayms(1000);
}
}
}
void Delayms(int ms)
{
int i,j;
for(i=0;i<ms;i++)
for(j=845;j>0;j--);
}
void exint0(void) interrupt 0
{
if(P32==1) //松开S4触发外部中断0
{
seg=0;
}
}
void exint1(void) interrupt 2
{
if(P33==1) //松开S5触发外部中断1
{
seg=1;
}
}
大致思路:初始化数码管,初始化配置外部中断0和外部中断1,按键S4,S5分别用外部中断1,0控制,按下和松开都会触发中断,但是我们只想要松开时候触发,因此使用了if函数,只有松开时才会赋值seg,根据触发中断引起的seg值分别指向数码管的正计时和倒计时。
注:
1.num值用于表示数组中的第几个数据,由于自减过程会出现负值,故此时不能再定义其为无符号型。
2.曾经尝试使用了for循环用于数码管倒计时正计时,但是此时会出现的情况是每次重新触发后,数码管需要继续走完此次计时才可以响应之后的计时,而选用if函数的话,数码管变化一次数值则判断一次,能够立即从所在位置开始正计时或者倒计时,响应更加及时。
3.再次尝试编写:数码管9秒倒计时,计时完成L1灯点亮
#include<STC15F2K60S2.H>
unsigned char tab[]={0X90,0X80,0XF8,0X82,0X92,0X99,0XB0,0XA4,0XF9,0XC0};
unsigned char num=0;
unsigned char tt=0;
unsigned char t=0;
void Timer0Init(void);
void main(void)
{
//定时器0初始化配置
Timer0Init();
ET0=1;
EA=1;
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; //初始化程序
while(1)
{
}
}
void Timer0Init(void) //5毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x00; //设置定时初值
TH0 = 0x28; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
void Timer0(void) interrupt 1
{
tt++;
if(tt==200)
{
tt=0;
t++;
P2=0XC0;P0=0X01;P2=0XE0;
P0=tab[num];
num++;
if(num==10)num=0;
}
if(t==10)
{
P2=0X80;P0=0XFF;
P00=0;
}
if(t==11)
{
t=t-10;
P2=0X80;P0=0XFF;
P00=1;
}
}
大致思路:此程序在上次课后练习尝试编写程序的基础上,使用了定时器来控制间隔为1s。定时器程序每次5ms,那么200次就是1s,我们只需要让每200次,数码管变化一次,用t记录变化次数,变化10次也即倒计时结束时L1点亮,变化11次时也即重新开始倒计时时L1熄灭且t变量归1。关于数码管和LED的初始化程序,可以参考后来一篇有关初始化程序的博客。
4.再次尝试编写:数码管99秒倒计时程序,用定时器延迟。
#include<STC15F2K60S2.H>
unsigned char tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};
unsigned char num=99;
unsigned char tt=0;
void Delayms(int ms);
void Timer0Init(void);
void main(void)
{
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; //关闭蜂鸣器继电器LED
//初始化配置定时器0
Timer0Init();
ET0=1;
EA=1;
while(1)
{
P2=0XC0; //打开数码管位选537锁存器
P0=0X01; //选中第一个数码管
P2=0XE0; //打开数码管段选537锁存器
P0=tab[num/10]; //数码管显示十位的数字
Delayms(1);
P2=0XC0; //打开数码管位选537锁存器
P0=0X02; //选中第二个数码管
P2=0XE0; //打开数码管段选537锁存器
P0=tab[num%10]; //数码管显示个位的数字
Delayms(1);
}
}
void Delayms(int ms)
{
int i,j;
for(i=0;i<ms;i++)
for(j=845;j>0;j--);
}
void Timer0Init(void) //5毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x00; //设置定时初值
TH0 = 0x28; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
void Timer0(void) interrupt 1
{
tt++;
if(tt==200)
{
tt=0;
if(num==0)num=100;
num--;
}
}
此程序实现了用定时器0来进行数码管计时间隔1s的延时,而扫描的1ms仍使用了软件延时。
大致思路:我们可以看到原来的程序是在主函数中,计数循环次数,循环500次即1s,操作使num自减,而此程序是在定时器中定时1s,定时到了num自减。其核心思想都是使num每1s自减1。