嵌入式学习笔记——使用寄存器编程操作GPIO

news2025/7/21 19:01:23

使用寄存器编程操作GPIO

  • 前言
  • GPIO相关的寄存器
    • GPIO 端口模式寄存器 (GPIOx_MODER) (x = A..I)
      • 位操作
    • GPIO 端口输出类型寄存器 (GPIOx_OTYPER) (x = A..I)
    • GPIO 端口输出速度寄存器 (GPIOx_OSPEEDR) (x = A..I/)
    • GPIO 端口上拉/下拉寄存器 (GPIOx_PUPDR) (x = A..I/)
    • GPIO 端口输入数据寄存器 (GPIOx_IDR) (x = A..I)
    • GPIO 端口输出数据寄存器 (GPIOx_ODR) (x = A..I)

前言

上一篇重点介绍了STM32 GPIO的输入输出模式,在整个框图中我们发现需要我们使用代码来控制GPIO的模式,本文的重点就是使用寄存器的编程方式,实现对于GPIO口的操作。
在这里首先需要做一个区分,我们常见的STM32的开发方式有两种,也就是寄存器开发与库函数开发。寄存器开发就是直接操作底层的寄存器来实现功能,而库函数,则是使用ST的官方库函数来实现功能,目前常用的库有基础库、HAL库、LL库。此系列都会采用直接操作寄存器的方式来实现功能。

GPIO相关的寄存器

既然是操作寄存器实现功能,就要知道与GPIO相关的寄存器有哪些,根据昨天的GPIO口模式以及框图我们可以大致猜出几个寄存器。
1.输入输出模式选择的寄存器;用来确定GPIO是输入模式还是输出模式;
2.输出类型选择的寄存器;用来选择是推挽还是开漏;
3.输出数据寄存器,暂存MCU输出的数字量;
4.输入数据寄存器,暂存外设输入的数字量;
5.上拉下拉寄存器,设置GPIO的上下拉模式;

没看手册之前,我们根据GPIO的功能以及结构猜测的有上面这五个寄存器,下面我们来看看编程手册关于GPIO的寄存器到底有哪些,又该怎么使用。
官方编程手册关于GPIO的寄存器介绍如下:
在这里插入图片描述
每个通用IO都有十个寄存器与之对应,在中文编程手册的第七章有关于这些寄存器的详细描述。
在这里插入图片描述
接下来我们来一一看一下这些寄存器的具体作用以及配置方式。

GPIO 端口模式寄存器 (GPIOx_MODER) (x = A…I)

端口模式寄存器,就是控制整个端口的模式,通过写入不同的高低电平来区分对应管脚是输入还是输出,(GPIOx_MODER) 这个中间的x就代表从A—I的端口号(x = A…I),也就是说一块STM32最多只有9个端口模式寄存器。
它是一个32位的寄存器,前面我们提当过,STM32的一个端口有0-15共16个管脚,而这个端口模式寄存器又是32位的,这就说明每个管脚的模式控制有
32/16=2位二进制数来实现。如下图所示就是端口模式的寄存器(中文编程手册第七章7.4 节 GPIO 寄存器):
在这里插入图片描述
整个寄存器一共是0-31共32位,其中第0位与第1位下面写着MODER0[1:0],这个MODER0就代表是该端口对应的0号管脚模式控制,其中00表示输入模式(复位状态也是此模式),01表示通用输出模式,10表示复用功能,11表示模拟功能。依次类推,此寄存器的第2位第三位表示该端口的1号管脚的模式控制,剩下的也都是依次类推,直至第30位与31位代表第16号管脚的模式控制。细心的同学肯定已经发现了,这个寄存器实现的功能就是我们根据结构图分析出来的第一个寄存器所需的功能啊,它就解决了GPIO口的模式问题。
举个栗子:假设我们要将GPIOA的10号管脚配置为复用功能模式,这时候我们就需要找到MODER10[1:0],,然后将复用输出模式的10写进这个寄存器。
这里就会产生一个新问题,要怎么将数据写入寄存器呢,首先能够想到的肯定是需要赋值,那么怎么赋值呢,我们来分析一下。

位操作

首先这个寄存器的命名ST公司已经给我们做好了,就在我们之前搭建工程时使用的使用的stm32f4xx.h中,这里给大家截图在下面:
在这里插入图片描述
而且ST公司还利用宏定义给出了每个端口对应结构体的指针名。
在这里插入图片描述
可以看出所有的寄存器都是用的一个结构体给封装起来了,我们要调用赋值的话就可以按照下面的语句来实现操作,还是以GPIOA端口的10号管脚配置为复用输出为例:

GPIOA ->MODER |= (1<<21); //GPIOA_MODER寄存器配置为复用模式
//经过此步骤,MODER10[1:0]的数据就被覆盖成为了10,也就是手册中的复用模式。
//这里的1左移21位就是依据移位操作来实现的,由于MODER10对应的寄存器位数就是20位与21位,其中,第21位需要写1,所以我们就需要将1左移21位到此位置。

换做其他管脚也是类似的操作,再举个例子,我们将GPIOC的4号管脚配置为通用输出模式,此时需要的操作如下:

GPIOC->MODER |= (1<<8); //GPIOA_MODER寄存器配置为通用输出模式
//经过此步骤,MODER4[1:0]的数据就被覆盖成为了01,也就是手册中的通用输出模式。
//这里的1左移8位就是依据移位操作来实现的,由于MODER4对应的寄存器位数就是8位与9位,其中,第8位需要写1,所以我们就需要将1左移8位到此位置。

上面都是写1操作,用的是|,我们再举一个清零操作的例子,将GPIOA0配置为输入模式,此时就需要对MODER0进行清零操作,具体写法如下:

	GPIOA ->MODER &=~(3<<0);//清0  GPIOA_MODER寄存器为00通用输入模式
	这里我们使用的是&=~的操作,3转换为二进制就是11,11左移0位,还是11,然后对11进行取反,变成00,再将00赋值给MODER,这样GPIOA_MODER0就被赋值成为了00,也就是将GPIOA0配置为了输入模式。

好了,到这里整个寄存器操作的赋值语句就学完了,就是一个赋值为一一个赋值为0的操作,两条语句,后面所有需要置一与清零的操作都是用的这个方法来实现的。

GPIO 端口输出类型寄存器 (GPIOx_OTYPER) (x = A…I)

我们再来看看GPIO的第二个寄存器,端口输出类型寄存器,既然是输出类型寄存器,说明我们如果再上一个寄存器中将GPIO口配置为输入模式后,这个寄存器就可以不用操作了。
这个寄存器就是用来实现对输出模式的控制的,我们根据结构图分析出来的第二个寄存器的功能是不是与这个寄存器不谋而合呢,我们来看看手册中的描述,如下图所示:
在这里插入图片描述
在这里插入图片描述
有了上一个寄存器的经验,再看这个是不是就很清晰了,首先这个寄存器的高16位是保留的没有使用,后面的0-15共16位是不是刚好一位对应一个管脚号,也就是说OT0对应的就是0号管脚,OT15对应的就是15号管脚,然后注意下面的描述,配置为0的时候是推挽模式,而1的时候是开漏模式。
还是举个栗子吧,假设我们需要将GPIOC的4号脚配置为推挽模式,此时就该向OTC4写入0;参照上面的代码操作,就是如下代码:

	GPIOC->OTC &=~(1<<4);//清0  GPIOA_OTC4寄存器为0推挽输出模式

GPIO 端口输出速度寄存器 (GPIOx_OSPEEDR) (x = A…I/)

然后是GPIO的第三个寄存器,GPIOx_OSPEEDR,端口输出速度寄存器,同理,由于是输出寄存器,所以如果在第一个寄存器中已经将端口配置为输入则再后续配置过程中不再需要操作本寄存器。
同样的,这个寄存器也是一个32位的寄存器,而且也是和第一个端口模式寄存器一样的,使用的是两个二进制位来控制一个管脚。这个寄存器是我们之前通过结构图所没能分析出来的,他主要作用就是控制IO的电平翻转速度。
在这里插入图片描述
根据手册的描述,我们还是举例将GPIOC端口的4号管脚配置为中速输出,首先在上图中找到OSPEEDR4[1:0],它对应的二进制位是第八位和第九位,配置为中速也就是25MHZ的输出速度,需要对这两位写入01,具体操作如下:

	GPIOC->OSPEEDR |= (1<<8);//25MHZ中速

GPIO 端口上拉/下拉寄存器 (GPIOx_PUPDR) (x = A…I/)

再然后就是第四个寄存器了,端口上拉下拉寄存器GPIOx_PUPDR,他的作用就是我们前面分析结构图提到的可以通过软件编程来实现IO内部上下拉功能的控制寄存器,通过配置它可以实现GPIO口的内部上下拉。此寄存器也是每两位二进制数控制一个管脚。
在这里插入图片描述
在这里插入图片描述
如上图所示,根据数据手册的描述,我们将GPIOA0设置为无上下拉模式,操作如下:找到对应0端口的控制位是第0位和第1位,要配置为无上下拉模式,就需要对这两位写入00。代码操作如下:

GPIOA ->PUPDR &=~(3<<0);//清0  GPIOA_PUPDR寄存器为00 浮空

GPIO 端口输入数据寄存器 (GPIOx_IDR) (x = A…I)

然后再来看个稍微不一样一点的,输入数据寄存器,说它不一样主要是因为他是一个只读寄存器,也就是说,我们对它的操作只有读取,没有上面的赋值操作了,至于怎么读,我们放到明天的按键操作进行描述;根据编程手册可以看出,它也是一个一位代表一个端口号的寄存器。另外就是他是输入寄存器,说明我们在配置GPIO为输出模式时,是不需要操作此寄存器的,在这里我们只需要了解这么多,至于怎么编程控制我们后面再说。
在这里插入图片描述

GPIO 端口输出数据寄存器 (GPIOx_ODR) (x = A…I)

可以看出这个寄存器的名字和上一个输入寄存器的名字刚好对应啊,它的作用就是将对应位上的值输出,同样的,它的命名是输出,说明配置输入时跟与它就没有关系了;它也是单个二进制位控制一个管脚。
在这里插入图片描述
这里举个栗子,假设我们需要GPIOC4输出高电平,我们就需要对ODR4写1;具体编程操作如下:

GPIOC->ODR |= (1<<4);

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

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

相关文章

Python bool 到底怎么用? 【源码拆解】

人生苦短 我用python 一、布尔类型描述 布尔类型是计算机中最基本的类型&#xff0c; 它是计算机二进制世界的体现&#xff0c;一切都是 0 和 1 。 Python中的布尔类型只有两种值&#xff1a;True 和 False 。 &#xff08;注意&#xff1a;首字母都是大写&#xff0c;与C、Ja…

女生学习大数据怎么样~有前景么

当前大数据发展前景非常不错&#xff0c;且大数据领域对于人才类型的需求比较多元化&#xff0c;女生学习大数据也会有比较多的工作机会。大数据是一个交叉学科涉及到的知识量比较大学习有一定的难度&#xff0c;女生则有女生的优势&#xff0c;只要认真学习了都是可以做大数据…

STM32定时器的编码器接口模式

MCU为STM32L431&#xff0c;通用定时器框图&#xff1a; 编码器接口模式一共有三种&#xff0c;通过TIMx_SMCR寄存器的SMS[3:0]位来选择。模式1计数器仅在TI1FP1的边沿根据TI2FP2的电平来判断向上/下计数&#xff1b;模式2计数器仅在TI2FP2的边沿根据TI1FP1的电平来判断向上/下…

Python面向对象的三大特征 - - 封装、继承、多态

目录 一、三大特征介绍 1、封装&#xff08;隐藏&#xff09; 2、继承 3、多态 二、继承 1、子类扩展父类 1.语法格式 2.构造函数 2、类成员的继承和重写 1. 成员继承 2. 方法重写 3、查看类的继承层次结构 4、object根类 1.描述 2. dir() 查看对象属性&#xff…

JVM-可达性分析算法

JVM是Java Virtual Machine&#xff08;Java虚拟机&#xff09;的缩写&#xff0c;JVM是一种用于计算设备的规范&#xff0c;它是一个虚构出来的计算机&#xff0c;是通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机包括一套字节码指令集、一组寄存器、一个栈…

maven的学习

为啥要用maven 1、不用认为添加jar包所依赖的其他jar包 2、能在本地仓库只保留一份jar包&#xff0c;避免了多个工程使用相同jar包&#xff0c;需要重复导入的问题&#xff0c;减少冗余 3、能够规范添加jar包&#xff0c;在下载需要的jar包时有多种方法&#xff0c;但是不能保…

TeeChart VCL/FMX v2023 crack

TeeChart VCL/FMX v2023 crack TeeChart Pro VCL允许您为所有领域(包括商业、工程、金融、统计、科学、医疗、实时和网络)创建通用和专用图表和绘图应用程序。TeeChart Pro VCL具有多种图表类型的图表库&#xff0c;包括2D或3D线条、条形图、水平条、区域、点、饼图、箭头、气泡…

MySQL OCP888题解043-GTID模式下如何解决主键冲突问题

文章目录1、原题1.1、英文原题1.2、答案2、题目解析2.1、题干解析3、知识点3.1、知识点1&#xff1a;GTID模式下跳过一个事务的方法4、总结1、原题 1.1、英文原题 A simple master-to-slave replication is currently being used. This information is extracted from the SH…

Kubernetes学习(三)Service

Service对象 为什么需要Service 每个Pod都有自己的IP地址&#xff0c;但是在Deployment中&#xff0c;在同一时刻运行的Pod集合可能与稍后运行该应用程序的Pod集合不同。 这就导致了一个问题&#xff1a;如果一组Pod&#xff08;称为后端&#xff09;为集群内其他Pod&#x…

Java测试题

选择题&#xff08;共15题&#xff0c;每题2分&#xff09;( B ) 1、使用下面哪个表达式能产生[20,999]之间的数&#xff1f;A.(int)(20Math.random( )*979) B.20(int)(Math.random( )*980)C.(int)Math.random( )*999 D.20(int)Math.random( )*980( C )2、请仔细阅读下面的程序…

【记录】Samba|Windows 11的Samba连接切换用户

Samba是一个用于共享文件和打印机的网络协议&#xff0c;可以使不同的操作系统之间共享文件和资源变得容易。在Windows 11上&#xff0c;可以使用Samba来连接到网络共享。 如果您想在Windows 11上切换用户并连接到另一个Samba共享&#xff0c;可以按照以下步骤操作。 文章目录…

乐山持点电商:抖音外卖上线全国18城公告

抖音日前在全国15个城市上线外卖业务&#xff0c;包括南京、厦门、合肥、嘉兴、宁波、广州、无锡、杭州、武汉、深圳、温州、苏州、金华、长沙、福州等。加上此前抖音外卖试点的北京、上海和成都&#xff0c;抖音外卖已覆盖全国18个城市&#xff0c;入驻商家主要集中在餐饮行业…

基于声网 Flutter SDK 实现多人视频通话

前言 本文是由声网社区的开发者“小猿”撰写的Flutter基础教程系列中的第一篇。本文除了讲述实现多人视频通话的过程&#xff0c;还有一些 Flutter 开发方面的知识点。该系列将基于声网 Fluttter SDK 实现视频通话、互动直播&#xff0c;并尝试虚拟背景等更多功能的实现。 如果…

lvgl 笔记 基础对象与组件

一、基础对象 1.1基础对象简介 lvgl 库是纯 c 语言编写的&#xff0c;使用结构体实现类的操作。其所有组件都继承字lv_obj_t&#xff0c;可以使用他的属性和方法。 创建一个基本对象非常简单&#xff1a; lv_obj_t* obj1 lv_obj_create(lv_scr_act()); 其中填入的 lv_scr_a…

KUKA U盘备份系统

KUKA U盘备份系统 原创 March Cai Cass 机器人 2022-03-10 12:39 首先想做系统备份&#xff0c;需要KUKA 官方的U盘&#xff0c;需要设置如下 双击KUKA U盘里的Recovery.exe 打开如右上图&#xff0c;点开专家设置 设置好需要的功能 返回主菜单组选择 配置界面&#xff0c;…

20230306 LS-DYNA悬臂梁案例学习笔记

一、创建材料 在左侧linear elastic,将这个拉至新建的mat材料上

【立体匹配论文阅读】Pyramid Stereo Matching Network

Authors: Jia-Ren Chang, Yong-Sheng Chen Link: https://arxiv.org/abs/1803.08669 Years: 2018 Credit Novelty and Question set up 本文提出之时&#xff0c;基于深度学习的立体匹配主流方式仍是patch-based孪生结构&#xff0c;这种方式缺乏上下文信息的获取能力&#xf…

buuctf-web-[SUCTF 2018]MultiSQL1

打开界面&#xff0c;全部点击一遍&#xff0c;只有注册和登录功能可以使用注册一个账号&#xff0c;注册admin提示用户存在&#xff0c;可能有二次注入&#xff0c;注册admin自动加了一个字符&#xff0c;无法二次注入&#xff0c;点击其他功能点换浏览器重新登录后&#xff0…

java多线程(二一)并发协作生产者消费者设计模式

1.两个线程一个生产者一个消费者 需求情景 两个线程&#xff0c;一个负责生产&#xff0c;一个负责消费&#xff0c;生产者生产一个&#xff0c;消费者消费一个。 涉及问题 同步问题&#xff1a;如何保证同一资源被多个线程并发访问时的完整性。常用的同步方法是采用标记或加…

如何查看并读懂昇腾平台的应用日志

当您完成训练/推理工程开发后&#xff0c;将工程放到昇腾平台运行&#xff0c;以调试工程是否正常&#xff0c;此时&#xff0c;可能会出现各种各样、五花八门的异常状况。当问题发生时&#xff0c;我们的第一反应是不是查看日志&#xff0c;看看哪里报错了。昇腾平台有哪些日志…