STM32学习和实践笔记(9): 使用位带操作实现LED闪的实验

news2024/11/27 14:53:50

控制GPIO的那些寄存器,都在位带区。

根据上一篇讲的原理,要想每次只操作这些寄存的某一个bit而不影响别的bit,可以使用与这些bit相对应的位带别名区。

因此,在使用GPIO的位带操作之前,先要按上篇讲的原理,先在软件上做好位带区的每一个bit位与位带别名区的关连。

下面这些代码就实现这个目的:

一行行来看,首先看:

一行一行来看,先看第一行:

这个是使用宏定义,来定义和传递参数。(可以看到在用宏定义传递形参时,并没有事先另外去声明形能addr和bitnum的数据类型,直接就这样定义并使用了!见识了!)

当编译器看到BITBAND(0x40000,3),它就会把传进来实参,传到后面的公式进行计算,从来得到位带区某一个bit在位带别名区的地址。

读代码时,直接把它看作已计算好的位带别名区的地址就行了。

第二行:

这一行是根据位带区的基地址,取出对应的值。

这个*((volatile unsigned long  *)(addr)) 有两层,第一层是:

(volatile unsigned long  *)(addr),

这是强制声明一个32位(unsigned long)的数据类型,这个数据类型是一个指针变量,这个变量保存的是一个32位的地址

volatile是一个关键字,其作用是:

volatile 提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。

如 果没有 volatile 关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。所以遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

第二是把第一层的内容是括号包起来,在外面又加了一个*,这表示取出这个地址里面的数据。简言之,就是取出那个地址里的byte。读代码时,直接把它看作是位带区对应地址里的值就可以了。

(为方便理解这两层,可以以*((int *) a)这样一个结构作作说明:

int a, 这是声明a是一个整数型变量。

int *a ,这表明a是指针变量,a里存放的是一个地址,而不是数据。这个时侯的a与int a完全不同的变量声明了,因为它是指针变量。

在int *a这里,不要把*作为取值理解,它仅仅是声明a是指针变量作用,不要把它当成运算符里的a

*((int *) a),就是操作a所向的地址内的值,最外面的这个*,才是运算符,表示取这个指针变量指向地址里的值)

第三行:

这一行的作用,就是操作位带别名区地址里的值

理解了前面的三行后,后面的就很好理解了!

比如,当我main.c中输入一个语句PAout(1)时,编译器会直接使用

来替代,并且把其中的n置换为1,

GPIOA_ODR_Addr置换为:

也就是对应端口的ODR寄存器的地址。

所以,当我输入PAout(1) =1时,根据上面所说的第三行的作用,那我通过对位带别名区对应地址的操作,而更改到了ODR寄存器里数据的某一bit位,从而实现了对某一个具体的pin的输入输出的直接操作!

现在,把整个的逻辑再理一遍:

假定我要让GPIO 的A端口的第1个引脚输出一个高电压,那么,我首先要找到GPIO A端口的控制输出的寄存器ODR:

其以看到我只要使ODR0变为高电平,那么GPIO 的A端口的第1个引脚就输出一个高电压。

而GPIOA_ODR在哪里呢?

根据前面的memory mapping也就是地址总图:

我知道A端口的所有寄存器的基地址是0x4001 0800,这就是GPIOA_BASE。

在这个基地址上,偏移0Ch,也就是12个地址,就是GPIOA_ODR的地址。

(其它的端口都是依此类推,都是在各自的基地址上偏移0Ch),

所以从这里我知道了ODR这个寄存器的地址,也由第几个引脚,知道在这个地址数据的第几个bit位。(这个地方与前面的描述有不一致,前面这个bit只有0-7这三8个值,但是这里可以从0-15,但根据公式,只要基地址不变,那么算过来的相应的地址也会是正确的,这个n在公式里,就起到每多一个位,就偏移4个地址的作用。)

再由前面的公式,就算出对应的位带别名区的地址,并对该地址的值进行操作。而对其的操作,就是对应ODR里的某一个bit位的操作(硬件设计决定的)

把这些宏定义加到程序里,用位带操作来控制LED,试验是成功的。

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

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

相关文章

从 Oracle 到 MySQL 数据库的迁移之旅

文章目录 引言一、前期准备工作1.搭建新的MySQL数据库2 .建立相应的数据表2.1 数据库兼容性分析2.1.1 字段类型兼容性分析2.1.2 函数兼容性分析2.1.3 是否使用存储过程?存储过程的个数?复杂度?2.1.4 是否使用触发器?个数&#xff…

知识图谱与人工智能:携手共进

知识图谱与人工智能:携手共进 一、引言:知识图谱与人工智能的融合 在这个数据驱动的时代,知识图谱与人工智能(AI)之间的融合不仅是技术发展的必然趋势,也是推动各行各业创新的关键。知识图谱,作…

[C++][算法基础]树的重心(树图DFS)

给定一颗树,树中包含 n 个结点(编号 1∼n)和 n−1 条无向边。 请你找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。 重心定义:重心是指树中的一个结点,如果将这个点删除后&a…

Unity之PlayableGraph实现动画的正播和倒播

内容将会持续更新,有错误的地方欢迎指正,谢谢! Unity之PlayableGraph实现动画的正播和倒播 TechX 坚持将创新的科技带给世界! 拥有更好的学习体验 —— 不断努力,不断进步,不断探索 TechX —— 心探索、心进取&am…

python-study-day1

ps:前言 可做毕设,html,web,app,小程序,bug修改,可加急 作者自述 作为一名前端开发工程师,这个大环境不好的情况下,我试过我前端接单子但是没有后端&#xff0c…

Leetcode 239. 滑动窗口最大值和Leetcode 347. 前 K 个高频元素

目录标题 Leetcode 239. 滑动窗口最大值题目描述C语言代码和题解解题思路 Leetcode 347. 前 K 个高频元素题目描述C语言题解和思路解题思路 Leetcode 239. 滑动窗口最大值 题目描述 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最…

Java基础07--多线程-网络编程-Java高级

一、多线程 1.认识多线程 ①线程 ②多线程 2.创建线程方式 ①方式一:继承Thread类 1.让子类继承Thread线程类 2.重写run方法,就是这个线程执行会执行的操作。 3.创建继承Thread的子类对象就代表一个线程 4.启动线程:.start()-自动执行run方法 注意&am…

微服务demo(四)nacosfeigngateway(2)gatewayspringsercurity

一、思路 1、整体思路 用户通过客户端访问项目时,前端项目会部署在nginx上,加载静态文件时直接从nginx上返回即可。当用户在客户端操作时,需要调用后端的一些服务接口。这些接口会通过Gateway网关,网关进行一定的处理&#xff0…

Spring Boot REST API - CRUD 操作

Spring Boot REST API - CRUD 操作 这里主要提一下 spring boot 创建 rest api,并对其进行 CRUD 操作 jackson & gson 目前浏览器和服务端主流的交互方式是使用 JSON(JavaScript Object Notation),但是 JSON 没有办法直接和 Java 的 POJO 创建对应…

基于STC12C5A60S2系列1T 8051单片机的液晶显示器LCD1602显示汉字的功能

基于STC12C5A60S2系列1T 8051单片机的液晶显示器LCD1602显示汉字的功能 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍LCD1602字符型液晶显示器介绍一、LCD1602字符型…

20240411,内存分区模型

一,内存分区模型 生成可执行文件EXE文件之前代码区【函数体的二进制代码——共享-对于被频繁执行的程序,只需要在内存中有一份代码?,只读】,全局区【全局变量,静态变量,常量,该区域…

012:vue结合纯CSS实现蛇形流程图/步骤条

文章目录 1. 实现效果2. 实现代码 1. 实现效果 2. 实现代码 <template><div class"container"><div v-for"(item, index) in list" class"grid-item"><div class"step">step{{index1}}</div></div&…

计算机网络知识等汇总补充

计算机网络知识汇总补充 一、四次挥手1、为什么TCP要等待2MSL2、如果说一个系统中&#xff0c;有大量的time_wait和close_wait&#xff0c;会是什么原因&#xff1f; 二、你是怎么解决粘包问题&#xff1f;三、你觉得哪些场景适合redis四、redis的持久化策略五、你会怎么保证my…

视频基础学习六——视频编码基础三(h264框架配合图文+具体抓包分析 万字)

系列文章目录 视频基础学习一——色立体、三原色以及像素 视频基础学习二——图像深度与格式&#xff08;RGB与YUV&#xff09; 视频基础学习三——视频帧率、码率与分辨率 视频基础学习四——视频编码基础一&#xff08;冗余信息&#xff09; 视频基础学习五——视频编码基础…

WinRAR再爆0 day漏洞,0 day漏洞该如何有效预防

WinRAR再爆0 day漏洞&#xff0c;已被利用超过4个月。 Winrar是一款免费的主流压缩文件解压软件&#xff0c;支持绝大部分压缩文件格式的解压&#xff0c;全球用户量超过5亿。Group-IB研究人员在分析DarkMe恶意软件时发现WinRAR在处理ZIP文件格式时的一个漏洞&#xff0c;漏洞…

基于Springboot的笔记记录分享网站(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的笔记记录分享网站&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…

牛客 NC36 在两个长度相等的排序数组中找到上中位数【中等 模拟 Java,Go,PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/6fbe70f3a51d44fa9395cfc49694404f 思路 直接模拟2个数组有顺序放到一个数组中&#xff0c;然后返回中间的数参考答案java import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息 pu…

使用htmlentities()和nl2br()将文本数据正确显示到前台

问题&#xff1a; 在后台textarea里编辑了有一串字符串&#xff0c;虽然在textarea里编辑是有换行效果的&#xff0c;但是数据获取到就只是\n&#xff0c;前端是不认识这个的&#xff0c;正确输出到前台的换行只能是<br/>。 $str "ABCDEFGHIJKLMNOPQ"; echo…

Multisim仿真二极管、晶体管和场效应管学习笔记

Multisim仿真二极管、晶体管和场效应管 &#xff08;note&#xff1a;使用Multisim14.0版本进行仿真&#xff09; 文章目录 Multisim仿真二极管、晶体管和场效应管二极管的I-V特性晶体管的I-V特性场效应管的I-V特性 二极管的I-V特性 插入I-V analyzer 原理图绘制 改变仿真…

【MCU开发规范】:MCU的性能测试

MCU的性能测试 前序性能评判方法MIPSCoreMark EEMBC其他参考 前序 我们平时做MCU开发时&#xff0c;前期硬件选型&#xff08;选那颗MCU&#xff09;基本由硬件工程师和架构决定&#xff0c;到软件开发时只是被动的开发一些具体功能&#xff0c;因此很少参与MCU的选型。 大部分…