第 2 章 点亮你的 LED
本章的标题是点亮 LED,虽然任务很简单,但是需要了解的单片机基础知识却很多,特别是对于初学者,刚开始要在头脑中建立一个单片机的概念,然后通过点亮一个 LED 小灯来增加初学者对单片机的兴趣和自信。
2.1 单片机的内部资源
B站在线视频教程:2-1认识51单片机
在这里所讲到的单片机内部资源,和传统单片机书籍中讲单片机内部结构不同,这里讲到的内部资源,是指作为单片机用户,单片机提供给用户可使用的东西。总结起来,主要是三大资源:
(1)Flash——程序存储空间,早期单片机是 OTPROM。
(2)RAM——数据存储空间。
(3)SFR——特殊功能寄存器。
早期的单片机中,主要是用 OTPROM(One Time Programmable Read-Only Memory,即一次可编程只读存储器)来存储单片机的程序,程序只能写入一次,如果发现错了,没办法,只能换一片重新写入。随着技术的发展,Flash 以其可重复擦写且容量大、成本低的优点成为现在绝大多数单片机的程序存储器。对于单片机来说 Flash 最大的意义是断电后数据不丢失,这个概念类似于计算机的硬盘,保存了电影、文档、音乐等文件,把电源关掉后,下次重新开计算机,所有的文件都还照样存在。
RAM 是单片机的数据存储空间,用来存储程序运行过程中产生的和需要的数据,跟计算机的内存是相似的概念,其实最典型的比喻是计算器。用计算器计算加减法,一些中间的数据都会保存在 RAM 里边,断电后数据丢失,所以每次打开计算器都是从归零开始计算。但是它的优点是读写速度非常快,理论上是可无限次写入的,即寿命无限,不管程序怎么运行怎么读写,它都不会坏。
第三个资源是 SFR,特殊功能寄存器。这个概念可能刚开始理解不了,但需要记住。单片机有很多很多特殊功能,每个功能都会对应一个或多个 SFR,用户就是通过对 SFR 的读写来实现单片机的多种多样的功能的。
讲到这里,首先来了解一下 51 单片机。通常一说到 51 单片机,指的都是兼容 Intel MCS-51体系架构的一系列单片机,而 51 是它的一个通俗的简称。全球有众多的半导体厂商推出了无数款这一系列的单片机,比如 Atmel 的 AT89C52,NXP(Philips)的 P89V51,宏晶科技的STC89C52……具体型号千差万别,但它们的基本原理和操作都是一样的,程序开发环境也是一样的。这里要分清楚 51 这个统称和具体的单片机型号之间的关系。
单片机内部资源的三个主要部分清楚了,那么就选择 STC89C52RC 这款单片机来进行学习。STC89C52RC 是宏晶科技出品的一款 51 内核的单片机,具有标准的 51 体系结构,全部的 51 标准功能,程序下载方式简单,方便学习。它的资源情况:Flash 程序空间是 8K 字节(1K=1024,1 字节= 8 位),RAM 数据空间是 512 字节,SFR 后边会逐一提到并且应用。
2.2 单片机最小系统
什么是单片机最小系统呢?单片机最小系统是指用最少的原件组成单片机可以工作的系统。单片机最小系统的三要素就是电源、晶振、复位电路,如图 2-1 所示。
这张最小系统的电路图节选自 Kingst51 开发板原理图,下面就照这张电路图来具体分析最小系统的三要素。
2.2.1 电源
这个很好理解,电子设备都需要供电。目前主流单片机的电源分为 5V 和 3.3V 这两个标准,当然现在还有对电压要求更低的单片机系统,一般多用在一些特定场合,在学习中不做过多的关注。
STC89C52 需要 5V 的供电系统,Kingst51 开发板是使用 USB 口输出的 5V 直流电直接供电的。从图 2-1 可以看到,供电电路在 38 脚和 16 脚的位置上,38 脚接的是+5V,通常也称为 VCC 或 VDD,代表的是电源正极,16 脚接的是 GND,也可称为 VSS,代表的是电源的负极。+5V 和 GND 之间还有个电容,作用下节课介绍。
此处普及一个看电路原理图的知识。电路原理图是为了表达这个电路的工作原理而存在的,很多器件在绘制的时候更多考虑的是方便原理分析,而不是表达各个器件实际位置。比如原理图中的单片机引脚图,引脚的位置是可以随意放的,但是每个引脚上有一个数字标号,这个数字标号代表的才是单片机真正的引脚位置。
单片机通常有不同的封装形式,所谓的不同封装可以理解为,同样是加了水的面,但是捏成不同的形状的馒头,只是表现形式不同,实现的功能完全一致。在 2014 年《手把手教你学 51 单片机--C 语言版》(第 1 版)时所设计的 Kingst51 开发板采用了 DIP40 封装,是一种双列直插式的封装形式。目前编写第 3 版的时候,决定采用 QFP-44 的封装形式,是一种方形扁平式,如图 2-2 所示。
除部分单片机开发板还采用 DIP40 封装外,当前现实中的产品几乎见不到这种封装的身影了。一方面 QFP 封装体积更小,密度更高,集成度更高,占据空间更少;另外一方面产品设计要考虑成本,QFP 封装采用 SMT 表面贴技术焊接,而 DIP 封装采用波峰焊或者手工焊接,后者单个引脚的焊接费用接近前者的 10 倍。这样一片 DIP40 封装的单片机的焊接费可能都会超过一片单片机的价格,因此在实际产品开发当中除特殊需求外(比如散热性能考虑),很少采用 DIP 封装形式的芯片了。无限接近实际项目,从单片机封装选择开始。
图 2-2 可以看出,DIP 封装的 1 脚在其最左上角,逆时针旋转引脚号依次增加,一直到右上角是最大引脚号 40 脚。QFP 封装中,有一个小圆圈的位置为 1 脚,逆时针旋转引脚号依次增加,一直旋转一圈到最大引脚号 44 脚。图 2-2 的封装图就是单片机实际引脚的位置。
2.2.2 晶振
晶振,又叫晶体振荡器,从这个名字就可以看出来,它注定一生都要不停振荡的。它起到的作用是为单片机系统提供基准时钟信号,类似于部队训练时喊口令的人,单片机内部所有的工作都是以这个时钟信号为步调基准来进行工作的。STC89C52RC 单片机的 14 脚和 15脚是晶振引脚,接了一个 11.0592M 的晶振(它每秒钟振荡 11059200 次),外加两个 20pF的电容,电容的作用是帮助晶振起振,并维持振荡信号的稳定。 2.2.3 复位电路
在图 2-1 左侧是一个复位电路,接到了单片机的 4 脚 RST(Reset)复位引脚上,这个复位电路如何起作用后边再讲,现在着重讲一下复位对单片机的作用。单片机复位一般分为三种情况:上电复位、手动复位、程序自动复位。假如单片机程序有 100 行,当某一次运行到第 50 行的时候,突然停电了,这个时候单片机内部有的区域数据会丢失,有的区域数据可能还没丢失。那么下次打开设备的时候,用户希望单片机能正常运行,所以上电后,单片机要进行一个内部的初始化过程,这个过程就可以理解为上电复位,上电复位保证单片机每次都从一个固定的相同的状态开始工作。这个过程跟打开计算机电源开机的过程是一致的。当单片机的程序运行时,如果遭受到意外干扰而导致程序死机,或者程序跑飞的时候,就可以按下一个复位按键,让程序重新初始化重新运行,这个过程就叫做手动复位,最典型的就是计算机的重启按钮(目前大多数电脑都没有重启按钮了,而是通过长按开机键关闭电源的方式)。当程序死机或者跑飞的时候,单片机往往有一套自动复位机制,比如看门狗,具体应用以后再了解。在这种情况下,如果程序长时间失去响应,单片机看门狗模块会自动复位重启单片机。还有一些情况是程序故意重启复位单片机。
电源、晶振、复位构成了单片机最小系统的三要素,也就是说,一个单片机具备了这三个条件,就可以运行下载的程序了,其他的比如 LED 小灯、数码管、蜂鸣器等设备都是属于单片机的外部设备,即外设。最终完成用户想要的功能就是通过对单片机编程来控制各种各样的外设实现的。
2.3 LED 小灯
LED(light-emitting diode),即发光二极管,俗称 LED 小灯,它的种类很多,参数也不尽相同,Kingst51 开发板上用的是普通的贴片发光二极管。这种二极管通常的正向导通电压是1.8V 到 2.2V 之间,工作电流一般在 1mA~20mA 之间。其中,当电流在 1mA~5mA 之间变化时,随着通过 LED 的电流越来越大,肉眼会明显感觉到这个小灯越来越亮,而当电流从5mA~20mA 之间变化时,看到的发光二极管的亮度变化就不太明显了。当电流超过 20mA时,LED 就会有烧坏的危险了,电流越大,烧坏的速度也就越快。所以在使用过程中应该特别注意它在电流参数上的设计要求。
下面来看一下发光二极管在 Kingst51 开发板上的设计应用。USB 供电接口图以及电源开关图如图 2-3 所示。
B站在线视频教程:2-2认识LED小灯
2-3 是 Kingst51 开发板上的 USB 接口电路。通过 USB 线,电脑给开发板供电和下载程序以及实现电脑和开发板之间的通信。这是一个标准 16 引脚的 type-C 的 USB 接口,从图上可以看出,其中 A6 脚和 A7 脚是数据通信引脚,+5IN 为 USB 电源正极,GND 为电源负极。将电源开关左边的 LED 部分的电路单独摘出来分析,如图 2-4 所示。
发光二极管是二极管中的一种,因此和普通二极管一样,这个二极管也有阴极和阳极,习惯上也称之为负极和正极,方向必须接对了才会有电流通过让 LED 小灯发光。刚才提到接入的 VCC 电压是 5V,发光二极管自身压降大概是 2V,那么在右边 R34 这个电阻上承受的电压就是 3V。现在要求电流范围是 1~20mA 的话,就可以根据欧姆定律 R=U/I,把这个电阻的上限和下限值求出来。U=3V,当电流是 1mA 的时候,电阻值是 3K;当电流是 20mA 的时候,电阻值是 150欧,也就是 R34 的取值范围是 150~3K 欧姆。这个电阻值大小的变化,直接可以限制整条通路的电流的大小,因此这个电阻通常称之为“限流电阻”。在图 2-3 中用的电阻是 1K,这条支路电流的大小可以计算出来了,而这个发光二极管在这里的作用,是作为电源指示灯的,使用 USB 线将开发板和电脑连起来,这个灯就会亮了。同理,在电源开关后级控制的位置,又添加了一个 LED10 发光二极管,当打开开关时,这个二极管才会亮起,如图 2-5 所示。
把图 2-4 进行一下变化,把右侧的 GND 去掉,改成一个单片机的 I/O 口,如图 2-6 所示。
图 2-4 由于电源从正极到负极有电压差,并且电路是导通的,所以就会有电流通过,LED小灯因为有了电流通过,就会发光。把右侧的原 GND 处接到单片机 P0.0 引脚上,那么如果单片机输出一个低电平,也就是跟 GND 一样的 0V 电压,就可以让 LED 小灯和图 2-4 一样发光了。因为单片机是可以编程控制的,可以让 P0.0 这个引脚输出一个高电平,就是跟 VCC 一样的 5V 电压,那么这个时候,左侧 VCC 电压和右侧的 P0.0 的电压是一致的,那就没有电压差,没有电压差就不会产生电流,没有电流 LED 小灯就不会亮,也就是会处于熄灭状态。下面,就用编程软件来实现控制小灯的亮和灭。
2.4 程序代码编写
这是第一个实验程序,编程之前,需要先来了解一些 51 单片机特有的程序语法以及 Keil软件的基本操作步骤。
B站在线视频教程:2-3单片机的SFR与新建一个工程
2.4.1 特殊功能寄存器和位定义
不同厂家的单片机除了采用通用的 C 语言编程外,有的厂家的单片机会有那么几条很特殊的独有的编程语句,51 单片机就有,先介绍 2 条。第一条语句是:sfr P0 = 0x80;
sfr 这个关键字,是 51 单片机特有的,它的作用是定义一个单片机特殊功能寄存器(special function register)。51 单片机内部有很多个小模块,每个模块居住在拥有唯一房间号的房间内,同时每个模块都有 8 个控制开关。P0 就是一个功能模块,就住在了 0x80 这个房间里,用户就是通过设置 P0 内部这个模块的 8 个开关,来让单片机的 P0 这 8 个 I/O 口输出高电平或者低电平的。而 51 单片机内部有很多寄存器,如果想使用必须提前进行 sfr 声明。不过 Keil软件已经把所有这些声明都预先写好并保存到一个专门的文件中去了,用户只需要文件开头添加一行#include<reg52.h>
即可,这个在后边有用法详解。第二条语句是:sbit LED = P0^0;
这个 sbit,就是对刚才的 SFR 里边的 8 个开关其中的一个进行定义。经过上边第二条语句后,以后只要在程序里写 LED,就代表了 P0.0 口(“^”这个符号在数字键 6 上边),注意这个 P 必须大写,也就是说给 P0.0 又取了一个更形象的名字叫做 LED。
了解了这两个语句后,再来看一下单片机的特殊功能寄存器。请注意,每个型号的单片机都会配有生产厂商所编写的数据手册(Datasheet),STC89C52 的数据手册从 21 页到 24 页,全部是对特殊功能寄存器的介绍以及地址映射列表。用户在使用这个寄存器之前,必须对这个寄存器的地址进行说明。是不是花花绿绿的太多了记不住,这个没关系的,不需要记住,后边大部分都会解释,少部分需要用到的时候过来查手册就可以,再次强调做技术不是为了应付考试,可以随时翻阅手册查找需要的资料。如图 2-7,是截取的手册中第 22 页最下边的一个表格。
来看一下这个表,其中 STC89C52RC 的 P4 口对标准 51 的扩展,先忽略它,只看前边的P0、P1、P2、P3 这 4 个,每个 P 口本身又有 8 个控制端口。可以结合 Kingst51 开发板原理图或者图 2-1 来看,那么这样就确定了单片机一共有 32 个 I/O 口(I/O,Input 和 Output,分别是输入和输出)。其中 P0 口所在的地址是 0x80,一共有从 7 到 0 这 8 个 I/O 口控制位,后边有个 Reset Value(复位值),这个很重要,是看寄存器必看的一个参数,8 个控制位复位值全部都是 1。这就是告诉用户,每当单片机上电复位的时候,所有的引脚的值默认是都是 1,即高电平,在设计电路的时候也要充分的考虑这个问题。前边那 2 条语句写 sfr
的时候,必须根据手册里的这个地址(Add)去写,写 sbit
的时候,就可以直接将一个字节其中某一位取出来。编程的时候,也有现成的写好寄存器地址的头文件,直接包含该头文件就可以了,不需要逐一去写了。
2.4.2 新建一个工程
对于单片机程序来说,每个功能程序都必须要有一个配套的工程(Project),即使是点亮 LED 这样简单的功能程序也不例外。因此首先要新建一个工程,打开 Keil 软件后,点击:Project-->New uVision Project...然后会出现一个新建工程的界面,如图 2-8 所示。
在计算机硬盘上建立一个 lesson2 的目录,然后把 LED 这个工程的路径指定到这里,这样方便今后管理程序,不同的功能程序放到不同的文件夹下,并且给这个工程起一个名字叫做 LED,软件会自动添加扩展名.uvproj,如图 2-9 所示。
点击“保存”按钮,工程会自动保存成 LED.uvproj 文件,下次要打开 LED 这个工程时,可以直接找到文件夹,双击这个.uvproj 文件就可以直接打开。保存之后会弹出一个对话框,这个对话框让用户选择单片机型号。因为 Keil 软件是外国人开发的,所以国内的 STC89C52 并没有上榜,但是只要选择同类型号就可以了。因为 51内核是由 Intel 公司创造的,所以这里直接选择 Intel 公司名下的 80/87C52 来代替,这个选项的选择对于后边的编程没有任何的不良影响。如图 2-10 所示
点击 OK 之后,会弹出一个对话框,如图 2-11 所示,每个工程都需要一段启动代码,如果点“否”按钮,编译器会自动处理这个问题,如果点“是”按钮,这部分代码会提供给用户,用户就可以按需要自己去处理这部分代码,那这部分代码在初学 51 的这段时间内,一般是不需要去修改的,但是随着技术的提高和知识的扩展,就有可能会需要了解这块内容,因此这个地方单击“是”按钮,让这段代码出现,但是暂时不需要修改它,大家知道这么回事就可以了。
这样工程就建立好了,如图 2-12 所示,如果点击 Target 1 左边的加号,会出现刚才加入的初始化文件 STARTUP.A51,这个先不管。
工程有了之后,要建立编写代码的文件,点击 File-->New,如图 2-13 所示,新建一个文件,也就是编写程序的平台。然后点 File-->Save 或者直接点击 Save 的快捷键,可以保存文件,保存时把它命名为 LED.c,这个地方必须加上.c,如果写汇编语言,这个地方的扩展名是.asm,头文件就是.h 等等,这里编写的是 C 语言程序,这个地方必须自己添加文件的扩展名.c,如图 2-14 所示。
现在就可以在已经建立好的文件中输入程序代码了,在编写之前还有个工作要做,每做一个功能程序,必须要新建一个工程,一个工程代表了单片机要实现的一个功能。但是一个工程有时可以把程序分多个文件写,所以每写一个文件,都要添加到所建立的工程中去,右键点 Source Group 1,点 Add Files to Group ‘Source Group 1’...,如图 2-15 所示。
在弹出的对话框中,单击 LED.c 选中它,然后点 Add,或者直接双击 LED.c 都可以将文件加入到这个工程下,然后单击 Close,关闭添加。这个时候会看到在 Source Group 1 下边又多了一个 LED.c 文件。
2.4.3 编写点亮小灯的程序
准备工作做了那么多,终于要编写程序代码了。如果学过 C 语言,应该很轻松的编程,如果没学过 C 语言也没关系,先照着抄,后边有针对一些 C 语言语法的讲解,多看几遍就懂了。
B站在在线视频教程:2-4编写点亮小灯的程序
#include <reg52.h>//包含特殊功能寄存器定义的头文件
sbit LED = P0^0;//位地址声明,注意:sbit必须小写、P大写!
void main() //任何一个程序都必须有且仅有一个main函数
{//{ } 是成对存在的,在这里表示函数的起始和结结束
}
先从程序语法上来分析一下。
1、
main
是主函数的函数名字,每一个 C 程序都必须有且仅有一个main
函数。
2、void
是函数的返回值类型,本程序没有返回值,用void
表示。
3、{}
在这里是函数开始和结束的标志,不可省略。
4、每条 C 语言语句以;
结束的。
逻辑上来看,程序这样写就可以了,但是在单片机实际应用中存在一个问题。比如程序空间可以容纳 100 行代码,但是实际的程序只用了 50 行代码,当运行完了 50 行,再继续运行时,第 51 行的程序不是用户的程序,而是不确定的未知内容,一旦执行下去程序就会出错从而可能导致单片机自动复位,所以通常在程序中加入一个死循环,让程序停留在所希望的这个状态下,不要乱运行,有以下两种写法可以参考:
参考程序一:
#include <reg52.h>
sbit LED = P0^0;
void main()
{
while(1)
{
LED = 0;
}
}
参考程序二:
#include <reg52.h>
sbit LED = P0^0;
void main()
{
LED = 0;
while(1);
}
程序一的功能是程序在反复不断的无限次执行LED = 0;
这条语句,而程序二的功能是执行一次,然后程序直接停留下来等待,相对程序一来说程序二更加简洁一些。针对于图 2-6,这个程序能够把小灯点亮,但是这个程序却点不亮 Kingst51 开发板上的小灯,这是为什么呢?这里就要培养一个意识,单片机编程实际上算是硬件底层驱动程序开发,这种程序的开发是离不开电路图的,必须根据电路图来进行程序的编写。如果电路板的电路图和图 2-6 一样的话,程序可以成功点亮小灯,但是如果不一样,就可能点不亮。开发板上还有一个 74HC138 作为 8 个 LED 小灯的总开关,而 P0.0
仅仅是个分开关。如同家里有一个供电总闸,然后每个电灯又有一个专门的分支开关。刚才的程序仅仅打开了那个电灯的分支开关,但是没有打开那个总电闸。所以程序需要加上这部分代码。因为这节课要介绍的内容比较多,所以 74HC138 的原理以及为什么要加额外的代码在下节课统一介绍,这节课直接加上这部分代码做一下功能演示。
#include <reg52.h> //包含特殊功能寄存器定义的头文件
sbit LED = P0^0; // 位地址声明,注意:sbit必须小写、 P大写!
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
void main()
{
ENLED = 0;
ADDR3 = 1;
ADDR2 = 1;
ADDR1 = 1;
ADDR0 = 0;
LED = 0; //点亮小灯
while (1); //程序停止在这里
}
为什么有的书上程序很简单就可以点亮小灯,这里却要麻烦一些呢?Kingst51 开发板虽然仅仅提供给大家简单学习使用,但是也是按照实际产品的开发模式去设计,所以综合考虑因素很多,学到后边就会明白它的设计价值了,这里只要跟着去做就可以,后续章节会慢慢理解其中的价值。程序编好了,要对程序进行编译,生成可以下载到单片机里的文件,在编译之前要勾选一个选项,Project-->Options for Target ‘Target1’...,或者直接点图 2-17 中红框内的快捷图标。
在弹出的对话框中,点击 Output 选项页,勾选其中的Create HEX File复选框,然后点 OK,如图 2-18 所示。
设置好以后,点击Project-->rebuild all target files
,或者点击图 2-19 中红框内的快捷图标,就可以对程序进行编译了。
编译完成后,在 Keil 下方的 Output 窗口会出现相应的提示,如图 2-20,这个窗口提供了编译完成后的信息,data=9.0,xdata=0 指的是本程序使用了单片机内部的 data 区域 RAM资源中的 9 个字节,xdata 区域的 RAM 使用为 0,data 和 xdata 是 51 单片机特定的内存区域划分,这两部分都属于 51 单片机的内存;code=29 的意思是使用了 8K 代码 Flash 资源中的29 个字节。当提示0 Error(s), 0 warning(s)表示程序没有错误和警告,就会出现creatinghex file from “LED”...,意思是从当前工程生成了一个 HEX 文件,要下载到单片机的就是这个 HEX 文件。如果出现有错误和警告提示的话,Error 和 warning 不是 0,那么就要对程序进行检查,找出问题,解决好了再重新编译产生 HEX 才可以。
到此为止,程序就编译好了,下边就要把编译好的程序文件下载到单片机里了。
2.5 程序下载
首先连接好硬件,把板子插到计算机,打开设备管理器查看所使用的是哪个 COM 口,如图 2-21 所示,找到“USB-SERIAL CH340(COM5)”这一项,这里最后的数字就是开发板目前所使用的 COM 端口号(如果更换 USB 口,这个 COM 端口号会发生变化)。
STC 系列单片的下载软件——STC-ISP,如图 2-22 所示。
下载程序 5 个步骤:
第 1 步:芯片型号,选择 STC89C52RC 系列下的 STC89C52RC/LE52RC,一定不能选错。
第 2 步:扫描串口,根据查到的 COM 口选择,波特率使用默认的就行。
第 3 步:点击“打开程序文件”,找到刚才建立工程的 lesson2 文件夹,找到 LED.hex文件,点击打开。
第 4 步:这里的所有选项都使用默认设置,不要随便更改,有的选项改错了以后可能会产生麻烦。
第 5 步:STC 单片机要冷启动下载,就是先点下载,然后再给单片机上电,所以先关闭板子上的电源开关,然后点击“Download/下载”按钮后,软件信息框就会出现“检测目标单片机”的信息,如图 2-23 所示,再按下板子的电源开关,就可以将程序下载到单片机里边了。
当软件显示“操作成功”就表示程序下载成功了,如图 2-24 所示。
程序下载完毕后就会自动运行,这次在板子上看到那一排 LED 中最右侧的小灯已经发光了。如果把 LED = 0
改成 LED = 1
,再重新编译程序而后下载进去新的 HEX 文件,灯就会熄灭。至此,点亮一个 LED 的实验已经完成,终于迈出了第一步,是不是还挺好玩的呢?
2.6 练习题
1、了解普通发光二级管的参数,掌握限流电阻的计算方法。
2、理解单片机最小系统,单片机外围电路,Flash,RAM 和 SFR 等基本概念。
3、了解 Keil 的基本用法和单片机编程流程,能够独立完成编程下载等基本操作。