一.实验目的:
1. 了解51单片机I/O口的电气特性和驱动能力。
2. 了解LED电路中加入限流电阻的原因。
3. 掌握定时器原理及编程。
4. 掌握并口程序的编辑、编译、调试和运行。
二.实验设备和器件
1. PC机
2. PROTEUS仿真软件
3. 实验箱
4. ISP下载器
5. 51仿真器
三.实验内容
(1)编程实现:采用定时器0,每隔1s点亮1只发光二极管
① 电路图:
② 代码:
Ø 中断处理方式:
ORG 0000H
LJMP MAIN
ORG 000BH
LJMP INTT0
ORG 0100H
MAIN:
MOV TMOD,#01H //TMOD为方式寄存器,该题是定时器0,且为方式1,则TMOD=0000_0001
MOV TH0,#3CH
MOV TL0,#0B0H //初值的计算
MOV R2,#00H //计数寄存器
MOV A,#0FEH
MOV P0, A //设置灯的初状态,第D0个灯亮
SETB EA // 允许单片机总中断,SETB bit:位置1
SETB ET0 //允许T0溢出中断
SETB TR0 //开启定时器0
SJMP $ //必须要有死循环,表示等待定时过程,否者只有一个灯亮
INTT0: //定时到进入中断
MOV TH0,#3CH
MOV TL0,#0B0H //每次定时都需要重新赋初值
INC R2 //计数次数加1
CJNE R2,#0AH,NEXT //判断计数次数是否等于10,不等跳转到NEXT
RL A //计数次数到10次之后,A左移
MOV P0, A //下一个灯亮
MOV R2,#00H //计数清0
NEXT:
RETI
END
Ø 查询处理方式:
ORG 0000H
LJMP MAIN
ORG 0100H
MAIN:
MOV TMOD,#01H
MOV TH0,#3CH
MOV TL0,#0B0H
MOV R2,#00H
MOV A,#0FEH
MOV P0,A
SETB TR0
LOOP:
JBC TF0,NEXT1 //判断TF0是否溢出,及TF0是否为1,有则跳转到NEXT1,并把TF0清0
SJMP LOOP //无溢出,一直查询
NEXT1:
MOV TH0,#3CH
MOV TL0,#0B0H //每次定时都需要重新赋初值
INC R2
CJNE R2,#0AH,NEXT
RL A
MOV P0, A
MOV R2,#00H
SJMP LOOP
NEXT:
SJMP LOOP
SJMP $
END
③ 分析:
初值的计算:系统时钟为6MHz,机器周期为2,当采用工作方式1时,最大的定时时间为:,则每隔1s一个定时器不能直接实现,即用定时器T0产生周期为100ms=0.1s的定时,用一个寄存器R2对100ms计数10次,则可以产生1s的定时。
T0的定时为100ms时,初值:
十六进制数为3CB0H
(2)编程实现:上电时, 8个发光二极管全亮;按下K1时,发光二极管向左(向下)移一位;按下K2时,发光二极管向右(向上)移一位。
① 电路图:
② 代码:
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
uint i;
sbit P1_0=P1^0; sbit P1_1=P1^1; //定义并口P1的第0、1位
void Time_Init() //定时器装入初值 T0定时时间为100ms,T1定时时间为50ms
{
TMOD=0x11;
TH0=0x3c; TL0=0xb0;
TR0=0;//初始化后并不启动定时器T0,待命
TH1=0x9e; TL1=0x58;
TR1=0;//初始化后并不启动定时器T1,待命
}
void main()
{
Time_Init(); //初始化定时器
i=0;
P0=0x0; //上电时, 8个发光二极管全亮
while(1)
{
if(P1_0==0) //当P1.0有效时,及开关K1按下
{ EA=1; TR1=0;//关闭定时器1
TR0=1; ET0=1;//允许中断0,打开定时器0
P0=0x7f; // 给灯赋初值,第8个灯亮
}
if(P1_1==0) //当P1.1有效时,及开关K2按下
{
EA=1;
TR0=0; //关闭定时器0
TR1=1; ET1=1; //允许中断1,打开定时器1
P0=0xfe; // 给灯赋初值,第1个灯亮
}}}
void time0_int(void) interrupt 1 //中断服务程序1
{
TH0=0x3c; TL0=0xb0; //每次定时都需要重新赋初值
i++; //计数加1
if(i==10)
{
i=0;
P0= _cror_(P0,1); //循环右移(向上)1位,点亮下一个灯
}}
void time1_int(void) interrupt 3
{
TH1=0x9e;TL1=0x58; //每次定时都需要重新赋初值
i++;
if(i==20)
{
i=0;
P0= _crol_(P0,1); //循环左移(向下)1位,点亮下一个灯
}}
③ 分析:
Ø 该题中最上面的灯为第一个灯,
K1---P0=0x7f---向上移
K2---P0=0xfe---向下移
Ø 该题才用的两个定时器T0、T1
T0的初值计算:
十六进制数为3CB0H 计数10次
T0的初值计算:
十六进制数为9E58H 计数10次
四.部分知识点及遇到的问题:
(1) 定时/计数器T0工作方式:
Ø 方式0 M1 M0=00 13 位定时/计数器
Ø 方式1 M1 M0=01 16 位定时/计数器(每次定时均需重新赋值,TF0=0)
Ø 方式2 M1 M0=10 8位自动充值定时/计数器
Ø 方式3 M1 M0=11 两个9位定时/计数器
(2) 用了T1之后,T0不可以执行:定时器T1比定时器T0优先级高
(3) 开关与灯在该仿真电路中均是低电平有效
(4) 中断服务程序的格式:void 函数名(void) interrupt 寄存器组(1、2、3、4)