位带操作其实很简单,就是把位带区某寄存器的特定位,用公式给映射到位带别名区的32位地址上,该地址在编译器看来是个立即数,因此需要强制类型转换成32位地址指针,最后对指针取值操作。
特别值得注意的是,在强制类型转换成地址时,一定要加volatile关键词,不然一定会被编译器level-3优化掉,导致程序出错。博主一开始是直接使用(unsigned int *),然后在这里调试了很久,一直没发现问题所在,突然想到三级优化,加上volatile后程序正常执行。
以下是位带宏定义和输入—输出测试代码,转载请说明出处,谢谢!
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_key.h"
/**
* @brief 位带操作
* @cal ((addr & 0xF0000000) + 0X02000000 + ((addr & 0x00FFFFFF) << 5) + ((bitnum) << 2))
* @note 上述公式将位带区的寄存器addr第bitnum位,转化为位带别名区的一个32位地址
* @attention 强制类型时一定要加volatile,不然会被level-3优化掉(ODR正常,IDR错误)
*/
// 位带输出
#define GPIOA_ODR_Addr (GPIOA_BASE + 0X0C)
#define GPIOB_ODR_Addr (GPIOB_BASE + 0X0C)
#define GPIOC_ODR_Addr (GPIOC_BASE + 0X0C)
#define GPIOD_ODR_Addr (GPIOD_BASE + 0X0C)
#define GPIOE_ODR_Addr (GPIOE_BASE + 0X0C)
#define GPIOF_ODR_Addr (GPIOF_BASE + 0X0C)
#define GPIOG_ODR_Addr (GPIOG_BASE + 0X0C)
#define PAout(n) *(volatile unsigned int *)((GPIOA_ODR_Addr & 0xF0000000) + 0X02000000 + ((GPIOA_ODR_Addr & 0x00FFFFFF) << 5) + ((n) << 2))
#define PBout(n) *(volatile unsigned int *)((GPIOB_ODR_Addr & 0xF0000000) + 0X02000000 + ((GPIOB_ODR_Addr & 0x00FFFFFF) << 5) + ((n) << 2))
#define PCout(n) *(volatile unsigned int *)((GPIOC_ODR_Addr & 0xF0000000) + 0X02000000 + ((GPIOC_ODR_Addr & 0x00FFFFFF) << 5) + ((n) << 2))
#define PDout(n) *(volatile unsigned int *)((GPIOD_ODR_Addr & 0xF0000000) + 0X02000000 + ((GPIOD_ODR_Addr & 0x00FFFFFF) << 5) + ((n) << 2))
#define PEout(n) *(volatile unsigned int *)((GPIOE_ODR_Addr & 0xF0000000) + 0X02000000 + ((GPIOE_ODR_Addr & 0x00FFFFFF) << 5) + ((n) << 2))
#define PFout(n) *(volatile unsigned int *)((GPIOF_ODR_Addr & 0xF0000000) + 0X02000000 + ((GPIOF_ODR_Addr & 0x00FFFFFF) << 5) + ((n) << 2))
#define PGout(n) *(volatile unsigned int *)((GPIOG_ODR_Addr & 0xF0000000) + 0X02000000 + ((GPIOG_ODR_Addr & 0x00FFFFFF) << 5) + ((n) << 2))
// 位带输入
#define GPIOA_IDR_Addr (GPIOA_BASE + 0X08)
#define GPIOB_IDR_Addr (GPIOB_BASE + 0X08)
#define GPIOC_IDR_Addr (GPIOC_BASE + 0X08)
#define GPIOD_IDR_Addr (GPIOD_BASE + 0X08)
#define GPIOE_IDR_Addr (GPIOE_BASE + 0X08)
#define GPIOF_IDR_Addr (GPIOF_BASE + 0X08)
#define GPIOG_IDR_Addr (GPIOG_BASE + 0X08)
#define PAin(n) *(volatile unsigned int *)((GPIOA_IDR_Addr & 0xF0000000) + 0X02000000 + ((GPIOA_IDR_Addr & 0x00FFFFFF) << 5) + ((n) << 2))
#define PBin(n) *(volatile unsigned int *)((GPIOB_IDR_Addr & 0xF0000000) + 0X02000000 + ((GPIOB_IDR_Addr & 0x00FFFFFF) << 5) + ((n) << 2))
#define PCin(n) *(volatile unsigned int *)((GPIOC_IDR_Addr & 0xF0000000) + 0X02000000 + ((GPIOC_IDR_Addr & 0x00FFFFFF) << 5) + ((n) << 2))
#define PDin(n) *(volatile unsigned int *)((GPIOD_IDR_Addr & 0xF0000000) + 0X02000000 + ((GPIOD_IDR_Addr & 0x00FFFFFF) << 5) + ((n) << 2))
#define PEin(n) *(volatile unsigned int *)((GPIOE_IDR_Addr & 0xF0000000) + 0X02000000 + ((GPIOE_IDR_Addr & 0x00FFFFFF) << 5) + ((n) << 2))
#define PFin(n) *(volatile unsigned int *)((GPIOF_IDR_Addr & 0xF0000000) + 0X02000000 + ((GPIOF_IDR_Addr & 0x00FFFFFF) << 5) + ((n) << 2))
#define PGin(n) *(volatile unsigned int *)((GPIOG_IDR_Addr & 0xF0000000) + 0X02000000 + ((GPIOG_IDR_Addr & 0x00FFFFFF) << 5) + ((n) << 2))
void delay(uint32_t count);
int main(void)
{
LED_GPIO_Config();
KEY_GPIO_Config();
#if 0
while (1)
{
// 位带输出测试
PBout(1) = 1;
delay(0XFFFFF);
PBout(1) = 0;
delay(0XFFFFF);
}
#else
while (1)
{
// 位带输入测试
if (PAin(0) == KEY_ON)
{
while (PAin(0) == KEY_ON);
LED_B_OFF;
LED_R_TOGGLE;
}
if (PCin(13) == KEY_ON)
{
while (PCin(13) == KEY_ON);
LED_R_OFF;
LED_B_TOGGLE;
}
}
#endif
}
void delay(uint32_t count)
{
for (; count != 0; count--);
}