为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

AVR端口位操作头文件

2009-12-14 12页 doc 70KB 51阅读

用户头像

is_773818

暂无简介

举报
AVR端口位操作头文件2009-10-24 10:26AVR端口位操作头文件 AVR位操作的实现一般有两种 一种是利用移位 或与 比如DDRA&=(1<<5); PORTA|=(1<<5); 这种的话估计大家都会的 还有一种就是利用位段实现(位段的更多知识可以参照有关C语言书籍 我就不多说啦) 看不懂代码也不要紧 会用就可以! #ifndef _bit_h #define _bit_h typedef struct //定义一个8字节的位段 bit0~7是每个位段名称 1代表一位 PBIT就是整个位段的名称 { ...
AVR端口位操作头文件
2009-10-24 10:26AVR端口位操作头文件 AVR位操作的实现一般有两种 一种是利用移位 或与 比如DDRA&=(1<<5); PORTA|=(1<<5); 这种的话估计大家都会的 还有一种就是利用位段实现(位段的更多知识可以参照有关C语言籍 我就不多说啦) 看不懂代码也不要紧 会用就可以! #ifndef _bit_h #define _bit_h typedef struct //定义一个8字节的位段 bit0~7是每个位段名称 1代一位 PBIT就是整个位段的名称 { unsigned bit0 : 1 ; unsigned bit1 : 1 ; unsigned bit2 : 1 ; unsigned bit3 : 1 ; unsigned bit4 : 1 ; unsigned bit5 : 1 ; unsigned bit6 : 1 ; unsigned bit7 : 1 ; }PBIT; #define PORTABIT (*(volatile PBIT *)0x3B) /*0x3B是PORTA的地址 (volatile PBIT *)0x3B 就是将这个地址强制类型装换为我们前面定义过的位段 volatile关键字还不懂的话去查点~~前面加个*号 不用我说也知道什么意思吧*/ #define DDRABIT (*(volatile PBIT *)0x3A) #define PINABIT (*(volatile PBIT *)0x39) #define PORTBBIT (*(volatile PBIT *)0x38) #define DDRBBIT (*(volatile PBIT *)0x37) #define PINBBIT (*(volatile PBIT *)0x36) #define PORTCBIT (*(volatile PBIT *)0x35) #define DDRCBIT (*(volatile PBIT *)0x34) #define PINCBIT (*(volatile PBIT *)0x33) #define PORTDBIT (*(volatile PBIT *)0x32) #define DDRDBIT (*(volatile PBIT *)0x31) #define PINDBIT (*(volatile PBIT *)0x30) /*使用方法:要将PORTA的第一位输出为高电平 DDRABIT.bit0=1; PORTABIT.bit0=1; 或者为了便于程序的移植我们一般用宏定义 #define power PORTABIT.bit0 power=1; #define power_out() DDRABIT.bit0=1 */ //当然PORTABIT.bit0敲起来有点长 可以用宏定义把他改小一点 #define PORTABIT0 PORTABIT.bit0 //可以改成自己看的习惯的 但不要与系统头文件中定义过的冲突 比如PA0 PORTA0 #define PORTABIT1 PORTABIT.bit1 #define PORTABIT2 PORTABIT.bit2 #define PORTABIT3 PORTABIT.bit3 #define PORTABIT4 PORTABIT.bit4 #define PORTABIT5 PORTABIT.bit5 #define PORTABIT6 PORTABIT.bit6 #define PORTABIT7 PORTABIT.bit7 #define PORTBBIT0 PORTBBIT.bit0 #define PORTBBIT1 PORTBBIT.bit1 #define PORTBBIT2 PORTBBIT.bit2 #define PORTBBIT3 PORTBBIT.bit3 #define PORTBBIT4 PORTBBIT.bit4 #define PORTBBIT5 PORTBBIT.bit5 #define PORTBBIT6 PORTBBIT.bit6 #define PORTBBIT7 PORTBBIT.bit7 #define PORTCBIT0 PORTCBIT.bit0 #define PORTCBIT1 PORTCBIT.bit1 #define PORTCBIT2 PORTCBIT.bit2 #define PORTCBIT3 PORTCBIT.bit3 #define PORTCBIT4 PORTCBIT.bit4 #define PORTCBIT5 PORTCBIT.bit5 #define PORTCBIT6 PORTCBIT.bit6 #define PORTCBIT7 PORTCBIT.bit7 #define PORTDBIT0 PORTDBIT.bit0 #define PORTDBIT1 PORTDBIT.bit1 #define PORTDBIT2 PORTDBIT.bit2 #define PORTDBIT3 PORTDBIT.bit3 #define PORTDBIT4 PORTDBIT.bit4 #define PORTDBIT5 PORTDBIT.bit5 #define PORTDBIT6 PORTDBIT.bit6 #define PORTDBIT7 PORTDBIT.bit7 //********************** #define DDRABIT0 DDRABIT.bit0 #define DDRABIT1 DDRABIT.bit1 #define DDRABIT2 DDRABIT.bit2 #define DDRABIT3 DDRABIT.bit3 #define DDRABIT4 DDRABIT.bit4 #define DDRABIT5 DDRABIT.bit5 #define DDRABIT6 DDRABIT.bit6 #define DDRABIT7 DDRABIT.bit7 #define DDRBBIT0 DDRBBIT.bit0 #define DDRBBIT1 DDRBBIT.bit1 #define DDRBBIT2 DDRBBIT.bit2 #define DDRBBIT3 DDRBBIT.bit3 #define DDRBBIT4 DDRBBIT.bit4 #define DDRBBIT5 DDRBBIT.bit5 #define DDRBBIT6 DDRBBIT.bit6 #define DDRBBIT7 DDRBBIT.bit7 #define DDRCBIT0 DDRCBIT.bit0 #define DDRCBIT1 DDRCBIT.bit1 #define DDRCBIT2 DDRCBIT.bit2 #define DDRCBIT3 DDRCBIT.bit3 #define DDRCBIT4 DDRCBIT.bit4 #define DDRCBIT5 DDRCBIT.bit5 #define DDRCBIT6 DDRCBIT.bit6 #define DDRCBIT7 DDRCBIT.bit7 #define DDRDBIT0 DDRDBIT.bit0 #define DDRDBIT1 DDRDBIT.bit1 #define DDRDBIT2 DDRDBIT.bit2 #define DDRDBIT3 DDRDBIT.bit3 #define DDRDBIT4 DDRDBIT.bit4 #define DDRDBIT5 DDRDBIT.bit5 #define DDRDBIT6 DDRDBIT.bit6 #define DDRDBIT7 DDRDBIT.bit7 //***************** #define PINABIT0 PINABIT.bit0 #define PINABIT1 PINABIT.bit1 #define PINABIT2 PINABIT.bit2 #define PINABIT3 PINABIT.bit3 #define PINABIT4 PINABIT.bit4 #define PINABIT5 PINABIT.bit5 #define PINABIT6 PINABIT.bit6 #define PINABIT7 PINABIT.bit7 #define PINBBIT0 PINBBIT.bit0 #define PINBBIT1 PINBBIT.bit1 #define PINBBIT2 PINBBIT.bit2 #define PINBBIT3 PINBBIT.bit3 #define PINBBIT4 PINBBIT.bit4 #define PINBBIT5 PINBBIT.bit5 #define PINBBIT6 PINBBIT.bit6 #define PINBBIT7 PINBBIT.bit7 #define PINCBIT0 PINCBIT.bit0 #define PINCBIT1 PINCBIT.bit1 #define PINCBIT2 PINCBIT.bit2 #define PINCBIT3 PINCBIT.bit3 #define PINCBIT4 PINCBIT.bit4 #define PINCBIT5 PINCBIT.bit5 #define PINCBIT6 PINCBIT.bit6 #define PINCBIT7 PINCBIT.bit7 #define PINDBIT0 PINDBIT.bit0 #define PINDBIT1 PINDBIT.bit1 #define PINDBIT2 PINDBIT.bit2 #define PINDBIT3 PINDBIT.bit3 #define PINDBIT4 PINDBIT.bit4 #define PINDBIT5 PINDBIT.bit5 #define PINDBIT6 PINDBIT.bit6 #define PINDBIT7 PINDBIT.bit7 #endif /*--------------------------------------------------------------*/ //ICC-AVR application builder : // Target : M8 // Crystal: 1.000Mhz /*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/ //防止重复定义 #ifndef __ICCAVRIO_H__ #define __ICCAVRIO_H__ /*--------------------------------------------------------------*/ //定义新的数据类型,方便进行IO端口操作。 //定义一个8字节的位域 bit0~7是每个位域名称, 1代表一位, bit_field就是整个位域的名称 typedef struct { unsigned bit0: 1 ; unsigned bit1: 1 ; unsigned bit2: 1 ; unsigned bit3: 1 ; unsigned bit4: 1 ; unsigned bit5: 1 ; unsigned bit6: 1 ; unsigned bit7: 1 ; }bit_field; #define GET_BIT(adr) (*(( volatile bit_field * )(&adr))) /*--------------------------------------------------------------*/ //设置是否自动初始化IO方向寄存器 //自动初始化IO方向寄存器无需在初始化程序中用PORTA=0X..;形式来初始化io控制寄存器, //同时也不争的证明了avr单片机的端口输入/出切换功能 #define AUTOINIT 1 // 0 //手动配置IO方向寄存器 // 1 //自动配置IO方向寄存器 /*--------------------------------------------------------------*/ //输出端口设置 #if (AUTOINIT == 1) //自动初始化IO方向寄存器 #define PORT(m, n) GET_BIT(DDR##m).bit##n = 1;\ GET_BIT(PORT##m).bit##n #define P_OUT(m, n) DDR##m |= n;\ PORT##m #else //需手动配置IO方向寄存器 #define PORT(m, n) GET_BIT(PORT##m).bit##n #endif /*--------------------------------------------------------------*/ //输入端口设置(输入端口) #if (AUTOINIT == 1) //自动初始化IO方向寄存器 #define PIN(m, n) (!(GET_BIT(DDR##m).bit##n = 0) &&\ (GET_BIT(PORT##m).bit##n = 1) &&\ GET_BIT(PIN##m).bit##n) #define P_IN(m, n) (DDR##m &= ~n, PORT##m = n, PIN##m & n) #else //需手动配置IO方向寄存器 #define PIN(m, n) GET_BIT(PIN##m).bit##n #endif /*-------------------------------------------------------------*/ //端口输入输出方向设置 //方便直观操作 自由设定单个io口的方向 #define DRA(n) GET_BIT(DDRA).bit##n #define DRB(n) GET_BIT(DDRB).bit##n #define DRC(n) GET_BIT(DDRC).bit##n #define DRD(n) GET_BIT(DDRD).bit##n #define DDR(m, n) GET_BIT(DDR##m).bit##n /*--------------------------------------------------------------*/ #endif /*-------------------------------------------------------------*/ /* //在我们实际项目中,需要用到按键输入,继电器,SPI器件输出, //两者分别为输入,和输出之用,这时候可以方面的在各自c文件对应的.h文件中写下如下语句: #define KEY1 PIN(C, 3) //定义三个按键,使能上拉 #define KEY2 PIN(C, 4) #define KEY3 PIN(C, 5) #define SCLK_SPI PORT(B, 5) //定义spi口的两个控制引脚 #define CS_SPI PORT(C, 0) //多位定义(数据总线端口) #define KEY_IN P_IN(D, 0x0f) //按键手动输入 低四位设置为输入,其他位方向不变 #define LED_OUT P_OUT(C, 0x0f) //LED显示输出 低四位设置为输出,其他位方向不变 定义后直接赋值: LED_OUT = ~KEY_IN; //高电平点亮LED, 按键低电平有效 #define LCD_DATA_IN P_IN(D, 0xff) //LCD数据总线设置为输入 #define LCD_DATA_OUT P_OUT(D, 0xff) //LCD数据总线设置为输出 定义后直接赋值: TEMP = LCD_DATA_IN; //读入数据 LCD_DATA_OUT = TEMP; //输出数据 //上述PIN PORT 自动化定义的方法中,有些不足, //如:在DS18B20这样的应用中,需要切换引脚的输入输出,就必须为18B20的引脚安排两套定义, //类似于: #define DS18B20_IN PIN(A, 1) #define DS18B20_OUT PORT(A, 1) //此外:PORT和PIN的自动化定义中,含有DDR的操作, //凡是用到PIN和PORT定义过的端口的地方都需要重复DDR操作,带来冗余代码。 //呵呵,虽然代码有点繁琐,但却很方便的,便于程序的移植。 //希望朋友们能够用得上! /*-------------------------------------------------------------*/ AVR的两种位操作的比较(位域方式和移位宏方式) 测试环境如下: 硬件:AT90S2313 软件:     WiinAVR gcc3.3    -Os级优化(最小size)。 说明:      由于AVR不支持位操作,所以必须通过软件来实现。下面对我所知道的两种方法进行一个简单的比较。      1、位域方式。先定义一个位域,              typedef struct _bit_struct              {                  unsigned char bit0 : 1 ;                  unsigned char bit1 : 1 ;                  unsigned char bit2 : 1 ;                  unsigned char bit3 : 1 ;                  unsigned char bit4 : 1 ;                  unsigned char bit5 : 1 ;                  unsigned char bit7 : 1 ;                  unsigned char bit6 : 1 ;              }bit_field;          再用一个宏     ,来指向要操作的位。               #define LED              GET_BITFIELD(PORTB).bit0               #define BUTTON       GET_BITFIELD(PINB).bit7          使用时只需要直接赋值即可:如LED =      0 ,LED = 1,   或者直接判断 LED==0     ,     LED ==1.          这种方法类似C51中的位操作。直接。      2、位移宏方式。主要有三个.                  #define Set_Bit(val, bitn)     (val |=(1<<(bitn)))                  #define Clr_Bit(val, bitn)      (val&=~(1<<(bitn)))                  #define Get_Bit(val, bitn)     (val &(1<<(bitn)) )           三个分别用来设置某一位,清除某一位,取某一位的值.             使用方法为.Set_Bit(PORTA,3);    Clr_Bit(PORTB,2);    Get_Bit(val,5);      3、测试程序.             说明,假设PORTB.7接按纽,PORTB.0 接LED             测试程序完成如下操作。                     当BUTTON == 0时 ,LED输出1 否则输出0,                     这样的目的是即测试了输入,又测试了输出1和输出0,相对全面一点。   C代码如下.                      // testled.c      测试AVR的位操作.                  // 这是gcc;如是其它编译器,请修改。                  #include                  // 定义一个寄存器(Register)或端口(Port)的八个位                  typedef struct _bit_struct                  {                      unsigned char bit0 : 1 ;                      unsigned char bit1 : 1 ;                      unsigned char bit2 : 1 ;                      unsigned char bit3 : 1 ;                      unsigned char bit4 : 1 ;                      unsigned char bit5 : 1 ;                      unsigned char bit7 : 1 ;                      unsigned char bit6 : 1 ;                  }bit_field;                    //定义一个宏,用来得到每一位的值                  #define GET_BITFIELD(addr) (*((volatile   bit_field *) (addr)))                  //定义每一个位                  #define LED              GET_BITFIELD(PORTB).bit0                  #define BUTTON       GET_BITFIELD(PINB).bit7                  #define Set_Bit(val, bitn)     (val |=(1<<(bitn)))                  #define Clr_Bit(val, bitn)      (val&=~(1<<(bitn)))                  #define Get_Bit(val, bitn)     (val &(1<<(bitn)) )                  int main( void )                  {                      DDRB = 0x41;    //配置PB0为输出,PB7为输入                      if ( BUTTON==0 )      LED = 1; else LED = 0;                      //if(!Get_Bit(PINB,7) )   Set_Bit(PORTB,0);     else Clr_Bit(PORTB,0);                      while(1);                  }                  //      ----------------------         end          -----------------------------      4、测试过程。         a.先使用位域方式。         主程序中使用 if ( BUTTON==0 )      LED = 1; else LED = 0;         结果如下:                       int main( void )                      {                        4a:     cf ed            ldi     r28, 0xDF     ; 223                        4c:     d0 e0            ldi     r29, 0x00     ; 0                        4e:     de bf            out     0x3e, r29     ; 62                        50:     cd bf            out     0x3d, r28     ; 61                          DDRB = 0x41;       //配置PB0为输出,PB7为输入                        52:     81 e4            ldi     r24, 0x41     ; 65                        54:     87 bb            out     0x17, r24     ; 23                          if ( BUTTON==0 )      LED = 1; else LED = 0;                        56:     86 b3            in     r24, 0x16     ; 22                        58:     e8 2f            mov     r30, r24                        5a:     ff 27            eor     r31, r31                        5c:     80 81            ld     r24, Z                        5e:     86 fd            sbrc     r24, 6                        60:     07 c0            rjmp     .+14          ; 0x70                        62:     88 b3            in     r24, 0x18     ; 24                        64:     e8 2f            mov     r30, r24                        66:     ff 27            eor     r31, r31                        68:     80 81            ld     r24, Z                        6a:     81 60            ori     r24, 0x01     ; 1                        6c:     80 83            st     Z, r24                        6e:     06 c0            rjmp     .+12          ; 0x7c                        70:     88 b3            in     r24, 0x18     ; 24                        72:     e8 2f            mov     r30, r24                        74:     ff 27            eor     r31, r31                        76:     80 81            ld     r24, Z                        78:     8e 7f            andi     r24, 0xFE     ; 254                        7a:     80 83            st     Z, r24                          while(1);                        7c:     ff cf            rjmp     .-2           ; 0x7c           main函数共52Bytes.其中,从lst文件看得出:main函数的初始化用了4条指令,8Bytes. 最后一句while(1);用了1条指令2Bytes.( for循环和do-while也是)           DDRB=0x41用了2条指令4Bytes. 计算一下:52-8-4-2=38Bytes,即if ( BUTTON==0 )      LED = 1; else LED = 0; 这句用了19条指令38Bytes. (居然运用了3个寄存器白r24,r30,r31,和一个Z,代码真是苦涩,,我看不懂,准备以后作代码加密用:).   )         b.使用移位宏方式。         将 if ( BUTTON==0 )      LED = 1; else LED = 0;   换为等效的      if(!Get_Bit(PINB,7) )   Set_Bit(PORTB,0);     else Clr_Bit(PORTB,0);         结果,main函数仅24Bytes.其它代码一样,略去. 所以,上面这句代码仅用了24-14=10Bytes ,5条指令。生成的代码如下:                56:     b7 99            sbic     0x16, 7     ; 22                58:     02 c0            rjmp     .+4           ; 0x5e                5a:     c0 9a            sbi     0x18, 0     ; 24                5c:     01 c0            rjmp     .+2           ; 0x60                5e:     c0 98            cbi     0x18, 0     ; 24      5. 菜论:鱼和熊掌。        由于AVR可以对I/O脚进行sbic,sbi,cbi,这样的位操作,所以使用I/O脚操作时,移位宏可以产生高效的代码。        例如,要实现上面的几个简单的指令,为了实现LED=1这样的类似C51的sbit的效果,我必须多付出(38-10=28Bytes)的代价。      6......          对于I/O脚,可以产生这样高效的代码,是因为有sbi和cbi这样的指令,那么对于一般的变量,又如何呢?................ AVR的位操作只能对地址小于$1F的寄存器使用 大于$1F的寄存器,AVR 芯片本身就不支持位操作,什么语言都一样,只能用操作RAM的方式来处理 几个位操作的小函数,经过了CVAVR的编译(其他编译器也是一样的),AVRStudio的模拟调试。结果是正确的,但运行时间约10uS,有兴趣的网友可以来交流。 1 测试指定的位 unsigned char BitTst(unsigned char *Pa,char b) //Pa为被测试的对象的地址,b值为指定的位 { return *Pa & (1<
/
本文档为【AVR端口位操作头文件】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索