STM32F4_位带操作

news2024/11/26 18:53:15

目录

1. 位带简介

2. 别名区地址的计算

2.1 合并计算

3. 位带操作访问ODR和IDR寄存器

4. GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2 / GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2


        位带操作在写单片机程序时,或者在宏定义某个变量时,是非常有用且方便的。

1. 位带简介

位带操作其实就是库函数操作下最底层的操作逻辑。

//在STM32中如果要使PA0输出低电平,可以是
GPIOA->ODR|=0<<0;


//在51单片机中,位带操作是通过sbit来定义的。

//P0=0xFF; //总线操作

sbit LED1=P^0   //位操作

LED1=0;

在51单片机中,通过 sbit 定义的LED1,在函数中调用 LED1 就等同于调用了 P0 引脚,给 LED1 低电平,LED 灯就会亮。

拿一个寄存器来说明位带操作的必要性:

        一个32位的寄存器,整个寄存器是有自己特定的地址的,当访问寄存器的地址时,会操作整个寄存器。但有些时候,我们只需要访问寄存器的某一位,将该位设为低电平0/高电平1就可以实现特定功能,寄存器的每一位都是有特定地址的,访问寄存器中特定位的操作,就称为位带操作

支持了位带操作以后,可以使用普通的加载/存储指令来对单一的比特进行读写。SRAM静态存储器的最低1MB范围内可以实现位带,也可以在片内最低1MB范围内实现位带操作。这两个区的地址除了可以像普通的ARM一样使用外,还都有自己的 位带别名区 ,位带别名区把每个比特膨胀成一个32位的字。当你通过位带别名区访问这些字时,就可以达到访问原始比特的目的。

比方说:PB引脚的ODR寄存器的地址是0x40010C0C,此时我们操作PB0,其最底层的操作逻辑就是操作ODR寄存器的第0位,那么这个位新的地址就是0x42000000+(0x40010C0C-0x40000000)32+0*4;通过宏定义给这个地址命名为PBout(0)。

#define PBout(0)  0x42000000+(0x40010C0C-0x40000000)84+0*4

2. 别名区地址的计算

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

0x2000_0000-0x200F_FFFF(SRAM区中的最低1MB)

0x4000_0000-0x400F_FFFF(片上外设区中的最低1MB)

对于SRAM位带区的某个比特位,记它所在字节地址为A,位序号为n(0<=n<=7),则该比特位在别名区的地址为:

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

对于片上外设的某个比特位,记它所在字节的地址为A,位序号为n(0<=n<=7),则该比特位在别名区的地址为:

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

其中,4表示一个字为4个字节,8表示一个字节中有8个比特位 

2.1 合并计算

外设与SRAM位带区与位带别名区的地址统一用一个公式表示

((addr&0xF000000)+0x02000000+((addr&0x00FFFFFF)<<5)+(bitnum<<2))

其中:addr:要操作的位所在的寄存器地址

           bitnum:位号,也就是在寄存器中的第几位 

公式中:

        addr&0xF0000000的意思是拿出要操作位所在的寄存器的最高位,如果是外设位带区,由上图,则拿出的最高位就是4,0x40000000+0x02000000=0x42000000,也就是外设位带别名区地址;如果是SRAM位带区,由上图,则拿出来的最高位就是2,0x20000000+0x02000000=0x22000000,也就是SRAM位带别名区地址;整个过程本质就是区分是外设位带操作还是SRAM位带操作

        addr&0x00FFFFFF的意思是屏蔽掉高两位,由上图可知,对于没有合并之前的公式来说,A-0x40000000就是最高位地址减去起始地址。对于外设位带区来说,最高地址就是0x40100000,SRAM位带区的最高地址就是0x20100000,不管是0x40100000-0x40000000还是0x20100000-0x20000000,其最终相减的地址都是低六位有效,最高两位是相同的,在做减法的过程中没有实际作用,所以&0x00FFFFFF就是把高2位屏蔽掉

        (addr&0x00FFFFFF)<<5左移5位的意思表示乘以2^{5},也就是乘以32,正好是对应没有合并之前的公式,左移5位表示放大了32倍。因为在C语言的位操作中,左移表示向左移位,右侧补0。

        bitnum<<2左移2位表示乘以2^{2},也就是乘以4,正好也是对应了没有合并公式之前的*4,表示 bitnum 放大了4倍。

3. 位带操作访问ODR和IDR寄存器

在学习GPIO口时,我们已经学习过了GPIO的ODR寄存器IDR寄存器,分别是GPIO输出数据寄存器GPIO输入数据寄存器

//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    (GPIOA_BASE+20) //0x40020014
#define GPIOB_ODR_Addr    (GPIOB_BASE+20) //0x40020414 
#define GPIOC_ODR_Addr    (GPIOC_BASE+20) //0x40020814 
#define GPIOD_ODR_Addr    (GPIOD_BASE+20) //0x40020C14 
#define GPIOE_ODR_Addr    (GPIOE_BASE+20) //0x40021014 
#define GPIOF_ODR_Addr    (GPIOF_BASE+20) //0x40021414    
#define GPIOG_ODR_Addr    (GPIOG_BASE+20) //0x40021814   
#define GPIOH_ODR_Addr    (GPIOH_BASE+20) //0x40021C14    
#define GPIOI_ODR_Addr    (GPIOI_BASE+20) //0x40022014     

#define GPIOA_IDR_Addr    (GPIOA_BASE+16) //0x40020010 
#define GPIOB_IDR_Addr    (GPIOB_BASE+16) //0x40020410 
#define GPIOC_IDR_Addr    (GPIOC_BASE+16) //0x40020810 
#define GPIOD_IDR_Addr    (GPIOD_BASE+16) //0x40020C10 
#define GPIOE_IDR_Addr    (GPIOE_BASE+16) //0x40021010 
#define GPIOF_IDR_Addr    (GPIOF_BASE+16) //0x40021410 
#define GPIOG_IDR_Addr    (GPIOG_BASE+16) //0x40021810 
#define GPIOH_IDR_Addr    (GPIOH_BASE+16) //0x40021C10 
#define GPIOI_IDR_Addr    (GPIOI_BASE+16) //0x40022010 
 
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#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)  //输入 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

#define PHout(n)   BIT_ADDR(GPIOH_ODR_Addr,n)  //输出 
#define PHin(n)    BIT_ADDR(GPIOH_IDR_Addr,n)  //输入

#define PIout(n)   BIT_ADDR(GPIOI_ODR_Addr,n)  //输出 
#define PIin(n)    BIT_ADDR(GPIOI_IDR_Addr,n)  //输入

4. GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2 / GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2

在上一节IIC的代码程序中,其IIC.h头文件中使用位操作进行了串行数据总线SDA输入输出的设置。这里我们具体来讲解一下代码是如何定义的。


#define SDA_IN() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2;}  //PB9输入模式
#define SDA_OUT() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2;}  //PB9输出模式

        在GPIO口的学习中,我们知道访问某一IO口时,需要初始化GPIO结构体,结构体包括MODE、OTYPE、PUPD、PIN,其中MODE是通过GPIOx_MODER(GPIO端口模式寄存器)来控制的。

该寄存器为32位寄存器,每两位控制一个引脚,则分别控制GPIOx的Px0-15引脚(x可取A、B、C、D、E、F、G)。

操作该寄存器的位带操作的主要思想是首先将想要操作的那一确定位清0,即使用与&操作来清零;然后将想要的功能通过软件来写入,即用或|操作来赋值。功能主要也就是

  •         00:输入
  •         01:通用输出
  •         10:复用功能
  •         11:模拟功能

明白了这些,我们现在再来看代码:


#define SDA_IN() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2;}  //PB9输入模式
#define SDA_OUT() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2;}  //PB9输出模式


//GPIOB->MODER表示通过指针调用GPIOB模式寄存器
//该寄存器是每两个位控制一个引脚,9*2,也就是操作PB9引脚,这里也就默认我们想要操作的引脚就是PB9引脚
//3<<(9*2)的意思是:在32位寄存器下,
//3=0000 0000 0000 0000 0000 0000 0000 0011,左移9*2,那么最低2位11就会被移动到17 18位的地址上
//  0000 0000 0000 0011 0000 0000 0000 0000,然后取反就是
//  1111 1111 1111 1100 1111 1111 1111 1111,然后和GPIOB->MODER进行与&操作后就是
//  0000 0000 0000 0000 0000 0000 0000 0000,表示将17 18位地址清零,

//到这里完成了位带操作的第一步清0,然后第二部进行赋值

//0<<9*2表示 0000 0000 0000 0000 0000 0000 0000 0000,GPIOB->MODER|=0<<9*2就是把17 18位地址置为00,对应寄存器也就是PB9输入模式

//同理PB9输出模式也是这样,首先将17 18位清零,然后将这两位写入01

//1<<9*2表示  0000 0000 0000 0000 0000 0000 0000 0001
              0000 0000 0000 0001 0000 0000 0000 0000 此时根据寄存器,也就表示PB9输出模式

//寄存器定义
//00:输入
//01:通用输出
//10:复用功能
//11:模拟功能

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/585672.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

springboot+vue 刘老师

课程内容 前端&#xff1a;vue elementui 后端&#xff1a;springboot mybatisplus 公共云部署 ------boot-------- 热部署 不用devtools&#xff0c;交给jrebel工具 RequestMapping ​ 参数 value 路径 method 方法consumes 请求媒体类型 如 application/jsonproduces …

DJ5-7 缓冲区管理

目录 5.7.1 缓冲的引入 5.7.2 单缓冲和双缓冲 1、单缓冲&#xff08;Single Buffer&#xff09; 2、双缓冲&#xff08;Double Buffer&#xff09; 3、双机通信时缓冲区的设置 5.7.3 循环缓冲 1、循环缓冲的组成 2、循环缓冲区的使用 3、进程同步 5.7.4 缓冲池 …

Spring Security源码剖析从入门到精通.跟学尚硅谷

1.1 概要 Spring 是非常流行和成功的 Java 应用开发框架&#xff0c;Spring Security 正是 Spring 家族中的成员。Spring Security 基于 Spring 框架&#xff0c;提供了一套 Web 应用安全性的完整解决方案。 正如你可能知道的关于安全方面的两个主要区域是“认证”和“授权”…

Mediapipe人体识别库

一、简介 官网&#xff1a;MediaPipe | Google for Developershttps://developers.google.cn/mediapipe Mediapipe 是2012年起开始公司内部使用&#xff0c;2019年google的一个开源项目&#xff0c;可以提供开源的、跨平台的常用机器学习(machine learning)方案。Mediapipe…

python-sqlite3使用指南

python下sqlite3使用指南 文章目录 python下sqlite3使用指南开发环境sqlite3常用APICRUD实例参考 开发环境 vscode ​ 开发语言&#xff1a; python vscode SQLite插件使用方法&#xff1a; 之后在这里就可以发现可视化数据&#xff1a; sqlite3常用API Python 2.5.x 以上…

信息安全实践1.3(HTTPS)

前言 做这个实验对Tomcat的版本有要求&#xff0c;最好是使用Tomcat8。因为我之前使用Tomcat10&#xff0c;然后一直做不出来。 要求 部署Web服务器端HTTPS功能&#xff0c;通过网络嗅探分析HTTPS通过SSL实施安全保护的效果 关键步骤 首先要给tomcat配置https&#xff0c;也…

设计模式之美-实战一(上):业务开发常用的基于贫血模型的MVC架构违背OOP吗?

领域驱动设计&#xff08;Domain Driven Design&#xff0c;简称DDD&#xff09;盛行之后&#xff0c;这种基于贫血模型的传统的开发模式就更加被人诟病。而基于充血模型的DDD开发模式越来越被人提倡。所以&#xff0c;我打算用两节课的时间&#xff0c;结合一个虚拟钱包系统的…

超低功耗三通道低频无线唤醒ASK接收 125k soc芯片UM2082F08

UM2082F08 是基于单周期 8051 内核的超低功耗 8 位、、具有三通道低频无线唤醒 ASK 接收功能的 SOC 芯片。芯片可检测 30KHz~300KHz 范围的 LF&#xff08;低频&#xff09;载波频率数据并触发唤醒信号&#xff0c;同时可以调节接收灵敏度&#xff0c;确保在各种应用环境下实现…

代码随想录算法训练营15期 Day 6 | 242.有效的字母异位词 、349. 两个数组的交集 、202. 快乐数、1. 两数之和

由于昨天是周日&#xff0c;周日是休息日&#xff0c;所以就是什么也没有写啦。今天是day06天&#xff0c;继续加油。 哈希表理论基础 建议&#xff1a;大家要了解哈希表的内部实现原理&#xff0c;哈希函数&#xff0c;哈希碰撞&#xff0c;以及常见哈希表的区别&#xff0c;…

Toolkit.getDefaultToolkit()获得的java.awt.Toolkit是不是同一个? 是否为单例设计模式?答案是**是**

Toolkit.getDefaultToolkit()获得的java.awt.Toolkit是不是同一个? 是否为单例设计模式? 答案是是 反复调用Toolkit.getDefaultToolkit()获得的 java.awt.Toolkit 是同一个 import java.awt.Toolkit;public class GetDefaultToolkit是不是获得单例Toolkit {static public …

【P43】JMeter 吞吐量控制器(Throughput Controller)

文章目录 一、吞吐量控制器&#xff08;Throughput Controller&#xff09;参数说明二、测试计划设计2.1、Total Executions2.2、Percent Executions2.3、Per User 一、吞吐量控制器&#xff08;Throughput Controller&#xff09;参数说明 允许用户控制后代元素的执行的次数。…

中级软件设计师考试总结

目录 前言考前学习宏观什么是软考涉及的知识范围软考整体导图总结 微观我的分享——希尔排序学习过程结构化做题 考试阶段确定不确定 考后总结 前言 作为一名中级软件设计师&#xff0c;考试是衡量自己技能和水平的一项重要指标。在备考和考试过程中&#xff0c;我通过总结经验…

【TI毫米波雷达笔记】IWR6843AOPEVM-G的DCA1000EVM模式配置及避坑(官方手册有误)

【TI毫米波雷达笔记】IWR6843AOPEVM-G的DCA1000EVM模式配置及避坑&#xff08;官方手册有误&#xff09; IWR6843AOPEVM-G版本可以直接与DCA1000EVM连接 进行数据获取 不需要连接MMWAVEICBOOST版 直接使用 DCA1000mmWave Studio 软件进行数据采集 在官方手册中 User’s Guide…

linux环境下安装gitlab

前几天跟朋友聊天时说到gitlab版本控制。其实&#xff0c;之前也对它只是知道有这个东西&#xff0c;也会用。只是对于它的安装和配置&#xff0c;那我还是没整过。这两天&#xff0c;我找了一下网上的资料&#xff0c;还是写下吧。 一安装&#xff1a; 按网上所说&#xff0c;…

2023年上半年信息系统项目管理师下午真题及答案解析

试题一(25分) 为实现空气质量的精细化治理&#xff0c;某市规划了智慧环保项目。该项目涉及网格化监测、应急管理、执法系统等多个子系统。作为总集成商&#xff0c;A公司非常重视&#xff0c;委派李经理任项目经理&#xff0c;对公司内研发部门与项目相关的各产品线研发人员及…

带你开发一个远程控制项目---->STM32+标准库+阿里云平台+传感器模块+远程显示-------之 阿里云平台项目建造。

第一篇章&#xff1a; (13条消息) 带你开发一个远程控制项目----&#xff1e;STM32标准库阿里云平台传感器模块远程显示。_海口飞鹏岛科技有限公司的博客-CSDN博客 本次文章是指引开发者进行开发阿里云平台建造设备项目&#xff0c;可观看UP主教程&#xff0c;完成如下&#x…

今天面了一个9个月测试经验的人,开口就跟我要18K,我都愣住了....

2月初我入职了深圳某家创业公司&#xff0c;刚入职还是很兴奋的&#xff0c;到公司一看我傻了&#xff0c;公司除了我一个测试&#xff0c;公司的开发人员就只有3个前端2个后端还有2个UI&#xff0c;在粗略了解公司的业务后才发现是一个从零开始的项目&#xff0c;目前啥都没有…

测试之路,你知道这些变化吗?突破后助你走得更远...

前言 Python自动化测试&#xff1a;7天练完这60个实战项目&#xff0c;年薪过35w。 目前的面试求职市场上&#xff0c;测试领域有哪些变化&#xff1f; 以这两年软件测试发展经历来看&#xff0c;现在的求职市场&#xff0c;已经不仅仅只考察个人的项目经验和技术能力了&#…

十五、多线程(上)

文章目录 一、线程&#xff08;一&#xff09;什么是线程&#xff08;二&#xff09;Linux下的多线程&#xff08;三&#xff09;总结&#xff08;四&#xff09;线程优点&#xff08;五&#xff09;线程缺点&#xff08;六&#xff09;线程异常&#xff08;七&#xff09;线程…

字节跳动测试开发岗 3+1 面经+经验分享(收到offer,入职月薪27K)

现在&#xff0c;招聘黄金时间已经过了&#xff0c;在网上看了很多大佬的面经&#xff0c;也加了很多交流群&#xff0c;受到了很多朋友的提点&#xff0c;今天终于轮到我来分享面经啦&#xff0c;之前面试了几家公司&#xff0c;最后在八月初拿到了字节跳动测试岗的 offer&…