STM32f103指南者标准库-位带操作GPIO输出和输入

1、位操作:
就是可以单独的对一个比特位读和写,这个在 51 单片机中非常常见。51 单片机 中通过关键字 sbit 来实现位定义,STM32 没有这样的关键字,而是通过访问位带别名区来 实现(通俗一点就是STM32的位带操作可以像51单片机一样可以对某个GPIO进行单独操作输入或输出)。
2、有两个地方实现了位带:一个是 SRAM 区的最低 1MB 空间,令一个是 外设区最低 1MB 空间。这两个 1MB的空间除了可以像正常的 RAM 一样操作外,他们还有 自己的位带别名区,位带别名区把这 1MB 的空间的每一个位膨胀成一个 32 位的字,当访 问位带别名区的这些字时,就可以达到访问位带区某个比特位的目的。(个人理解就STM32有两个位带区,这个区域范围里面的地址可以膨胀成位带别名区,进行位带操作)
3、位带别名区的地址:
  • 外设外带区的地址为:
  • 0X40000000~0X40100000,大小为 1MB,这 1MB 的大小在 103 系列大//小容量型号的单片机中包含了片上外设的全部寄存器,这些寄存器的地址为:
  • 0X40000000~0X40029FFF 。 外 设 位 带 区 经 过 膨 胀 后 的 位 带 别 名 区 地 址 为 :
  • 0X42000000~0X43FFFFFF,这个地址仍然在 CM3 片上外设的地址空间中。在 103 系列大/ 中小容量型号的单片机里面,0X40030000~0X4FFFFFFF 属于保留地址,膨胀后的 32MB 位 带别名区刚好就落到这个地址范围内,不会跟片上外设的其他寄存器地址重合。
  • SRAM 的位带区的地址为:
  • 0X2000 0000~X2010 0000,大小为 1MB,经过膨胀后的位
  • 带别名区地址为:0X2200 0000~0X23FF FFFF,大小为 32MB。操作 SRAM 的比特位这个
  • 用得很少。

4、想要使用位带别名区的步骤:

  • 先找到片上外设的基地址:如GPIOB的起始地址为APB2的基地址+GPIOB的偏移0x0C,在固件库函数表示 (GPIOB_BASE+0x0C)
  • 接下来引入计算位带别名区的公式:
  • 外设位带区:AliasAddr= =0x42000000+ (A-0x40000000)*8*4 +n*4
  • SRAM位带区:AliasAddr= =0x22000000+ (A-0x20000000)*8*4 +n*4
  • 解释含义:
  • 0X42000000 是外设位带别名区的起始地址,0x40000000 是外设位带区的起始地址
  • (A-0x40000000)表示该比特前面有多少个字节,一个字节有 8 位,所以*8,一个位膨胀后是 4 个字节,所以*4,n 表示该比特在 A 地址的序号,因为一个位经过膨胀后是四个字 节,所以也*4。(后面SRAM位带区一样含义,起始地址换成0x20000000)
  • 在代码中体现(二合一)
((GPIOB_ODR_Addr&0xF0000000)+0x02000000+((GPIOB_ODR_Addr&0x00FFFFFF)<<5)+(n<<2)) 
  • addr & 0xF0000000 是为了区别 SRAM 还是外设,实际效果就是取出 4 或者 2,如果是 外设,则取出的是 4+0X02000000 之后就等于 0X420000000X42000000 是外设别名区的 起始地址。如果是 SRAM,则取出的是 2+0X02000000 之后就等于 0X220000000X22000000 SRAM 别名区的起始地址。
  • addr & 0x00FFFFFF 屏蔽了高三位,相当于减去 0X20000000 或者 0X40000000,但是为 什么是屏蔽高三位?因为外设的最高地址是:0X2010 0000,跟起始地址 0X20000000 相减 的时候,总是低 5 位才有效,所以干脆就把高三位屏蔽掉来达到减去起始地址的效果,具 体屏蔽掉多少位跟最高地址有关。
  • SRAM同理分析即可。<<5相当于*8*4<<2相当于*4这两个我们在上面分析过。
  • 最后我们就可以通过指针的形式操作这些位带别名区地址,最终实现位带区的比特位 操作

5、代码操作:宏定义 main.c

#define GPIOB_ODR_Addr          (GPIOB_BASE+0x0C) // 定义GPIOB的基地址
#define GPIOA_IDR_Addr          (GPIOA_BASE+0x08) // 定义GPIOA寄存器的基地址
#define GPIOC_IDR_Addr          (GPIOC_BASE+0x08) // 定义GPIOC寄存器的基地址

// PBout为odr寄存器控制GPIOB端口x位输出,转换成位带别名区
#define PBout(n)  *(unsigned int *)((GPIOB_ODR_Addr&0xF0000000)+0x02000000+((GPIOB_ODR_Addr&0x00FFFFFF)<<5)+(n<<2)) 

// PAout为idr寄存器控制GPIOA端口x位输入,转换成位带别名区
#define PAinp(n)  *(unsigned int *)((GPIOA_IDR_Addr&0xF0000000)+0x02000000+((GPIOA_IDR_Addr&0x00FFFFFF)<<5)+(n<<2))

// PCout为idr寄存器控制GPIOC端口x位输入,转换成位带别名区
#define PCinp(n)  *(unsigned int *)((GPIOC_IDR_Addr&0xF0000000)+0x02000000+((GPIOC_IDR_Addr&0x00FFFFFF)<<5)+(n<<2))
#define KEY_1     PAinp(0)	   // GPIOA_PIN_0 口
#define KEY_2     PCinp(13)    // GPIOC_PIN_13口
#define LED_1     PBout(0)	   // GPIOB_PIN_0 口
#define LED_2     PBout(1)
#define LED_3     PBout(5)

完整代码操作:

通过位带操作控制按键按下时点亮LED,蜂鸣器伴随响。

#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_key.h"
#include "beep.h"

#define GPIOB_ODR_Addr          (GPIOB_BASE+0x0C)
#define GPIOA_IDR_Addr          (GPIOA_BASE+0x08)
#define GPIOC_IDR_Addr          (GPIOC_BASE+0x08)
#define PBout(n)  *(unsigned int *)((GPIOB_ODR_Addr&0xF0000000)+0x02000000+((GPIOB_ODR_Addr&0x00FFFFFF)<<5)+(n<<2)) 
#define PAinp(n)  *(unsigned int *)((GPIOA_IDR_Addr&0xF0000000)+0x02000000+((GPIOA_IDR_Addr&0x00FFFFFF)<<5)+(n<<2))
#define PCinp(n)  *(unsigned int *)((GPIOC_IDR_Addr&0xF0000000)+0x02000000+((GPIOC_IDR_Addr&0x00FFFFFF)<<5)+(n<<2))
#define KEY_1     PAinp(0)	
#define KEY_2     PCinp(13)
#define LED_1     PBout(0)	
#define LED_2     PBout(1)
#define LED_3     PBout(5)


int main(void)
{
    LED_GPIO_Config();
	KEY_GPIO_Config();
	BEEP_GPIO_Config();
	LED_R(OFF);
	LED_G(OFF);

    while(1)	
    {
		 if(KEY_1 == KEY_ON)
		 {
			while(KEY_1 == KEY_ON)
			LED_1 = 0;
			Beep_Res();  // 蜂鸣器响
		 }
		   else LED_1 = 1;
				
		 if(KEY_2 == KEY_ON)
		 {
		    while(KEY_2 == KEY_ON)
		    LED_2 = 0;
		    Beep_Res();
		 }
			else LED_2 = 1;	
	}
}

总结:多练习,举一反三,比如说视频教程教你配置GPIO1,你可以去配置2,3甚至更多,多看看源码函数的实现和注释

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值