历史上的今天
今天是:2024年09月01日(星期日)
2021年09月01日 | STM32—位带操作
2021-09-01 来源:eefocus
STM32中的位带操作: 名字为位带操作,实际上是对位的操作,位操作就是可以单独的对一个比特位读和写,这个在 51 单片机中非常常见。 51 单片机中通过关键字 sbit 来实现位定义, STM32 没有这样的关键字,而是通过访问位带别名区来实现。STM32 的全部寄存器都可以通过访问位带别名区的方式来达到访问原始寄存器比特位的效果,这比 51 单片机强大很多。因为 51 单片机里面并不是所有的寄存器都是可以比特位操作,有些寄存器还是得字节操作,比如 SBUF。
51单片机中的位操作:
51单片机中可以对寄存器实现单个位的操作,靠的就是关键字sbit,如
sbit led=P1^0; led=1;就可实现对P1.0位置1的效果。
为什么STM32不推崇直接进行位操作?
本人认为STM32是32位MCU,一次处理32位数据,所以一次只处理一位的数据未必大材小用了,除非特殊情况,否则都以32位处理。
如何处理STM32中要对某一位进行操作时的情况?
要知道STM32中采用库函数编程,所以有很多的对位操作的任务都用具体的函数来完成,而这些函数都已经做好了我们只需要知道怎么用就行。但我们仍然可以自己实现位操作,这种神操作就是位带操作 。
位带区与位带区别名:
在 STM32 中,有两个地方实现了位带,一个是 SRAM 区的最低 1MB 空间,令一个是外设区最低 1MB 空间。这两个 1MB 的空间除了可以像正常的 RAM 一样操作外,他们还有自己的位带别名区,位带别名区把这 1MB 的空间的每一个位膨胀成32 位 (要知道 STM32 的系统总线是 32 位的,按照 4 个字节访问的时候是最快的,所以膨胀成 4 个字节来访问是最高效的。),当访问位带别名区的这些字时,就可以达到访问位带区某个比特位的目的。
位带区就是就是可以进行位带操作的寄存器的映射地址。
位带区别名可以理解为将位带区每一个位都膨胀32倍(用一个字节代表一个位,以便于32位MCU操作)后的地址。
如何实现位带操作?
要进行位带操作需要知道被操作的位的地址,因为SRAM和外设中都可以位带操作,所以形式上可以将位带操作归纳为俩个公式。
对于位带区的某个比特,记它所在字节的地址为 A,位序号为 n(0<=n<=7),则其在位带区别名地址为:
外设: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。
当然,也可以将俩个公式合二为一:
// 把“位带地址+位序号”转换成别名地址的宏
AliasAdd = (addr & 0xF0000000)+0x02000000+((addr &0x00FFFFFF)<<5)+(bitnum<<2)
知晓了位带区别名的地址,然后将此地址转换为指针类型就可以通过位带操作对原始的为进行操作。
附上野火的位带操作代码:
#include "stm32f10x.h"
#include "./led/bsp_led.h"
#define PCout(n) (*(unsigned int*)(((GPIOC_BASE+0x0c) & 0xF0000000)+0x02000000+(((GPIOC_BASE+0x0c) &0x000FFFFF)<<5)+(n<<2)))
#define PBout(n) (*(unsigned int*)(((GPIOB_BASE+0x0c) & 0xF0000000)+0x02000000+(((GPIOB_BASE+0x0c) &0x000FFFFF)<<5)+(n<<2)))
void delay(uint32_t count)
{
for(; count!=0; count--);
}
int main(void)
{
LED_GPIO_Config(); //LED初始化函数
while(1)
{
PCout(2) = 1;
//GPIO_SetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);
delay(0xfffff);
PCout(2) = 0;
//GPIO_ResetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);
delay(0xfffff);
PCout(3) = 1;
//GPIO_SetBits(LED2_GPIO_PORT, LED2_GPIO_PIN);
delay(0xfffff);
PCout(3) = 0;
//GPIO_ResetBits(LED2_GPIO_PORT, LED2_GPIO_PIN);
delay(0xfffff);
}
代码简述:用宏定义的方法来操作GPIOC中的ODR寄存器和IDR寄存器中的某一位来实现led灯的亮灭
#define PCout(n) (*(unsigned int*)(((GPIOC_BASE+0x0c) & 0xF0000000)+0x02000000+(((GPIOC_BASE+0x0c) &0x000FFFFF)<<5)+(n<<2)))
史海拾趣
|
1 引言 LIN 是低成本网络中的汽车通讯协议标准,LIN(Local Interconnect Network)是低成本的汽车网络,它是现有多种汽车网络在功能上的补充由于能够提高质量、降低成本,LIN 将是在汽车中使用汽 ...… 查看全部问答> |
|
昨日与友人闲谈,得知其急需一FDD接口的U盘.用于工控.遂发此贴,求助于诸位.提及FDD(即软驱),众皆笑曰:\"淘汰久矣!\"然,君不见其依然服役于众多工控场合?随之FPGA/RAM等先进技术之普及.待处理数据之大,昔日之1.44何以满足?市有产品曰:仿真软驱,价格奇 ...… 查看全部问答> |
|
请问各位大侠,C++.net能开发硬件程序吗,就是那种控制门口挡车杆升降的程序。 如果不能,那可以用VisualC++开发吗? 多种语言开发的程序可不可以组成一个软件上那? 谢谢各位。… 查看全部问答> |
|
偶然在网上看到了AMD的一个“我为三核狂”活动,整个活动的主旨都是围绕“三核”的概念来的,网友的热情和创意也是让人叹为观止,大家下面这些有趣的作品吧。简直是神了!大家也来欣赏一下哦 &n ...… 查看全部问答> |
|
每种STM32的产品都由16个字母或数字构成的编号标示,用户向ST订货时必须使用这个编号指定需要的产品。这16个字符分为8个部分,下面通过一个例子说明它们的意义: STM32 F 103 C 6 T 7 xxx 1 2& ...… 查看全部问答> |
|
我用P1口接4*4矩阵键盘,现在为了省出P1.0口作为AD通道,采用P2口接4*4矩阵键盘。 然后配置P2.6和P2.7作为GPIO口,然后程序的其他地方都是把P1改为P2,为什么不能用呢?????? 大家有过这样的经历吗?… 查看全部问答> |
|
经过一段时间的调试,EELogic的第一版硬件基本测试完成。 电源工作正常,68013能正常下载固件,FPGA能正常下载及运行。 基本硬件测试通过,起码保证了大家申请到板子回去焊接后能工作,避免浪费大家的时间及经费。 软件开发主要有三个部分: 1 ...… 查看全部问答> |
|
通过usb blaster ii接口烧写过一次jic文件,后来再烧写时点击“Auto Detect”就再也检测不到型号了,提示信息“unable to scan device chain.Hardware is not connected.” 求助给位怎么解决。 … 查看全部问答> |




