位带操作其实很简单,就是把位带区某寄存器的特定位,用公式给映射到位带别名区的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--);
}
上一篇:stm32专题二:GPIO输入—按键检测
下一篇:stm32专题四:启动文件分析
推荐阅读最新更新时间:2024-11-10 10:58
设计资源 培训 开发板 精华推荐
- A5974AD 的典型应用 适用于汽车应用的高达 2 A 的降压开关稳压器
- LDK120PU32R 3.2V低压降稳压器典型应用(可调版)电路
- 300W隔离型DC-DC转换器
- 使用 Microchip Technology 的 TC05BC 的参考设计
- MAXREFDES1265:使用 MAX32625PICO 和 MAX7360 的简单键盘接口
- IS31FL3730 音频调制矩阵 LED 驱动器的典型应用电路 Dual 6x10
- 典型应用 使用 TC7106 ADC 实现 200 mV 满量程、3RPS、VIN- 为单端输入连接到 GND
- AVR481、DB101为图形液晶模块应用电路
- 3键CV小键盘_三键工程师键盘_CH552G
- 使用 Analog Devices 的 AD9888KS-205 的参考设计