首页 > 其他分享 >调试Debug,读,写 GPIO 寄存器(含实例代码)

调试Debug,读,写 GPIO 寄存器(含实例代码)

时间:2024-12-18 09:28:05浏览次数:6  
标签:引脚 PA8 配置 GPIOA 寄存器 Debug GPIO

以STM32G070CBT6 PA8为例 注:下面调试界面的打开方式为 下面图中调试界面中的寄存器仅用于指明具体位置,并不代表实际的实验现象 本文涉及寄存器的读写操作,不熟悉的可以移步 STM32寄存器读写操作-CSDN博客

MODER寄存器

GPIOA->MODER
  • 作用:配置 PA8 的工作模式(输入、输出、复用或模拟)。
  • 位置:MODER[17:16] 对应 PA8。
    • 00:输入模式。
    • 01:输出模式。
    • 10:复用功能。
    • 11:模拟模式。
if ((GPIOA->MODER & GPIO_MODER_MODE8_Msk) != 0x0) {
    // 如果 MODER8 不为 00,说明未配置为输入模式
    // 应清除 MODER8 对应的位:
    GPIOA->MODER &= ~GPIO_MODER_MODE8_Msk; // 设置为输入模式
}
如图PA8被配置为输入模式

1.输入模式(MODE = 0x00)

PA8 被配置为输入模式 (MODER = 0) 时,重点观察以下寄存器:
  1. GPIOA->IDR:读取输入引脚的电平状态。
  2. GPIOA->PUPDR:检查内部上拉/下拉电阻配置。
  3. RCC->AHB2ENR:确保 GPIO 时钟使能。
  4. GPIOA->LCKR:检查引脚配置是否被锁定。
  5. SYSCFG->EXTICR:检查是否被配置为外部中断。

1. GPIOx_IDR(输入数据寄存器)

  • 作用:用于读取引脚的当前输入电平状态。
  • 位置:GPIOA->IDR 的第 n 位对应引脚 PAx。
  • 观测值:
    • 0:引脚电平为低电平。
    • 1:引脚电平为高电平。
if (GPIOA->IDR & GPIO_IDR_ID8) {
    // PA8 当前为高电平
} else {
    // PA8 当前为低电平
}

2. GPIOx_PUPDR(上下拉电阻配置寄存器)

  • 作用:确定输入模式下引脚是否启用了内部上拉或下拉电阻。
  • 位置:PUPDR[2n:2n+1],其中 n 是引脚编号。
  • 配置值:
    • 00:无上下拉(浮空)。
    • 01:上拉。
    • 10:下拉。
    • 11:保留。
uint32_t pupd = (GPIOA->PUPDR & GPIO_PUPDR_PUPD8_Msk) >> GPIO_PUPDR_PUPD8_Pos;


if (pupd == 0x1) {
    // PA8 配置为上拉
} else if (pupd == 0x2) {
    // PA8 配置为下拉
} else {
    // PA8 无上下拉(浮空)
}

3. RCC_IOPENR(GPIO 时钟使能寄存器)

  • 作用:确保 GPIO 端口的时钟已经使能。
  • 位置:RCC->IOPENR 的对应位。
  • 如果 GPIO 时钟未使能,GPIO 引脚的配置和状态读取将无效。
if ((RCC->IOPENR & RCC_IOPENR_GPIOAEN_Msk)>>RCC_IOPENR_GPIOAEN_Pos) {
    // GPIOA 时钟已使能
} else {
    // GPIOA 时钟未使能
}

4. GPIOx_LCKR(引脚锁定寄存器)

  • 作用:用于检查引脚配置是否被锁定。
  • 位置:GPIOA->LCKR 的第 n 位对应引脚 PAx。
  • 如果引脚配置被锁定,任何对引脚配置的更改将被禁止。
if (GPIOA->LCKR & GPIO_LCKR_LCK8) {
    // PA8 配置已被锁定
}

5. SYSCFG_EXTICR(外部中断配置寄存器)

  • 位置:EXTICR3[3:0]
  • 作用:检查引脚是否被配置为外部中断源。
  • 如果 EXTI 被配置为与输入引脚关联,那么外部信号可能影响引脚的行为。
if ((SYSCFG->EXTICR[2] & SYSCFG_EXTICR3_EXTI8_Msk) == SYSCFG_EXTICR3_EXTI8_PA) {
    // PA8 被配置为 EXTI8 信号源
}
为什么是在这个位置呢? SYSCFG_EXTICR3 之所以对应 EXTI8,是因为在 STM32 系列芯片中, EXTI 控制寄存器16 个 EXTI 线路(EXTI0 ~ EXTI15) 分配到 4 个配置寄存器(EXTICR1 ~ EXTICR4) 中,每个寄存器管理 4 条 EXTI 线路
EXTICR 寄存器的分配规则
寄存器 管理的 EXTI 线
EXTICR1 EXTI0 ~ EXTI3
EXTICR2 EXTI4 ~ EXTI7
EXTICR3 EXTI8 ~ EXTI11
EXTICR4 EXTI12 ~ EXTI15

为什么 PA8 属于 EXTICR3?
  • PA8 对应的 外部中断线(EXTI8)。
  • 根据上述分配表,EXTI8 位于 SYSCFG_EXTICR3 中。
  • 在 EXTICR3 的 低 4 位(位 0-3) 用于配置 EXTI8 的引脚来源。

EXTICR3 的位定义SYSCFG_EXTICR3 寄存器中:
位段 描述
[3:0] EXTI8 的引脚映射
[7:4] EXTI9 的引脚映射
[11:8] EXTI10 的引脚映射
[15:12] EXTI11 的引脚映射
[31:16] 保留

EXTI8 的引脚映射值
值 (位 3:0) GPIO 引脚
0000 PA8
0001 PB8
0010 PC8
0011 PD8
0100 PF8
但是,当 PA8 的复位值和配置为外部中断对应的寄存器值都为 0 时(即 SYSCFG_EXTICR3 的 EXTI8 对应位段为 0000),的确容易让人产生混淆。此时,你需要结合 其他调试手段和寄存器的状态 来确认 PA8 是否真正被配置为外部中断引脚。 检查 EXTI 寄存器   EXTI_IMR1(Interrupt Mask Register 1) EXTI_IMR1 寄存器位定义 EXTI_IMR1 是 32 位寄存器,具体位定义如下:
位段 描述
Bit 0 EXTI0 中断屏蔽
Bit 1 EXTI1 中断屏蔽
Bit 2 EXTI2 中断屏蔽
... ...
Bit 8 EXTI8 中断屏蔽
... ...
Bit 19 EXTI19 中断屏蔽
Bit 20:31 保留
例如,当 EXTI_IMR1 的第 8 位(Bit 8)= 1 时,表示 EXTI8(对应 PA8 等)被使能,可以触发中断。

2.输出模式(MODE = 0x01)

PA8 被配置为输出模式 (MODER = 0x01) 时,重点观察以下寄存器:
  1. GPIOA->ODR:控制引脚的输出电平。
  2. GPIOA->BSRR:原子性设置/清除引脚输出。STM32原子性设置-CSDN博客
  3. GPIOA->OTYPER:确认输出类型(推挽/开漏)。
  4. GPIOA->OSPEEDR:配置输出速度(低速、中速、高速、超高速)。

1. GPIOx_ODR(输出数据寄存器)

  • 作用:控制引脚的输出电平状态。
  • 描述:写 0 输出低电平,写 1 输出高电平。
  • 观察内容:
    • 通过设置 ODR 的某一位,改变引脚输出电平(非原子性操作,谨慎使用)。
    • 读取 ODR 确认当前设置的输出值。
// 设置 PA8 输出高电平
GPIOA->ODR |= GPIO_ODR_OD8;

// 设置 PA8 输出低电平
GPIOA->ODR &= \~GPIO_ODR_OD8;

// 读取 PA8 当前输出状态
if (GPIOA->ODR & GPIO_ODR_OD8) {
    // PA8 输出高电平
} else {
    // PA8 输出低电平
}

2. GPIOx_BSRR(位设置/清除寄存器)

  • 作用:用于原子性地设置或清除引脚输出状态,避免读-改-写引发竞态条件。
  • 描述:
    • GPIOx_BSRR[15:0]:设置引脚为高电平。
    • GPIOx_BSRR[31:16]:清除引脚(设置为低电平)。
    • 两个位段同时被置1时,以清除位优先
// 设置 PA8 为高电平(使用 BSRR)
GPIOA->BSRR = GPIO_BSRR_BS8;

// 设置 PA8 为低电平(使用 BSRR)
GPIOA->BSRR = GPIO_BSRR_BR8;

3. GPIOx_OTYPER(输出类型寄存器)

  • 作用:配置引脚输出类型。
  • 描述:
    • 0:推挽输出(Push-Pull)。
    • 1:开漏输出(Open-Drain)。
  • 用途:确认引脚的输出类型是否符合设计要求。
// 设置 PA8 为开漏输出
GPIOA->OTYPER |= GPIO_OTYPER_OT8;

// 设置 PA8 为推挽输出
GPIOA->OTYPER &= \~GPIO_OTYPER_OT8;

4. GPIOx_OSPEEDR(输出速度寄存器)

  • 作用:配置引脚的输出速度,影响引脚的转换速率。
  • 描述:
    • 00:低速。
    • 01:中速。
    • 10:高速。
    • 11:非常高速。
  • 用途:观察输出速度是否满足电路需求。
// 设置 PA8 为高速输出
GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED8_1;
GPIOA->OSPEEDR &= \~GPIO_OSPEEDR_OSPEED8_0;

3.复用模式(MODE = 0x10)

PA8 被配置为复用模式 (MODER = 0x10) 时,重点观察以下寄存器:
  1. GPIOA->AFRL/AFRH:选择复用功能编号。
  2. 外设寄存器(以后介绍)。

1. GPIOx_AFRL 和 GPIOx_AFRH(复用功能选择寄存器)

  • 作用:指定复用功能的具体类型,例如连接到 USART、TIM、I2C 等外设。
  • 寄存器分为两个部分:
    • AFRL(低 32 位引脚 AF0-AF7):用于配置引脚 0-7。
    • AFRH(高 32 位引脚 AF8-AF15):用于配置引脚 8-15。
我们通过手册查看PA8的复用编号

PA8 的复用功能及 AFR 寄存器值

PA8 的复用功能存储在 AFRH 的第 0-3 位中(低 4 位)。以下是每种复用模式的值和功能:
复用模式 (AF) 功能描述 AFR 值
AF0 MCO (Microcontroller Clock Output) 0x0
AF1 SPI2_NSS 0x1
AF2 TIM1_CH1 0x2
AF3 - 0x3
AF4 - 0x4
AF5 - 0x5
AF6 - 0x6
AF7 EVENTOUT 0x7

AFR 寄存器中的具体配置

GPIOx_AFRH 是 32 位寄存器,其中每 4 位对应一个引脚复用配置。PA8 是 GPIO 高复用寄存器(AFRH)的第 0-3 位。
  • 寄存器位置:
    • GPIOA->AFR[1] 是复用高寄存器 (AFRH)。
    • PA8 使用 AFR[1] 的 第 0-3 位。
  • 值对应表:
    • 0000(AF0):配置为 MCO。
    • 0001(AF1):配置为 SPI2_NSS。
    • 0010(AF2):配置为 TIM1_CH1。
    • 0011(AF3):未定义。
    • 0100(AF4):未定义。
    • 0101(AF5):未定义。
    • 0110(AF6):未定义。
    • 0111(AF7):配置为EVENTOUT。
// 配置 PA8 为 SPI2_SCK (AF1)
GPIOA->AFR[1] &= \~GPIO_AFRH_AFSEL8_Msk;  // 清除 AFRH 第 0-3 位
GPIOA->AFR[1] |= (0x1 << GPIO_AFRH_AFSEL8_Pos); // 设置为 AF1

4.模拟模式(MODE = 0x11)

PA8 被配置为模拟模式 (MODER = 0x11) 时,重点观察以下寄存器: 在模拟模式下,引脚不受数字输入/输出电路控制,通常用于 ADC(模数转换)、DAC(数模转换) 和其他模拟信号功能。

1. GPIO 寄存器观察

1.1 GPIOx_MODER(模式寄存器)

  • 作用:配置 GPIO 引脚的工作模式。
  • 值含义:
    • 00:输入模式。
    • 01:通用输出模式。
    • 10:复用功能模式。
    • 11:模拟模式。
观察内容
  • 确保对应引脚的模式设置为 11。
  • 每个引脚占据 2 位。例如,配置 PA8 为模拟模式:
GPIOA->MODER &= \~(0x3U << (2 * 8)); // 清零
GPIOA->MODER |= (0x3U << (2 * 8));  // 设置为模拟模式

1.2 GPIOx_PUPDR(上下拉寄存器)

  • 作用:配置引脚的上拉/下拉电阻。
  • 在 模拟模式 下,通常不需要上拉/下拉电阻,因此应设置为 无上下拉(00)。
观察内容
  • 确保对应引脚的上下拉配置为 00。
    GPIOA->PUPDR &= \~(0x3U << (2 * 8)); // 设置为无上下拉

1.3 GPIOx_OTYPER 和 GPIOx_OSPEEDR

  • 在模拟模式下:
    • OTYPER(输出类型):无效。
    • OSPEEDR(输出速度):无效。
  • 这些寄存器与模拟模式无关,GPIO 输出电路已关闭。

2. 相关外设寄存器观察

在模拟模式下,通常对应 ADC(模数转换器) 或 DAC(数模转换器) 等外设,需要配置对应的寄存器。

2.1 ADC(模数转换器)相关寄存器

当引脚配置为模拟输入(如 PA8 作为 ADC 输入通道),需要观察和配置以下寄存器:
  1. ADCx_CR(控制寄存器):控制 ADC 的启动、停止、校准等操作。
  2. ADCx_SQRx(规则组序列寄存器):配置 ADC 通道序列,指定转换顺序。
  3. ADCx_DR(数据寄存器):放 ADC 转换后的数据。
示例:配置 PA8 为 ADC 输入通道 8
// 1. GPIO 配置为模拟模式
GPIOA->MODER |= (0x3U << (2 * 8)); // PA8 设置为模拟模式
GPIOA->PUPDR &= \~(0x3U << (2 * 8)); // 无上下拉

// 2. ADC 配置
RCC->AHB2ENR |= (1U << 13);          // 使能 ADC 时钟

ADC1->CR &= \~(1U << 29);             // 清除深度省电模式(ADVREGEN)
ADC1->SQR1 |= (8U << 6);             // 规则组第一个通道配置为通道 8
ADC1->SMPR1 |= (0x7U << (3 * 8));    // 采样时间选择最大值

ADC1->CR |= (1U << 0);               // 启动 ADC
while (!(ADC1->ISR & (1U << 0)));    // 等待 ADC 就绪

ADC1->CR |= (1U << 2);               // 开始转换
while (!(ADC1->ISR & (1U << 2)));    // 等待转换完成

uint32_t value = ADC1->DR;           // 读取 ADC 数据寄存器

2.2 DAC(数模转换器)相关寄存器

如果引脚用于 DAC 输出,需要配置以下寄存器:
  1. DACx_CR(控制寄存器):启用 DAC 通道,设置触发方式等。
  2. DACx_DHRx(数据保持寄存器):写入要输出的数值。
  3. DACx_DORx(数据输出寄存器):存放 DAC 当前输出值。
示例:配置 DAC 输出到 PA4(DAC 通道 1)
RCC->APB1ENR1 |= (1U << 29);         // 使能 DAC 时钟

DAC->CR |= (1U << 0);                // 使能 DAC 通道 1
DAC->DHR12R1 = 2048;                 // 输出中间值(12 位,范围 0-4095)

3. 总结:观察和配置的寄存器

GPIO 寄存器

  1. MODER:设置为模拟模式(11)。
  2. PUPDR:设置为无上下拉(00)。
  3. OTYPER 和 OSPEEDR:在模拟模式下无效,不需要配置。

外设寄存器

根据具体功能配置:
  • ADC 寄存器:
    • CR:控制 ADC 
    • SQRx:配置输入通道。
    • SMPRx:设置采样时间
    • DR:读取 ADC 转换结果。
  • DAC 寄存器:
    • CR:启用 DAC 通道 
    • DHRx:设置输出值。
    • DORx:输出寄存器,表示当前输出值。

完整示例:PA8 配置为 ADC 输入

// 1. 配置 PA8 为模拟模式
GPIOA->MODER &= \~(0x3U << (2 * 8));
GPIOA->MODER |= (0x3U << (2 * 8));
GPIOA->PUPDR &= \~(0x3U << (2 * 8)); // 无上下拉

// 2. 配置 ADC
RCC->AHB2ENR |= (1U << 13);        // 使能 ADC1 时钟

ADC1->CR &= \~(1U << 29);           // 清除深度省电模式
ADC1->SQR1 |= (8U << 6);           // 配置规则通道 8
ADC1->SMPR1 |= (0x7U << (3 * 8));  // 采样时间最大值

ADC1->CR |= (1U << 0);             // 使能 ADC
while (!(ADC1->ISR & (1U << 0)));  // 等待 ADC 就绪

ADC1->CR |= (1U << 2);             // 开始转换
while (!(ADC1->ISR & (1U << 2)));  // 等待转换完成

uint32_t adc_value = ADC1->DR;     // 读取 ADC 数据

如有侵权,联系删除

标签:引脚,PA8,配置,GPIOA,寄存器,Debug,GPIO
From: https://blog.csdn.net/Flocx/article/details/144549621

相关文章

  • VHDL时序电路:D触发器/十进制加减可逆计数器/偶数分频器/位移寄存器
    时序电路概述什么是时序电路与时序电路相对的是组合逻辑电路,其没有记忆功能,输出取决于输入而时序电路有记忆功能,下一步的输出受被记忆的当前状态影响,还可以进一步分为两类Moore型下一状态的输出依赖于电路的当前状态,其状态变化依赖于时钟(只能同步更新)Mealy型输出......
  • 【翻译_by_gpt】通过一个奇怪的技巧让你的 QEMU 快 10 倍(软件开发中的一个典型的debug
    标题:通过一个奇怪的技巧让你的QEMU快10倍URL来源:https://linus.schreibt.jetzt/posts/qemu-9p-performance.htmlMarkdown内容:这篇关于QEMU的工作和文章由DeterminateSystems资助,并在DeterminateSystems博客上共同发布。背景NixOS广泛使用基于QEMU的虚拟机......
  • C++ 出现异常“.... \debug_heap.cpp Line:980 Expression:__acrt_first_block==head
      1. “修改了当前程序的vc运行库配置,问题解决(1)修改:项目-属性-配置属性-C/C++-代码生成-运行库,将其改为“多线程调试(/MTd)”。”其中:【多线程/MT】【多线程调试/MTd】-----【多线程DLL/MD(默认)】-------【多线程调试DLL/MDd】 /MT、/MTd、/MD、/MDd什么......
  • Debug版本与Release版本有哪些不同?
    Debug版本和Release版本主要有以下不同: 代码优化程度 -Debug版本通常不会进行大量优化,代码和原始的编写状态比较接近,方便调试时理解程序执行流程。-Release版本会进行编译器优化,例如代码可能会被重组、函数内联等,让程序运行得更快、占用更少的资源,但这也使得代码较难......
  • debug
    欢迎来到我的友链小屋展示本站所有友情站点,排列不分先后,均匀打乱算法随机渲染的喔! 友链信息博客名称:麋鹿鲁哟博客网址:https://www.cnblogs.com/miluluyo/博客头像:https://pic.cnblogs.com/avatar/1273193/20190806180831.png博客介绍:大道至简,知易行难。joinus如需友链,......
  • 最全Arduino的GPIO和基础外设介绍,告别新手期,成为点灯大师(一)
         很多时候学习很多外设和传感器的使用,但是对开发板的了解却并不深入,本文章深入解析arduinouno这块开发板.知己知彼百战不殆.1.arduino的引脚图极其介绍1.1直流电源插孔-可以使用电源插孔为Arduino开发板供电。电源插孔通常连接到一个适配器。开发板的供电范围......
  • STM32 进阶 SPI外设读写Flash 寄存器代码书写
    目录SPI外设SPI外设框图需求描述硬件电路设计相关寄存器文字说明:spi.hspi.c W25Q32.hSPI外设与I2C外设一样,STM32芯片也集成了专门用于SPI协议通讯的外设。STM32的SPI外设可用作通讯的主机及从机,支持最高的SCK时钟频率为fpclk/2(STM32F103型号的芯片默认f......
  • PCIe扫盲——PCI总线配置周期产生和配置寄存器
    上一篇文章中也是说到了,I/OAddressSpace的空间很有限(64KB),所以一般在I/OSpace中都有两个寄存器,第一个指向要操作的内部地址,第二个存放读或者写的数据。因此,对于PCI的配置周期来说,包含了两个步骤:Step1:CPU先对IOAddress中的0xCF8~0xCFB写入要操作的配置寄存器的地址。如下图所示......
  • C++ debug
    C++debug在C++中,查看程序的调用栈(CallStack)通常用于调试崩溃、性能问题或逻辑错误等场景。以下是几种常用的方法来查看调用栈:1.使用GDB调试器查看调用栈GDB(GNUDebugger)是Linux上非常流行的调试工具,可以用来查看C++程序的调用栈。示例:假设有以下C++程序:#includ......
  • python debug
    pythondebug在Python中,查看程序的调用栈(callstack)可以帮助你调试代码,了解函数调用的顺序和上下文。以下是查看Python调用栈的常用方法。1.使用traceback模块traceback是Python标准库模块,可用于打印异常发生时的调用栈或程序的当前调用栈。示例:打印当前调用栈impo......