Cortex-M3/M4有位带区(BIT-BAND),可以进行位带操作,而Cortex-M0是没有此功能区域的。
必须说明一点,BIT-BAND的本质可以说是空间换时间。是为追求速度而设置的功能。像STM32F0XX这些Cortex-M0系列的MCU,如果追求速度,还是老老实实操作BSRR/BRR这类专门的寄存器。
如果不介意速度损失,单纯想做出类似"位带"操作(比如:PAout(0)= 0,可让GPIOA.0拉低),还是可以的。
以STM32F0XX为例,因为16个IO为一组(比如PA0~PA16),则可定义一个包含16个位的结构体
typedef struct
{
u16 bit0 : 1;
u16 bit1 : 1;
u16 bit2 : 1;
u16 bit3 : 1;
u16 bit4 : 1;
u16 bit5 : 1;
u16 bit6 : 1;
u16 bit7 : 1;
u16 bit8 : 1;
u16 bit9 : 1;
u16 bit10 : 1;
u16 bit11 : 1;
u16 bit12 : 1;
u16 bit13 : 1;
u16 bit14 : 1;
u16 bit15 : 1;
} Bits16_TypeDef;
这样,对各个IO的读取和赋值可以定义成以下宏:"模仿位带宏"
#define PAin(n) ( ( GPIOA->IDR&(1 << (n)) )>>n )
#define PBin(n) ( ( GPIOB->IDR&(1 << (n)) )>>n )
#define PCin(n) ( ( GPIOC->IDR&(1 << (n)) )>>n )
#define PDin(n) ( ( GPIOD->IDR&(1 << (n)) )>>n )
#define PEin(n) ( ( GPIOE->IDR&(1 << (n)) )>>n )
#define PFin(n) ( ( GPIOF->IDR&(1 << (n)) )>>n )
#define PAout(n) ( ((Bits16_TypeDef *)(&(GPIOA->ODR)))->bit##n )
#define PBout(n) ( ((Bits16_TypeDef *)(&(GPIOB->ODR)))->bit##n )
#define PCout(n) ( ((Bits16_TypeDef *)(&(GPIOC->ODR)))->bit##n )
#define PDout(n) ( ((Bits16_TypeDef *)(&(GPIOD->ODR)))->bit##n )
#define PEout(n) ( ((Bits16_TypeDef *)(&(GPIOE->ODR)))->bit##n )
#define PFout(n) ( ((Bits16_TypeDef *)(&(GPIOF->ODR)))->bit##n )
这样,就可以类似Cortex-M3/M4那样操作了。在STM32F030上测试OK。使用限制是:PXout(n)中的n只能是0~15,不能是变量。
对比一下STM32F0XX对应的库函数
/**
* @brief Reads the specified input port pin.
* @param GPIOx: where x can be (A, B, C, D or F) to select the GPIO peripheral.
* @param GPIO_Pin: specifies the port bit to read.
* @note This parameter can be GPIO_Pin_x where x can be:(0..15) for GPIOA,
* GPIOB or GPIOC,(0..2) for GPIOD and(0..3) for GPIOF.
* @retval The input port pin value.
*/
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
uint8_t bitstatus = 0x00;
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GET_GPIO_PIN(GPIO_Pin));
if ((GPIOx->IDR & GPIO_Pin) != (uint32_t)Bit_RESET)
{
bitstatus = (uint8_t)Bit_SET;
}
else
{
bitstatus = (uint8_t)Bit_RESET;
}
return bitstatus;
}
/**
* @brief Sets or clears the selected data port bit.
* @param GPIOx: where x can be (A, B, C, D or F) to select the GPIO peripheral.
* @param GPIO_Pin: specifies the port bit to be written.
* @param BitVal: specifies the value to be written to the selected bit.
* This parameter can be one of the BitAction enumeration values:
* @arg Bit_RESET: to clear the port pin
* @arg Bit_SET: to set the port pin
* @note The GPIO_Pin parameter can be GPIO_Pin_x where x can be: (0..15) for GPIOA,
* GPIOB or GPIOC,(0..2) for GPIOD and(0..3) for GPIOF.
* @retval None
*/
void GPIO_WriteBit(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, BitAction BitVal)
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GET_GPIO_PIN(GPIO_Pin));
assert_param(IS_GPIO_BIT_ACTION(BitVal));
if (BitVal != Bit_RESET)
{
GPIOx->BSRR = GPIO_Pin;
}
else
{
GPIOx->BRR = GPIO_Pin ;
}
}
考虑到Cortex-M0为3级流水线RISC处理器,搞不好我的"模仿位带宏"速度更快,至少时间稳健性更好。