winavr位操作的探讨
本帖最后由 neo 于 2014-5-3 09:07 编辑CVAVR下的程序
#include <mega16.h>
#define LED PORTA.4
void main( void )
{
DDRA=0x10;
LED=0;
}
对应的反汇编
--- 无源文件 -----------------------------------------------------------------------
--- C:\Users\AX\Desktop\avr_test2\main.c ---------------------------------------
DDRA=0x10;
00000048LDI R30,0x10 Load immediate
00000049OUT 0x1A,R30 Out to I/O location
LED=0;
0000004ACBI 0x1B,4 Clear bit in I/O register
--- 无源文件 -----------------------------------------------------------------------
0000004BRJMP PC-0x0000 Relative jump
0000004CNOP Undefined
0000004DNOP Undefined 在winAVR里没有和CVAVR里同样的位操作指令,在网上看到一篇帖子WINAVR中avr单片机的位操作 其中提到了位域的方法,从C编写的角度看该方法和CVAVR里的比较类似,对应的C代码如下:
#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 bit6: 1 ;
unsigned char bit7: 1 ;
}bit_field;
//定义一个宏,用来得到每一位的值
#define GET_BITFIELD(addr)(*((volatile bit_field *) (addr)))
//定义每一个位
#define LED GET_BITFIELD(PORTA).bit4
int main( void )
{
DDRA=0x10;
LED=0;
return 0;
}
其反汇编如下:
--- C:\Users\AX\Desktop\avr_test/main.c ----------------------------------------
{
DDRA=0x10;
00000036LDI R24,0x10 Load immediate
00000037OUT 0x1A,R24 Out to I/O location
LED=0;
00000038IN R30,0x1B In from I/O location
00000039LDI R31,0x00 Load immediate
0000003ALDD R24,Z+0 Load indirect with displacement
0000003BANDI R24,0xEF Logical AND with immediate
0000003CSTD Z+0,R24 Store indirect with displacement
}
0000003DLDI R24,0x00 Load immediate
0000003ELDI R25,0x00 Load immediate
0000003FRET Subroutine return
--- 无源文件 -----------------------------------------------------------------------
00000040CLI Global Interrupt Disable
00000041RJMP PC-0x0000 Relative jump
从中可见CVAVR使用的是CBI指令对PORTA.4进行操作。WINAVR位域的方法是使用掩码的间接实现方法对PORTA.4进行操作,共使用了5条指令,代码效率不高。
CVAVR这种PORTA.x这种赋值方法有一大好处就是可以实现如下的定义
当LED点灯电路使用的是OC接法时
#define OFF 1
#define ON 0
#define LED PORTA.4
如果LED电路是直接高电平驱动则定义
#define OFF 0
#define ON 1
#define LED PORTA.4
对应的点亮部分只需执行LED=ON就可以了,不必要关心硬件电路究竟如何,这样就非常方便硬件的调试。不知WinAVR里有没有类似的方法。
1、C接口友好。
2、直接使用SBI CBI对端口位操作。
#define LED_FLASH PORTB ^= (1 << PB1)
#define LED_ON PORTB |= (1 << PB1)
#define LED_OFF PORTB &= ~(1 << PB1) PORTA&=~(1<<PA5);
0000003DCBI 0x1B,5 Clear bit in I/O register
PORTA&=~(1<<PA5);会直接被编译为CBI,如果能实现PORTA(addr,value)封装就方便了。 szxszx 发表于 2014-5-3 09:30
#define LED_FLASH PORTB ^= (1
如果定义了N多个端口 当外部硬件发生了变化就要一个个修改定义 这样不是很方便 #define DEF_2( a, b ) a ## b
#define PORT( a ) DEF_2( PORT, a )
#define SBI(a, b ) a != (1<<b )
#define SBI_P( a, b ) SBI( PORT(a), b )
SBI_P( A, 2 ); //PORTA |= (1<<2 );
这样移植比较方便
页:
[1]