原创 AVR学习记录和例子

2009-6-4 11:40 2907 7 7 分类: MCU/ 嵌入式

 AVR单片机学习的点点滴滴,下来很大决心才开始学AVR单片机,在网络上找了很多书籍、例程,也购买了前段时间比较热门的书籍《深入浅出AVR单片机》,也许是自己天生不如人吧,还是不得要领。只能自己厚着薄脸请教同事。方得点点。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


根据其意。就是要程序模块化设计,将一个大的程序按功能分割成一些小模块, 特点: 各模块相对独立,功能单一,结构清晰,接口简单 控制了程序设计的复杂性 提高元件的可靠性 缩短开发周期 避免程序开发的重复劳动 易于维护和功能扩充 开发方法: 自上向下,逐步分解。


   MEGA32ICCV7 for AVR为工具,并把学习的过程记录下来。MEGA32是一款比较常用的AVR单片机。


                               例子一: 建立总模板


打开ICCV7 for AVR,新建工程。在工程里添加main.c,main.h两个总工程文件。其中main.c为所有程序汇总。main.h汇总总工程的头文件。在.h头文件中加入#ifndef __systen_h #define __systen_h是为了避免重复编译。


如下:


///////////////////////////////////////////////////////////


Main.c


/////////////////////////////////////////////////////////////


#include "main.h"  //包含总头文件
void main(void)
{
    init_devices(); //AVR
硬件初始化
    while (1)        //
循环
    {
        led_light();   
       led_disp( );
    }
}


////////////////////////////////////////////////////////////////


main.h


/////////////////////////////////////////////////////////////////


#ifndef __systen_h


#define __systen_h


/*********************************************/


#define M8    1


#define M16   2


#define M32   3


#define M64   4


#define M128  5


/*********************************************/


#define CPU_TYPE  M32


 


//定义MCU时钟频率


//#define F_CPU 14745600


#define F_CPU 7372800


//**************************************************


//包含系统头文件,请根据实际需要进行裁减


//**************************************************


//#pragma REGPARMS


#if CPU_TYPE == M128


#include <iom128v.h>


#endif


#if CPU_TYPE == M64


#include <iom64v.h>


#endif


#if CPU_TYPE == M32


#include <iom32v.h>


#endif


#if CPU_TYPE == M16


#include <iom16v.h>


#endif


#if CPU_TYPE == M8


#include <iom8v.h>


#endif


//#include <intrins.h>


//#include <absacc.h>


//#include <string.h>


//#include <FLOAT.H>


//#include <math.h>


//#include <stdlib.h>


#include <macros.h>


//#include <eeprom.h>


//#define const code


 


//**************************************************


//系统数据类型定义


//**************************************************


#ifndef TRUE


#define TRUE  1


#endif


#ifndef FALSE


#define FALSE 0


#endif


#ifndef NULL


#define NULL 0


#endif


#define MIN(a,b)                 ((a<b)?(a)b))


#define MAX(a,b)                ((a>b)?(a)b))


#define ABS(x)                            ((x>0)?(x)-x))


typedef unsigned char  uint8;                                   /* 定义可移植的无符号8位整数关键字            */


typedef signed   char  int8;                                    /* 定义可移植的有符号8位整数关键字            */


typedef unsigned int   uint16;                                  /* 定义可移植的无符号16位整数关键字           */


typedef signed   int   int16;                                   /* 定义可移植的有符号16位整数关键字           */


typedef unsigned long  uint32;                                  /* 定义可移植的无符号32位整数关键字           */


typedef signed   long  int32;                                   /* 定义可移植的有符号32位整数关键字           */


 


//**************************************************


//包含工程头文件,请根据需要进行裁减


//**************************************************


#include "devices.h"


#include "led.h"


 


//**************************************************


//一下为工程变量、端口定义


//**************************************************


 


/********************************/


/*     "以下为工程配置"         */


/********************************/


 


#endif


 


 


/**********************end****************************************/


例子二  软件延时


建立软件延时delay.c,delay.h并加到工程中。


///////////////////////////////////////////////////////////////////////////////////////


delay.c


///////////////////////////////////////////////////////////////////////////////////////


#include "main.h"


//1us


extern void delay_us(uint8 u)


{


    uint8 i;


    for (i=177;u!=0;u--)


    {


        while (i--);


    }


}


//1ms


extern void delay_ms(uint<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />16 m)


{


    for (;m!=0;m--)


    {


        delay_us(10);


    }


}


//1s


extern void delay_s(uint16 s)


{


    s=s*40;


    for (;s!=0;s--)


    {


        delay_ms(100);


    }


}


////////////////////////////////////////////////////////////////////////////////////////////


delay.h


/////////////////////////////////////////////////////////////////////////////////////////////


#ifndef __delay_h


#define __delay_h


//1us


extern void delay_us(uint8 u);


//1ms


extern void delay_ms(uint16 m);


//1s


extern void delay_s(uint16 s);


 


 


#endif


例子三  7段共阳数码管的显示


7段共阳数码管的显示例子是学习AVR单片机的端口操作。


AVR端口是真正的双向端口,不像51伪双向。这也是AVR的一项优势,只是操作时大家注意DDRn就可以了。真正双向端口在模拟时序方面不如伪双向的方便。
   DDRn PORTn PINn
解释:n为端口号:ABCDE
   DDRn
:控制端口是输入还是输出,0为输入,1为输出。个人记忆方法:一比零大所以往外挤,即1为输出,0为输入。
   PORTn
:从引脚输出信号,当DDRn1时,可以通过PORTnx等端口操作语句给引脚输出赋值。
   PINn
:从引脚读输入信号,无论DDRn为何值,都可以通过xPINn获得端口n的外部电平。
  
当引脚配置为输入时,若PORTxn "1“,上拉电阻将使能。内部上拉电阻的使用在键盘扫描的时候还要说到。
端口更详细功能及介绍以及端口第二功能请参考数据手册。
端口引脚配置
DDxn    PORTxn    PUD (in SFIOR)    I/O   
上拉电阻说明
0    0    X   
输入    No 高阻态 (Hi-Z)
0    1    0   
输入    Yes被外部电路拉低时将输出电流
0    1    1   
输入    No高阻态(Hi-Z)
1    0    X   
输出    No输出低电平 ( 漏电流)
1    1    X   
输出    No输出高电平 ( 源电流)

  
如果有引脚未被使用,建议给这些引脚赋予一个确定电平。最简单的保证未用引脚具有确定电平的方法是使能内部上拉电阻。但要注意的是复位时上拉电阻将被禁用。如果复位时的功耗也有严格要求则建议使用外部上拉或下拉电阻。不推荐直接将未用引脚与VCC GND 连接,因为这样可能会在引脚偶然作为输出时出现冲击电流。
下面我们来看例子:
void port_init(void)
{
PORTA = 0x03;
DDRA = 0x03;
PORTB = 0x00;
DDRB = 0x01;
PORTC = 0x00;
DDRC = 0x00;
PORTD = 0x00;
DDRD = 0x00;//
建议赋值为零
}

PORTA = 0x03;DDRA = 0x03;
这两句使PA口的PA1PA0处于输出状态,PA7—PA2处于输入状态,因为先定义了PORTA=0x30PA1PA0的内部上拉电阻也使能了。这里的0x03即二进制的00000011,从左到右对应于Pn7--Pn0八个IO口。

通过跑马灯程序来深入理解IO口的操作:
//ICC-AVR application builder : 2006-11-21 9:20:57
// Target : M32
// Crystal: 7.3728Mhz

#include
#include

void _delay(unsigned char n) //
延时函数定义
{
unsigned char i,j;
for(;n!=0;n--) //n*10ms
{
for(j=100;j!=0;j--) //100us*100=10ms
{
   for(i=147;i!=0;i--) //delay 100us
   ;
}
}
}

int main(void)
{
unsigned char i,j,k; //
PORTA=0xFF;          //PA
口设为输出高电平,灯灭
DDRA=0xFF;            //PA?ú?aê?3??£ê?
while(1)
{
   i="1";
   for (j=0;j<8;j++) //
循环8次,即PA0~~PA7轮流闪亮
   {
     PORTA=~i;      //
反相输出,低电平有效,对应的灯亮
     for (k=0;k<10;k++) _delay(100);    //
延时 100*10=1秒,可自行调节          i="i"<<1;          //左移一位,I的值将向下面的列表那样变化
   // 0b00000001 PA0
   // 0b00000010 PA1
   // 0b00000100 PA2
   // 0b00001000 PA3
   // 0b00010000 PA4
   // 0b00100000 PA5
   // 0b01000000 PA6
   // 0b10000000 PA7
   }
}
}

其他IO口操作指令:

void main(void)
{
PORTA=0xff;
DDRA=0xff; //
输出 模式 IO口上拉电阻有效,1为输出,0为输入。
PORTA=0xf0; //

以下三条指令只对操作符号右边的数字位是一的位操作。
PORTA&=~0xf0; //
清零 0xf0 01110000 ,即把654三位清零,其余数位不变。
PORTA|=0x77; //
置一 0xf0 01110111 ,即把654210六位清零,其余数位不变。
PORTA^=0x70; //
翻转 如果是零变成1,是一变成0
(P & 0x80)==0x80; //
按位与 判断p的第七位是否是一,是则成立
}

关于1< ADIF是一个寄存器变量,可以堪称数字4 跟手册中的定义,包含芯片头文件的定义是一样的。
(1< ADCSR=(1< ADCSR|=(1< ADCSR&=~(1< while(ADCSR&(1<
while(1)
{
while(ADCSR&(1< {
程序......
}
例子:


建立led.cled.h并添加到工程:


//////////////////////////////////////////////////////////////////////


led.C


///////////////////////////////////////////////////////////////////////


#include "main.h"


/*0,1,2,3,4,5,6,7,8,9,A,b,C,d,E,F,*/


extern const uint8 led_seg[]=


{


    0xC0,//0


    0xF9,//1


    0xA4,//2


    0xB0,//3


    0x99,//4


    0x92,//5


    0x82,//6


    0xF8,//7


    0x80,//8


    0x90,//9


    0x88,//a


    0x83,//b


    0xC6,//c


    0xA1,//d


    0x86,//e


    0x8E,//f


};


void led_light()


{


    uint8 i;


    for (i=0;i<=7;i++)


    {


        led_port^=BIT(i);//输出低电平


        delay_ms(200);


    }


       for (i=0;i<=7;i++)


    {


        led_port^=BIT(i);//输出低电平


        delay_ms(200);


    }


}


void led_disp(void)


{


    uint8 i;


    for (i=0;i<=16;i++)


    {


        led_disp_port=led_seg;//输出低电平


        delay_ms(200);


    }


}


//////////////////////////////////////////////////////////////////////


led.h


///////////////////////////////////////////////////////////////////////


#ifndef __led_h


#define __led_h


 


#define  led_port   PORTA


#define  led_ddr    DDRA


#define  led_pin    PINA


#define  led_disp_port PORTB


extern void led_light(void);


extern void led_disp(void);


#endif


 


其中使用单片机的PB口为数码管数据口


1使用“数码管计算”小软件自动生成16进制(0~9的数组)如下:


   16进制: led_disp[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,};


2、把数组定义到FLASH中,使用const unsinged char led_disp[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,};


 


https://static.assets-stash.eet-china.com/album/old-resources/2009/6/4/6ecbc6d3-a458-4012-9914-52da01b2a9e7.rar

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
7
关闭 站长推荐上一条 /3 下一条