第三集 点亮第一颗LED
大家好,欢迎收看本系列视频的第三讲——8051U深度入门到32位51大型实战。上一讲我们介绍了硬件基础知识和软件安装。本讲将开始编写第一个程序,但在动手之前,需要先创建一个新工程。此过程分为三步:首先创建一个空工程,其次添加头文件,最后输入并编译源代码。怎么编译呢?我们将在软件中找到两个图标,分别对应单个文件编译和所有文件编译。如果C文件只有一个,我们使用第一个选项;若C文件有多个,则选择第二个选项进行编译。
首先,我们将参照手册,实现6.5章节中新创建的空工程。现在,我们可以启动该软件。此时,可能会出现一些提示信息,但我们可以直接点击“确定”按钮。如果同学们之前已经运行过该软件或其它代码,可能会看到上一节课的代码,这没有关系,我们可以忽略这些代码。
第二步是打开手册,上节课我们是不是下载过这个手册?我们把手册放在左边,然后打开这个。我们先新建工程,怎么新建呢?我们可以按照手册6.5的章节,我们上节课也说过,下载一个PDF软件,可以在这个地方打开书签,然后我们直接选择6,选择6.5的部分,那我们直接打开,然后我们就可以把书签隐藏起来。好,我们看一下怎么样先6.5.1设置项目路径和项目名称,先点击project,然后选择new。好,这个时候它会提示我们选择一个路径,那我们路径选择今天的文件夹,文件名称叫demo,我们这里直接点保存,这样是不是新建就已经结束了?
首先,我们选择单片机型号。这里我们选择的是STC的MCU。尽管有多种选择,包括AI的不同型号,但它们都来自同一家公司。接下来,我们从AI中选择一个单片机,具体型号为STC8051U 32-bit。选择这个型号后,我们无需关注其他细节,只需直接选择对应的型号。点击确定后,新工程即被创建。此时,系统提示我们添加源代码到项目文件。我们首先新建一个源文件,点击界面中的小白纸图标即可实现。然后,我们将源文件保存至刚生成的目录中,命名为main.c。对于新工程,我们通常将第一个文件命名为main.c,因为函数或工程的入口是从main函数开始的,因此我们直接选择它。
可以看到我们这里main.c文件已经新建好了,但是文件里面还是空白的。我们可以先不管它,按照它的右键对吧?它可以选择双击add的图标,那我们可以忽略,我们也可以有别的办法,我们直接双击就可以打开,然后找到这个main.c再双击,再点击add。可以看到这个地方就已经被添加进来了。
添加完项目后,工程创建似乎已经完成。然而,工程创建后,我们还需要对其进行一些设置。在“设置项目”中,当看到CPU mode提示时,我们可以发现有选项。那么我们应该如何选择呢?参考提示,我们应该选择Source 251,因为80251的指令有这两种,而AR8051U目前仅支持其中一种。因此,我们直接选择这一种。按照提示选择后,它还提示我们是否要勾选4 byte选项,为什么呢?这是因为该选项对应的是四字节,我们后面会讲到。在这里我们先给它勾上6.5.4,我们已经结束了。
6.5.5这里展示了下拉模式的选择,我们选择了x small。好,这个也选好了。下一部分介绍了不同模式之间的区别。对于新工程,建议直接采用手册中默认的配置。后续如有需要,再回顾相关内容。
继续看下一个,我们再看第三个设置,设置项目3,这里选择的是large 64K。我们已经选好,再来看这个地方。如果代码超过64K,我们则需要设置一下下方的地址。但在这个例子中,我们的代码并未达到64K,因此无需进行修改。
接下来,我们再次关注设置项,在“output”选项卡中,提示如果程序空间超过64K则必须选择“HEX 386”,64K以内可以选择“HEX 80”。我们直接选择“HEX 80”并勾选此选项,这样做的目的是为了生成烧写的HEX文件。如果不勾选此选项,程序将无法被下载至单片机。至此,一个新的工程已经完成。
第二步,添加头文件。在头文件中,我们可以看到提示信息,建议使用ISP软件结合手册的6.4章节。首先,查看手册中的6.4部分,通过点击书签并选择6.4直接跳转,然后关闭书签。
这提示了我们头文件的一种使用方法。若要使用系统路径下的头文件,可使用尖括号。而如果要使用当前文件夹或自定义文件,应优先考虑采用双引号。
有哪两种方法可以使用头文件。我们推荐将所有需要用到的头文件放在自己的文件夹里。这样做可以避免在发送工程文件给他人时出现错误提示,因为这样做的工程文件更不容易出问题。否则可能会出现缺少头文件的提示。最简单的做法是将这些文件保存到项目文件夹中。这时,系统首先会在当前目录下查找所需的头文件,即C源文件所在的路径,然后去查找那个路径下的文件。
首先,我们需要将头文件放置到指定目录中。当前目录下尚未看到头文件,头文件通常以".h"为结尾。接下来,我们将打开ISP软件,STC公司开发的所有产品相关功能均在此软件中。通过软件,我们可以定位到头文件的位置。在软件中,我们可以看到AI8051U系列的32-bit头文件选项卡。选择 ".c" 格式的头文件,因为这是C语言的文件。
在保存文件时,我们通常会赋予什么名称呢?首先需要选择路径,刚刚说过,该路径位于文件夹的根目录下。文件名的确定方法是:以“AI8051.h”为基本名,通常以".h"结尾。头文件的名字一般与代码中的名字相同,例如“AI8051U”。这里再加个U,我们后面会讲到原因。保存后,我们可以到文件夹下查看,此时是否已经生成了这个头文件?
好的,有了这个头文件,我们就可以在代码中开始编写。可以看到输入如下代码。首先是一个井号#include,这是C语言中的一个关键词,用于包含头文件。后面跟随着AI8051U.h,这是我们之前保存的头文件,注意大小写的对应。接下来,我们再敲入一个万能公式,即void。
在该示例中,void表示空。通过这种方式,可以创建一个基础工程。在编写代码时,可能不会像我展示的这样,但当按下特定键后,此处会自动出现四个空格。这是如何实现的呢?实际上,只需按下键盘上的'tab'键即可实现自动缩进四格。如果软件刚安装时并未设置为四格缩进,该如何调整呢?在这种情况下,需点击软件界面中的扳手图标进行设置。选择C++,并将缩进值设置为4,这样就可以实现按下'tab'键后自动缩进四个空格的功能。此外,还可以在此对语言格式进行进一步的设计,例如选择汉字编码GB2312,以确保注释不会出现乱码。
什么样的?这是一个简单的设置。我们的代码已经编写完成,并且不会有问题。现在,让我们进行编译,可以看到编译结果显示没有错误和警告。我们刚才点击的编译,由于我们只有一个C文件,所以结果和耗时都是一样的,因为这个文件很小。
首先,我们需要解释一下什么是“最小的代码”。这涉及到调用头文件。在英文模式下,我们可以通过双击或者按下键盘上的反斜杠来实现。连续按两次会出现两条杠,随后这些杠会变为绿色,这表示我们已经进入了注释状态。在这里,我们正在对调用头文件进行注释。
头文件包含了什么内容呢?我们可以通过左键双击或右键点击open来查看,它主要包含了一系列的定义。这些定义对应于每个关键寄存器的地址等信息。在我们后续具体操作硬件时,会用到这些信息。新建工程时,必须包含头文件,否则我们将无法操作硬件。
我的意思是,这是一个主函数。当我们的工程创建并下载到单片机后,程序会首先找到这个函数,并从大括号开始执行。那和这个里面的V二有什么区别呢?区别在于,从大括号开始执行后,程序会持续执行直到大括号结束,不会跳出这个范围。这意味着,大括号内的代码只会执行一次。如果想要实现LED灯的闪烁效果,是不是就应该把闪烁的代码放在这里?而如果想让LED灯常亮,是不是只要写在这里即可?
这里有一个生动的例子:假设某处记载“张三打了李四一拳”,没有任何其他动作。这算什么呢?这可以被认为是张三的肇事罪,对吗?他打了人,所以就构成了犯罪。但如果记载的是“张三打了人”,而没有明确具体情节,这样的记录是否足以构成犯罪呢?
例如,如果李四攻击了张三,这算什么?这算两个人互殴。我们再看另一个例子,张三攻击了李四,而李四随后又对张三进行了多次攻击。尽管李四只对张三进行了一次攻击,但因为李四持续不断地攻击张三,大家都能理解,这已经构成了犯罪。
好的,这是一个简单的例子,旨在说明单片机程序中两个地方执行一次和多次执行的问题。至此,我们的工程已经顺利完成。现在,我们将编写第一个代码,目的是点亮开发板上的第一个LED灯。我们直接写出这个代码,并先观察其效果,之后再详细解释实现原理。首先,切换到大写P0M0等于0x00好,然后P0M1等于0X00好,因为头文件是一样的,函数也相同。然后在该位置新增了三句话,对吗?
这样是不是就结束了?让我们来解析这段代码。首先,每个语句都以分号作为结束标志,除非该语句是一个大括号,此时大括号本身即为结束。如果大括号后面跟有一个大括号,那么它也不需要分号。除了大括号外,每个语句后面都应该跟有一个分号。实际上,每个分号应独占一行,一个语句也应只占一行。因此,这段代码实际上只有四行。当然,若你愿意将这四行都写在一行中,虽然语法上不错误,但这样做并不美观,容易引发阅读者的不适。
我们的代码编写工作已经完成。接下来,点击编译按钮,我通常选择一次性编译所有文件。此时,系统提示成功创建了hex文件,并且在OBJ目录下也生成了相应的文件。下方显示没有错误和警告信息,这表明我们的代码编写工作是成功的。
我们直接下载程序。首先选择单片机,然后可以看到没有我们想要的HID writer的那个。按下板子上的P32按钮,再按一下off按键再松开,是不是就出现了这个下载选项。然后在这个地方打开程序文件,点亮第一个,我们刚刚提示这里在OBJ文件夹下,在这个文件夹下选择这个,看一下hex文件的修改日期,是22点51分,没问题。大家下载程序的时候尽量都去看一眼时间,否则可能辛苦写好的代码结果下载了一个错误的文件。然后在这个地方运行时钟,因为我们这里不需要用到时钟的一个概念,那我们这里随便选一个就默认这也行,好,我们直接点击下载。
下载成功后,我们打开摄像头进行测试。然而,设备并未启动。这是由于缺少了一行设置。我们只需添加这一行设置即可。
好的,这样一来,配置和赋值是不是就变得完全一样了?每行配置都经过编译。那么在本例中,因为我勾选了“当目标文件变化时,自动装载并发送下载命令”,所以当目标文件有变动时,系统会自动执行相应的操作。
为什么选择在这里停止呢?这是因为我们找不到指定的端口。我们再次按下按钮进行下载,然后查看头文件日期。正确,我们再次点击下载,接着检查摄像头,在我们这个地方需要对P40和P4进行修改。好的,我们重新编译并下载。重新进入下载模式,好的,开始下载编程。
经历了多次尝试后,这个灯终于亮了,是吧?数码管上的灯也亮了。在后续讲解数码管时,我们会解释为何这个灯已经亮了。这个灯是P00上的一个LED灯,现在我们放大来观察它,是不是LED00?它正是P00脚上的那个灯。因此,我们的代码已经实现了点亮第一颗LED灯的功能。现在,让我们分析为何我们的代码能够点亮这颗灯。
让我们再次查看PPT。大家是否做过这个实验?它展示了电池的连接方式:一节电池的电压为1.5伏,两节电池串联后电压为3伏。通过开关和LED灯,我们便可以实现LED灯的点亮。
那么,我们这个LED灯是如何点亮的呢?电流从电源正极流出,经过开关后流向LED灯,然后向下流到电源负极。在这个地方我们这个电源正极是3伏,我们用3伏来代替电源正极。那么在这一端用0伏来代替电源负极,只要给LED灯两端施加3伏电压,LED灯就能亮,对不对?
基于此原理,我们再来分析今天的实验。实验的等效电路图如下所示:这是一个电源,3.3伏电压经过三极管,它作为开关使用。Q2即为这个开关,下方的LED00是实验板上被点亮的灯,它位于P0.0端口,因此是一个LED。要使这盏灯亮起来,需要在该位置施加3.3伏电压并打开开关,同时在另一端接上0伏电压,最终实现LED灯点亮的效果。
那么,如何判断该开关是否导通或打开呢?我们注意到,指示箭头指向的是这里。有一个记忆小技巧是:电源从正极指向负极,即3.3伏指向0伏,意味着需要在这里添加一个令符,这样开关就能正常开启。这个也是一个速记的办法,大家可以看这个箭头的指向,从高电压指向低电压,3.3伏指向0伏就可以打开,只要给零它就能打开。
这就是我们今天实验的步骤。在P4.0这个端口输出0V,P0.0的这个端口也输出0V,就可以正常的点亮这一颗灯。在实验板上的蜂鸣器也是用的这个电路。是不是说我们像蜂鸣器的这个三极管,我们这里就要给高电平或者说给5或3.3伏,它才能正常打开。
进一步观察我们的单片机,发现其采用的是48脚的单片机,且编号最大为48。其中,0.0脚位于此处,而4.0脚则在这里。这意味着,通过控制特定引脚的信号输出,我们可以点亮今天的LED灯。
我们已经编写了代码,那么现在让我们回顾一下这段代码的具体含义。首先,我们需要配置一个IO口。单片机上有许多IO口,那么IO是什么意思呢?IO是GPIO的缩写,它代表着可以作为输入或输出的通用接口。其中,“I”代表“input”,“O”代表“output”,因此它具有输入输出功能。
我们将如何配置它以实现输入输出模式呢?可以看到,它有几种模式可以选择。当配置为00时,它是一个准双向口;配置为01时,它是一个推挽输出;配置为10时,它是一个高阻输入。那么这个配置要怎么配呢?实际上,我们只需要用到一个准双向口。传统的单片机在刚上电时默认为准双向口。而新型的单片机则通常设置为高阻输入。例如,这个新型单片机在上电后默认为高阻输入。
那么,如何配置呢?我们有PnM0和PnM1两种组合方式可供选择。通过查看它们对应的符号,例如P00,我们可以看到与P0M0、P0M1相对应的P00M0和P00M1,它们能够控制P00端口的模式。
我的目标是让P40和P00输出低电平。为了实现这一目标,我需要将P00的模式配置为准双向口,这意味着当写入0时,相应的引脚会输出低电平。由于P00端口有8个引脚,我们有8个LED要同时点亮,所以所有这些引脚都应配置为零。为什么这里写了八个0?这是因为这是二进制数,逢二进一,这八个就是全都是零,对不对?同样,下面的寄存器也全是零,为什么这里还有一个0X00呢?这是因为0X00是16进制的写法,前面加一个零X就是一个16进制。
好的,我们后面通过一个计算器再演示一下。现在,让我们来关注与IO相关的寄存器。我们即将用到的端口编号是00,对吗?因此,我们将P00设置为0,这是否就能向该端口输出一个0?这是因为它是二进制,每个小格子里面只有一个零或者一可以写入。也因为是二进制,这个端格子里只有零或者一,可以写0,也可以写一。那如果写了2,是不是就是进一了?逢二进一,这是二进制的基本原则,那么它就是往上这样子,这个是不是就瞬间可以理得通了。
需要理解的一点是,每个语句结束时必须添加分号,同时大括号应换行并缩进。再次检查代码,确保每个语句结束都有分号。大括号内需按压Enter实现缩进。例如,通过删除一个按压Enter的操作,是否可以实现自动缩进?回到这个代码上,为什么0X00代表八个0?
计算器功能在电脑上是预装的,点开更多里面有一个程序员。可以看一下这个hex就是16进制。DEC是十进制,还有这个是二进制,这是八进制,就是逢八进一,这个就是逢二进一。
观察这八个小格子,我们是否需要在每个格子中都写上00,因为似乎0无法直接输入。我将演示如何操作:首先输入数字1,然后在后面添加八个0。这样,是不是已经有八个零了?可以发现,每四个零对应一个16进制数的零,而八个零则对应16进制数的后两位零。这四位是对应16进制数的哪一位呢?
如果大家还未能完全理解,我们可以借助计算器来说明。在十六进制中,当我们写下两个零时,它代表的是两个独立的零。也就是说,如果这个地方全部填零,实际上写一个零即可。这一操作意味着我们将该端口模式寄存器配置为一个准双向口。
好的,如果已经讲到这里,大家心里是不是已经有数了?让我们再重新敲一遍代码,以加深大家的理解。首先,我们之前说过,编程时应该先搭建一个大的框架。比如,我们创建一个名为“void main”的文件,然后在其中写入一个word,接着按回车键,再输入一个大括号。完成大括号后,回到中间位置,按一下“Tab”键,代码会自动跳转到中间的“while”部分。
好的,接着是进入一个死循环,这表明初始化已经成功。我们需要为它设置P0端口,使其成为输出或准双向端口,即它可以同时进行输入和输出操作。那么,P4端口是否也应该设置为准双向口呢?我们如何编写相关代码?首先,将P0M0设置为0,对不对?好的,接下来,检查P0M1是否也为0。这样就将P0端口的八个端子都设置为准双向口。
我们如何理解这一点呢?通过软件可以找到相关说明。我们使用的封装脚位是48脚的单片机。打开详细信息,我们可以看到P0端口有PP00、P01、P02、P03、P04、P05、P06、P07、P0这些以“P0”打头的IO,共计八个。而P0M0则是将这八个端口均设置为输入输出口。同样地,P0M1也设置了所有端口为准双向口。在P0端口,也可以将其写作P00到P07为准双向口。通过这两个寄存器共同控制为准双向口。
好的,我们已经完成了P0端口的设置,接下来设置P4。P4等于,复制一行,M1等于0,这样是不是已经将P4口设置为准双向口?好,至此,所有设置已经完成。
在我们的程序中,为了点亮LED灯,我们之前提到需要给它一个三极管或者说开关,也就是P40输出一个低电平信号。因此,我们直接写P40=0,并添加注释以便于后期理解,P40端口输出低电平信号。
那么,P00端口是否也需要输出0伏?P00端口输出零伏,这样我们的代码是不是就完成了?为了使代码更易读,我们可以在按下table这些用户代码的时候,让每个注释都对齐,是不是形成了一段完整的代码。如果说这几行代码无论是在循环中执行还是在循环外执行,它们有什么区别吗?实际上没有区别,因为它们本质上都是让P00端口输出低电平,不需要切换电源,执行一次或无数次效果都是一样的。最后,我们再进行一次下载操作。
好的,我们再次操作,系统提示已进入下载模式。我们先手动进行操作,或者对代码进行修改。之前我们点亮的是P00,现在我们再尝试点亮P01。修改后的代码意味着当P40开关被打开时,P00和P01端口都将输出,即同时点亮。我们再次进行编译,编译完成后系统会自动下载代码。此时,打开摄像头查看情况,可以看到两个LED灯同时亮起。这就是我们今天实现的首个LED点亮效果。
课后大家也可以尝试一下,把我们这个板子上的八颗灯都点亮,看一下是什么样的效果。这节课即将结束,希望各位同学能熟练掌握并记住这一操作。
这是一个最简单且最通用的框架,上手基本都是从这个基础开始,然后往后增加代码。在此基础上,我们增加了初始化代码,是不是?这是P4,我们在这里设置端口模式。通常,如果大家的板子上没有什么影响,我们可以把所有的端口都写上,可以在这里查看它是否有P0、P4、P2、P5等端口。如果大家想要方便,可以一次性写上。一般情况下,作为准双向口,可以满足大多数应用需求。
许多人喜欢直接将所有端口设置为复制准双向口,即P0M1、P0M0、P1M1、PEM0等均设置为零。X00表示将每个端口设置为准双向口。在打开开关管之后,又打开了对应的LED端口,这便是我们最简单的代码实现。
我们已经讲解了它的原理。你可能会说,设置端口有点麻烦,不想自己设置。那有什么办法呢?STC公司早为大家想到了,我们有一个IO配置工具。比如你想设置P0端口为准双向口,只需勾选相应的选项,点击确认,它就会自动生成相应的默认配置代码,你只需点击复制。如果想设置P0端口为推挽输出,也只需点击选择,对应的模式就会自动生成在你的代码中。这就是我们IO的模式。
本节将首先介绍准双向口,之后再讲述其他相关内容。确认本节课没有遗漏的重要内容后,这节课就结束了。希望各位同学课后能自行巩固所学。再见。