51单片机最小系统
今天我们开始进行51单片机编程学习,首先我们要了解一下单片机工作需要的基本条件。前面的内容中我们知道了51单片机的引脚有电源引脚,时钟引脚,控制引脚,以及通用输入输出端口。那要怎样才能让单片机工作呢?
如果将单片机与人类比,那它的电源就像人的心脏;时钟信号就像人的脉搏;控制引脚就如人的五官;通用端口就如人的四肢;芯片内部的控制逻辑就如我们的神经系统。这么说的话我们就很容易确定单片机的最小系统了吧。首先我们需要给单片机供电,再给他提供时钟,然后配置它的控制电路,最后给它的引脚接上一些外部电路,据此我们就可以绘制出下图这个最小系统电路了。
例程实图
以上最小系统电路图中使用的是89C51单片机,因为它的功能没有现在市场上具有更多拓展功能的增强版单片机那么多,我们就以C52单片机来进行实验。考虑到接下来我们需要讲解一些程序延伸内容,因此额外又添加了几个LED电路。
说到增强版51系单片机就再讲个题外话,现在的51内核单片机已经开发出了丰富的功能,以国产芯片厂商STC为例,他们开发出来多个系列的51型单片机,甚至有了32位的51内核单片机,内核时钟也提升到了最高72MHz,其他方面RAM,FLASH,电压参数等等,各种功能外设都更丰富了,看的出来他们的目标是在对标ARM内核(ARM是另一个概念,以后我们再详细讲解)的标准32位单片机,具体使用效果怎么样我没有做个测试,因为平时工作中没到这些单片机,以上信息是在他们官网看到的,大家有空或者需要下载资料可以前往看看:STC官网
看到他们的官网是不是感觉很魔幻,哈哈,有没有一种像传销网站的感觉?不过他这官网风格还真是十几年如一日(我不知道它之前不计),我大学期间刚学单片机那会它就是这种风格了,没想到我都成油腻阿叔了它还是这般婀娜多姿哈。或许网页设计者的目的就是想让人一看记终生吧,效果是非常不错,然后每次吐槽我就拿它开刷。
不得不说风格是真的太俗了,也不知道他们老板是怎么想的,估计他们公司内部人员都会吐槽吧
你搞简洁一点不行吗?随便看看别人国外大厂,做到世界前列也没哪家官网这么会夸自己呀,咋看这都不像太官网,就是一纯粹的pdf
先不吐槽了,槽点太多,图个乐子就行。
点亮一个灯的程序
我们先来看看这个最简单的例程之后我在具体解释程序功能:
#include
sbit led1 = P1^0;
void main()
{
led1 = 0;
}
可以看到程序内容是不是非常简单?就这么几行代码即可。
#include 这是单片机开发必须包含的头文件,它是KEIL公司自己编写的文件,里面包含对单片机特殊功能寄存器地址声明以及部分寄存器位的声明,搞不清楚的朋友可以打开该文件看一下。
以后的工作或学习过程中我们碰到的其他单片机在对其进行程序开发时都需要调用编译器平台对单片机基础声明的头文件。即现在我们使用keil编译器就使用他们提供的头文件,如果我们使用其他编译器平台,如IAR,则调用它们平台提供的头文件,不同平台编写的头文件是不一样的,使用这些头文件是保障程序功能正常的前提。
sbit led1 = P1^0; 这一句程序是使用单片机的位操作异或运算对单片机P1端口寄存器第一位进行声明,把它定义为一个叫led1的变量。如果是设置其他引脚也是以此类推。
void main() 就是我们之前说的主函数,注意不要写错了哟,否则你就不会得到想要的效果。
最后这句主函数中的内容led1 = 0; 就是我们需要的实现点灯的代码,它就是将刚刚声明的变量led1,即P1端口寄存器的第一位写入0,意思就是然他输出低电平。为什么这样就达到目的了呢?因为我们原理图中二极管的阴极接的是单片机,阳极接的是电源,所以要使LED发光,它阴极就必须是低电平,所以我们把对应的单片机引脚输出低电平他就可以点亮了。如果要把它熄灭那将他改成led1 = 1; 即对应的寄存器位被置位了,该引脚就会输出高电平,这时灯自然就灭了。
整个控制过程代码就讲解完了,是不是非常简单,很容易就能接受吧?如果还有问题的话自己一定要动手多试试,或者看看视频内容。
点亮一排灯
有了以上的基础讲解,可能有人就会问,如果要点亮一排灯呢?
是不是马上就有办法了,直接把前面的内容都重复一遍,想点亮哪个就控制哪个就行了。
#include
sbit led1 = P1^0;
sbit led2 = P1^1;
sbit led3 = P1^2;
sbit led4 = P1^3;
sbit led5 = P1^4;
sbit led6 = P1^5;
sbit led7 = P1^6;
sbit led8 = P1^7;
void main()
{
led1 = 0; led2 = 0;led3 = 0;led4 = 0;led5 = 0;led6 = 0;led7 = 0;led8 = 0;
}
这么看程序确实都很简单,但就是有点怪怪的吧,差不多的代码非要写那么多,即使复制,粘贴,修改起来也麻烦呀。有没有更好的办法呢,少写几行也行呀。办法当然是有的,只是理解起来就相对上面的难一点。
我们都知道P0P3这4个端口寄存器本来在reg52.h这个头文件中是定义好的呀,它本来就可以当做一个整体使用的吧。初学者可能不好理解这个意思,详细说明就是P0P3这4个端口寄存器都是8位寄存器,每个刚好是一个字节,每个字节上的07位也一一对应每组端口上的07位引脚,这也是我们上面使用异或运算来定义led1led8这些变量的初衷吧。那当我们使用多个引脚时,我们也可以直接对这个寄存器进行赋值的吧比如我们编写代码P1 = 0xf0;这样就可以对寄存器的所有位进行输出赋值了吧,上面代码中将0xf0由十六进制转化为二进制就是11110000B对应的就是将P1寄存器中高四位赋值1,低四位赋值0,那么此时P1端口信息就是P1.0P1.3输出低电平,对应的LED灯亮,P1.4~P1.7引脚输出高电平,对应的LED不亮。
这时我们输入如下代码:
#include
void main()
{
P1 = 0x00;
}
执行这段程序我们就可以点亮所有LED了吧。代码量瞬间少了很多了吧,是不是看起来更顺眼了
当然如果修改一下:P1 = 0xff;就是熄灭所有灯吧
如果修改成P1 = 1;那会变成什么结果呢?1是不是就是0x01这么转换就明白什么意思了吧,它对应的就是除P1.0外其他引脚对应的LED都点亮。其他情况当然也可以以此类推。后面我们的例程中会经常这样操作寄存器,并且还会涉及更多的编程技能。
思考:
P1 &= 0xf2;
P1 |= 0x23;
P1 ^= 0x8;
这几句是什么意思呢?
前面内容看懂的朋友这几句应该能够看懂是什么意思吧。