在很多不同种类的单片机教程中都是以流水灯作为第一个实验的,最为突出的是在51单片机的教程中。这里也以它为例进行介绍。
流水灯程序用于实现对PD口下的8个LED灯进行操作:每500ms亮一个,当全部灯点亮后,每500ms灭一个,如此重复。这里还没接触到定时器的相关知识,因此可以使用库文件来实现延时500ms,不过由于该延时不是很准确,所以需要在代码工程中的2个地方做相应的设置:在源文件中添加#include<util/delay.h>;在工程选项中写入当前使用的晶振频率,如图3.2所示。图3.2中给出了一些重要信息,如工程所选择的器件型号“atmega88”,使用的晶振频率为“7372800”,优化级别默认为-0s。优化级别有以下几种。
(1) -00:无优化。
(2) -01:减少代码尺寸和执行时间,不进行需要大量编译时间的优化。
(3) -02:几乎执行所有优化,而不考虑代码大小和执行时间。
(4) -03:执行“-02”所有的优化及内联函数,重命名寄存器的优化。
(5) -0s:针对代码大小的优化,执行所有“-02”优化而不增加代码的大小。
开发时,应选择适合自己的一个优化级别。图3.2中框选标出的1~4这4个复选框的意义依次如下:
(1) 所有char认为是unsined char;
(2) 所有bitfields认为是unsigned;
(3) 定义结构体时,连续存储;
(4) 定义枚举类型时,使用最大需要的存储空间。
图3.2 工程选项
流水灯程序如下:
在这里有一个地方需要注意,就是_BV是在sfr_defs.h中定义的,其定义为#define_BV(bit)(1<<(bit))。当没有其他编译,而在移植时希望尽可能减少修改量时,就可以将该定义添加到代码中。
流水灯最早是用51单片机实现的,这里将其在AVR单片机上重现。由于没有实际的板子,故这里采用仿真软件来实现。
下面根据前面介绍的Proteus的运用,重新建立一个流水灯的工程。首先添加MCU、晶振、电阻、电压表和示波器。在这里,电压表用来查看引脚的电压,示波器用来观察各个引脚的延时。仿真电路如图3.3所示。注意:仿真电路跟实际电路是有区别的,如仿真电路中的晶振需要接2个匹配的负载电容。
图3.3 仿真电路
然后向MCU添加流水灯程序的可执行文件,并将晶振的频率设置为7.3728MHz,其他根据需要进行相应的设置。完成一系列设置后,单击界面右下角中的 ,开始仿真,如图3.4 所示。从图中可以看到电压表的值一直在变化(从0到3.3V变化),说明I/O端口在来回不停地被置高清零。还可以通过示波器来查看仿真结果。一个示波器只能有4个输入源,则8个I/O端口需要使用2个示波器。在仿真中选中示波器后单击鼠标右键,再单击“Digital Oscilloscope”,会弹出如图3.5所示的界面。
图3.4 仿真界面
图3.5 虚拟示波器界面1
在图3.5中显示出了4条不同颜色的线,黄色、蓝色、红色、绿色(从上到下)分别对应的是PD0、PD1、PD2和PD3。界面的右侧是示波器的相关设置,4个通道选择的都是DC源,电压单位是1V/格,扫描时间为50ms/格。将扫描时间调整为20ms/格,如图3.6所示,这样就比较容易看出延时的间隔。3.2.1节介绍的流水灯程序中实现的是500ms的间隔,而从图3.6中得到的只有40ms左右的一个间隔,与程序要求相差太多,但是在这里先不做调整,只是简单地给读者介绍一下这个可以用来测量程序中所要求的时序的工具而已。实际中也有类似的工具,可以用来代替示波器,如逻辑分析仪,其在价格和使用方面都是比较适合单片机工程师的。在程序运行过程中可以看到LED0~LED7不停地来回亮灭,这样流水灯便得以重现了。如果你手上有硬件调试板,则可以直接在板上运行以查看效果。
图3.6 虚拟示波器界面2