为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

3 让你的单片机眨眨眼睛

2011-06-13 21页 pdf 854KB 19阅读

用户头像

is_234021

暂无简介

举报
3 让你的单片机眨眨眼睛 AT89C51-Proteus仿真 老杨工作室 young45.cublog.cn 1 第 3章 让你的单片机眨眨眼睛 工具介绍过了,我们就要开始练习技术了。本章就引导大家真正的学习单片 机程序设计,用我们的单片机管理发光二极管的亮与灭。 3.1 我们的第一个单片机程序 3.1.1 先画出我们要用的电路 废话少说,我们先用学过的 Proteus画个要用的图出来。 第一步:运行我们的 Proteus ISIS; 第二步:用对象选择按钮 添加我们要用的单片机 AT89C51; 图 3-1...
3 让你的单片机眨眨眼睛
AT89C51-Proteus仿真 老杨工作室 young45.cublog.cn 1 第 3章 让你的单片机眨眨眼睛 工具介绍过了,我们就要开始练习技术了。本章就引导大家真正的学习单片 机程序设计,用我们的单片机管理发光二极管的亮与灭。 3.1 我们的第一个单片机程序 3.1.1 先画出我们要用的电路 废话少说,我们先用学过的 Proteus画个要用的图出来。 第一步:运行我们的 Proteus ISIS; 第二步:用对象选择按钮 添加我们要用的单片机 AT89C51; 图 3-1 选择芯片 AT89C51 还记得添加方法吧,在 Keywords 项输入关键字 AT89C,然后在 Results 列 中选择 AT89C51,点击 OK按钮就可以画图了。 第三步:用同样的方法添加其他器件:普通电容 CAP、电解电容 CAP-ELEC、 晶振 CRYSTAL、电阻 RES、发光二极管 LED-RED; 图 3-2 电路要用的器件 AT89C51-Proteus仿真 老杨工作室 young45.cublog.cn 2 第四步:用绘图工具栏的 按钮,在对象选择器窗口可以看到 POWER、 GROUND项,选择该项在图形编辑区添加; 图 3-3 添加电源和地 第五步:用导线连接电路; 图 3-4 用导线连接电路 注意:在连接电路时,可以选择元器件根据需要用鼠标拖动元器件到合适的 位置,也可以用鼠标右键旋转元器件到合适的方向,如图 3-5: AT89C51-Proteus仿真 老杨工作室 young45.cublog.cn 3 图 3-5 旋转选中的元器件 第六步:调整各个元器件的参数; 图 3-6 设置各元器件的参数 注意:其中晶振X1的参数是 12MHz,AT89C51的晶振频率也设定为 12MHz, 其他元器件参数如上图设置。 下面简单介绍一下我们画的电路: 图 3-7 电路划分 电路中共包括三部分:晶振电路、复位电路、发光电路,其中晶振电路的来 AT89C51-Proteus仿真 老杨工作室 young45.cublog.cn 4 源可以从 AT89C51 的数据上找到。有关 AT89C51 的数据手册下载可以到 www.21ic.com 网站或 ATmel 的官方网站 http://www2.atmel.com/上搜索,下面 我把数据手册中的相关贴出来比较一下: 图 3-8 AT89C51的晶振电路 看图 3-8可以发现,数据手册不但给出了电路的连接方式,还给出了电容参 数值的使用。 复位电路是根据 AT89C51 单片机内部的复位电路设计的。在 AT89C51 的 RST管脚上加两个机器周期以上的高电平,可以使其复位。简单一点的描述就是 把 RST管脚的电压拉高一定的时间可以使 AT89C51单片机复位,程序重新运行。 最后就是我们要用程序控制的电路了,根据发光二极管的特性,我们将二极 管的正极连接到电源,负极通过电阻连接到单片机的 P1.0 管脚,这样我们用程 序控制 P1.0管脚的电平变化就可以实现发光二极管的状态改变。 其实在 Proteus中晶振电路和复位电路都可以不画的,AT89C51的晶振频率 我们可以直接在其设置属性页中设定。因而电路可以简化为: AT89C51-Proteus仿真 老杨工作室 young45.cublog.cn 5 图 3-9 简化电路 电路画完后要注意保存,别发生意外丢失了。在后面的学习中,我们还要使 用该电路。 【附】在 21IC搜索数据手册的方法 进入 21IC的主页 www.21ic.com,在搜索条件中填写要搜索的元器件名称, 点击搜索按钮: 图 2-10 在 21IC搜索元器件 图 2-11 搜索结果 在搜索结果中,我们可以看到厂家的列表和 AT89C51 资料,我们可以在这 里下载 AT89C51 的资料;也可以在列表中看到芯片的提供厂商是 ATmel,我们 可以找到 ATmel公司的官网 www2.atmel.com,到其官网下载。学会看数据手册 对单片机开发来说非常重要,因而,我们要尝试着去看看 AT89C51的数据手册。 这里提到 21ic,不得不说两句外话,那就是 21ic的论坛 bbs.21ic.com和它 的站长“程序匠人”。21ic 的论坛是高手经常出没的地方,可以这里学很多书上 学不到的东西。站长“程序匠人”有本书很值得大家去看《匠人手记》,不过要 有一定开发基础才能读懂其中的精华。 3.1.2 用程序点亮我们的灯 AT89C51-Proteus仿真 老杨工作室 young45.cublog.cn 6 上面我们把要用到的电路实现了,接下来我们就写段程序来点亮我们的灯。 第一步:运行 Keil C51开发环境; 第二步:使用菜单 ProjectàNew Project新建一个工程; 图 3-12 选择芯片 新建工程时,系统提示保存位置,根据自己要保存的位置设置路径,我保存 的工程名是 Open_Led,接下来系统提示芯片选择,我们先在列表中找到 Atmel, 然后在它的子选项中找到 AT89C51,选择确定。 第三步:写程序,用菜单 FileàNew…建立代码文件; 第四步:编写代码; #include void main(void) { P1 &= 0xFE; while(1); } 第五步:用 FileàSave保存代码文件,我们保存为 main.c; 第六步:将 main.c添加到工程中; AT89C51-Proteus仿真 老杨工作室 young45.cublog.cn 7 图 3-13 添加文件到工程 选择左侧 Project Workspace列表中的 Source Group1文件夹,然后使用鼠标 右键点击该文件夹,弹出菜单如图 2-13所示。 第七步:设置工程; 图 3-14 设置工程菜单 设置工程时,要选择左侧 Project Workspace列表中的 Target 1文件夹,然后 使用右键弹出菜单或在 Project菜单中查找,如图 3-14所示。 图 3-15 设置工程属性页 修改 Target属性页的Xtal项为 12.0;选中Output属性页的 项; 设置 Debug属性页如下图: AT89C51-Proteus仿真 老杨工作室 young45.cublog.cn 8 图 3-16 Debug属性页 第八步:编译程序; 还记得怎么编译工程吧,用工具栏的 按钮(在 project 菜单中也可找到该 菜单项)编译整个工程。 如果编译失败,请仔细检测自己的代码,是否出现如下错误: Ø P1中的 P小写了(C语言是区分大小写的); Ø 是否漏掉“;”等其他语句不全的现象; Ø 是否使用了中文输入法,{}<>;等都要使用英文输入,否则会报错,这 是初学者最容易出现的错误。 完成以上工作,我们的准备工作就完成了,下面就要看运行结果和调试状态 了。 进入 Proteus集成环境,在我们前面设计的电路中设置AT89C51的运行程序: 图 3-17 设置运行程序 在 Program File项找到我们保存 Keil C51工程的位置,然后选择编译后的 Open_led.hex文件(根据你自己建的工程名找该文件)。 完成设置后,开始仿真,仿真时注意 R1的阻值是 300,其默认阻值是 10K, 如果没有修改,仿真时将看不到灯亮。看看我们的仿真结果: AT89C51-Proteus仿真 老杨工作室 young45.cublog.cn 9 图 3-18 仿真结果 完成仿真后,我们在 Proteus中停止仿真,返回到 Keil C51集成环境,进入 调试状态,使用按钮 先在代码中设置一个断点: 图 3-19 设置断点 然后使用调试按钮 开始调试: 图 3-20 程序停在断点处 程序在断点处 P1 &= 0xFE,停了下来(如果未运行到此处,可以使用调试 工具栏 的 run 按钮运行程序),这时看 Proteus 中的 电路,灯未被点亮,我们单步执行 ,程序跳到下一句,这时再看 Proteus中的 AT89C51-Proteus仿真 老杨工作室 young45.cublog.cn 10 发光二极管亮了。观察发现,就是语句 P1 &= 0xFE实现了点亮 Led的工作。 图 3-21 单步执行程序 到此为止,我们完成了自己的第一个单片机系统的设计、程序的编写、编译、 调试工作。怎么样,感觉很好玩吧! 3.1.3 分析代码 亲手做完实验了,满足了我们的好奇心,那我们就回头看看我们写的代码: #include void main(void) { P1 &= 0xFE; while(1); } 代码很少,除去括号,和 main函数的声明,仅仅三行代码。不过 main函数 的声明我还要说一句,为养成好的编程习惯,要在声明函数时注明返回值和参数 类型。 第一句#include 看起来也很面熟吧,在上一章我们学习 Keil C51 开发环境时,在例子程序里有句#include 。同样,reg51.h也在 Keil C51 的安装目录 C:\Keil\C51\INC 目录下,我们可以通过右键菜单 Open document 打开该文件。 图 3-22 Reg51.h部分代码 该文件和 Reg52.h一样,也是声明了一些寄存器和特殊寄存器的位,例如我 AT89C51-Proteus仿真 老杨工作室 young45.cublog.cn 11 们在代码中用的 P1就是在这里声明的:sfr P1 = 0x90。 接下来再说说 P1 &= 0xFE,P1也就是地址为 0x90的寄存器,该寄存器是 8 位寄存器,每位表示 AT89C51的 P1端口的各个管脚,最低位就代表 P1端口的 0管脚即 P1.0,我们在设计电路图时用的就是该端口。解释到这里就不用再说这 个&运算符了吧。 最后就是一个 while(1);语句,这个语句什么也不做,一个让单片机永远 在这里循环下去。这是单片机程序的特点,我们会在后面的练习中发现,每个例 子程序,我们在 main函数中都会找到 while语句的身影。 3.1.4 补充点发光二极管的知识 实验也动手做,程序也分析过了,我们接下来就看看我们用到的一个主要元 器件:发光二极管。 发光二极管英文名称是 light emitting diode简称 LED,由镓(Ga)与砷(AS)、 磷(P)的化合物制成的二极管,当电子与空穴复合时能辐射出可见光,因而可 以用来制成发光二极管。在电路及仪器中作为指示灯,或者组成文字或数字显示。 磷砷化镓二极管发红光,磷化镓二极管发绿光,碳化硅二极管发黄光。 下面我们就看看一些常见的发光二极管的图片: 图 3-23 常见发光二极管 发光二极管的反向击穿电压约 5伏。它的正向伏安特性曲线很陡,使用时必 须串联限流电阻以控制通过管子的电流。因而我们在电路中串联了一个 300欧姆 的电阻。 图 3-24 发光二极管的构造和电路符号 发光二极管的引脚有正负之分,通常支架式发光二极管的较长的那根引脚是 正极、较短的一根是负极,具体的还要看说明资料或加电测试。 AT89C51-Proteus仿真 老杨工作室 young45.cublog.cn 12 图 3-25 发光二极管的应用 最初 LED用作仪器仪表的指示光源,后来各种光色的 LED在交通信号灯和 大面积显示屏中得到了广泛应用,汽车信号灯也是 LED 光源应用的重要领域。 另外,LED 灯在室外红、绿、蓝全彩显示屏,匙扣式微型电筒等领域都得到了 应用。如今在家用液晶电视、液晶显示器、LED 投影仪中都有该技术的应用。 随着科学技术的发展,LED 的应用越来越广泛,我们千万不可小看这个小小的 发光二极管。 3.2 不仅仅是让它亮起来 我们完成了上一个实例的分析,也了解了一些 LED 的知识,那么我们能不 能写段代码,让 P1.0管脚上那个 LED像晚上的霓虹灯那样不断的闪烁呢? 3.2.1 怎么让发亮的灯闪闪呢 下面我们就用一段代码让我们的 LED 闪起来,直接在刚才的工程中修改 main.c文件: /**************************************************************** * 文件名:main.c * 说 明:实现 LED灯闪烁的效果 ****************************************************************/ #include //宏定义 #define uint unsigned int #define uchar unsigned char /****************************************************** * 函 数:延时函数,延时 timer毫秒 * 参 数:timer要延时的毫秒数 * 返回值:无 ******************************************************/ void delay_ms(uint timer) { uchar j = 0; while(timer--) { for(j = 124; j>0; j--) AT89C51-Proteus仿真 老杨工作室 young45.cublog.cn 13 { ; } } } /****************************************************** * 函 数:主函数,实现 LED的闪烁效果 * 参 数:空 * 返回值:无 ******************************************************/ void main(void) { while(1) { P1 &= 0xFE; delay_ms(100); P1 |= 0x01; delay_ms(100); } } 完成代码的编写工作,后面就是编译、仿真。 编译、仿真的过程我就不再重复了,和上面的例子一样。由于我们的代码是 在原有的工程中修改的,因而不需要再对 Keil C51 的工程再做设置,直接编译 就可以了;在 Proteus的电路中也不需要再对 AT89C51再做配置,直接仿真就可 以看到仿真结果,我们的灯忽明忽暗闪起来了! 3.2.2 代码分析 动手做完实验,我们就看看我们的这段代码。首先看到的是多了两行#define 语句,这是C语言中的宏定义语句,用uint表示unsigned int,用uchar表示unsigned char。因为在单片机编程中很少用有符号类型,多是无符号类型,为了后面书写 方便,这里我们就先声明一个宏定义。 看完宏定义,我们跳过 delay_ms函数,看主函数 main,主函数中的变化是 将 P1 &= 0xFE;放在 while(1)语句的括号里面了,后面跟了一个 delay_ms函数 的调用,对 P1做了第二次赋值 P1 |= 0x01;又一次调用了 delay_ms函数。 从函数的名字上我们可以理解 delay_ms 函数:延时一个毫秒,就是这个意 思,函数的参数刚好是要延时的毫秒数。这就要求我们在以后的程序设计中,在 定义函数和变量时要定义些有意义的名称,以方便程序的阅读。 主函数的意思就是先对 P1的 0管脚输出低电平,延时 100ms后再对该管脚 输出高电平,再延时 100毫秒,周而复始的做这个工作。这样我们就看到我们的 灯亮一下,再灭一下,达到了闪灯的效果。 分析完程序的工作流程,我们再分析一下函数 delay_ms: /****************************************************** * 函 数:延时函数,延时 timer毫秒 * 参 数:timer要延时的毫秒数 AT89C51-Proteus仿真 老杨工作室 young45.cublog.cn 14 * 返回值:无 ******************************************************/ void delay_ms(uint timer) { uchar j = 0; while(timer--) { for(j = 124; j>0; j--) { ; } } } 该函数用了两个循环语句,外部是 while(timer--)语句,内部是 for(j=124; j>0;j--)语句。 我们先分析 while(timer--)语句,想想这和 while(--timer)是不是一样呢? 用在这里区别就比较大了。while(timer--)是先判断 timer 的值是否为真(是 否非 0)再对 timer的值自减 1;而 while(--timer)是先对 timer的值自减 1,再判 断 timer的值是否为真。 别的值还都好说,这里就有个临界值的问题,如果 timer 的初值是 0,那区 别就大了。while(timer--)判断 timer 的值是 0 后就跳出循环了,也就是一次也不 执行;而 while(--timer)就不同了,timer是无符号整型,0-1=65535(Keil C51编译 环境中,int类型占两个字节),也就是要再循环 65535次,是不是区别很大呢! 接下来的 for语句,内部是个空语句,也就是要执行 124次循环,做这种空 操作,这是在单片机程序中经常用到的一种非精确延时的方法。但是我们为什么 要用 124这个值,而不用别的值呢? 3.2.3 调试分析 要分析这个值,我们就要用 Keil C51 的调试功能了,在调试之前,我们要 在程序中添加断点,也就是让程序运行到断点的地方停下了,方便我们查看我们 关心的值。添加断点的方法还记得吧:用工具栏的 按钮,或在程序中要添加断 点的行上直接双击鼠标左键。添加断点的位置如下图: AT89C51-Proteus仿真 老杨工作室 young45.cublog.cn 15 图 3-26 调试工程 接下来我们就用调试按钮 启动调试程序,这里说明一点,在调试程序时, 要在 Proteus中打开我们画的电路图,因为现在是和 Proteus联合调试的,否则会 报错。 启动调试状态后,程序自动运行到第一个断点处停了下来。这时我们在左侧 的 Protect Workspace列表中可以找到一项 Sysàsec我仿真的值是 0.000388998, 这是程序运行到此处所用的时间,单位是秒,也就是 0.389ms。我们全速运行程 序 让程序接着往下走,在一下个断点停下来,再看 sec 的值是 0.101107, 101.107-0.389=100.718ms,两个断点中间刚好是我们的调用函数 delay_ms(100), 也就是说我们的延时函数误差是 0.7%。 为了检验我们的设定值,我们可以在 delay_ms函数中修改 for语句中 j的初 始值,然后调试、仿真看延时时间的误差。 另外,我们再看看不同数据类型对我们程序运行效率的影响。修改 delay_ms 函数中变量 j的数据类型,修改为 uint类型,再调试观察延时时间,是不是在别 的语句都不变的情况下,时间变长了呢? 还有一点值得我们观察的,就是 delay_ms函数中的 while语句,我们修改为 for语句 for(;timer>0;timer--),从C语言的语句分析上看,这个语句和while(timer--) 所表达的意思是一样的。但是,我们调试观察时间会发现,延时函数延时的时间 变 小 了 , 而 且 小 了 很 多 , 在 我 机 子 上 仿 真 的 值 是 0.0264039 , 26.4039-0.389=26.0149ms和原来的 100.718比较一下,少了 74.7ms。会很惊讶吧! 我也很差异,不同的语句,Keil C51编译环境对其执行的效率相差是这么大。 一个小小的延时函数告诉我们,在写单片机程序的时候,如果能用 char 类 型的变量就不要用 int 类型的,我们要尽量提高程序执行的效率,减小程序所占 空间;在 Keil C51编译环境中用循环语句时尽量用 for语句,但在别的编译环境 中并没有发现该问题。 3.2.4 优化程序 上面对程序即做了实验,也分析了程序,下面我们就根据 AT89C51 单片机 的 P1寄存器可以按位设定的特性,优化一下程序: /**************************************************************** * 文件名:main.c * 说 明:实现 LED灯闪烁的效果 ****************************************************************/ #include //宏定义 #define uint unsigned int #define uchar unsigned char sbit LED = P1^0; /****************************************************** * 函 数:延时函数,延时 timer毫秒 AT89C51-Proteus仿真 老杨工作室 young45.cublog.cn 16 * 参 数:timer要延时的毫秒数 * 返回值:无 ******************************************************/ void delay_ms(uint timer) { uchar j = 0; while(timer--) { for(j = 124; j>0; j--) { ; } } } /****************************************************** * 函 数:主函数,实现 LED的闪烁效果 * 参 数:空 * 返回值:无 ******************************************************/ void main(void) { while(1) { LED = ~LED; delay_ms(100); } } 这段程序没什么特别,主要是简化了主函数中 while 语句的书写。其中 sbit LED = P1^0语句也比较熟悉了吧,在 reg51.h中有这种书写方式,这是对特殊寄 存器的位的声明方式,也就是将 P1的 0位声明为我们用的 LED。 3.3 做些程序的改动 3.3.1 改动延时时间 我们下面做点小小的修改,看我们的仿真结果会有什么变化。首先修改 main 函数的延时时间: void main(void) { while(1) { LED = 0; delay_ms(500); LED = 1; delay_ms(50); } AT89C51-Proteus仿真 老杨工作室 young45.cublog.cn 17 } 修改完成后,编译、仿真,观察 Proteus的仿真结果,会发现 LED灯不灭了, 但有点闪烁(如果不闪烁,也许和电脑的配置有关,可以修改第二个 delay_ms 的参数,使其尽量小)。我们进一步修改: void main(void) { while(1) { LED = 0; delay_ms(800); LED = 1; delay_ms(10); } } 再次编译、仿真会发现,LED 变的常亮了,也不闪烁了。这就是我们的眼 睛欺骗了我们,看到的不一定是真实的。其原理和放电影的原理是一样的,LED 短暂的熄灭有会有余晖,而我们的眼睛又有视觉暂留作用,因而我们看到的 LED 是常亮的。为什么我们要做这个实验呢?到下一章你就知道了。 3.3.2 做个众人皆知的跑马灯 学习完上面的单个灯闪烁的程序后,我们就学习一下跑马灯程序也叫流水 灯,这是几乎所有单片机入门者都必学的一个例子程序。和上面的例子一样,在 我们写代码之前先画电路图: 图 3-27 跑马灯电路图 这个电路图和第一个电路图有几点不同:其一是增加了灯的数量,其二是通 过电阻后不是接电源而是接地,发光二极管的正极接在 AT89C51的 P1端口上。 为什么可以这样接呢?那就要看看我们找到的 AT89C51的数据手册了: Port 1 Port 1 is an 8-bit bidirectional I/O port with internal pullups.The Port 1 output buffers can sink/source four TTL inputs.When 1s are written to Port 1 pins they are pulled high by the internal pullups and can be used as inputs. As inputs,Port 1 pins that are externally being pulled low will source current (I ) because of the internal AT89C51-Proteus仿真 老杨工作室 young45.cublog.cn 18 pullups. Port 1 also receives the low-order address bytes during Flash programming and verification. 将其翻译为中文意思就是: P1口: P1是一个带内部上拉电阻的 8位双向 I/O口,P1的输出缓冲级可驱动(吸 收或输出电流)4个 TTL逻辑门电路。对端口写“1”,通过内部的上拉电阻把端 口拉到高电平,此时可作输入口。作输入口使用时,因为内部存在上拉电阻,某 个引脚被外部信号拉低时会输出一个电流(IIL)。 FIash编程和程序校验期间,P1接收低 8位地址。 刚开始看英文数据手册可能不太习惯,可以找份中文的数据手册作参考,看的多了就 容易明白了,因为单片机的资料介绍也就那么多内容,只是各个单片机有各个的特点,但用 到的专业术语基本相同。而且很多芯片的数据手册都是英文的,没有中文版,所以我们要学 会看英文的数据手册。 因为 P1口有内部上拉电阻,所以我们这里可以这样连接电路。再去研读一 下数据手册,可以发现 P0 口是没有上拉电阻的,而 P1、P2、P3 口都有内部上 拉电阻,所以只有 P0口我们不能这样使用。 好了,电路图画完了,我们就写段程序来让跑马灯跑起来吧! /**************************************************************** * 文件名:main.c * 说 明:实现 P1端口的 8个 LED依次点亮,产生跑马灯的效果 ****************************************************************/ #include #include “main.h” #include “delay.h” void main(void) { uchar i = 0; while(1) { for(i=0; i<8; i++) { P1 = (1<0; j--) { ; } } } /**************************************************************** * 文件名:delay.h ****************************************************************/ #ifndef _DELAY_H #define _EDLAY_H void delay_ms(uint timer); #endif 先创建一个工程,选择芯片 AT89C51,命名为 Horse_led,然后创建 4个文 件:main.c、main.h、delay.c、delay.h,文件内容如上。 编写代码后就要设置工程,设置工程的 target、output、debug几个属性页, 设置晶振为 12MHz、输出 Hex文件、调试选择 proteus。具体设置方法在讲解工 具和第一个例子程序时已经讲过,可以参考设置。 接下来就是编译该工程了。编译无误后,进入 Proteus 集成环境,设置 AT89C51的属性,设置晶振为 12MHz,Program File为刚编译的 hex文件。然后 运行仿真看看仿真结果。 AT89C51-Proteus仿真 老杨工作室 young45.cublog.cn 20 做完实验,我们就要分析一下上面的程序了。这个程序段用到了以下: 头文件的引用、条件编译、程序模块化等。 先看看 main.c文件中对头文件的引用方式。#include 和#include “main.h”这是两种对头文件的引用方式,使用<>引用的头文件,编译器会先从 软件安装的文件夹开始搜索,及 Keil\C51\INC目录;而使用“”引用的头文件, 编译器会先从工程所在的文件夹开始搜索,找不到该文件会自动到软件安装的目 录搜索。但在 Keil C51中兼容这两种写法,写哪种引用方式编译器都可以编译 通过,但根据编程习惯,我们还是沿用引用库文件时,使用<>的引用方式;引用 我们自己写的头文件时,用“”的引用方式。 再看看条件编译语句,每个头文件中都使用了#ifdef…#define…#endif的 语句,该语句是条件编译语句,其功能是防止重复引用。 最后要说的就是程序的模块化了,这里我们不仅把程序分解为函数,而且还 将函数放在不同的文件中,这样的好处是,我们可以复用代码。例如,在后面再 次用到 delay_ms函数时,直接将 delay.h、delay.c拷贝到该工程中,然后在要 用的文件中引用 delay.h文件,直接调用 delay_ms函数就可以了。而且也方便 管理和代码的阅读,如果是代码量大的复杂工程,我们根据函数类型分为不同的 文件,这样,我们管理起来很方便,阅读时也很清晰。 在以后的程序编写过程中,我们要养成良好的习惯,多写注释语句,将程序 模块化,定义函数、变量要有意义,方便自己以后阅读,也方便别人阅读理解。 3.4 能不能连点花样呢 3.4.1想想你能画什么 想想看,你能用发光二极管模拟什么呢?我想到的是连接个数字出来,我们 用 7个 LED表示 7段显示,表示数字的 7个段。下面我们就根据自己的想想来 画电路: 图 3-28 模拟的数字 电路根据自己的想想来画,我只是给出一个建议图,你也许会画出比我的更 好像数字的电路来。 3.4.2 用代码显示数字 电路设计完了,我们就考虑怎么样用程序去实现我们要显示的数字 0、1、2、 3等。考虑一下,是不是很简单呢,其实就是根据数字要显示的段,我们将需要 点亮的 LED点亮,其他 LED不点亮就可以了。 /**************************************************************** AT89C51-Proteus仿真 老杨工作室 young45.cublog.cn 21 * 文件名:main.c * 说 明:实现 P1端口控制 7个 LED,显示 0、1、2、3三个数字 ****************************************************************/ #include #include “main.h” #include “delay.h” void main(void) { while(1) { P1 = 0x04; delay_ms(800); P1 = 0x6D; delay_ms(800); P1 = 0x18; delay_ms(800); P1 = 0x48; delay_ms(800); } } 我们就以数字 0为例说明代码,要想显示数字 0,我们就要控制电路使中间 那个 LED不亮,而其他 6个 LED都点亮。根据电路的画法,中间的 LED是由 P1.2控制的,而要控制该 LED不亮就要在该管脚输出高电平,其余输出低电平, 因而我们写为P1 = 0x04。分析过数字 0的原理,我想你也就明白 1、2、3的显 示原理了吧。同样的道理你还可以扩展到数字 9的显示。 做完这些实验,感觉很好玩吧。其实在 LED 的应用上我们还有很多可以模 拟。例如你可以用红、绿、蓝三色 LED模拟交通灯的程序,可以从简单的入手, 开始就用 P1.0、P1.1、P1.2连接三个颜色的 LED灯,然后让其按不同的时间亮; 要注意,其中黄灯亮的时间比较短;做完简单的实验,可以仿真丁子路口交通灯 的实验,用三组三色 LED灯实现,也就是 9可 LED灯来实现。 怎么样,是不是会有更多的想法呢?到这里可以先休息一下了,下一章我们 会讲真正的数码管显示数字。
/
本文档为【3 让你的单片机眨眨眼睛】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
热门搜索

历史搜索

    清空历史搜索