AVR单片机教程——流水灯

2019-12-03来源: eefocus关键字:AVR  单片机教程  流水灯

上次我们用 delay 函数与 while 循环实现了一个LED的闪烁。这一次我们把所有LED加入进来,让它们依次闪烁,形成流水灯的效果。


开发板上有4个LED,我们可以用不多的语句把循环体直接描述出来(看看就行,不用敲):


 1 led_set(LED_RED   , LED_ON);

 2 delay(250);

 3 led_set(LED_RED   , LED_OFF);

 4 led_set(LED_YELLOW, LED_ON);

 5 delay(250);

 6 led_set(LED_YELLOW, LED_OFF);

 7 led_set(LED_GREEN , LED_ON);

 8 delay(250);

 9 led_set(LED_GREEN , LED_OFF);

10 led_set(LED_BLUE  , LED_ON);

11 delay(250);

12 led_set(LED_BLUE  , LED_OFF);


但是如果LED多了怎么办?这样写一点都不优雅。一个更合理的方法是,用数组把LED存储起来,在无限循环中套循环,对LED进行遍历。代码如下:


 1 #include

 2 #include

 3 

 4 int main()

 5 {

 6     led_init();

 7     const uint8_t leds[LED_COUNT] = {LED_RED, LED_YELLOW, LED_GREEN, LED_BLUE};

 8     while (1)

 9     {

10         for (uint8_t i = 0; i < LED_COUNT; i++)

11         {

12             led_set(leds[i], LED_ON);

13             delay(250);

14             led_set(leds[i], LED_OFF);

15         }

16     }

17 }


在代码中,uint8_t 是一种无符号8位整数类型,定义在 中。相应地有 int8_t 表示带符号8位整数,以及 int16_t 、uint16_t 等,一直到64位。avr-gcc还提供了24位整型作为编译器扩展:__int24、 __uint24 ,但它们毕竟是编译器扩展,尽量别用;同时如果你的单片机程序中有16位整数搞不定的东西,那就应该考虑简化一下了。


我们用的单片机是8位机,指令只能处理8位整数,如果是16位,则需要多条指令进行组合。而C语言内置类型 int 在这个环境中是16位的。因此,为了节省空间、提升性能,当一个数可以用8位表示时,应该使用 int8_t 或 uint8_t 代替 int 。


讲了这么多,为什么LED可以用 uint8_t 表示呢?把光标移动到任一表示LED的宏上,右键,点击Goto Implementation,或按下快捷键Alt+G,你就能看到头文件中对这些宏的定义:


1 #define LED_RED    (uint8_t)(0)

2 #define LED_YELLOW (uint8_t)(1)

3 #define LED_GREEN  (uint8_t)(2)

4 #define LED_BLUE   (uint8_t)(3)


同时,led_set 等函数都接受 uint8_t 类型的参数表示LED:


1 void led_set(uint8_t _which, bool _on);

2 void led_flip(uint8_t _which);

这些都能说明为什么用 uint8_t 就能保存一个表示LED的宏。至于我为什么选择用 uint8_t ,当然是因为刚才说过的性能因素。


顺便,我们可以发现表示LED状态的宏本质上就是 true 和 false ,表示LED的宏就是简单的0、1、2、3,因此程序中可以不用数组来存储LED,也不再需要任何宏,并且 true 和 false 也很容易对应到灯的亮和暗上:


 1 #include

 2 

 3 int main(void)

 4 {

 5     led_init();

 6     uint8_t i = 0;

 7     while (1)

 8     {

 9         led_set(i % 4, true);

10         delay(250);

11         led_set(i % 4, false);

12         i++;

13     }

14 }


第一行包含了头文件 ee.h ,相当于包含了库中所有的头文件。


这样的程序是不是更好看一些?实际上 LED_RED 等宏的作用都只有让程序变得直观,如果直接用数字表示更方便,也完全没有问题。


这里还用到一个小技巧来消除内层循环:在循环外设一个变量,每次循环让它加1,传入的参数由它本身改为它对4的模。


你可能会想如果 i 过大了怎么办?当 i 等于255时, i++ 会让 i 变为0,而此时传入函数的参数还是从3回到0,符合控制逻辑。


为什么程序没有 #include 就能直接使用 true 和 false ?因为你包含的头文件中用到了它们,这个头文件必定或直接或间接地包含了标准库头文件,因此你就可以直接用了。


还有一个你可能疑惑的地方是,流水灯的逻辑本应是关闭上一个灯,打开下一个灯,然后延时一段时间,为什么在程序中是打开、延时,再关闭?想一想你会发现没什么不对,不过是把循环体的界限移动了一步。


实际上,如果按前一种逻辑来写程序的话,循环体得写成这样:


1 led_set((i + 3) % 4, false);

2 led_set(i % 4, true);

3 delay(250);

这样虽然逻辑也正确,但反而更难理解。


你也许还有疑问:把上一个灯关闭了以后,程序还要运行一会才能打开下一个灯,会不会看起来有一段时间是没有灯亮的?观察一下你的开发板,你就知道不会,原因也很简单,关灯和开灯之间的时间是微秒级的,人眼根本无法察觉。


除了上述实现,流水灯还有一种效果,就是灯依次亮起,再依次关闭。

关键字:AVR  单片机教程  流水灯 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic481808.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:AVR单片机教程——烧写HEX文件
下一篇:AVR单片机教程——闪烁LED

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

avr单片机功能特性介绍
RISC 优先选取使用频率最高的简单指令,避免复杂指令:并固定指令宽度,减少指令格式和寻址方式的种类,从而缩短指令周期,提高运行速度。由于 AVR 采用了 RISC 的这种结构,使AVR系列单片机都具备了1MIPS/MHz(百万条指令每秒/兆赫兹)的高速处理能力。早期单片机主要由于工艺及设计水平不高、功耗高和抗干扰性能差等原因,所以采取稳妥方案:即采用较高的分频系数对时钟分频,使得指令周期长,执行速度慢。以后的CMOS单片机虽然采用提高时钟频率和缩小分频系数等措施,但这种状态并未被彻底改观(51以及51兼容)。此间虽有某些精简指令集单片机(RISC)问世,但依然沿袭对时钟分频的作法。AVR单片机的推出,彻底打破这种旧设计格局,废除
发表于 2019-12-14
avr单片机功能特性介绍
avr单片机按键程序
  什么是avr单片机  AVR单片机是1997年由ATMEL公司研发出的增强型内置Flash的RISC(Reduced InstrucTIon Set CPU) 精简指令集高速8位单片机。可以广泛应用于计算机外部设备、工业实时控制、仪器仪表、通讯设备、家用电器等各个领域。AVR单片机是 Atmel 公司 1997 年推出的 RISC 单片机。RISC(精简指令系统计算机)是相对于CISC(复杂指令系统计算机)而言的。RISC 并非只是简单地去减少指令,而是通过使计算机的结构更加简单合理而提高运算速度的。  RISC 优先选取使用频率最高的简单指令,避免复杂指令:并固定指令宽度,减少指令格式和寻址方式的种类,从而缩短指令周期,提高
发表于 2019-12-14
avr单片机按键程序
三分钟告诉你:AVR单片机的熔丝与解锁
AVR单片机的熔丝位配置是AVR单片机初学者很容易出错的地方,其实只要注意一些事项,还是能够尽量避免单片机被锁死,即使单片机被锁死,也可以使用一些方法解锁,本文讲述我在刚开始接触AVR单片机时熔丝位配置出现的一些问题。1、AVR单片机的熔丝位是比较独到的特征,可以控制系统的时钟,JTAG调试、看门狗、芯片加密等等。图1是progisp软件,对于初学者来说,对熔丝位不熟悉,可以先将2处的编程熔丝对勾去掉,这样在编程的时候,就不会对熔丝位进行编程,单片机出厂的默认设置就可以使用。点击1处进入熔丝位配置界面。图1图2为位配置方式,这里的每一位都不能随意点击,尤其是熔丝低位控制时钟的地方,一般来说,直接对位进行配置并不安全,一定要确定是
发表于 2019-12-14
三分钟告诉你:AVR单片机的熔丝与解锁
avr单片机和stm32区别与优缺点分析
  摘要:avr单片机和stm32单片机是目前使用较广泛的单片机,那么avr单片机和stm32单片机有什么区别呢?有什么优劣势呢?  一、AVR单片机介绍  AVR单片机是1997年由ATMEL公司研发出的增强型内置Flash的RISC(Reduced InstrucTIon Set CPU) 精简指令集高速8位单片机。可以广泛应用于计算机外部设备、工业实时控制、仪器仪表、通讯设备、家用电器等各个领域。  avr单片机特点:  1. avr系列没有类似累加器A的结构,它主要是通过R16~R31寄存器来实现A的功能。在avr中,没有像51系列的数据指针DPTR,而是由X(由 R26、R27组成)、Y(由R28、R29组成)、Z
发表于 2019-12-14
AVR系列单片机的主要特性及选型
AVR单片机是ATMEL公司研制开发的一种新型单片机,它与51单片机、PIC单片机相比具有一系列的优点:在相同的系统时钟下AVR运行速度最快;芯片内部的Flsah、EEPROM、SRAM容量较大;所有型号的Flash、EEPROM都可以反复烧写、全部支持在线编程烧写(ISP);多种频率的内部RC振荡器、上电自动复位、看门狗、启动延时等功能,零外围电路也可以工作;每个IO口都可以以推换驱动的方式输出高、低电平,驱动能力强;内部资源丰富,一般都集成AD、DA模数器;PWM;SPI、USART、TWI、I2C通信口;丰富的中断源等。目前支持AVR单片机编译器的语言主要有汇编语言、C语言、BASIC语言等。其中C编译器主要有
发表于 2019-12-14
AVR系列单片机的主要特性及选型
如何设计一个以AVR单片机为控制芯片的电子镇流器?
引言电子镇流器是新型节能产品,不仅能带动一些照明灯具,还可以和一些紫外灯结合在一起,对于空气净化和水源净化都有着非常大的作用。当前,全世界都在大力提倡环境保护,电子镇流器间接地为环保提供了原动力。AVR单片机是一款性价比较高的单片机,用这种单片机来对电子镇流器进行调光和时间采样非常合适,首先是AVR单片机本身较稳定,抗干扰能力比较强,其次是其本身的Harvard结构使得运行速度比较快,数据回读时间较快,可以实现实时在线控制。1 AVR单片机介绍1.1 AVR单片机的特点与以往的8位单片机相比,AVR单片机采用Harvard结构,也就是程序总线和数据总线分开,并采用两级流水线,具备1MIPS/MHz的高速运行处理能力。片内集成多种
发表于 2019-12-14
如何设计一个以AVR单片机为控制芯片的电子镇流器?
小广播
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2019 EEWORLD.com.cn, Inc. All rights reserved