stm32位带操作

发布者:温暖的微风最新更新时间:2024-07-16 来源: elecfans关键字:stm32  位带操作  指针 手机看文章 扫描二维码
随时随地手机看文章

  STM32系列基于专为要求高性能、低成本、低功耗嵌入式应用专门设计的ARM Cortex-M3内核(ST‘s product portfolio contains a comprehensive range of microcontrollers, from robust, low-cost 8-bit MCUs up to 32-bit ARM-based Cortex®-M0 and M0+, Cortex®-M3, Cortex®-M4 Flash microcontrollers with a great choice of peripherals. ST has also extended this range to include an ultra-low-power MCU platform)[1] 。按内核架构分为不同产品:

  其中STM32F系列有:

  STM32F103“增强型”系列

  STM32F101“基本型”系列

  STM32F105、STM32F107“互联型”系列

  增强型系列时钟频率达到72MHz,是同类产品中性能最高的产品;基本型时钟频率为36MHz,以16位产品的价格得到比16位产品大幅提升的性能,是32位产品用户的最佳选择。两个系列都内置32K到128K的闪存,不同的是SRAM的最大容量和外设接口的组合。时钟频率72MHz时,从闪存执行代码,STM32功耗36mA,相当于0.5mA/MHz。

  

  在CM3中,有两个区中实现了位带。其中一个是 SRAM 区的最低 1MB 范围,第二个则是片内外设区的最低 1MB 范围。这两个区中的地址除了可以像普通的 RAM 一样使用外,它们还都有自己的“位带别名区”,位带别名区把每个比特膨胀成一个 32 位的字。当你通过位带别名区访问这些字时,就可以达到访问原始比特的目的。

  在位带区中,每个比特都映射到别名地址区的一个字(这是只有 LSB 有效的字)。当一个别名地址被访问时,会先把该地址变换成位带地址。对于读操作,读取位带地址中的一个字,再把需要的位右移到 LSB,并把 LSB 返回。对于写操作,把需要写的位左移至对应的位序号处,然后执行一个原子的“读-改-写”过程。

  支持位带操作的两个内存区的范围是:

  0x2000_0000‐0x200F_FFFF(SRAM 区中的最低1MB) 0x4000_0000‐0x400F_FFFF(片上外设区中的最低 1MB) 位带(Bit-band)操作是Cortex-M3提供的特殊操作:位带区的每个位都有位带别名区的一个字与之对应。Bit-band区域的存储器以32位方式进行访问,其中有效的仅仅是BIT0位,只有BIT0的值才对应到相应的普通区域的比特位上,其他位无效。STM32F系列芯片为所有外设寄存器和SRAM提供相对应的Bit-band区域,以简化对外设寄存器和SRAM的操作位带操作最重要的一环就是寻址,即为需要操作的“目标位”找到位带别名区相对应的地址:

  位带别名区首地址+(操作字节的偏移量*32) +(操作位的偏移量*4) 内置SRAM区的位带别名区首地址 = 0x2200,0000 外设寄存器区的位带别名区首地址 = 0x4200,0000

  例如:GPIOA的端口输出数据寄存器地址0x4001080c(stm32f1xx系列),对于PA.0来说控制其输出电平的比特位的位带操作地址为:

  0x42000000+(0x1080c*32)+(0*4) = 0x42021018 以stm32f207为例,介绍stm32的位带操作。

  

  在《ARM Cortex M3权威指南》92页介绍了如何在C语言中使用位带操作。个人在使用位带操作过程中将其大致总结为三种:

  ① 查找需要定义的位所在的地址,将地址强制转换为指针,通过取指针内容的方式使用。

  例如:

  #define PD12 ((volatile unsigned long *)(0x424182b0))

  //0x424182b0为GPIOD_Pin12引脚对应的映射地址

  *PD12=0x01; //PD12引脚置高

  ② 直接使用地址进行操作

  (*((u32*)0x424182b0))=0x01; //PD12引脚置高 当然也可以通过如下定义使用 例如:

  #define PD12 *((volatile unsigned long *)(0x424182b0))

  //0x424182b0为GPIOD_Pin12引脚对应的映射地址

  PD12=0x01; //PD12引脚置高

  ③在多个引脚需要定义时,显然上面两种方法都比较繁琐。为简化位带操作,也可以定义一些宏。比如,我们可以建立一个把“位带地址+位序号”换成别名地址的宏,再建立一个把别名地址转换成指针类型的宏。

  例如

  #define GPIOD_ODR_Addr ((uint32_t)(GPIOD_BASE+0x14)) // GPIOD_BASE已经定义过 #define BITBAND(addr,bitnum) ((addr&0xF0000000)+0x2000000+((addr&0xFFFFF)《《5)+(bitnum《《2)) #define MEM_ADDR(addr) (*((volatile unsigned long *)(addr)) ) #define BIT_ADDR(addr, bitnum) MEM_ADDR( BITBAND(addr, bitnum) ) #define PD12 BIT_ADDR(GPIOD_ODR_Addr, 12) //12为GPIOD对应的引脚号 #define PD12 BIT_ADDR(GPIOD_ODR_Addr, 13) //13为GPIOD对应的引脚号 PD12=0x01; //PD12引脚置高 PD13=0x01; //PD13引脚置高

  

  说明:GPIOD_BASE已经在库文件stm32f2xx.h中定义过,直接使用即可,对应地址是GPIOD的基地址,0x14是ODR的偏移地址。第二条语句是把“位带地址+序号”转换为对应的位带别名区地址。第三条语句MEM_ADDR(addr)代表的是(addr)地址中的内容。volatile必须使用,原因如下。

  volatile 是易变的、不稳定的意思。用它修饰的变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

  先看看下面的例子: int i=10; int j = i;//(1)语句 int k = i;//(2)语句

  这时候编译器对代码进行优化,因为在(1)、(2)两条语句中,i 没有被用作左值。这时候编译器认为 i 的值没有发生改变,所以在(1)语句时从内存中取出 i 的值赋给 j 之后,这个值并没有被丢掉,而是在(2)语句时继续用这个值给 k 赋值。编译器不会生成出汇编代码重新从内存里取 i 的值,这样提高了效率。但要注意:(1)、(2)语句之间 i 没有被用作左值才行。

  再看另一个例子: volatile int i=10; int j = i;//(3)语句 int k = i;//(4)语句

  volatile 关键字告诉编译器 i 是随时可能发生变化的,每次使用它的时候必须从内存中取出 i的值,因而编译器生成的汇编代码会重新从 i 的地址处读取数据放在 k 中。这样看来,如果 i 是一个寄存器变量或者表示一个端口数据或者是多个线程的共享数据,就容易出错,所以说 volatile 可以保证对特殊地址的稳定访问。


关键字:stm32  位带操作  指针 引用地址:stm32位带操作

上一篇:STM32CubeMX+使用教程
下一篇:stm32单片机用什么语言 编程 stm32各种型号

推荐阅读最新更新时间:2026-03-21 23:16

关于STM32中的(bit-band)操作说明
支持了位带操作后,可以使用普通的加载/存储指令来对单一的比特进行读写。在 CM3 中,有两个区中实现了位带。其中一个是 SRAM 区的最低 1MB 范围,第二个则是片内外设区的最低 1MB范围。这两个区中的地址除了可以像普通的 RAM 一样使用外,它们还都有自己的“位带别名区”,位带别名区把每个比特膨胀成一个 32 位的字。当你通过位带别名区访问这些字时,就可以达到访问原始比特的目的。 位带操作的概念其实 30 年前就有了,那还是8051 单片机开创的先河,如今,CM3 将此能力进化,这里的位带操作是 8051 位寻址区的威力大幅加强版。 CM3 使用如下术语来表示位带存储的相关地址: 位带区:支
[单片机]
关于<font color='red'>STM32</font>中的<font color='red'>位</font><font color='red'>带</font>(bit-band)<font color='red'>操作</font>说明
STM32操作
一、带位操作 位带操作就是将 位带区 中的每一位(bit)膨胀成位带别名区中的一 个 32 位的字 ,通过访问位 带别名区中的字 就实现了访问位带区中位的目的.可以使用指针来访问位带别名区的地址,从而实现访问 位带区内位的 目 的。 1.1、什么是带位操作 51单片机通过关键字sbit对单片机IO口进行位定义的过程即带位操作。 1.2、STM32如何实现带位操作 每个比特为膨胀成一个32位字,当访问这些字的时候就达到访问比特的目的。 举例:BSRR 寄存器有 32 个位,那么可以映射到 32 个地址上,当我们去访问这 32 个地址就达到访问 32 个比特的目的。 STM32F1 中有两个区域支持位带操作,一个是 S
[单片机]
<font color='red'>STM32</font><font color='red'>带</font><font color='red'>位</font><font color='red'>操作</font>
STM32中的(bit-band)操作
//位带操作,实现51类似的GPIO控制功能 //具体实现思想,参考 CM3权威指南 第五章(87页~92页). //IO口操作宏定义 #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF) 5)+(bitnum 2)) #define MEM_ADDR(addr) *((volatile unsigned long *)(addr)) #define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum)) //IO口地址映射 #define GPIOA_ODR_Addr
[单片机]
STM32中的(bit-band)操作
//位带操作,实现51类似的GPIO控制功能 //具体实现思想,参考 CM3权威指南 第五章(87页~92页). //IO口操作宏定义 #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF) 5)+(bitnum 2)) #define MEM_ADDR(addr) *((volatile unsigned long *)(addr)) #define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum)) //IO口地址映射 #define GPIOA_ODR_Addr
[单片机]
stm32:操作
/*位带区在片上外设的地址范围:0x4000 0000-0x400F FFFF(片上外设区中的最低1MB), 位带识别区在片上外设的地址范围:0x4200 0000~0x42FF FFFF; 对应关系:位带区的每个bit位的值 对应 位带识别区1个 32位的地址的内容; 所以位带操作是:当你通过位带别名区访问这些32位的地址的内容时,就可以达到访 问位带区对应的比特位。 */ //-----位带操作宏定义 //功能:将位带区地址addr 的 bitnum 位 转换为对应 位带识别区的地址 #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((add
[单片机]
STM32——C语言知识点:指针、结构体
1 /* 2 ============================================================================ 3 Name : Cyuyanfuxi.c 4 Author : 5 Version : 6 Copyright : Your copyright notice 7 Description : Hello World in C, Ansi-style 8 ============================================================================ 9 */ 10 11
[单片机]
<font color='red'>STM32</font>——C语言知识点:<font color='red'>指针</font>、结构体
STM32指针使用
CALCBILL_DATA_ST是个结构体占地址10个 uint8 txbuf1 ={1,2,3,4,5,6,7,8,9,10}; uint8 txbuf2 ={11,12,13,14,15,16,17,18,19,20}; uint8 *pbuf1 = txbuf1; CALCBILL_DATA_ST *pbuf2 = txbuf2; 如此pbuf1和pbuf2分别指向txbuf1和txbuf2空间 uint8 *pbuf1 = txbuf1; CALCBILL_DATA_ST *pbuf2 ; memcpy(pbuf2 ,txbuf2,10); pbuf2 指向的地址是系统分配的,分配只是个
[单片机]
STM32—数组作为被调用函数的入口参数时定义成指针
STM32—数组作为被调用函数的入口参数时,要两个条件, 1:数组首地址 2:数组长度 在被调用函数中,比如把数据保存到数组pbuffer 中,那么在入口参数定义时要定义成指针u8 *pbuffer, 1 而在调用时,比如要保存到tab 中,要在入口参数处强制转换成(u8 *)tab,
[单片机]
<font color='red'>STM32</font>—数组作为被调用函数的入口参数时定义成<font color='red'>指针</font>
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved