前言:
了解了前面篇章的内容,工程模板就不多赘述了,这篇就开始写51 单片机的第一个入门实验,点亮一颗LED。另外我是以购买的普中开发板进行学习写的笔记,所以本专栏就围绕的此开发板实验和分享,谢谢。
代码中引用头文件,其实际意义就是将这个头文件中的全部内容放到引用头文件的位置处,免去我们每次编写同类程序都要将头文件中的语句重复编写。
通常都是以 #include 预编译格式符引导 <头文件>,如:#include
在代码中加入头文件有两种书写方法,分别为 #include
主要区别:
①当使用 < > 包含头文件时,编译器先进入到软件安装文件夹处开始搜索这个头文件,也就KEILC51/C51/INC 这个文件夹下,如果这个文件夹没有引用的头文件,编译器将会报错。
②当使用 " " 包含头文件时,编译器先进入到当前工程所在文件夹处开始搜索该头文件,如果当前工程所在文件夹下没有该头文件,编译器将继续回到软件安装文件夹处搜索这个头文件,若找不到该头文件,编译器将报错。
我们如何查看头文件中存放的什么内容呢?以 “reg52.h” 为例,想打开该头文件查看其内容,只需要将鼠标移动到 reg52.h 上,单击右键,选择“Open document
以后若需打开工程中的其他头文件,也可采用这种方式,或者使用将工程编译后,通过右边工程组“+”下拉找到对应头文件双击打开的方法,同样可以查看头文件的内容。如图所示:
打开 “reg52.h”头文件,部分内容如图所示:
该头文件中定义了 52 系列单片机内部所有的功能寄存器,所以以后凡是编写 51 内核单片机程序时,我们再源代码的第一行就可以直接包含该头文件,直接调用进行操作即可。
头文件里的 sfr 和 sbit 这两个关键字,比如:“sfr P0=0x80;” 语句的意义是,把单片机内部地址 0x80 处的这个寄存器重新起名叫 P0,以后我们在程序中可直接操作 P0,就相当于直接对单片机内部的 0x80 地址处的寄存器进行操作。又比如:sbit CY=PSW^7;” 语句的意思是,将 PSW 这个寄存器的最高位重新命名为 CY,以后我们要单独操作 PSW 寄存器的最高位时,便可直接操作 CY,其他的定义都相仿如此。
开发板上 LED 模块电路原理图如下图所示:
看上图中 LED 采用共阳接法,D1-D8 连接到单片机的 P20-P27 口,即所有LED 阳极管脚接电源 VCC,阴极管脚通过一个 470 欧的限流电阻接到 P2 口上。根据前面篇章 LED 的介绍我们知道,要让 LED 发光即对应的阴极管脚应该为低电平,若为高电平则熄灭。
所以如果要想 51 单片机控制 LED,就必须通过单片机管脚在 P2 口上输出低电平。
实物图,如图所示:
实现的功能是:点亮 D1 指示灯,即让 P2.0 管脚输出一个低电平。
第一个程序很简单,我先贴代码如下:
//实验现象:下载程序后开发板的“LED 模块”D1 指示灯点亮/闪烁
//区别头文件< >和" "
//1.< >是优先从软件安装目录中搜索头文件的
//2." "是优先从当前工程中搜索头文件的
//#include
#include "reg52.h"
sbit LED1 = P2^0;//将 P2.0 管脚定义为 LED1
//LED1用户自定义变量名
//P2^0 指P2.0 --- D1的LED灯
//原理图LED端口对应 --- P2端口
void main()
{
LED1 = 0;//LED1 端口设置为0低电平,形成通路从而点亮一颗led
while(1)//死循环,兜圈子避免反复改写寄存器,减少资源小消耗
{
}
}
解释说明:
前面我们知道了头文件的重要性,所以开始直接调用声明头文件,然后就能使用 sbit 关键字来定义 P2.0 管脚,定义好后即可使用 LED1 来替代 P2.0口的操作。
(1)、LED用户自定义变量名
(2)、P2^0 指P2.0 — D1的LED灯
(3)、看原理图LED端口对应 — P2端口
(4)、sbit 位类型符用于定义在可位寻址字节或特殊功能寄存器中的位,定义时须指明其位地址,可以是位直接地址,可以是可位寻址变量带位号,也可以是特殊功能寄存器名带位号。
格式如下:
sbit 位变量名 = 位地址;
然后经过前面原理图的分析,我们主函数中,只需要将刚定义的LED1端口拉低即可,也就是置逻辑‘0’,即低电平,与阳极的高电平达成通路,同时也满足发光二极管的特性单向导通,从而成功点亮。
那么此时已经按照分析来说已经能够完成点亮一颗LED了,那么为什么主函数中还会继续写一个while(1)
死循环呢?
主要有以下两个方面的原因:
(1)、因为当我们只操作寄存器使P2.0端口拉低时,程序总是从主函数mian开始执行,达成的始终点亮LED,但是在单片机的内部其实是随着程序重复的开始和结束,反复的在调用寄存器改写端口的电平信号,所以相比之下就造成了内存等资源的消耗或功耗浪费。
(2)、另外一个原因,就是由于我们是软硬件相互结合的使用,程序会下载到开发板的,要求同样是始终执行当前代码的内容,基本不会只要求执行一遍就不跑程序了。所以常常写入while(1)里面执行的。
所以,这里仅仅是点亮一颗LED,可以把控制语句放在 while 之前来执行,也可以写在循环内部都是可以的。
至此,整个程序就编写完成,我们编译一下,如下图所示:
可以看到没有错误,也没有警告,说明我们整个程序的编写没有什么大的问题。同理,想要点亮D1~D8任意一颗LED都是一样的道理。
从上图编译信息可以看出,我们的代码占用FLASH 大小为:code = 19 字节,所用的 SRAM 大小为:data = 9 个字节(9+0)。
这里解释一下,编译结果里面的几个数据的意义:
code:表示程序所占用 FLASH 的大小。
data:数据储存器内部 RAM 占用大小。
xdata:数据储存器外部 RAM 占用大小。
通过查看这些编译信息,就可以知道当前使用的 flash 和 sram 大小了。
一定要注意的是程序的大小不是.hex 文件的大小,而是编译后的 code 和 data 之和
写这篇文章记录作为自己学习的笔记,有错误的地方还请多多指教,谢谢阅读。