1、端口位设置/清除
可对BSRR、BRR寄存器相应的位置1,以实现置位和清零操作,如:
GPIOA->BSRR = (1<<3); // 设置端口A的位3为1
GPIOA->BRR = (1<<3); // 清除端口A的位3为0
2、端口直接输出
可对ODR寄存器相应的位置1或0,以实现置位和清零操作,如:
GPIOA->ODR |= (1<<3); // 端口A的位3输出1
GPIOA->ODR &= ~(1<<3); // 端口A的位3输出0
3、端口位带输出
参考《Cortex-M3 权威指南》第五章,第5小节 位带操作(87页~92页)。
为简化位带操作,可以定义一些宏。比如,我们可以建立一个把“位带地址+位序号”转换成别名地址的宏, 再建立一个把别名地址转换成指针类型的宏。
//1):把“位带地址+位序号”转换成别名地址的宏
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr & 0xFFFFF)<<5)+(bitnum<<2))
//2):把该地址转换成一个指针
#define MEM_ADDR(addr) *((volatile unsigned long *) (addr))
//3):使用位带别名地址访问
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
应用如下:
#define PAout(n) BIT_ADDR((uint32_t)&GPIOA->ODR, n)
PAout(3) = 1; //端口A的位3输出1
PAout(3) = 0; //端口A的位3输出0
4、端口位域输出
定义一个端口位域
#pragma anon_unions //以便结构体或共用体无需另起名字
typedef union{
uint32_t WORDS;
struct{
int bit00 :1;
int bit01 :1;
int bit02 :1;
int bit03 :1;
int bit04 :1;
int bit05 :1;
int bit06 :1;
int bit07 :1;
int bit08 :1;
int bit09 :1;
int bit10 :1;
int bit11 :1;
int bit12 :1;
int bit13 :1;
int bit14 :1;
int bit15 :1;
int bit16 :1;
int bit17 :1;
int bit18 :1;
int bit19 :1;
int bit20 :1;
int bit21 :1;
int bit22 :1;
int bit23 :1;
int bit24 :1;
int bit25 :1;
int bit26 :1;
int bit27 :1;
int bit28 :1;
int bit29 :1;
int bit30 :1;
int bit31 :1;
};
}PORT;
应用如下:
#define PAout03 (((PORT *)(&GPIOA->ODR))->bit03)
PAout03 = 1; //端口A的位3输出1
PAout03 = 0; //端口A的位3输出0
5、综述
以上4种方法,1、2两种较为多见;方法3为位带操作,速度最快,但只对具备位带的U有效;方法4是一种新颖的通用方法,只要找到输入或输出寄存器即可,对任意U有效!
|