本文曾经在以前探讨过.现在再次来讨论一下. 以讲述avr单片机的io口操作。很多朋友都是由51单片机走向嵌入式系统,经历了51->430 51->pic 51->avr,这样一些转换,本人粗略学了51,后直接专攻avr,为此有一些心得,和一些雕虫小技的小伎俩,希望能抛砖引玉,引发同行反思,在工作中提供举一反三后的便利。 想像51一样,在winavr中直接写上sbit KEY1 = p1^1, 然后用下列语句扫描键盘吗?? if(KEY1==0) keyval=1; 请看下面的宏定义,其中位段的手法来源于网络,本人纯属借鉴。之后的##,宏链接符,纯属自创, 各位先行使用以下宏后,有问题直接联系本人qq21332560讨论:注明验证信息:io口 //定义新的数据类型,方便进行IO端口操作。 typedef 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_BIT(adr) (*(( volatile bit_field * )(&adr))) //////////////////////////////////////// #define AUTOINIT 1 //自动初始化IO方向寄存器无需在初始化程序中用PORTA=0X..;形式来初始化io控制寄存器,同时也不争的证明了avr单片机的端口输入/出切换功能 #if AUTOINIT==1 #define PORT(m,n) GET_BIT(DDR##m).bit##n=1;\ GET_BIT(PORT##m).bit##n #else #define PORT(m,n) GET_BIT(PORT##m).bit##n #endif //////////////////////////////////////// #if AUTOINIT==1 #define PIN(m,n) (!(u08)(GET_BIT(DDR##m).bit##n=0) &&\ (u08)(GET_BIT(PORT##m).bit##n=1) &&\ GET_BIT(PIN ##m).bit##n ) #else #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 在我们实际项目中,需要用到按键输入,继电器,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) 上述PIN PORT 自动化定义的方法中,有些不足,如:在DS18B20这样的应用中,需要切换引脚的输入输出,就必须为18B20的引脚安排两套定义, 类似于:#define DS18B20_IN PIN(A,1) #define DS18B20_OUT PORT(A,1) 此外:PORT和PIN的自动化定义中,含有DDR的操作,凡是用到PIN和PORT定义过的端口的地方都需要重复DDR操作,带来冗余代码。 以上是对单片机端口的位操作的一点浅显认识;.在avr中有不错的便利应用. 可以看本人的一些实例代码;, 例程1: 定义3个按键输入口; #define KEY1 PIN(A,5)// #define KEY2 PIN(A,4)/ #define KEY3 PIN(A,3) 那么 : 按键读取就可以按照以下方式来进行: u08 keyinput(void) { u08 KeyVal=0; if(KEY_SET==0) KeyVal= 3; if(KEY_DEC==0) KeyVal= 2; if(KEY_ADD==0) KeyVal= 1; return KeyVal; } 例程2: 定义:2个数据口,操作hc164,若干位选, 共同用于led数码管扫描显示; #define HC164CLK PORT(B,4)//Hardware:4703v1.0 #define HC164DIO PORT(B,3) #define BIT1 PORT(B,2) #define BIT2 PORT(B,1) #define BIT3 PORT(B,0) #define BIT4 PORT(A,0) #define BIT5 PORT(A,1) #define BIT6 PORT(A,2) /* 功能:发送一个字节8段码至hc164 *| 注意:HC164CLK为自定义位域字段, *| */ void HC164_send_byte(unsigned char a) { unsigned char i; HC164_DIGRST();//传送数据时候的消隐处理 for( i = 0 ; i < 8 ; i++ ) { HC164CLK = 0; if( a & 0x80 ) { HC164DIO = 1; } else { HC164DIO = 0; } a |
RE:MCU实战经验+关于mcu的IO操作问题.
RE:MCU实战经验+关于mcu的IO操作问题.
RE:MCU实战经验+关于mcu的IO操作问题.
RE:MCU实战经验+关于mcu的IO操作问题.
RE:MCU实战经验+关于mcu的IO操作问题.
用单个IO口操作 不论是8位机还是32位都感觉非常方便。
下面是stm8s 我常用的IO操作方式,其实地址修改一下,应该是可以
在其他8位IC里面的。
typedef struct GPIOX_struct
{
union
{
volatile unsigned char DDR_;
volatile unsigned char CR1_;
volatile unsigned char CR2_;
volatile unsigned char ODR_;
volatile unsigned char IDR_;
struct
{
volatile unsigned char R0:1;
volatile unsigned char R1:1;
volatile unsigned char R2:1;
volatile unsigned char R3:1;
volatile unsigned char R4:1;
volatile unsigned char R5:1;
volatile unsigned char R6:1;
volatile unsigned char R7:1;
}BIT_;
};
}GPIOX_TypeDef;
#define GPIO_PAOUT ((GPIOX_TypeDef *)0X5000)
#define PA (GPIO_PAOUT->ODR_)
#define PA0 (GPIO_PAOUT->BIT_.R0)
#define PA1 (GPIO_PAOUT->BIT_.R1)
#define PA2 (GPIO_PAOUT->BIT_.R2)
#define PA3 (GPIO_PAOUT->BIT_.R3)
#define PA4 (GPIO_PAOUT->BIT_.R4)
#define PA5 (GPIO_PAOUT->BIT_.R5)
#define PA6 (GPIO_PAOUT->BIT_.R6)
#define PA7 (GPIO_PAOUT->BIT_.R7)
。。。。。。。
。。。。。。。
32位的 例如st 已经有大侠全部写好了 类似:
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)
RE:MCU实战经验+关于mcu的IO操作问题.