假设说:
#define PIN0 (1u<<0)
#define PIN1 (1u<<1)
#define PIN2 (1u<<2)
// etc...
然后:
char process_key(int a)
{
if( a != 0 )
{
// Set bit
GPIO_PORTC_DATA_R |= PIN0 ;
}
else
{
// Clear bit
GPIO_PORTC_DATA_R &= ~PIN0 ;
}
}
在How do you set, clear, and toggle a single bit? 上介绍了这种惯用技术的概括
但是,如果寄存器可能在不同的线程/中断上下文中被访问,那么|= / &= 所暗示的读取-修改-写入可能会出现问题,并且可能会增加不必要的开销。 Cortex-M3/4 部件具有称为位带的功能,允许直接和原子地寻址各个位。给定:
volatile uint32_t* getBitBandAddress( volatile const void* address, int bit )
{
__IO uint32_t* bit_address = 0;
uint32_t addr = reinterpret_cast<uint32_t>(address);
// This bit maniplation makes the function valid for RAM
// and Peripheral bitband regions
uint32_t word_band_base = addr & 0xf0000000u;
uint32_t bit_band_base = word_band_base | 0x02000000u;
uint32_t offset = addr - word_band_base;
// Calculate bit band address
bit_address = reinterpret_cast<__IO uint32_t*>(bit_band_base + (offset * 32u) + (static_cast<uint32_t>(bit) * 4u));
return bit_address ;
}
那么你可以:
char process_key(int a)
{
static volatile uint32_t* PC0_BB_ADDR = getBitBandAddress( &GPIO_PORTC_DATA_R, 0 ) ;
*PC0_BB_ADDR = a ;
}
您当然可以确定并硬编码位带地址;例如:
#define PC0 (*((volatile uint32_t *)0x420C7F88u))
然后:
char process_key(int a)
{
PC0 = a ;
}
位带地址计算的详细信息可以找到ARM Cortex-M Technical Reference Manual,还有一个在线计算器here。