STM32位带操作详细介绍

前言

//在STM32中,如果我们要使PB0端口输出低电平,可以用如下语句
GPIOB->ODR |= 0<<0;
//在51单片机中我们是这样的
P0 = 0xff;   //总线操作
//还有一种方法
sbit LED1 = P0^0;
LED1 = 0;//位操作

在STM32中能不能实现位操作呢,当然是可以的,这种方法我们叫做位带操作。位操作就是可以单独的对一个比特位读和写。

1.位带简介

位带
在STM32中,有两个地方实现了位带,一个是 SRAM 区的最低 1MB 空间,另一个是外设区最低 1MB 空间。这两个 1MB 的空间除了可以像正常的 RAM 一样操作外,他们还有自己的位带别名区,位带别名区把这 1MB 的空间的每一个位膨胀成一个 32 位的字,当访问位带别名区的这些字时,就可以达到访问位带区某个比特位的目的。

比如位带区:外设区,这其中的一个位,可以在位带别名区重新找到4个字节的地址,也就是32位,来重新命名,而这32位,只有最低位有效。所以空间利用不是很充足,但是提供了方便。

例子:
PB的ODR寄存器地址为0x40010C0C,假设我们就操作PB0,即操作ODR寄存器第0位,那么这个位新的地址Addr= =0x42000000+ (0x40010C0C-0x40000000)84 +0*4。

给这个地址命名为PBout(0);

2.计算公式

外设区:

AliasAddr= =0x42000000+ (A-0x40000000)84 +n*4

0X42000000 是外设位带别名区的起始地址, 0x40000000 是外设位带区的起始地址,(A-0x40000000)表示该比特前面有多少个字节,一个字节有 8 位,所以8,一个位膨胀后是 4 个字节,所以4, n 表示该比特在 A 地址的序号,因为一个位经膨胀后是四个字节,所以也*4。

SRAM区:

AliasAddr= =0x22000000+ (A-0x20000000)84 +n*4

公式分析同上

统一公式

为了方便操作,我们可以把这两个公式合并成一个公式,把“位带地址+位序号”转
换成别名区地址统一成一个宏。

 // 把“位带地址+位序号”转换成别名地址的宏
2 #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x02000000+((addr & 0x00FFFFFF)<<5)+(bitnum<<2))

addr & 0xF0000000 是为了区别 SRAM 还是外设,实际效果就是取出 4 或者 2,如果是外设,则取出的是 4, +0X02000000 之后就等于 0X42000000, 0X42000000 是外设别名区的起始地址。如果是 SRAM,则取出的是 2, +0X02000000 之后就等于 0X22000000,0X22000000 是 SRAM 别名区的起始地址。
addr & 0x00FFFFFF 屏蔽了高三位,相当于减去 0X20000000 或者 0X40000000,但是为什么是屏蔽高三位?因为外设的最高地址是: 0X2010 0000, 跟起始地址 0X20000000 相减的时候,总是低 5 位才有效,所以干脆就把高三位屏蔽掉来达到减去起始地址的效果,具体屏蔽掉多少位跟最高地址有关。 SRAM 同理分析即可。 <<5 相当于84, <<2 相当于*4,这两个我们在上面分析过。

最后我们就可以通过指针的形式操作这些位带别名区地址,最终实现位带区的比特位操作。

// 把一个地址转换成一个指针
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
// 把位带别名区地址转换成指针
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))

3.GPIO位带实现

// 把“位带地址+位序号”转换成别名地址的宏
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x02000000+((addr & 0x00FFFFFF)<<5)+(bitnum<<2))

// 把一个地址转换成一个指针
#define MEM_ADDR(addr)           *((unsigned long *)(addr))
// 把位带别名区地址转换成指针
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))

//GPIO ODR 和 IDR 寄存器地址映射
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C
#define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C
#define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C

#define GPIOA_IDR_Addr (GPIOA_BASE+8) //0x40010808
#define GPIOB_IDR_Addr (GPIOB_BASE+8) //0x40010C08
#define GPIOC_IDR_Addr (GPIOC_BASE+8) //0x40011008
#define GPIOD_IDR_Addr (GPIOD_BASE+8) //0x40011408

//单独操作 GPIO 的某一个 IO 口, n(0,1,2...16),n 表示具体是哪一个 IO 口
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n) //输出
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n) //输入

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n) //输出
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n) //输入

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n) //输出
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n) //输入

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n) //输出
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n) //输入

这样就可以使用PBout(0),相比之下还是很方便的。

  • 5
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32F103C8T6芯片中,可以通过位带操作来实现对IO口或特殊寄存器的按位操作位带操作是在8051单片机中首先出现的,而在STM32中,它是对8051位寻址区的进一步加强。具体来说,位带操作可以通过映射一个内存地址到一个特定的位来实现对该位的直接操作。 举例来说,如果我们想要在STM32F103C8T6中对某个IO口的某一位进行操作,我们可以使用位带操作来实现。首先,我们需要将该IO口对应的内存地址映射到一个位带别名区域。然后,我们可以直接对位带别名区域中的位进行读操作,而不需要再使用位操作的方式。这样可以提高代码的可读性和执行效率。 要使用位带操作,在STM32F103C8T6中,你可以参考《ARM Cortex-M3权威指南》中关于位带操作介绍。该指南可以提供关于位带操作详细说明和示例代码。通过阅读该指南,你可以了解如何在STM32F103C8T6芯片上实现位带操作,并且可以根据自己的需求进行相应的编程。 总结起来,位带操作是一种在STM32F103C8T6中实现按位操作的方法,可以提高代码的可读性和执行效率。你可以参考《ARM Cortex-M3权威指南》中的介绍来了解如何在该芯片上实现位带操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [STM32 进阶教程 8 - 位带操作](https://blog.csdn.net/zhanglifu3601881/article/details/94902480)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值