前提提醒

激活Keil4/5
下面学习及图片以Keil4为例,Keil5方法类似

创建项目

打开Keil4,在上方的导航栏中依次选择Project->New μVersion Project,找到一个地方存储所有文件,注意路径中不能有中文,这里我在D盘中创建了一个叫Project的文件夹作为这次学习记录初始路径,接着再创建一个叫class01的文件夹作为这次学习创建项目的文件夹,进入文件夹中,文件名填class01,点击保存。

目录结构:

1
2
3
4
D盘

├── Project
└── class01

接着在数据库(Data base)中找到Atmel点击左边的加号找到AT89C51这里应该是根据自己购买的单片机去选择,但是因为是最基础的学习,所有选择AT89C51就可以),然后点击OK

并在接着弹出的提示中选择
然后在左侧的Explorer中就可以看到新创建的文件项目
在上方的导航栏中找到这个图标(NEW)创建新文件,再点击右侧的保存按钮(SAVE

将目录选择到class01中,文件名命名为text1.c(文件名不能有中文,不能以数字开头),点击保存

回到Keil4中,在左侧的Explorer栏中点击Target 1左侧的加号,右键Source Group 1再点击Add files to Group ‘Source Group 1’...选择刚刚新建的文件text1.c,再点击Add,然后就可以在左侧的Explorer栏中看见新加入的text1.c
Explorer栏在这里

实验

**实验名:**LED亮灭控制
**实验现象:**LED以0.2S为间隔亮灭
实验目的:

  1. 掌握单片机IO口操作的基本方法
  2. 掌握软件延时函数的设计方法

运行原理

先看原理图
原理图1

锁存器M74HC573M1R

LED由锁存器M74HC573M1R控制

设想一个电路,初始输入为0,输出为0;然后输入为1,输出变为1(状态发生了变化)。对于迄今为止所有的电路,我们都能保证当输入回到0时,输出也会同时归0;但这个电路不同,它保持在了1,也就是状态没有发生变化,而是被存储了下来。此时,这种电路便可以被叫做锁存器

锁存器M74HC573M1R与LED
LED阳接VCC(高电压)、阴接锁存器M74HC573M1R
锁存器M74HC573M1R真值表如下:

OE LE D Q
L H H H
L H L L
L L X Q0
H X X Z

OE、LE、D为输入端,Q为输出端
L表示低电平,H表示高电平,X表示任意电平,Z表示高阻抗,Q0表示输出上一次输出的数据

由真值表可以知道,当OE使能端接入低电平时,芯片才有效,若是OE接高电平,输出端永远是高阻抗状态,相当于芯片断开,因此在设计电路的时候通常将OE引脚接在电源地(GND)上面。当OE使能端接低电平后,若LE为高电平,则输出端Q的数据和输入端D的数据相同,相当于直通;若LE为低电平,则无论输入端D输入任何数据,输出端Q都保持上次的数据状态Q0不变,相当于将数据锁存起来了。

所以Y4C为低电平时,无论输入端D给什么信号,输出端Q都无变化,即锁存

再看M74HC573M1R的输出端,LED两端阴极接M74HC573M1R输出端、阳极接VCC(即高电平),也就是说当M74HC573M1R输出低电位时,LED两端才有电位差,LED才能导通亮起,这里以L4为例,当P03为低电压时,D3为低电压,Q4为低电压,L4导通。

或非门74HC02

接下来看M74HC573M1R的输入端,锁存器受到Y4C控制,找到Y4C的另一端,Y4C的另一端由或非门74HC02控制
或非门74HC02
或非门真值表:

输入11 输入12 输出13
L L H
H L L
L H L
H H L

这里WR通过CON3与GND相连,也就是输入端12一直为0,所以Y4为低电压时,Y4C为高电压,反之,Y4为高电压时,Y4C为低电压。
CON3
也就是当Y4为H时Y4C为L,此时锁存器锁存

三八译码器74HC138

看原理图,Y4的另一端由三八译码器74HC138控制,2的三次方刚好是8,将这3位二进制数写出刚好可以表示0-7这8个电平的高低
三八译码器74HC138
下面是三八译码器74HC138的真值表:
三八译码器74HC138真值表
要想锁存器收信号,则Y4应为L,查表可知CBA应该分别输出HLL,即100
当CBA是100时,锁存器收信号;当CBA是非100时,锁存器锁存
至此,LED亮灭的原理已经介绍完毕,下面是原理图汇总:
Class01原理图

程序编写

头文件

1
#include "reg51.h"

reg51.h是51单片机最基础的头文件,在比较基础的学习环境中使用reg51.h足以

关闭蜂鸣器

1
2
3
4
5
6
void cls_buzz(void)
{
P2 = (P2&0x1F|0xA0);
P0 = 0x00;
P2 &= 0x1F;
}

51单片机在启动时会使用蜂鸣器,这里将蜂鸣器关闭,直接提供命令,这里不做的详细解读

延时函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void delay()		//@11.0592MHz
{
unsigned char i, j, k;

_nop_();
_nop_();
i = 9;
j = 104;
k = 139;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}

延迟函数主要用于LED灯亮灭间转换时间的延迟,每一款单片机的晶震频率不同,这里以11.0592M的振荡器频率作为演示,delay函数精准度不高,在后期的学习中将使用其他的高精准度计时函数

主函数

关闭蜂鸣器

1
cls_buzz();

直接执行之前写的函数

进入永久循环

1
2
while(1){
}

导通数据流

1
P2 = P2&0x1f; \\也可以写成 P2 &= &0x1f

这里是进行按位与运算
十六进制数0x1f写成二进制为 0001,1111

与运算:任何数与0相与等于0,与1相与等于其本身

所以进行运行按位与后,P2的数值变为 000x,xxxx

1
P2 = P2|0x80; \\也可以写成 P2 |= 0x80

这里进行按位或
十六进制数0x80写成二进制为 1000,0000

或运算:任何数与0相与等于其本身,与1相与等于1

所以进行运行按位或后,P2的数值变为 100x,xxxx
即P2.7、P2.6、P2.5的值分别为1、0、0,即控制LED的锁存器接受信号

上面两步也可以写成一步

1
P2 = ((P2&0x1f)|0x80);

熄灭全部LED灯

LED灯由P0.0-P0.7控制

1
P0 = 0xff;

十六进制数0xff写成二进制为 1111,1111
即P0.0-P0.7都为高电平,LED两端电压相等,回路不通,LED全灭

关闭数据流

1
P2 &= 0x1f;

按位与后 P2 = 000x,xxxx
P2.7、P2.6、P2.5的值分别为0、0、0,控制LED的锁存器不再接受信号

延迟函数

1
delay();

导通数据流

1
P2 = ((P2&0x1f)|0x80);

含义不再赘述

点亮全部LED灯

1
P0 = 0x00;

十六进制数0x00写成二进制为 0000,0000
即P0.0-P0.7都为低电平,LED两端电压不相等,回路导通,LED全部被点亮

锁存

1
P2 &= 0x1f;

按位与后 P2 = 000x,xxxx
P2.7、P2.6、P2.5的值分别为0、0、0,数据流关闭

延迟函数

1
delay();

主程序示例

至此,主函数的编写全部完成,下面提供主函数整体示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void main(void)
{
cls_buzz();
while(1)
{
P2 = ((P2&0x1f)|0x80); //0001,1111,掩码(又叫MASK) ,0x80=1000,0000
P0 = 0xff; //LED关
P2 &= 0x1f;//锁存
delay();

P2 = ((P2&0x1f)|0x80);
P0 = 0x00; //LED开
P2 &= 0x1f;
delay();
}
}

尾声

至此,本节内容结束,这节内容主要讲解一下几点

  1. Keil的简单使用
  2. 51单片机原理图的学习使用
  3. 锁存器M74HC573M1R
  4. 或非门74HC02
  5. 三八译码器74HC138
  6. 按位与、按位或

下面是整个程序的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include "reg51.h" 

//关闭蜂鸣器
void cls_buzz(void)
{
P2 = (P2&0x1F|0xA0);
P0 = 0x00;
P2 &= 0x1F;
}

//延时200ms
void delay() //@11.0592MHz
{
unsigned char i, j, k;

_nop_();
_nop_();
i = 9;
j = 104;
k = 139;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}


void main(void)
{
cls_buzz();
while(1)
{
P2 = ((P2&0x1f)|0x80); //0001,1111,掩码(又叫MASK) ,0x80=1000,0000
P0 = 0xff; //LED关
P2 &= 0x1f;//锁存
delay();

P2 = ((P2&0x1f)|0x80);
P0 = 0x00; //LED开
P2 &= 0x1f;
delay();
}
}