文章目录
一、LED指示灯
学习任务:在CT107D单片机综合训练平台上实现LED的基本控制,首先让8路LED
指示灯闪烁3遍然后熄灭,接着依次点亮LED指示灯,最后依次熄灭指示灯,程序循环实现上述功能。
74HC138译码器
本次使用单片机中的三八译码器:
三八译码器,三个输入控制八路互斥的低有效输出。
八路仅有一路低电平,其余均为高电平。
输入原则实质上只是二进制的运算:
例:
C B A
0 0 0 对应Y0
0 0 1 Y1
……
1 1 0 Y6
1 1 1 Y7
74HC573锁存器
LE、OE为控制电平,D_为输入电平,Q_为输出电平
74HC573锁存器为八路三态输出的非反转透明锁存器。(非反转:输入与输出相同,均为0或均为1)
tip:OE——片选(片选信号一般是在划分地址空间时,由逻辑电路产生的。在数字电路设计中,一般开路输入管脚呈现为高电平,因此片选信号绝大多数情况下是一个低电平。)
当锁存使能端LE为高时,这些器件的锁存对于数据是透明的(也就是说输出同步)。当锁存使能变低时,符合建立时间和保持时间的数据会被锁存(输入端无法再影响输出端)。
(使能:让某一个功能起作用,有时候需要外部给个触发,或许是高电平,或许又是一个脉冲)
控制LED灯
与门:(A&&B)
或门:(A||B)
非门:(!A)
而或非门即或门加上非门:!(A||B)
D1-D8与Q1-Q8打通。
IO扩展中,WR是0(接低电平),可知Y4输出0,Y4C可输出高电平,以点亮LED。
#include "reg52.h"
sbit HC138_A = P2^5;
sbit HC138_B = P2^6;
sbit HC138_C = P2^7; //宏定义
void Delay(unsigned int t) //延时函数
{
while(t--);
while(t--);
}
void LEDRunning()
{
unsigned char i;
HC138_C = 1;
HC138_B = 0;
HC138_A = 0;
for(i = 0;i < 3;i++) //完成任务:闪烁3次
{
P0 = 0x00; //点灯
Delay(60000);
Delay(60000);
P0 = 0xff; //关灯
Delay(60000);
Delay(60000);
}
for(i = 1;i <= 8;i++) //完成任务:流水灯
{
P0 = 0xff << i; // P0每次左移i位,原本是11111111,i=1时,P0变为11111110
Delay(60000);
Delay(60000);
}
for(i = 1;i <= 8;i++)
{
P0 = ~(0xff << i);
Delay(60000);
Delay(60000);
}
}
void main()
{
while(1)
{
LEDRunning();
}
}
二、蜂鸣器与继电器
任务:在CT107D单片机综合训练平台上实现蜂鸣器与继电器的基本控制,首先让8路LED指示灯闪烁3遍后熄灭,接着依次点亮LED指示灯,继电器吸合会后断开,然后依次熄灭LED指示灯,蜂鸣器鸣叫一会后关闭,程序循环实现上述功能。
ULN2003
非门电路,可以近似认作是三极管,放大电流信号。
实现
P25P26P27控制Y0-Y7,P04控制N_RELAY(继电器),P06控制N_BUZZ(蜂鸣器)。
要让Y5C输出高电平,需要让Y5输出低电平,设置P04、P06使蜂鸣器鸣叫,使继电器吸合。
代码:
#include "reg52.h"
void Delay(unsigned int t)
{
while(t--);
while(t--);
}
void InitHC138(unsigned char n) //根据n来决定P2电平
{
switch (n)
{
case 4:
P2 = (P2 & 0X1f) | 0x80; //0x1f就是二进制的00011111,保留低五位,清除高三位,然后在将第七位设为1
break;
case 5:
P2 = (P2 & 0x1f) | 0xa0; //第四、六、七位均设为1
break;
}
}
void LEDRunning()
{
unsigned char i;
InitHC138(4);
for(i=0;i<3;i++)
{
P0=0X00;
Delay(60000);
Delay(60000);
P0=0XFF;
Delay(60000);
Delay(60000);
}
InitHC138(5); //继电器
P0=0x10;
Delay(60000);
Delay(60000);
P0=0x00;
InitHC138(4);
for(i=1;i<=8;i++)
{
P0 = (0xff << i);
Delay(60000);
}
InitHC138(5); //蜂鸣器
P0=0x40;
Delay(60000);
Delay(60000);
P0=0x00;
InitHC138(4);
for(i=1;i<=8;i++)
{
P0 = ~(0xff << i);
Delay(60000);
}
}
void Initsystem() //初始化
{
InitHC138(5);
P0=0x00;
}
void main()
{
Initsystem();
while(1)
{
LEDRunning();
}
}
三、数码管
静态显示
任务:在CT107D单片机综合训练平台上,8个数码管分别单独依次显示0~9的
值,然后所有数码管一起同时显示0~F的值,如此往复。
数码管的编码思路
以共阳数码管显示6为例:除了“b”不亮其他段都得亮,于是向"b"输出高电平,
其余输出低电平,编码值即为0x02。
实现
R15-R22只是起限流作用。com1-com8分别控制对应数码管,且需要输入高电平。
#include "reg52.h"
unsigned char code SMG_duanma[18]= //数码管段码
{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x80,0xc6,0xc0,0x86,0x8e,
0xbf,0x7f};
void Delay(unsigned int t)
{
while(t--);
while(t--);
}
void InitHC138(unsigned char n)
{
switch(n)
{
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 ShowSMG_Bit(unsigned char dat,unsigned posi)
{
InitHC138(6); //数码管位置
P0 = 0x01 << posi;
InitHC138(7); //数码管内容
P0 = dat;
}
void SMG_Static() //实现静态显示
{
unsigned char i,j;
for(i = 0;i < 8;i++) //实现0-9的单次依次显示
{
for(j = 0;j < 10; j++)
{
ShowSMG_Bit(SMG_duanma[j],i); //遍历显示
Delay(60000);
}
}
for(j = 0;j < 16; j++) //实现0-F的同时显示
{
InitHC138(6);
P0 = 0xff;
InitHC138(7);
P0 = SMG_duanma[j];
Delay(60000);
}
}
void main()
{
while(1)
{
SMG_Static();
}
}
动态显示
任务:在CT107D单片机综合训练平台上,实现数码管的动态显示,在8位数码管中,前面4位显示年份“2024”,接着2位是分隔符“”,最后两位是月份,从1月份开始,每隔一段时间加1个月,到12月之后又从1月开始递增,如此往复。
动态显示设计思路:
动态显示实质上就是轮流点亮单个数码管实现多位数码管整体显示的效果。在轮流显示过程中,每位数码管点亮时间为1~2s,由于人的视觉暂留现象及发光二极管的余辉效应,尽管实际上各位数码管并非同时点亮,但只要扫描的速度足够快,给人的印象就是一组稳定的显示数据,不会有闪烁感,动态显示的效果和静态显示是一样的,能够节省大量的O端口,而且功耗更低。
对于一组4位数码管来说,静态显示和动态显示都能实现同样的效果,但需要的O端口是不同的。
静态显示需要/O端口:8个段码*4+4个COM端=36个/O引脚
动态显示需要/O端口:8个段码+4个COM端=12个/O引脚
实现:
#include "reg52.h"
unsigned char yu = 12;
unsigned char code SMG_duanma[18]=
{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x80,0xc6,0xc0,0x86,0x8e,
0xbf,0x7f};
void SelectHC573(unsigned char channel)
{
switch(channel)
{
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 DisplaySMG_Bit(unsigned char value, unsigned char posi)
{
SelectHC573(6);
P0 = 0x01 << posi;
SelectHC573(7);
P0 = value; //不应写成P0 = 0x01 << value;(结果会显示8个一样的字符)
}
void DelaySMG(unsigned int t)
{
while(t--);
}
void Display_Dynamic() //输出显示结果
{
DisplaySMG_Bit(SMG_duanma[2],0);
DelaySMG(500);
DisplaySMG_Bit(SMG_duanma[0],1);
DelaySMG(500);
DisplaySMG_Bit(SMG_duanma[2],2);
DelaySMG(500);
DisplaySMG_Bit(SMG_duanma[4],3);
DelaySMG(500);
DisplaySMG_Bit(SMG_duanma[16],4);
DelaySMG(500);
DisplaySMG_Bit(SMG_duanma[16],5);
DelaySMG(500);
DisplaySMG_Bit(SMG_duanma[yu/10],6);
DelaySMG(500);
DisplaySMG_Bit(SMG_duanma[yu%10],7);
DelaySMG(500);
}
void Delay(unsigned char t) //为了防止延时过长,影响输出结果观感
{
while(t--)
{
Display_Dynamic();
}
}
void main()
{
while(1)
{
Display_Dynamic();
yu++;
if(yu > 12) //实现月份遍历
{
yu = 1;
}
Delay(100);
}
}
也就是说,在点亮2024时,实际上是先点2再点0,因为间隔相差少,几乎可以认为是一次点亮2024。
静态显示”2014“则需要4个IO端口。
四、独立按键
任务1
在CT107D单片机综合训练平台上,首先将J5处的跳帽接到2-3引脚,使按键S4~S7四个按键的另外一端接地从而成为4个独立键盘。在扫描按键的过程中,发现有按键触发信号后,先做去抖动处理,当确认为按键按下时,才进行相应的功能处理。
J5接上2、3,使用的是独立按键,接上1、2,使用的是矩阵键盘。
本单片机使用的P36->P42,P37->P44.
按键按下,原本的高电平显示低电平,但要排除抖动的干扰。
实现:
#include "reg52.h"
sbit S7 = P3^0; //宏定义
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;
sbit L1 = P0^0;
sbit L2 = P0^1;
sbit L3 = P0^2;
sbit L4 = P0^3;
sbit L5 = P0^4;
sbit L6 = P0^5;
void DelayK(unsigned char t)
{
while(t--);
}
void ScanKeys_Alone()
{
if(S7 == 0) //如果按键按下
{
DelayK(100); //排除抖动影响
if(S7 == 0)
{
L1 = 0;
while(S7 == 0); //要是松开,L1就灭
L1 = 1;
}
}
if(S6 == 0)
{
DelayK(100);
if(S6 == 0)
{
L2 = 0;
while(S6 == 0);
L2 = 1;
}
}
if(S5 == 0)
{
DelayK(100);
if(S5 == 0)
{
L3 = 0;
while(S5 == 0);
L3 = 1;
}
}
if(S4 == 0)
{
DelayK(100);
if(S4 == 0)
{
L4 = 0;
while(S4 == 0);
L4 = 1;
}
}
}
void SelectHC573(unsigned char channel)
{
switch(channel)
{
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 main()
{
SelectHC573(4);
while(1)
{
ScanKeys_Alone();
}
}
任务2
按键S7和S6为选择键,确定控制键控制那组LED指示灯。
按键S5和S4为控制键,按键该键点亮指定的LED指示灯,松开后熄灭;
按下S7点亮L1指示灯,L1点亮后,S6不响应操作,S5控制L3,S4控制L4,
再次按下S7,L1指示灯熄灭,S6可可响应操作;
按下S6点亮L2指示灯,L2点亮后,S7不响应操作,S5控制L5,S4控制L6,
再次按下S6,L2指示灯熄灭,S7可可响应操作;
S7和S6未按下时,即L1或L2未点亮时S5和S4不响应操作也就是未作LED灯区域选择时,控制键不能操作。
#include "reg52.h"
sbit S7 = P3^0;
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;
sbit L1 = P0^0;
sbit L2 = P0^1;
sbit L3 = P0^2;
sbit L4 = P0^3;
sbit L5 = P0^4;
sbit L6 = P0^5;
void DelayK(unsigned char t)
{
while(t--);
}
unsigned char stat_k = 0; //作为媒介表征S7、S6的状态
void ScanKeys_Alone()
{
if(S7 == 0)
{
DelayK(100);
if(S7 == 0)
{
if(stat_k == 0) //没按下的状态
{
L1 = 0;
stat_k = 1;
}
else if(stat_k == 1) //按下过的状态
{
L1 = 1;
stat_k = 0;
}
while(S7 == 0); //等待循环,等到按键真正释放才会停止(防止抖动带来的影响)
}
}
if(S6 == 0)
{
DelayK(100);
if(S6 == 0)
{
if(stat_k == 0)
{
L2 = 0;
stat_k = 2;
}
else if(stat_k == 2)
{
L2 = 1;
stat_k = 0;
}
while(S6 == 0);
}
}
if(S5 == 0)
{
DelayK(100);
if(S5 == 0)
{
if(stat_k == 1)
{
L3 = 0;
while(S5 == 0);
L3 = 1;
}
else if(stat_k == 2)
{
L5 = 0;
while(S5 == 0);
L5 = 1;
}
}
}
if(S4 == 0)
{
DelayK(100);
if(S4 == 0)
{
if(stat_k == 1)
{
L4 = 0;
while(S4 == 0);
L4 = 1;
}
else if(stat_k == 2)
{
L6 = 0;
while(S4 == 0);
L6 = 1;
}
}
}
}
void SelectHC573(unsigned char channel)
{
switch(channel)
{
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 main()
{
SelectHC573(4);
while(1)
{
ScanKeys_Alone();
}
}
五、矩阵键盘
任务:在CT107D单片机综合训练平台上,首先将J5处的跳帽接到1、2引脚,使按键S4、S19按键组成4X4的矩阵键盘。在扫描按键的过程中,发现有按键触发信号后(不做去抖动),待按键松开后,在数码管的第一位显示相应的数字:从左至右,从上倒下,依次显示0~F。
按键结构:(上方是独立按键,下方是矩阵键盘中的按键)
按下后,是低电平,由IO端(行/列)决定,循环扫描。
思路:逐行扫描(扫描时该行为低电平,按下的按键同列为低电平)。
若恰好两边均为低电平,则接通。
#include "reg52.h"
#include "intrins.h"
unsigned char code SMG_number[18]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x80,0xc6,0xc0,0x86,0x8e,
0xbf,0x7f};
unsigned char value=0;
void Delay2ms() //@11.0592MHz //准确延时
{
unsigned char i, j;
_nop_();
_nop_();
i = 22;
j = 128;
do
{
while (--j);
} while (--i);
}
sfr P4 = 0xC0; //扩展P4
sbit R1=P3^0;
sbit R2=P3^1;
sbit R3=P3^2;
sbit R4=P3^3;
sbit C4=P3^4;
sbit C3=P3^5;
sbit C2=P4^2;
sbit C1=P4^4;
void SelectHC573(unsigned char channel)
{
switch (channel)
{
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 DisplayKeyNum(unsigned char value)
{
SelectHC573(6);
P0=0x80;
SelectHC573(7);
P0=SMG_number[value];
}
void DTInit() //初始化
{
SelectHC573(6);
P0=0xff;
SelectHC573(7);
P0=0xff;
}
void ScanfMaxKey()
{
R1=0; //第一行开始扫描
R2=R3=R4=1;
C1=C2=C3=C4=1;
if(0==C1)
{
Delay2ms();
while(0==C1);
Delay2ms();
value=0;
DisplayKeyNum(value);
}
else if(0==C2) //换列
{
Delay2ms();
while(0==C2);
Delay2ms();
value=1;
DisplayKeyNum(value);
}
else if(0==C3)
{
Delay2ms();
while(0==C3);
Delay2ms();
value=2;
DisplayKeyNum(value);
}
if(0==C4)
{
Delay2ms();
while(0==C4);
Delay2ms();
value=3;
DisplayKeyNum(value);
}
R2=0; //换行
R1=R3=R4=1;
C1=C2=C3=C4=1;
if(0==C1)
{
Delay2ms();
while(0==C1);
Delay2ms();
value=4;
DisplayKeyNum(value);
}
else if(0==C2)
{
Delay2ms();
while(0==C2);
Delay2ms();
value=5;
DisplayKeyNum(value);
}
else if(0==C3)
{
Delay2ms();
while(0==C3);
Delay2ms();
value=6;
DisplayKeyNum(value);
}
if(0==C4)
{
Delay2ms();
while(0==C4);
Delay2ms();
value=7;
DisplayKeyNum(value);
}
//
R3=0;
R2=R1=R4=1;
C1=C2=C3=C4=1;
if(0==C1)
{
Delay2ms();
while(0==C1);
Delay2ms();
value=8;
DisplayKeyNum(value);
}
else if(0==C2)
{
Delay2ms();
while(0==C2);
Delay2ms();
value=9;
DisplayKeyNum(value);
}
else if(0==C3)
{
Delay2ms();
while(0==C3);
Delay2ms();
value=10;
DisplayKeyNum(value);
}
if(0==C4)
{
Delay2ms();
while(0==C4);
Delay2ms();
value=11;
DisplayKeyNum(value);
}
//
R4=0;
R2=R3=R1=1;
C1=C2=C3=C4=1;
if(0==C1)
{
Delay2ms();
while(0==C1);
Delay2ms();
value=12;
DisplayKeyNum(value);
}
else if(0==C2)
{
Delay2ms();
while(0==C2);
Delay2ms();
value=13;
DisplayKeyNum(value);
}
else if(0==C3)
{
Delay2ms();
while(0==C3);
Delay2ms();
value=14;
DisplayKeyNum(value);
}
if(0==C4)
{
Delay2ms();
while(0==C4);
Delay2ms();
value=15;
DisplayKeyNum(value);
}
}
void Test() //测试LED
{
if(0==C4)
{
SelectHC573(4);
P0=0x01;
}
}
void main()
{
DTInit();
while(1)
{
// Test();
ScanfMaxKey();
}
}
六、中断系统
任务:在CT107D单片机综合训练平台上,首先将J5处的跳帽接到2~3引脚,即S5按键接到P32INT0,S4按键接到P33/INT1。定义一个Working()函数,使L1指示灯不断闪烁。将P32引脚定义成外部中断功能,按键S5按键就会产生外部中断触发信号,在中断响应函数中,点亮L8指示灯,延时一段较长的时间后熄灭,该功能用两种方式实现:1、直接在中断服务函数中延时。 2、在中断服务函数中标志变量,在外部执行延时。
基本概念
内核与外设之间的主要交互方式有两种:轮询和中断。(轮询的实际工作效率比较低,且不能及时响应紧急事件,中断系统则具备这种能力)
中断服务函数:内核响应中断后执行的相应处理程序。
中断向量:中断服务程序的入口地址。每个中断源都对应一个固定的入口地址。当内核响应中断请求时,就会暂停当前的程序执行,然后跳转到该入口地址执行代码。
结构
一般的51单片机有5个中断源:(忽略定时/计数器2) 中断号
外部中斯0:INT0 0
定时/计数器0:TF0 1
外部中断1:INT1 2
定时/计数器1:TF1 3
串口中断:RI/TI 4
中断系统结构:
IT0接1,高电平信号出发;接0.低电平信号触发(非门)
寄存器
中断相关寄存器:(均能位寻址)
2个控制寄存器:
2个中断请求标志:
ICON寄存器:
SCON寄存器:
中断初始化函数与普通函数要求一致,中断服务函数则有格式要求:
void 函数名() interrupt 中断号
实现:
#include "reg52.h"
sbit L1=P0^0;
sbit L8=P0^7;
void Delay(unsigned int t)
{
while(t--);
}
void SelectHC573()
{
P2=P2&0x1f|0x80;
}
void Working()
{
SelectHC573();
L1=0;
Delay(65535);
L1=1;
Delay(65535);
}
//=====================================
void Init_INT0() //初始化中断
{
IT0=1;
EX0=1;
EA=1;
}
void INT0_Itr() interrupt 0 //中断处理
{
L8=0;
Delay(65535);
Delay(65535);
Delay(65535);
Delay(65535);
Delay(65535);
Delay(65535);
L8=1; //值得注意的是,中断服务函数内不应有过多程序,不必要的程序应该在其外部执行
}
//===================================================
void main()
{
Init_INT0();
while (1)
{
Working();
}
}
S5直接与P32\INT0相连,故按下S5有中断信号。
七、定时器
原理
定时/计数器,是一种能够对内部时钟信号或外部输入信号进行计数,当计数值达到设定要求时,向CU提出
中断处理请求,从而实现定时或者计数功能的外设。定时/计数器的最基本工作原理是进行计数。作为定时器
时,计数信号的来源选择周期性的内部时钟脉冲:用作计数器时,计数信号的来源选择非周期性的外部输入信
号。
不管是定时器还是计数器,本质上都是计数器。
示意图:(以定时/计数器T0为例)
每次计数,T0加一,加到最大值(65535时),溢出后通知内核进行逻辑处理。
计数脉冲来源:
<1>系统时钟振荡器输出的12分频。
<2>T0或T1引脚输入的外部脉冲信号。
假设单片机的外部晶振为12MHz,那么,经过12分频后输入计数器的计数脉冲为1Mz,即每个脉冲的周期为1us。因此定时器T0的16位工作模式最大的定时时间为65535us,65.5ms。如果要定时10ms的话,计数器就不能够从0开始计数了,必须定义个高的计数初值。
比如说:
要定时10ms,则相当于计数10000个脉冲后计数器的值就到达65535了,那么开始计数的这个地方就是计数初值。
65535-10000=55535=0xd8ef
把这个计算得到的初值写入TH0和TL0寄存器即可:
TH0=0xd8:或者TH0=(65535-10000)/256;(高字节)
TL0=0xef;或者TL0=(65535-10000)%256;(低字节)
TMOD寄存器
为什么有些定时器无自动重装功能?
在定时器溢出后,TH0与TL0均为0,必须重新定义计数初值才能正常工作。
任务一
任务一:在CT107D单片机综合训练平台上,利用51单片机的定时/计数器T0的模式1实现间隔定时,每隔1秒L1指示灯闪烁一下,也就是点亮0.5秒,熄灭0.5秒;每隔10秒L8指示灯闪烁一下,即点亮5秒,熄灭5秒。
编程思路:
在定时/计数器的程序设计中,通常有两个函数:初始化函数和中断服务函数。
在初始化函数中,一般需要进行以下几个配置:
<1>配置工作模式,即对TMOD寄存器编程。
<2>计算计数初值,即对THx和TLx寄存器进行赋值。
<3>使能定时/计数器中断,即ET0或ET1置1。
<4>打开总中断,即EA=1。
<5>启动定时器,即TR0或TR1置1。
在中断服务函数中,一般需要进行以下的编程:
<1>如果不是自动重装模式,需要对THx和TLx重新赋值。
<2>进行间隔定时到达的逻辑处理(越少越好)
实现:
#include "reg52.h"
sbit L1 = P0^0;
sbit L8 = P0^7;
void SelectHC573()
{
P2 = (P2 & 0x1f) | 0x80;
}
//==============================
void InitTimer0()
{
TMOD=0x01; //16位计数
TH0 = (65535 - 50000) / 256; //高八位 记50ms
TL0 = (65535 - 50000) % 256; //低八位
ET0 = 1; //使计数器中断
EA = 1; //打开总中断
TR0 = 1; //启动定时器
}
unsigned char count = 0;
unsigned char count1 = 0;
void ServiceTimer0() interrupt 1
{
TH0 = (65535 - 50000) / 256; //因为没有自动重装而必须重新赋值
TL0 = (65535 - 50000) % 256;
count++;
count1++;
if(count == 10) //累计10次就是500ms,即0.5s
{
L1 = ~L1;
count = 0;
}
if(count1 == 100)
{
L8 = ~L8;
count1 = 0;
}
}
//==============================
void main()
{
SelectHC573();
InitTimer0();
}
任务二
任务二:在CT107D单片机综合训练平台上,利用定时器T0、数码管模块和2个独立按键(J5的23短接),设计一个秒表,具有清零、暂停、启动功能。
1.显示格式为:分-秒-0.05秒(即50ms)
08-26-18表示:8分26秒900毫秒
2.独立按键S4为:暂停/启动
独立按键S5为:清零
按键均为按下有效。
实现:
#include "reg52.h"
sbit S4 = P3^3;
sbit S5 = P3^2;
unsigned char code SMG_duanma[18]={0xc0,0xf9,0xa4,0xb0,0x99,
0x92,0x82,0xf8,0x80,0x90,
0x88,0x80,0xc6,0xc0,0x86,
0x8e,0xbf,0x7f};
unsigned char t_m = 0;
unsigned char t_s = 0;
unsigned char t_005s = 0;
void SelectHC573(unsigned char channel) //锁存器
{
switch(channel)
{
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 DisplaySMG_Bit(unsigned char value, unsigned char pos) //数码管显示
{
SelectHC573(6);
P0 = 0x01 << pos; //每次输出后左移
SelectHC573(7);
P0 = value;
}
void DelaySMG(unsigned int t)
{
while(t--);
}
void DisplayTime()
{
DisplaySMG_Bit(SMG_duanma[t_005s%10],7); //显示005s
DelaySMG(500);
DisplaySMG_Bit(SMG_duanma[t_005s/10],6);
DelaySMG(500);
DisplaySMG_Bit(SMG_duanma[16],5); //显示横杠
DelaySMG(500);
DisplaySMG_Bit(SMG_duanma[t_s%10],4); //显示秒
DelaySMG(500);
DisplaySMG_Bit(SMG_duanma[t_s/10],3);
DelaySMG(500);
DisplaySMG_Bit(SMG_duanma[16],2);
DelaySMG(500);
DisplaySMG_Bit(SMG_duanma[t_m%10],1); //显示分
DelaySMG(500);
DisplaySMG_Bit(SMG_duanma[t_m/10],0);
DelaySMG(500);
}
//============秒表=================
void InitTimer0() //中断初始化
{
TMOD = 0x01;
TH0 =(65535 - 50000) / 256;
TL0 =(65535 - 50000) % 256;
ET0 = 1;
EA = 1;
TR0 = 1;
}
void ServiceTimer0() interrupt 1
{
TH0 =(65535 - 50000) / 256;
TL0 =(65535 - 50000) % 256;
t_005s++; //计算时间
if(t_005s == 20)
{
t_s++;
t_005s = 0;
if(t_s == 60)
{
t_m++;
t_s = 0;
}
if(t_m == 99)
{
t_m = 0;
}
}
}
//=============================
void DelayK(unsigned char t)
{
while(t--);
}
void ScanKeys()
{
DelayK(500);
if(S4 == 0)
{
TR0 = ~TR0; //关计时器(停表)
while(S4 == 0) //
{
DisplayTime();
}
}
DelayK(500);
if(S5 == 0)
{
t_005s = 0; //清0
t_s = 0;
t_m = 0;
while(S5 == 0)
{
DisplayTime();
}
}
}
void main()
{
InitTimer0();
while(1)
{
DisplayTime();
ScanKeys();
}
}