1 回顾:
程序编写结构还是中断函数结构的写法,只是由于定时器涉及的寄存器较多,中断初始条件函数中条件也就随之增多。
void 函数名()
{
主要写一些初始化变量。(基本的就是3.1~3.5所涉及的寄存器的初值条件设定)
}
void 函数名() interrupt 中断号
{
就是写时间到后执行什么。(但是为了中断的实时性,有时只写只写中断状态的标志,紧急事件用另一个函数来写,后续实践篇代码有讲)
}
别忘了还要查看对应的中断号
涉及的寄存器要查看手册,通常会涉及到:
高低位寄存器
TMOD寄存器
中断寄存器
TCON寄存器
2 实践
2.1 任务
2.2 思路
涉及的模块:
这里涉及到了LED操作,故HC138接到4通道,才能是控制LED灯的,只有L1和L8两个灯,可以用sbit标出来,可读性比较强。
用到了定时,故定时的结构需要写出来。
在定时结构中,题目要求是Time0,查询资料手册,涉及的寄存器有如下,并写入代码:
L1灯单位是0.5秒,L8单位是5秒,两者成一个倍数关系,故只需要一个初值即可,以0.5秒为初值,但一个定时器运行完依次最多为65535us,即65.532ms,
需要0.5s即500ms即500000us,
故可以每次计时50000us,定时器运行10次,就到达了0.5s, 定时器运行100次,就到达了5秒。
按照之前所提的公式: TH0 = (65535 - 50000) / 256;
TL0 = (65535 - 50000) % 256;
void Init_Time0()
{
TMOD = 0x01;
TH0 = (65535 - 50000) / 256;
TL0 = (65535 - 50000) % 256;
TR0 = 1;
EA = 1;
ET0 = 1;
}
然后在中断服务函数上判断是否到达0.5s,到达了进行L1操作
在进一步判断是否到达5s,到达了进行L8操作。
2.3 完整代码:
这里解释以下:
(1)判断定时器运行10次和100次可以用一个变量累加来判断。然后取余操作判断是否达到了每一个10次,当达到100次时,变量清零重计数
(2)在中断中L1和L8的闪烁操作用的是取反:
为什么可以这样呢?中断程序是这样的,刚刚提到定时器运行10次才到达0.5s,默认L1初始为1,即不点亮,当定时器运行了10次才能到达0.5s,注意在这十次中,每一次,都进入了中断服务函数,但是执行到了count++后就不再执行下去,因为没满足if条件,故这段时间L1一直是熄灭的,熄灭时间为(0~9次),刚好10次,0.5秒。当执行第十次时,满足第一个if条件,到达0.5s,那么L1取反为0,点亮。在第11到第19次中,同样,每一次,都进入了中断服务函数,但是执行到了count++后就不再执行下去,因为没满足if条件,故在这段时间内L1一直=0,即L1一直是点亮状态,这段点亮持续了多久呢?(第10次到第19次),刚好10次,故点亮了0.5s。直到第20次,又满足了第一个if条件,L1取反为1,熄灭。
这就是在中断中可以用取反来表示LED闪烁的原因。
#include "stc15f2k60s2.h"
sbit L1 = P0^0;
sbit L8 = P0^7;
void selectHC138(unsigned int n)
{
switch(n)
{
case 0:
P2 = (P2 & 0x1f) | 0x00; break;
case 1:
P2 = (P2 & 0x1f) | 0x20; break;
case 2:
P2 = (P2 & 0x1f) | 0x40; break;
case 3:
P2 = (P2 & 0x1f) | 0x60; break;
case 4:
P2 = (P2 & 0x1f) | 0x80; break;
case 5:
P2 = (P2 & 0x1f) | 0xa0; break;
case 6:
P2 = (P2 & 0x1f) | 0xc0; break;
case 7:
P2 = (P2 & 0x1f) | 0xe0; break;
}
}
void Init_Time0()
{
TMOD = 0x01;
TH0 = (65535 - 50000) / 256;
TL0 = (65535 - 50000) % 256;
TR0 = 1;
EA = 1;
ET0 = 1;
}
unsigned char count = 0;
void Time0() interrupt 1
{
TH0 = (65535 - 50000) / 256;
TL0 = (65535 - 50000) % 256;
count ++;
if (count % 10 == 0)
{
L1 = ~L1;
}
if (count %100 == 0)
{
L8 = ~L8;
count = 0;
}
}
void close() //关闭外设
{
selectHC138(5);
P0 = 0x00;
selectHC138(4);
P0 = 0xff;
}
void main()
{
close();
Init_Time0();
selectHC138(4);
while(1)
{
}
}
3 进阶版实践
3.1 任务
3.2 思路
这里涉及到多种模块:
定时器 :故定时器结构得写下来
数码管计时: 故要数码管得动态变化:数码管内容表(0~F,-) 数码管函数(包括内容和位置),数码管显示函数(显示什么内容),延时函数,HC138选择通道。
独立按键的使用:跳帽接到对应位置。由于只用了两个独立按键,可用sbit表示出来,要写个独立按键函数,判断是否按下。
这里主要的核心是定时器怎么设置:
题目要求设计秒表,分—秒—毫秒。
最小单位为50ms,即数码管最后两位每加1代表每加50ms,即01=50ms,02=100ms。
又1s= 1000ms ,最小单位为50ms,故数码管最后两位加到20就为1s,秒的两个位置(s位)+1,且数码管最后两位(ms位)清零。
同理,1min=60s,当秒位加到60,清零,min位+1。
数码管显示动态显示对应的位置,由于分—秒—毫秒都是各占两位,如用除和区域可得到各自的十位和个位。
3.3完整代码
注意:
TR0 = ~TR0; //表停止计时
#include "stc15f2k60s2.h"
sbit S4 = P3^3;
sbit S5 = P3^2;
void selectHC138(unsigned int n)
{
switch(n)
{
case 0:
P2 = (P2 & 0x1f) | 0x00; break;
case 1:
P2 = (P2 & 0x1f) | 0x20; break;
case 2:
P2 = (P2 & 0x1f) | 0x40; break;
case 3:
P2 = (P2 & 0x1f) | 0x60; break;
case 4:
P2 = (P2 & 0x1f) | 0x80; break;
case 5:
P2 = (P2 & 0x1f) | 0xa0; break;
case 6:
P2 = (P2 & 0x1f) | 0xc0; break;
case 7:
P2 = (P2 & 0x1f) | 0xe0; break;
}
}
void Delay(unsigned char t)
{
while(t--);
}
code unsigned char SMG_Table[] =
{
0xc0, //0
0xf9, //1
0xa4, //2
0xb0, //3
0x99, //4
0x92, //5
0x82, //6
0xf8, //7
0x80, //8
0x90, //9
0x88, //A
0x83, //b
0xc6, //C
0xa1, //d
0x86, //E
0x8e, //F
0xbf //-
};
unsigned char t_min = 0;
unsigned char t_s = 0;
unsigned char t_ms = 0;
//==============================Timer============
void InitTime0()
{
TMOD = 0x01;
TH0 = (65535-50000) / 256;
TL0 = (65535-50000) % 256;
TR0 = 1;
ET0 = 1;
EA = 1;
}
void Time0() interrupt 1
{
TH0 = (65535-50000) / 256;
TL0 = (65535-50000) % 256;
t_ms++;
if (t_ms == 20)
{
t_s++;
t_ms = 0;
if (t_s == 60)
{
t_min++;
t_s = 0;
}
}
if (t_min == 99)
{
t_ms = 0;
t_s = 0;
t_min = 0;
}
}
//==============================================
void showSMG(unsigned char position, unsigned char number)
{
selectHC138(6);
P0 = 0x01 << position;
selectHC138(7);
P0 = SMG_Table[number];
}
void SMGDisplay()
{
showSMG(0,t_min/10);
Delay(500);
showSMG(1,t_min%10);
Delay(500);
showSMG(2,16);
Delay(500);
showSMG(3,t_s/10);
Delay(500);
showSMG(4,t_s%10);
Delay(500);
showSMG(5,16);
Delay(500);
showSMG(6,t_ms/10);
Delay(500);
showSMG(7,t_ms%10);
Delay(500);
}
//void SMGDelay(unsigned char t)
//{
// while(t--)
// {
//
// }
//}
void Key()
{
if(S4 == 0) //stop
{
Delay(50);
if(S4 == 0)
{
TR0 = ~TR0; //停止计时
while(S4 == 0)
{
SMGDisplay();
}
}
}
if(S5 == 0) // clear to 0
{
Delay(50);
if(S5 == 0)
{
t_ms = 0;
t_s = 0;
t_min = 0;
while(S5 == 0)
{
SMGDisplay();
}
}
}
}
void close()
{
selectHC138(5);
P0 = 0x00;
selectHC138(4);
P0 = 0xff;
}
void main()
{
close();
InitTime0();
while(1)
{
SMGDisplay();
Key();
}
}