[讨论] 第2/15原创:事无巨细,流水灯

losingamong   2010-3-11 12:30 楼主
事无巨细,流水灯简入
昨天写了GCC AVR的介绍,今天来做第一个同时也是最简单的实验:流水灯(又称跑马灯),是新手们为熟悉IO操作必做的第一个实验。
   顾名思义,流水灯,即像水一样流动的灯,这里的“灯”是指我们开发板上的发光二极管(LED),“流动”既是让它按一定规则依次点亮。所以这次的任务是:让数个发光二极管以一定规则依次点亮。
首先我们来看看CEPARK AVR开发板的LED显示部分:
11.jpg
显而易见,流水灯由5V驱动电源,跳线帽,限流排阻,八个LED以及连在LED负极的AVR的PB口构成,很简单的一个电路。
在此先把几个简单小知识点总结一下:
   1.在绝大部分的微控制器(MCU)以及数字逻辑器件应用中,5V电源恐怕是最常见的电源供应值了。包括我们熟悉的51单片机,LCD1602,大部分的LED,庞大的74系列IC都是5V供电。
  2.LED是灯,但它首先是个二极管,这表示它只在正向压降的情况下才有可能点亮,以上图为例,黑色三角形的尖端表示LED的负极,延伸到任何电路图都一样适用。正向压降即指LED正极的电压大于负极。
  3.排阻,一般是单列直插封装,即数个电阻的整合,有一个公共脚并且此脚对其他任意一脚直接的电阻都为某一额定值。
  4.1k限流电阻。它的作用是限制流过LED的电流,防止LED烧坏。可为什么是1K呢?大家都知道,功率器件都是有其指定的额定功率,额定电压,额定电流这些参数的,器件在这些参数下有最佳的工作效率。LED也不例外。LED一般有3V和5V供电两种,其工作电压和电流跟其大小,发光颜色等有关。
  这里我假设LED为3V工作电压,10mA工作电流(这些参数你可以在LED器件的数据手册上查阅,在此我只是假设),并且LED工作在额定电压和额定电流状态,那么限流电阻和LED是串联关系,所以加载在限流电阻上的电压应该是5-3=2V,电流是10mA,所以可以计算其阻值=2V/10mA=200欧姆。
  同样依据此思想,可以计算出CEPAR—K AVR开发板上的LED显示部分的限流电阻取1K时可以得到比较好的显示效果,同时不会严重影响LED的寿命。
   了解上述几点之后,点亮LED应该变得非常容易了。当单片机IO输出低电平,则LED承载正向压降,电流的路径为“5V驱动电源端——>限流电阻——>LED——>单片机IO”,LED即被点亮。值得一提的是,AVR单片机的IO口可以吸收大约20mA的电流,驱动能力要比51强了不少。
现在我们开始来编写流水灯的程序如下:
#include                 //IO操作头文件
#include            //延时函数头文件
#define uint unsigned int         
#define uchar unsigned char       //宏定义
uchar n;                                //定义全局变量
void init_portx(void);                //函数声明
int main(void)                    
{
    init_portx();                           //初始化子函数调用
    while(1)                  
    {
        for(n=0;n<8;n++)               //循环
        {
             PORTB=1<             _delay_ms(500);               //延时500ms
        }
    }
}
void init_portx(void)
{
     DDRB=0xff;                    //PB口方向寄存器,全部配置为输出模式
}
程序不长,短短26行,但是需要你有一点点C语言的基础才能看懂。
1.avr/io.h,util/delay.h都是GCC AVR本身自带的头文件,分别可以据此进行AVR的IO口操作和延时子函数调用。使用GCC AVR的朋友要逐渐熟悉各个常用的头文件。
2.AVR的IO口是标准的双向IO,即输出或者输入,需要配置方向寄存器来事先规定,DDRA,DDRB,DDRC和DDRD分别是4组IO的方向寄存器,都是八位,对应位置1则表示配置为输出状态,清0则表示输入状态。如DDRB=0xff这句语句则把PB口全部配置为输出状态。
3.标准C语言本身并不支持循环移位操作,只能通过移位符“<<”“>>”来进行左移和右移操作。比如0000 0001左移一位则变为0000 0010。注意,最高位丢弃,最低位补零,它是不带符号位的移位!右移类同。
4.延时程序的调用,_delay_ms(),经查看,头文件中的定义为_delay_ms(double ms),表示该函数的参数是double型的,即双精度浮点数,即保持小数点后两位。所以你可以填写位数为2位的小数比如_delay_ms(1.11)。这点也许很多人不曾意识到。
5.全局变量定义时默认赋初值0,但是局部变量(即在函数中定义的变量)定义时默认初值任意,所以定义局部变量一定要赋初值,这点要谨记。要养成给变量赋初值的习惯。
6.人的视觉停留时间大概是0.1秒,即100ms,所以如果延时太短,人眼是察觉不出来灯的“流动”的。
    程序的条理应该是比较清晰的,定义完全局变量,声明了函数之后,进入主函数,初始化端口,进入大循环,重复执行LED流动的for循环。
最后说说GCC AVR的一些特别的语法:
1.主函数要求返回值为int而不是一贯的void;
2.任何函数都要求填写形参,如果没有则要填void;
3.某些版本的GCC AVR,必须在最后添加一行空行,否则会出现警告(奇怪的现象);
希望能给需要的人一点帮助。

[ 本帖最后由 losingamong 于 2010-3-11 13:37 编辑 ]

回复评论 (4)

变量a好象没什么用啊
点赞  2010-3-11 12:56
嗯,调试程序的时候遗留的:L,改正
点赞  2010-3-11 13:37
引用: 原帖由 jxb01033016 于 2010-3-11 12:56 发表
变量a好象没什么用啊

哈哈哈,有我们的高手版主把关,帖子质量可有了个保证咯。
最好最后能给我们点评一下,
点赞  2010-3-12 17:23
很不错 .............
不断地学习,才会有创新! 淘宝小店:手机、qq点卡、游戏点卡自动充值 http://shop63727265.taobao.com/
点赞  2010-3-13 13:41
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复