打印
[AVR单片机]

动手学AVR单片机八、流水灯C语言程序讲解

[复制链接]
4491|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wangwo|  楼主 | 2009-12-20 22:37 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
上一讲我们对流水灯实验的电路实现和程序进行了分析,由于我们使用的是C语言编写AVR单片机程序,很多初学者对于怎样使用C语言来编写单片机程序有着很多迷惑,比如为什么PORTB = 0Xff这句话就能实现将单片机的PB口输出高电平。这一讲我们就来进行一下C语言编写AVR单片机程序的入门讲解。
我们还是先把上一讲的程序按行编号后进行分析讲解。


#include <avr/io.h>        //io端口寄存器配置文件,必须包含                                          1
#include <util/delay.h>       //GCC中的延时函数头文件                                                    2  
int main(void)            //GCC中main文件必须为返回整形值的函数,没有参数                  3
{
PORTB = 0Xff;         //PORTB输出高电平,使LED熄灭                                                 4
DDRB = 0XFF;           //配置端口PB全部为输出口                                                         5


while(1)                                                                                                                        6
{
  unsigned char Flow_LED,Delay500ms;     //定义流水灯循环次数以及延时时间变量         7     
  for(Flow_LED = 0;Flow_LED <= 7;Flow_LED++)  //流水灯从0-7总共循环8次                 8
  {   
   PORTB = 0xff & (~(1 << Flow_LED));         //每次循环中点亮一个LED                         9


   for(Delay500ms = 0;Delay500ms < 20;Delay500ms++)    //延时500ms                             10
   {
    _delay_ms(100);         //delay.h中的延时1ms函数                                                          11
   }
  }


}
}
AVR单片机C语言编程例子讲解
1、首先一个单片机的C语言程序框架如下:

//头文件包含(即预定义语句) #include<文件名> 或者#include"文件名"   ,<>和""的区别是程序在编译的时候搜  索头文件的路径不同,<>包含起来的文件先搜索编译软件安装目录下是否有这个文件,而""包含起来的文件则是先从我们编写程序存放的目录开始搜索,搜不到则再去搜索安装目录下的文件。习惯上我们在包含编译软件自带的头文件时使用<>,而包含我们自定义的头文件时使用"";

//全局变量定义,定义单片机程序中需要使用的全局变量,如果没有,这一块可以省略;
//函数声明            声明主函数中需要调用的子函数
主函数                格式为int main(void)  ,用 大括号{}把主函数的内容包含起来
{
局部变量定义       定义本函数中使用到的变量,没有可以省略
初始化代码          主要是对单片机上电后的端口,寄存器,以及变量进行初始化
while(1)                每个单片机C语言主程序必须包含一个死循环,用{}将循环体中需要执行的代码包括起来,
                            确保单片机程序能够一直执行
{

程序代码          需要循环执行的程序代码
}


函数定义          对函数声明中声明的函数进行定义,即定义函数需要实现的功能,编写相应程序代码


2、本程序的第一、第二两行是预定义语句,#include <文件名>的意思是包含(include的英文本意就是"包含")一个文件,通知编译器在编译程序的时候要将“我 ”这里包含的文件一起编译。io.h是GCC中对AVR单片机的各种寄存器进行标识的一个文件,主要是用一些含义明显的标识符来定义各种寄存器。delay.h是GCC编译器中定义的一些延时函数,有了这些延时函数我们就不必每次编写程序的时候都要自己辛苦的编写延时函数了,直接调用编译器定义好的延时函数即可。
3、PORTB = 0Xff;        DDRB = 0XFF;   这两句话是对寄存器进行赋值,其中PORTB和DDRB就是io.h头文件中定义好的寄存器标识符,我们直接使用就可以了(从这里可以看出预编译指令里包含的头文件的重要性),这里用到了标准C语言的两个知识:赋值表达式和赋值语句,赋值表达式与赋值语句的区别从程序里面来看就是赋值语句后面比赋值表达式多了一个“;”。用C语言编写AVR单片机程序的最主要内容其实就是使用赋值语句给各种寄存器赋值(给寄存器赋予不同的值将使单片机相应模块处于不同的工作状态),或者是读取各个寄存器的值(获得模块的工作状态等信息)。
4、unsigned char Flow_LED,Delay500ms;是变量的定义语句,由于是在函数内部,所以它们是局部变量,其实这个变量定义的位置有些不大规范,标准一点的做法是将这一语句放在程序的第四行之前。一般情况下局部变量的定义尽量放在一个函数的开始部分。局部变量定义的位置不同,它的作用域也就不同,关于变量的作用域请查看相关的C语言书籍。这里不作深究。变量是单片机程序中经常使用的。AVR单片机C语言中的变量与标准C语言的大致相同,但是需要提醒的是,在单片机中定义的变量应该避免使用实型变量,如果实在需要实型变量,应使用整形变量加小数点的方法。这样可以提高程序效率。
5、第8、9、10、11这几行包含了两个循环语句,单片机C语言中的循环语句的定义和使用与标准C语言中的循环语句的定义和使用相同。


以上我们分析完了流水灯C语言程序的总体结构和语句功能,在实际使用中不同的程序其结构一般不会脱离这个框架(函数声明和定义部分有的人喜欢不声明函数,直接在主函数之前定义子函数,但这种方法不直观,使程序的可读性变差,不提倡)。
新学AVR单片机C语言的时候会感到有些不知如何下手,其实这是很多人都会有的感觉,不必感到恐慌,我们可以先从最简单的程序入手,对照C语言教材,一行一行跟C语言对照,分清哪些是变量定义、预定义指令、赋值语句、选择语句、循环语句等,仔细分析几个程序后就会有豁然开朗的感觉了。

相关帖子

沙发
wangwo|  楼主 | 2009-12-20 22:38 | 只看该作者
本帖最后由 wangwo 于 2009-12-20 22:40 编辑

以下转贴一位高人对使用单片机C语言编程时需要从标准C语言中学习的知识,其实用C语言编写单片机程序时,用到的标准C语言知识是很少的一部分:
单片机 C 语言入门的一点体会(转帖)
单片机 C 语言入门的一点体会
一般的 C 语言教材中都具备以下几个章节,在刚刚开始学"单片机"的 C 语言时,我认为有些章节暂时不用学习:
1:C 语言的概述(学)
2:C 语言的绘图基础(暂时不用学习)
3:C 语言的数据类型(学)
4:C 语言的运算符、表达式、语句(学)
5:C语言的基本输入输出函数(就是printf之类函数,暂时不学也罢,因为这些函数的功能非常强大,这样也注定了它比较复杂,结果就是这些函数在单片机中占用资源非常恐怖,还不如自己编写)
6:顺序结构程序设计(学)
7:选择结构程序设计(学)
8:循环结构程序设计(学)
9:数组(学习一下一维数组就可以了,二维多维暂时不用学习
10:指针(一定要掌握,但是入门时也不必学习,就好像BASIC没有指针,但一样可以写程序)
11:函数(就是主函数,自定义函数之类,学)
12:预处理(学)
13:结构体与共用体(了解一下,暂时不用学习)
14:位运算(学)
15:文件操作(暂时不用学习)

使用特权

评论回复
板凳
linhai1986| | 2009-12-21 00:26 | 只看该作者
看看

使用特权

评论回复
地板
huamunv| | 2009-12-21 22:47 | 只看该作者
讲解不错

使用特权

评论回复
5
Karlshen| | 2009-12-25 11:54 | 只看该作者
多谢指教

使用特权

评论回复
6
wf395962475| | 2009-12-27 21:37 | 只看该作者
#include<reg52.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
void nilsd();
void zhengsr();
void delay(uint);
void main()
{  
    while(1)
     {delay(1000);
        zhengsr();
        delay(1000);
        nilsd();
        delay(1000);
      }
}
void zhengsr()
{   
               uint m=6;
        P1=0Xfe;
        while(m)
        {        delay(1000);
                P1=_crol_(P1,1);
                               delay(1000);
                                  m--;       
        }
}

void delay(uint z)
{
        uint x;
        uchar y;
        for(x=z;x>0;x--)
               for(y=110;y>0;y--);       
}
void nilsd()
{
               uint n=6;
        P1=0X7f;
        while(n)
        {
                delay(1000);
                P1=_cror_(P1,1);
                               delay(1000);  
                n--;       
        }
}
这个可以正逆点亮!先正后逆。已调试ok

使用特权

评论回复
7
laslison| | 2009-12-27 22:35 | 只看该作者
不错,值得一看

使用特权

评论回复
8
Karlshen| | 2009-12-29 22:49 | 只看该作者
很好,最近上了很多东西

使用特权

评论回复
9
潇湘小邪| | 2010-1-6 16:04 | 只看该作者
非常好的**,谢谢楼主

使用特权

评论回复
10
huamunv| | 2010-1-6 22:34 | 只看该作者
10楼给的小程序也不错嘛

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

99

主题

806

帖子

2

粉丝