|
|
|
| AVR (原ourAVR.com) 技术论坛 -> 分类清单 -> [转贴]gcc经验点滴(二)---鱼,熊掌.AVR的两种位操作的比较(wjc3k发于21ic)(位域与C位操作的比较) | 跳转至: | 未登录 |
| ↓↓ [转贴]gcc经验点滴(二)---鱼,熊掌.AVR的两种位操作的比较(wjc3k发于21ic)(位域与C位操作的比较) | 回复数:118,点击数:23343 |
|
抱歉本贴的回复数太多,为了减轻网络流量,只显示帖子正文的前后各10个回复。本贴的正文内容中间隐藏了98个回复。你需要 点击此处 才能查看全部内容。 对为你带来的访问不便表示歉意。不过我们仍会坚持即使没有登录,仍能共享我们网站的所有资料。你没有 登录后就能消除这个访问上的不便(可增加到显示60个回复)。 如果你是新用户请先 注册。注册是免费的,并且手续简单只需要填写用户名与口令。 ↓↓↓↓↓↓↓↓↓↓↓↓ |
|
【楼主位】 dfgeoff 嗜血蜗牛 积分:692 派别: 等级:------ 来自:江苏南京 |
转贴前言:一直看到做51转做AVR的朋友,想继续使用bit这样的操作,讨论也不少。其实对于设计人员的未来考虑,还是使用纯C比较好,毕竟适应性强。C51增加的bit、sbit是考虑了51的SRAM小的特点的。移植性就受到影响了。能放弃,尽量放弃。
------------------------------------------- wjc3k 发表于 3/5/2003 10:39:38 AM AVR 单片机 大家好,得到大家的大力支持,本小小菜现如今胆儿大了点,脸皮厚了点儿,又来献丑啦。今儿就不说没用的话了,免得鸡蛋横飞过来啦。 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 <avr/io.h> // 定义一个寄存器(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这样的指令,那么对于一般的变量,又如何呢?................ |
||
|
|
|
|
【1楼】 hotpower 菜农 积分:2136 派别: 等级:------ 来自:西安大雁塔村 |
通用MCU8位16位24位32位变量定义头文件MCUBIT.H
PICC菜鸟玩PICC位变量潇洒走一回 本人对移植的看法 -----此内容被hotpower于2005-01-12,19:21:46编辑过 |
||
|
|
|
|
【2楼】 jeewood 积分:760 派别: 等级:------ 来自: |
好贴子啊,不顶不行的! | ||
|
|
|
|
【3楼】 lanmp 积分:259 派别: 等级:------ 来自: |
3/5/2003 好早啊
atmel 的application note上面也有,很清楚。 |
||
|
|
|
|
【4楼】 onorg 自由之神 积分:347 派别: 等级:------ 来自:湖南 湘潭 |
看了不顶,是白痴 | ||
|
|
|
|
【5楼】 benladn911 AVR猎手 积分:2285 派别: 等级:------ 来自:孤独地带 |
我也有些小方法,呵呵,见笑了:
看下下面的程序吧: /******************************************************************** * 主 页 : HTTP://WWW.QLMCU.COM * * 程序功能 : 流水灯的左移右移实验 * * 应用软件 : WinAVR * * 版 本 : WinAVR-20050214-install * * 硬 件 : WS9500 * * 创建时间 : 2005-11-10 * * 编 写: benladn911 * * 注:为了有更多实用的实验程序供大家学习,部分程序参考网上的资源, * 在此谢谢这些无私奉献的朋友!!! * ********************************************************************/ #include <avr/io.h> #include <avr/delay.h> //注: 内部函数_delay_ms() 最高延时 262.144mS@1MHz 即 32.768ms@8MHz // 该函数可以实现较精确的定时for()/while()指令很难计算延时时间 // 为了使 _delay_ms()函数的延时正确,须在makefile中设定F_CPU为实际的系统时钟频 // 本范例为6MHz外部晶振振荡器 即 F_CPU=6000000 //-----------位操作定义------------------------<<<<<<<<<<<<<<<<<<<<<<<<<这里 #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #define LED_ON cbi(PORTD,7)//在程序用LED_ON代替cbi(PORTD,7)<<<<<<<<<<<<<< //--------------------------------------------------------------- //内部函数_delay_ms() 最高延时 262.144mS@1MHz 即 32.768ms@8MHz void delay_ms(unsigned int ms);//----ms级延时 //内部函数_delay_us() 最高延时 768 us@1MHz 即 96 us@8MHz void delay_us(unsigned int us);//----us级延时 //-------------------------------------------------------------------------- int main(void) { unsigned char i,j; //定义变量 DDRA=0xFF; //定义了端口PORTA全部为输出 PORTA=0xFF; //PA口设为输出高电平,灯灭PORTA //第一种方法选通PD7(LED的电源控制的端) //DDRD=0xFF; //PORTD全部设置为输出 //PORTD=PORTD & 0x7F; //0x7F=0b0111 1111 //第二种方法选通PD7(LED的电源控制的端) //DDRD=0xFF; //PORTD全部设置为输出 //PORTD=0x7F; //0b0111 1111 //第三种方法选通PD7(LED的电源控制的端) sbi(DDRD,7);//对PD7的DDR清零,PD7设置为输出 LED_ON;//PD7输出低电平 while(1) { i=0x01; for (j=0;j<8;j++) //循环8次,即PA0~~PA7轮流闪亮 { PORTA=~i; //反相输出,低电平有效 delay_ms(100); i=i<<1; //左移一位 // 0b00000001 PB0 // 0b00000010 PB1 // 0b00000100 PB2 // 0b00001000 PB3 // 0b00010000 PB4 // 0b00100000 PB5 // 0b01000000 PB6 // 0b10000000 PB7 } i=0x80; for (j=0;j<8;j++) //循环8次,即PA0~~PA7轮流闪亮 { PORTA=~i; //反相输出,低电平有效, delay_ms(100); i=i>>1; //右移一位 } } } //----------------ms级延时--------------- void delay_ms(unsigned int ms) { unsigned int i; for(i=0;i<ms;i++) _delay_ms(1); //延时 i*ms= 毫秒,可自行调节 } //----------------us级延时--------------- void delay_us(unsigned int us) { unsigned int i; for(i=0;i<us;i++) _delay_us(1); //延时 i*us= 毫秒,可自行调节 } |
||
|
|
|
|
【6楼】 hotpower 菜农 积分:2136 派别: 等级:------ 来自:西安大雁塔村 |
哈哈,现在被AVR感化了,反而见了bit就晕...
(1 << bit)挺好的,见了它就知道和位有关了,出错几率反而更小了. |
||
|
|
|
|
【7楼】 whaul 积分:64 派别: 等级:------ 来自:浙江宁波 |
新手学习中,致谢 | ||
|
|
|
|
【8楼】 zhi1980 积分:16 派别: 等级:------ 来自: |
不错,谢了 | ||
|
|
|
|
【9楼】 zhengkaike 菜鸟先飞 积分:52 派别: 等级:------ 来自: |
顶~~~~~~~~~~ | ||
|
|
|
|
【10楼】 rf232 积分:7 派别: 等级:------ 来自: |
顶一下 | ||
|
|
|
|
↑↑↑↑↑↑↑↑↑↑↑↑ 抱歉本贴的回复数太多,为了减轻网络流量,只显示帖子正文的前后各10个回复。本贴的正文内容中间隐藏了98个回复。你需要 点击此处 才能查看全部内容。 对为你带来的访问不便表示歉意。不过我们仍会坚持即使没有登录,仍能共享我们网站的所有资料。你没有 登录后就能消除这个访问上的不便(可增加到显示60个回复)。 如果你是新用户请先 注册。注册是免费的,并且手续简单只需要填写用户名与口令。 ↓↓↓↓↓↓↓↓↓↓↓↓ |
|
【109楼】 haso2007 错别字-妹影 积分:174 派别: 等级:------ 来自: |
【16楼】 alexant
注意GET_BITFIELD(&address).bit##b中的address前面的取址符"&",这是唯一与楼主所讲的不一样的地方,大家可以该该再看看 下面是if(dat&0x80)nRF905_MOSI=1;else nRF905_MOSI=0;的汇编代码: _______________________________________________________________ 着实代码效率也很高,是不是lz的定义不够好呢? |
||
|
|
|
|
【110楼】 yx0315 明晚的星星 积分:1 派别: 等级:------ 来自:湘农大机械 |
cvavr里面直接对位操作是何故? | ||
|
|
|
|
【111楼】 wcw19781009 积分:8 派别: 等级:------ 来自: |
方法挺多啊,挺好,以前我也一直被bit运算所困惑,不过现在我不了,我觉得我现在用的方法也很好,如下,大家可以看看。
在IAR 4.2 下 包含 iom16.h 库后,其实大家就能用位运算了。 规则如下 : sfr名称.BitN 例如 PORTB2 作为输出: 设置后 DDRB 后 可以这样写 PORTB.Bit2=1;或 PORTB.Bit2=0; 注意大小写 如果要将端口作为输入: 设置后 DDRB 后 可以这样写 N=PINB.Bit2;或 N=PINB.Bit2; 注意大小写 所以我们以后再也不怕位运算了,也无需去自己定义那个结构体和共用体了,方便吧?希望大家支持 |
||
|
|
|
|
【112楼】 yutianyiren 积分:382 派别: 等级:------ 来自: |
不错不错,都是好方法 | ||
|
|
|
|
【113楼】 wukaka 积分:332 派别: 等级:------ 来自: |
俺喜欢楼主的这个方法:
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)) ) 顶你 |
||
|
|
|
|
【114楼】 sxcrgm 积分:32 派别: 等级:------ 来自: |
很有学术性质啊 | ||
|
|
|
|
【115楼】 cain.lee 积分:113 派别: 等级:------ 来自: |
这个位移是我开始接触avr的时候兴起的··还要多多注意用法··· | ||
|
|
|
|
【116楼】 xyang18 狗头军师 积分:417 派别: 等级:------ 来自: |
好好学习中 | ||
|
__________________________ 不要相信我所说过的,希望大家能更多的指出我的不足 |
|||
|
|
|
|
【117楼】 xingyu 积分:21 派别: 等级:------ 来自: |
大大大ddddddddd | ||
|
|
|
|
【118楼】 sunpei0337115 积分:5 派别: 等级:------ 来自: |
好好学习了 | ||
|
|
|
|
↑↑↑↑↑↑↑↑↑↑↑↑ 抱歉本贴的回复数太多,为了减轻网络流量,只显示帖子正文的前后各10个回复。本贴的正文内容中间隐藏了98个回复。你需要 点击此处 才能查看全部内容。 对为你带来的访问不便表示歉意。不过我们仍会坚持即使没有登录,仍能共享我们网站的所有资料。你没有 登录后就能消除这个访问上的不便(可增加到显示60个回复)。 如果你是新用户请先 注册。注册是免费的,并且手续简单只需要填写用户名与口令。 |
| ↑↑  快速回复帖子主题:[转贴]gcc经验点滴(二)---鱼,熊掌.AVR的两种位操作的比较(wjc3k发于21ic)(位域与C位操作的比较) |
| 你尚未登录,不能回复以上帖子。 |
| AVR (原ourAVR.com) 技术论坛 -> 分类清单 -> [转贴]gcc经验点滴(二)---鱼,熊掌.AVR的两种位操作的比较(wjc3k发于21ic)(位域与C位操作的比较) | 跳转至: | 未登录 |
| 任何建议或投诉,欢迎随时与我们联系。 ourDEV.cn 我们的电子开发网,友好交流气氛,乐于开源共享,“这里远比混乱的现实世界美好”。 | ||||
| 网站负责人: | 阿莫(armok),手机:13433056000,电邮:armok ourdev.cn(请将空格改成@) | |||
| 地址与电话: |
东莞市东城八一路同沙工业园内,0769-22298000,传真请按4 阿莫邮购门市与雕刻机展示厅:东莞市莞城区莞太路和生文具礼品批发市场A2018,A2035 杨小姐 13711915767 雕刻机的技术咨询、订单查询、生产进度,可查询:13600266008吴先生(雕刻机设计人员kaif_w) |
|||
| 声明: |
本网站由东莞科士通(Infostone)科技有限公司属下的阿莫电子邮购部提供独家赞助。 有正式的工商注册与网站备案。详情可到东莞工商局查询。 本网站(ourDEV.cn)原名称为ourAVR.com(我们的AVR),自2007-09-01起从专业的AVR网转成综合电子网站。 本网站系统由armok Using Oracle + Java/JSP + WebLogic + Linux 2001/12/20 -- 2007/09/13 本BBS所有代码均为原创,版权归 armok 所有。本网站自:2004-10-03,16:31:17 起开始运行。 |
|||
| 法律顾问: | 本网站尊重知识产权,自2007年08月15日起,魏龙律师担任ourDEV.cn(原ourAVR.com)常年法律顾问。 | |||