51单片机入门(3)点灯的进阶 |
您所在的位置:网站首页 › led灯c语言 › 51单片机入门(3)点灯的进阶 |
上一节我们学习了用51单片机点亮LED,这节我们继续围绕点灯进行进一步学习——实现跑马灯效果。 跑马灯的核心就是LED闪烁,要实现LED的闪烁,那就需要周期性地控制LED的亮和灭,而亮和灭的间隔如何实现呢?这就得用到延时了,本实验的延时采用阻塞式延时(让程序不停地执行空语句,空耗处理器的时间)。 文章目录 一、单个LED闪烁实验代码编译+烧录实验效果 二、LED跑马灯实验代码实验效果 三、其他花样灯流水灯呼吸灯 先简单介绍本文将用到的硬件及软件: 硬件平台:普中51开发板-单核A2 软件:Keil5(C51)、STC-ISP(或其他ISP软件)、Proteus8.9(用于仿真,非必须) 一、单个LED闪烁在介绍代码前,我们先来讨论延时的实现,在学习定时器之前,我们只能通过空语句的方法实现延时。接下来的内容十分枯燥,建议跳过,直接看实验代码。 我们先看看单行C代码(一行空语句)在51单片机里需要运行的时间: _nop延时这里就不讨论了,只讨论空语句 首先使用软件调试,在空语句之前程序运行时间为0.00019550(0.1955ms)【单片机从0s开始运行】; 运行完一行空语句,程序运行时长为:0.00020550(0.2055ms),和上一个状态相差0.01ms,也就是10us,所以理论上(由于这是软件仿真,所以只能得出理论值),我这个51单片机一行空语句耗时10us。
答案是可以实现,但时间可能并不准,网上给出的答案是(单片机中)C代码是不能实现准确延时的,只有汇编(如nop)和定时器可以,由于后两项本文暂不考虑,所以依旧使用C语言的空语句实现延时,毕竟现在不需要精准延时,同时我们也能了解一下空语句延时到底能有多大误差【这是我最感兴趣的】。 这里需要注意一点,51单片机的int类型只有2个字节,最大的数值为32767,如果用unsinged int,最大能使用65535,虽然可以用long类型(4字节),但网上说效率会降低,作为新手,我们还是保险点,尽量使用常用的类型,我就先用0.5秒做实验(50000行空语句) 同样,使用软件仿真查看,由于空语句前的运行时间和之前相同,所以我直接给出执行完50000行空语句后的运行时间,0.22529850(225.29850ms),与空语句前的运行时间的差值大约为225ms。 这和我们设想的0.5秒相差得太大了吧。其实这里我犯了一个错误-----细心的朋友会发现,之前我算的并不是空语句的运行时长,而是一个while(1--);运行的时长,即一个while语句再加一个空语句。
执行完22222行空语句循环后,运行时间为0.10024300(100.243ms),与空语句前的运行时间的差值大约为100ms。准度还行,至少ms级的延时是没问题的。 上面的调试都是使用Keil软件进行的,软件仿真往往只能作为参考,所以我们还需对开发板进行实测 就测试250ms延时吧,利用刚才得出的结果-----while(i--);每次循环运行耗时为4.5us(i不能太小,也不能超过65535)。 0.25s需要的循环空语句数量约为250*1000/4.5=55555(保留整数) 测试代码见下文,其实就是LED闪烁的实验代码。 实验代码在写代码前,我们需要先创建一个Keil工程,创建工程的步骤已经在第一节讲述,传送门:🚀(点我)。这里就不进行赘述。 #include //此文件中定义了单片机的一些特殊功能寄存器 sbit led_out = P2^0; //将单片机的P2.0端口定义为led /****************************************************************************** * @ 函数名 : main * @ 功 能 : 主函数 * @ 参 数 : 无 * @ 返回值 : 无 ******************************************************************************/ void main() { unsigned int t = 55555; //250ms,t较小时,延时单位为10us,t较大时,延时单位为4.5us unsigned int i = 0; while(1) { i = t; //250ms led_out = 0; //P2.0端口设置为低电平(点亮LED) while(i--){} //空语句循环 led_out = 1; //灯灭 i = t; //250ms while(i--){} //空语句循环 } } 编译+烧录程序编写完成后,接下来的操作就是编译+烧录了,这些步骤已经在本系列第一篇文章中讲述,传送门:🚀(点我)。不过这里还是会简单描述一下操作过程: 点击编译按钮,如果怕出现意外,可以点第三个(重新编译),编译完成后Build Output窗口会显示报错信息,如果没有错误和警告(如果这几行都有警告,那说明有问题),且生成了hex文件,说明编译成功。从LED闪烁的实验我们可以得知用C语言的空语句实现的延时是十分不准确的,但这些误差人眼并不能识别出来,所以本实验继续使用while循环实现延时。这次我就不进行软件仿真来调延时时间了,因为仿真的时间和真实时间相差太大。 根据上文的延时时间实测结果,空语句循环次数为55555时,延时时间大约为540ms,所以我们可以算出运行一次while(1--){}耗时约10us(这和第一次软件仿真的结果相同,奇怪了)。 同时为了提高代码简洁度,我把延时代码封装成了一个函数,这样重复调用时就更加方便了: /****************************************************************************** * @ 函数名 : Delay_10us * @ 功 能 : 10us粗略延时 * @ 参 数 : 延时时间--单位10us * @ 返回值 : 无 ******************************************************************************/ void Delay_10us(unsigned int time) { while(time--); }接下来就是实现跑马灯了: 跑马灯大家应该听说过,有些人喜欢叫流水灯,这里我不对它们进行区分,我要实现的就是8个LED依次亮灭,这就是核心原理了,直接上代码吧(下文)。 实验代码下面是跑马灯的完整代码 #include //此文件中定义了单片机的一些特殊功能寄存器 #define led_out P2 //将单片机的P2端口定义为led,8个IO /****************************************************************************** * @ 函数名 : Delay_10us * @ 功 能 : 10us粗略延时 * @ 参 数 : 延时时间--单位10us * @ 返回值 : 无 ******************************************************************************/ void Delay_10us(unsigned int time) { while(time--); } /****************************************************************************** * @ 函数名 : main * @ 功 能 : 主函数 * @ 参 数 : 无 * @ 返回值 : 无 ******************************************************************************/ void main() { unsigned char i = 0; unsigned int t = 0; led_out = 0xff; //8个灯全部灭 while(1) { for(i = 0; i while(time--); } /****************************************************************************** * @ 函数名 : main * @ 功 能 : 主函数 * @ 参 数 : 无 * @ 返回值 : 无 ******************************************************************************/ void main() { unsigned char i = 0; unsigned int t = 0; led_out = 0xff; //8个灯全部灭 while(1) { for(i = 0; i while(time--); } /****************************************************************************** * @ 函数名 : Adjust_Brightness * @ 功 能 : 调节8个LED的亮度(模拟PWN占空比控制) * @ 参 数 : brightness 亮度 0--100 * @ 返回值 : 无 * @ 备 注 : 一个模拟PWM周期为10*100us(1ms) ******************************************************************************/ void Adjust_Brightness(unsigned char brightness) { unsigned char low = brightness; //点亮时间 unsigned char high = 100 - brightness; //熄灭时间 led_out = 0x00; //点亮8个LED Delay_10us(low); //点亮延时 led_out = 0xff; //熄灭8个LED Delay_10us(high); //熄灭延时 } /****************************************************************************** * @ 函数名 : main * @ 功 能 : 主函数 * @ 参 数 : 无 * @ 返回值 : 无 ******************************************************************************/ void main() { unsigned int i = 0, cnt = 1000; led_out = 0xff; //8个灯全部灭 while(1) { /* 呼吸灯逐渐变亮,持续时间为1000*1ms */ for(i = 0; i Adjust_Brightness(i / 10); } } } 实际效果:(不用管数码管)如果文章对你有帮助,请留下你的点赞吧👍,这是我继续更新的最大动力🚀。 |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |