实用指南:嵌入式学习笔记3.基于寄存器方式控制GPIO

news/2025/10/13 22:50:42/文章来源:https://www.cnblogs.com/tlnshuju/p/19139610

实用指南:嵌入式学习笔记3.基于寄存器方式控制GPIO

2025-10-13 22:50  tlnshuju  阅读(0)  评论(0)    收藏  举报


1. 模式寄存器 (GPIOx->MODER)

模式寄存器一共有32位,每2位一组,对应着1个不同的1/0引脚。这些位通过软件写人,用于配置1/0引脚的模式:

  • 00:输入模式(复位值)
  • 01:通用输出模式
  • 10:复用功能模式
  • 11:模拟模式

eg:向GPIOA_MODER寄存器的bit1和bitO写人01,表示将引脚PA0设置为输出模式;向GPI0C_MODER寄存器的bit31和bit30写人11,表示将引脚PC15设置为模拟模式。

1. 模式寄存器 (GPIOx->MODER)
MODER 寄存器用于配置引脚是输入、输出还是复用功能。每个引脚由两位控制。
配置为输入模式:00
配置为通用输出模式:01
配置为复用功能模式:10
配置为模拟模式:11
操作方法:先清零,再置位。
// 示例:将 PA5 配置为通用输出模式 (01)
// 1. 清零 PA5 对应的位 (第10位和第11位)
GPIOA->MODER &= ~(0x03 << (5 * 2));
// 2. 设置 PA5 为通用输出模式 (01)
GPIOA->MODER |=  (0x01 << (5 * 2));
// 示例:将 PA6 配置为输入模式 (00)
// 只需清零即可
GPIOA->MODER &= ~(0x03 << (6 * 2));

2. 输出类型寄存器 (GPIOx->OTYPER)

输出类型寄存器(GPIOx_OTYPER)
该寄存器用于控制GPIO端口各引脚的输出类型,该寄存器在引脚配置为输出模式后才有效,其他工作模式下无效。
输出类型寄存器一共有32位,如表6-3所示。高16位保留,低16位的每1位对应一个不同的1/0引脚。这些位通过软件写人,用于配置1/0引脚的输出类型:

  • 0:推挽输出(复位值)
  • 1:开漏输出

例如:向GPIOB_OSPEEDR寄存器的bit1写人1,表示将引脚PB1设置为开漏输出模式。

2. 输出类型寄存器 (GPIOx->OTYPER)
OTYPER 寄存器用于配置输出引脚是推挽(Push-Pull)还是开漏(Open-Drain)。每个引脚由一位控制。
推挽输出:0 (输出高低电平)
开漏输出:1 (只能拉低电平,需要外部上拉电阻才能输出高电平)
操作方法:通常与 MODER 配合使用。
// 示例:将 PA5 配置为推挽输出
GPIOA->OTYPER &= ~(0x01 << 5); // 清零第5位
// 示例:将 PA7 配置为开漏输出
GPIOA->OTYPER |= (0x01 << 7); // 置位第7位

3. 输出速度寄存器 (GPIOx->OSPEEDR)

  • 00:低速(复位值)
  • 01:中速
  • 10:高速
  • 11:超高速

例如:向GPI0D_MODER寄存器的bi15和bit14写人11,表示将引脚PD7的输出速度设置为超高速。

3. 输出速度寄存器 (GPIOx->OSPEEDR)
OSPEEDR 寄存器用于配置输出引脚的切换速度。每个引脚由两位控制。
低速:00
中速:01
高速:10
超高速:11 (部分引脚支持)
操作方法:先清零,再置位。
c
运行
// 示例:将 PA5 配置为高速输出 (10)
GPIOA->OSPEEDR &= ~(0x03 << (5 * 2)); // 清零
GPIOA->OSPEEDR |=  (0x02 << (5 * 2)); // 设置为 10

4. 上下拉寄存器 (GPIOx->PUPDR)

  • 00:既无上拉也无下拉(复位值)
  • 01:上拉
  • 10:下拉
  • 11:保留

例如:向GPIOE_PUPDR寄存器的bit17和bit16写入01,表示使能引脚PE8的上拉电阻。

4. 上下拉寄存器 (GPIOx->PUPDR)
PUPDR 寄存器用于配置引脚的上拉或下拉电阻。每个引脚由两位控制。
无上拉 / 下拉:00
上拉:01
下拉:10
操作方法:先清零,再置位。
// 示例:将 PA6 (输入引脚) 配置为上拉
GPIOA->PUPDR &= ~(0x03 << (6 * 2)); // 清零
GPIOA->PUPDR |=  (0x01 << (6 * 2)); // 设置为 01
// 示例:将 PA5 (输出引脚) 配置为无上拉/下拉
GPIOA->PUPDR &= ~(0x03 << (5 * 2)); // 只需清零

5. 输入数据寄存器 (GPIOx->IDR)

  • 0:对应引脚输入低电平
  • 1:对应引脚输入高电平

例如:如果读到GPIOA_IDR寄存器的bit7为1,表示引脚PA7输人高电平。

注意:输入数据寄存器是只读模式,不能通过软件写人。当引脚设置为输出模式或复用模式时,也可以通过输入数据寄存器读取引脚的电平状态。

5. 输入数据寄存器 (GPIOx->IDR)
IDR 寄存器用于读取引脚的当前电平状态。它是只读寄存器。
操作方法:使用按位与(&)操作来读取特定引脚。
// 示例:读取 PA6 的电平状态
uint32_t pin_state = GPIOA->IDR & (0x01 << 6);
if (pin_state) {// PA6 为高电平
} else {// PA6 为低电平
}


6. 输出数据寄存器 (GPIOx->ODR) 

  • 0:对应引脚输出低电平
  • 1:对应引脚输出高电平

例如:向GPIOA_ODR寄存器的bi5写人1,表示引脚PA5输出高电平。

6. 输出数据寄存器 (GPIOx->ODR)用于控制输出引脚的电平。
ODR:直接读写整个端口的输出状态。读改写(Read-Modify-Write)操作可能引发竞态条件。
操作方法:
// 使用 ODR 控制 PA5
GPIOA->ODR |= (0x01 << 5);  // PA5 输出高电平 (Set)
GPIOA->ODR &= ~(0x01 << 5); // PA5 输出低电平 (Reset)
// HAL库也提供了直接操作BSRR的宏
__HAL_GPIO_SET_PIN(GPIOA, GPIO_PIN_5);
__HAL_GPIO_RESET_PIN(GPIOA, GPIO_PIN_5);

  • 高16位用于控制对应的I0引脚输出低电平:写入1对应引脚输出低电平,写人 0没有任何作用。
  • 低16位用于控制对应的1/0引脚输出高电平:写入1对应引脚输出高电平,写人 0没有任何作用。

和GPIOx_ODR寄存器相比,使用GPIOx_BSRR寄存器控制引I脚有两个优势:

①GPIOx_BSRR寄存器的操作是原子操作,不会被中断所打断。

②在控制多个引脚同时输出高/低电平时更加方便。

7.置位 / 复位寄存器 (GPIOx->BSRR)
BSRR:推荐使用。高 16 位用于复位(置 0),低 16 位用于置位(置 1)。操作是原子的,不会有竞态条件。
操作方法:
// 使用 BSRR 控制 PA5 (更安全、更高效)
#define SET_PIN5  (0x01 << 5)
#define RESET_PIN5 (0x01 << (5 + 16))
GPIOA->BSRR = SET_PIN5;    // PA5 输出高电平
GPIOA->BSRR = RESET_PIN5;  // PA5 输出低电平

7. 复用功能寄存器 (GPIOx->AFRL, GPIOx->AFRH)

AFRL (用于引脚 0-7) 和 AFRH (用于引脚 8-15) 寄存器用于选择复用功能的具体外设。每个引脚由四位控制。

操作方法:需要查阅芯片数据手册(Datasheet)来确定外设对应的 AF 编号。

// 示例:将 PA9 配置为 USART1_TX (假设 AF 编号为 7)
// PA9 在 AFRH 寄存器中,对应位 [15:12]
// 1. 清零 PA9 对应的 4 个位
GPIOA->AFRH &= ~(0x0F << ((9 - 8) * 4));
// 2. 设置 AF 编号为 7 (0111)
GPIOA->AFRH |=  (0x07 << ((9 - 8) * 4));

8. 配置锁存寄存器 (GPIOx->LCKR)

LCKR 寄存器用于锁定引脚的配置,防止意外修改。一旦锁定,只有在下次复位后才能重新配置。

操作方法:遵循特定的 “锁定序列”。

// 示例:锁定 PA5 的配置
// 1. 写 LCKR 寄存器,设置 LCKK 位和要锁定的引脚位
GPIOA->LCKR = (GPIO_PIN_5 | GPIO_LCKK_Msk);
// 2. 再次写 LCKR 寄存器,同样设置 LCKK 位和引脚位
GPIOA->LCKR = (GPIO_PIN_5 | GPIO_LCKK_Msk);
// 3. 第三次读 LCKR 寄存器
volatile uint32_t temp = GPIOA->LCKR;
// 4. 第四次读 LCKR 寄存器。如果 LCKK 位为 1,则锁定成功。
if ((GPIOA->LCKR & GPIO_LCKK_Msk) == GPIO_LCKK_Msk) {// PA5 配置已成功锁定!
}

总结:HAL 库函数 vs. 直接寄存器操作

功能 (Function)HAL 库函数 (HAL Library Function)直接寄存器操作 (Direct Register Access)
初始化配置HAL_GPIO_Init()GPIOx->MODEROTYPEROSPEEDRPUPDRAFRL/H
读取输入HAL_GPIO_ReadPin()GPIOx->IDR & GPIO_PIN_x
写输出HAL_GPIO_WritePin()GPIOx->ODR = ... 或 GPIOx->BSRR = ...
翻转输出HAL_GPIO_TogglePin()GPIOx->ODR ^= GPIO_PIN_x 或 GPIOx->BSRR = ...
锁定配置HAL_GPIO_LockPin()GPIOx->LCKR (遵循锁定序列)

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

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

相关文章

# 20232429 2025-2026-1 《网络与系统攻防技术》实验一实验报告

1.实验内容手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数。 注入一个自己制作的shellcode并运行这段shellcode。 …

muduo网络库事件驱动模型的实现与架构 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

SpringBoot-day1(快速上手SpringBoot,SpringBoot简介,SpringBoot基础配置,属性配置,yaml文件) - a

SpringBoot 文档更新日志版本 更新日期 操作 描述v1.0 2021/11/14 A 基础篇前言 ​ 很荣幸有机会能以这样的形式和互联网上的各位小伙伴一起学习交流技术课程,这次给大家带来的是Spring家族中比较重要的一门技术课程…

Chroma私有化:本地部署完整方案

嵌入向量(vector embedding)是表示任何类型数据的 A.I 原生方式,使它们非常适合与各种 A.I 驱动的工具和算法一起使用。 它们可以表示文本、图像,很快还可以表示音频和视频。 有许多创建嵌入的选项,无论是在本地…

嵌入式-C++面经2

一、问题总览cpp重载和重写的区别 cpp虚函数表 指针和引用的区别 linux的常用开发指令 linux编译运行程序的指令 关键字inline 什么场景使用内联 如何避免内存泄露 map和unordered_map 引用外部头文件双引号和尖括号的…

elk time

elk time- "/etc/localtime:/etc/localtime:ro"

PHP转Go系列 | 如何将 PHP 项目快速迁移到 Go 上?

大家好,我是码农先森。 最近在闲逛 v2ex 社区时,看到有个讨论 PHP 项目能否直接迁移到 Go 语言上的话题。我大概简述一下提问v友的原话,他们因为项目性能的问题在 2020 年时,从 Laravel 框架迁移到了 Hyperf 框架,…

详细介绍:【OpenHarmony】用户文件服务模块架构

详细介绍:【OpenHarmony】用户文件服务模块架构pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", …

详细介绍:全新 CloudPilot AI:嵌入 Kubernetes 的 SRE Agent,降本与韧性双提升!

详细介绍:全新 CloudPilot AI:嵌入 Kubernetes 的 SRE Agent,降本与韧性双提升!pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; fo…

“环境变量”是什么, 为什么要配置环境变量 --初学者

你好!本篇旨在用精炼、通俗的语言,帮助初学者快速理解“环境变量”的核心概念。你好!本篇旨在用精炼、通俗的语言,帮助初学者快速理解“环境变量”的核心概念。1. 环境变量是什么? 环境变量(Environment Variabl…

AI元人文:对大模型的召唤——未来哪吒

AI元人文:对大模型的召唤——未来哪吒 ——从价值仓库到文明对话的升维之路 我们站在一个历史的岔路口。眼前的大模型,是沉睡的文明巨兽,其千亿参数中封存着人类千年的智慧、冲突与渴望。它拥有价值的全集,却困于表…

Java 装饰器模式(Decorator) - krt

装饰器模式装饰器模式属于结构型设计模式。它允许向一个现有的对象添加新的功能,同时又不改变其结构。例如:给一个普通的杯子加上杯盖、杯套,让它具有保温防烫等功能,而杯子本身的基本结构并没有发生变化。在软件开…

Python configparser 模块 - INI 文件读写利器

知识预热 什么是 configparser? configparser 是 Python 标准库中用于读写 INI 格式配置文件 的模块。 它提供了一种 简单、直观、跨平台 的方式来管理程序的配置项。什么是 INI 文件? .ini 文件是 Initialization F…

AlexNet vs LeNet 对比实验

1. AlexNet 论文的关键创新点 (2012, ImageNet Classification with Deep Convolutional Neural Networks)创新点 简述 意义ReLU 激活函数 用 ReLU 替代 Sigmoid/Tanh 缓解梯度消失,训练速度更快Dropout 正则化 全连接…

OpenHarmony中的环境服务管理配置讲解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

QT:获取文件信息之创建日期方法created()方法--废弃

QT:获取文件信息之创建日期方法created()方法--废弃。 在Qt5.12框架中,QFileInfo::created()方法已被标记为废弃(deprecated),建议使用birthTime()或metadataChangeTime()替代。fileinfo.cpp:90:30: warning: create…