F407之位带操作

news2025/2/9 8:27:24

位带操作的应用场景,通常在于对IO口进行输入输出读取和控制。

这就和51单片机中直接的端口赋值是一样的。

比如

P0.0 = 0;

P0.0 = 1;

直接就是对端口P0.0输出0和1。

如何实现呢?

什么是位带操作

位带操作简单的说,就是把每个比特膨胀为一个32位的字,当访问这些字的时候就达到了访问比特的目的,比如说GPIOODR寄存器有32个位,那么可以映射到32个地址上,我们去访问这32个地址就达到访问32个比特的目的。这样我们往某个地址写1就达到往对应比特位写1的目的,同样往某个地址写0就达到往对应的比特位写0的目的。

对于上图,我们往Address0地址写入1,那么就可以达到往寄存器的第0Bit0赋值1的目的。这里我们不讲得过于复杂,因为位带操作在实际开发中可能只是用来IO口的输入输出还比较方便,其他操作在日常开发中也基本很少用。

手册中的相关介绍

Cortex™-M4F 存储器映射包括两个位段区域。这些区域将存储器别名区域中的每个字映射 到存储器位段区域中的相应位。在别名区域写入字时,相当于对位段区域的目标位执行读-

-写操作。

STM32F4xx 器件中,外设寄存器和 SRAM 均映射到一个位段区域,这样可实现单个位段的读写操作。这些操作仅适用于Cortex™-M4F访问,对于其它总线主接口(如 DMA)无效。

可通过一个映射公式说明别名区域中的每个字与位段区域中各个位之间的对应关系。映射公

式为:

bit_word_addr = bit_band_base + (byte_offset x 32) + (bit_number × 4)

其中:

bit_word_addr 代表别名区域中将映射到目标位的字的地址

bit_band_base 代表别名区域的起始地址

byte_offset 代表目标位所在位段区域中的字节编号

bit_number 代表目标位的位位置 (0-7)

下例说明如何将 SRAM 地址 0x20000300 处字节的位 2 映射到别名区域:

0x22006008 = 0x22000000 + (0x300*32) + (2*4)

对地址 0x22006008 执行写操作相当于在 SRAM 地址 0x20000300 处字节的位 2 执行读-

-写操作。

对地址 0x22006008 执行读操作将返回 SRAM 地址 0x20000300 处字节的位 2 的值(0x01

表示位置位,0x00 表示位复位)。

有关位段的详细信息,请参见Cortex™-M4F编程手册。

具体定义

映射关系如下所示

具体不深究了,大概知道映射公式是这样的就行

膨胀关系示意图

通常可在头文件中定义

//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).M4同M3类似,只是寄存器地址变了.
//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)  //输入

以上代码的便是 GPIO 位带操作的具体实现,位带操作的详细说明,在权威指南中有详细讲解,请参考<<CM3 权威指南>>第五章(87 ~92 )。比如说,我们调用 PAout(1)=1是设置了 GPIOA 的第一个管脚 GPIOA.1 1,实际是设置了寄存器的某个位,但是我们的定义中可以跟踪过去看到却是通过计算访问了一个地址。上面一系列公式也就是计算GPIO 的某个 io 口对应的位带区的地址了。有了上面的代码,我们就可以像51/AVR一样操作STM32IO口了。比如,我要PORTA的第七个 IO 口输出 1,则可以使用 PAout(6)=1;即可实现。我要判断 PORTA 的第15个位是否等于 1,则可以使用 ifPAin14==1)…;就可以了。

注意:

使用前必须先进行IO口时钟的使能和 IO口功能初始化。

补充了解

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

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

相关文章

全面了解AES加密:入门指南

文章目录 I. 介绍A. 什么是加密B. 为什么要加密1. 保护数据的机密性2. 防止数据被篡改3. 防止数据被窃取4. 保护数据的可信度 C. AES加密的概述 II. 对称加密与非对称加密A. 对称加密的定义和特点1. 简单快速2. 安全性较低3. 适合大量数据加密4. 密钥管理困难5. 用途广泛 B. 非…

黑马版Redis基础篇

一、 初识redis 1.1 认识 NoSQL 关系型数据库&#xff1a; 1.2 认识Redis 二、Redis 常见命令 2.1 Redis 数据结构介绍 2.2 Redis 通用命令 2.3 String 类型 2.3.1 Key的层级格式 2.4 Hash 类型 2.5 List 类型 2.6 Set 类型 2.7 SortedSet 类型 三、Redis 的 Java 客户端 1.…

DelayQueue的核心属性和写入、读取流程分析

DelayQueue的核心属性 DelayQueue的写入流程分析 add方法也是包装使用offer方法。Delay是无解的&#xff0c;数组又可以动态扩容&#xff0c;不需要关注生产者的阻塞问题 offer方法分析 DelayQueue读取流程 消费者消费元素存在两种阻塞的情况&#xff1a; 1.消费者得到栈顶的…

华为OD机试真题 JavaScript 实现【预定酒店】【2022Q4 100分】

一、题目描述 放暑假了&#xff0c;小明决定到某旅游景点游玩&#xff0c;他在网上搜索到了各种价位的酒店(长度为n的 数组A)&#xff0c;他的心理价位是x元&#xff0c;请帮他筛选出k个最接近x元的酒店 (n>k>0) ,并由低到高打印酒店的价格。 二、输入描述 第一行: n,…

chatgpt赋能python:Python怎么开三次方?

Python怎么开三次方&#xff1f; Python是一门常用的高级编程语言&#xff0c;被广泛用于数据分析、人工智能、Web开发等领域。在Python中&#xff0c;我们可以使用几种方法轻松地计算三次方根&#xff0c;例如使用sqrt函数、cbrt函数和简单的数学表达式。本文将介绍三种方法&…

聊聊Scrum三大角色的质量意识和文化建设

这是鼎叔的第六十三篇原创文章。行业大牛和刚毕业的小白&#xff0c;都可以进来聊聊。 欢迎关注本专栏和微信公众号《敏捷测试转型》&#xff0c;星标收藏&#xff0c;大量原创思考文章陆续推出。 参考前文&#xff1a;聊聊Scrum价值观与测试启发 本篇从Scrum的主要角色视角…

开关电源精确到每个元件-分解电源电路

本次讲解电源以一个13.2W电源为例 输入&#xff1a;AC90~264V 输出&#xff1a;3.3V/4A 原理图&#xff1a; 变压器是整个电源供应器的重要核心&#xff0c;所以变压器的计算及验证是很重要的。 1.决定变压器的材质及尺寸: 依据变压器计算公式 2.决定一次侧滤波电容&#…

第五章JMM内存模型

文章目录 计算机硬件存储体系为什么要弄一个 CPU 高速缓存呢&#xff1f;为什么缓存能提高速度呢&#xff1f;缓存带来的问题 Java之JMM模型JMM 是如何抽象线程和主内存之间的关系线程之间如何通信Java 内存区域和 JMM 有何区别 JMM规范下&#xff0c;三大特性原子性可见性有序…

000mysql常用资源推荐

官网 MySQL :: MySQL 8.0 Reference Manualhttps://dev.mysql.com/doc/refman/8.0/en/ 博客 一树一溪 侧重原理https://mp.weixin.qq.com/mp/homepage?__bizMzg3NTc3NjM4Nw&hid2&snb5d65ce17893a722b6748b471412eab0&scene1&devicetypeandroid-33&ver…

Spring-Boot的创建与配置文件

文章目录 前言Spring与SpringBoot的区别SpringBoot的创建与使用 更改国内源配置SpringBoot目录介绍SpringBoot配置文件配置⽂件的格式properties 基本语法yml的基本语法yml的注意事项 properties VS yml 好坏 前言 前面讲述了 ,Spring的概念与使用方法 , 接下来要介绍的是 Spr…

华为OD机试真题 JavaScript 实现【服务中心选址】【2023Q1 100分 】

一、题目描述 一个快递公司希望在一条街道建立新的服务中心。公司统计了该街道中所有区域在地图上的位置&#xff0c;并希望能够以此为依据为新的服务中心选址&#xff0c;使服务中心到所有区域的距离的总和最小。 给你一个数组 positions&#xff0c;其中 positions[i] [le…

B+树:高效存储与索引的完美结合

目录 引言&#xff1a;一、定义&#xff1a;二、B树和B树三、特点&#xff1a;四、应用场景&#xff1a;总结&#xff1a; 引言&#xff1a; 在计算机科学领域中&#xff0c;数据结构的选择对于高效存储和索引数据至关重要。B树&#xff08;B tree&#xff09;作为一种自平衡的…

chatgpt赋能python:Python怎么并排输出

Python怎么并排输出 Python是一种高级编程语言&#xff0c;它受到了全球程序员的欢迎。在Python编程中&#xff0c;经常需要将多个变量或数据一起输出。 本文将介绍Python如何并排输出&#xff0c;使输出内容更加整齐美观&#xff0c;提高代码可读性和可维护性。 使用print(…

Chrome浏览器进程:了解多进程架构优劣的探索

文章目录 I. 介绍简述Chrome浏览器的进程模型和重要性 II. 多进程架构的优劣详述Chrome浏览器的多进程架构分析多进程架构对性能、安全性和稳定性的影响对比单进程架构的优缺点和Chrome浏览器多进程架构的差异 III. Chrome浏览器进程类型和作用解释Chrome浏览器中常见的进程类型…

OpenMMLab-AI实战营第二期——5-1.语义分割与MMSegmentation

文章目录 1. 基本概念1.1 案例演示1.2 应用1.3 语义分割概念 2. 语义分割算法2.1 语义分割基本思路2.1.1 按颜色2.1.2 逐像素分类 2.2 深度学习下的语义分割模型2.2.1 全卷积网络2.2.2 Unet2.2.3 上下文信息与PSPNet模型2.2.4 空洞卷积与DeepLab算法2.2.5 总结2.2.6 前言语义分…

我们该如何应对工作失误(How to Handle Failure at Work)

花时间反思 组织架构心理学家、Audrey Page & Associates执行服务总监&#xff0c;Penelope Faure博士表示&#xff1a;“人们在犯错后情绪往往会十分激动。”不论是因为老板在电子邮件中流露出对你的指责&#xff0c;还是因为你明显的疏忽导致客户利益受损&#xff0c;又…

Android 13(T) Media框架 - 智能指针

Android有一套自己的智能指针管理办法&#xff0c;并且将其运用在源码的各个角落&#xff0c;所以学习Media框架之前&#xff0c;我们有必要先了解下Android智能指针。 本节代码源自于Android 13(T)&#xff0c;参考 (aospxref.com) 1 概述 与智能指针相关的总共有5个类&#…

前端加载超大图片(100M以上)实现秒开解决方案

前端加载超大图片(100M以上)实现秒开解决方案 前言 前端加载超大图片时&#xff0c;一般可以采取以下措施实现加速&#xff1a; 图片压缩&#xff1a;将图片进行压缩可以大幅减小图片的大小&#xff0c;从而缩短加载时间。压缩图片时需要注意保持图片质量&#xff0c;以免影响…

CSS基础学习--9 边框(Border)

一、CSS 边框属性 CSS边框属性允许你指定一个元素边框的样式和颜色。 二、边框的样式 边框样式属性指定要显示什么样的边界。 border-style属性用来定义边框的样式 border-style 值: <!DOCTYPE html> <html> <head> <meta charset"utf-8">…

【爬虫】4.5 实践项目——爬取当当网站图书数据

目录 1. 网站图书数据分析 2. 网站图书数据提取 3. 网站图书数据爬取 &#xff08;1&#xff09;创建 MySQL 数据库 &#xff08;2&#xff09;创建 scrapy 项目 &#xff08;3&#xff09;编写 items.py 中的数据项目类 &#xff08;4&#xff09;编写 pipelines_1.py …