stm32专题三:位带操作—GPIO输出和输入

       位带操作其实很简单,就是把位带区某寄存器的特定位,用公式给映射到位带别名区的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--);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值