当前位置: 首页 > news >正文

STM32学习(MCU控制)(GPIO)

文章目录

    • MCU 和 GPIO
        • 1. 单片机 MCU
          • 1.1 单片机和嵌入式系统
          • 1.2 MCU
          • 1.3 ARM 公司
          • 1.4 市场主流 32 芯片
          • 1.5 STM32 开发版概述
        • 2. GPIO
          • 2.1 GPIO 概述
          • 2.2 STM32F103ZET6 GPIO 相关内容
          • 2.3 GPIO 开发流程
          • 2.4 GPIO 控制 LED 灯
          • 2.5 GPIO 端口内部基本电路情况
            • **2.5.1. 浮空输入模式(Floating Input)**
            • **2.5.2. 上拉输入模式(Pull - up Input)**
            • **2.5.3. 下拉输入模式(Pull - down Input)**
            • **2.5.4. 模拟输入模式(Analog Input)**
            • **2.5.5. 开漏输出模式(Open - Drain Output)**
            • **2.5.6. 推挽输出模式(Push - Pull Output)**
            • **2.5.7. 复用开漏输出模式(Alternate Function Open - Drain Output)**
            • **2.5.8. 复用推挽输出模式(Alternate Function Push - Pull Output)**
          • 2.6 时钟使能【小重点】
          • **2.7 寄存器开发模式【重点】**
            • 2.7.1 时钟使能,对应寄存器 RCC
            • 2.7.2 GPIO 对应引脚配置
            • 2.7.3 GPIO 引脚输出高低电平配置
            • 2.7.4 代码实现
            • 2.7.5 程序烧录和重启
        • 3. GPIO 控制案例
          • 3.1 Beep 蜂鸣器控制
            • 3.1.1 BEEP 原理图分析
            • 3.1.2 代码实现
          • 3.2 多文件编程
          • 3.3 非精准延时控制函数
          • 3.4 Key 按键控制
            • 3.4.1 原理图分析
            • 3.4.2 开发流程
            • 3.4.3 代码实现

MCU 和 GPIO

1. 单片机 MCU
1.1 单片机和嵌入式系统

嵌入式系统

  • 硬件 + 软件的嵌入式系统。嵌入到特定设备中,从而控制设备的执行。
  • 硬件:处理单元,内存 + 硬盘
  • 软件:裸机程序 或者 实时操作系统。

生活中实现的常见场景

  • 智能家居,智能穿戴设备,无人设备,智能驾驶,军事
  • 汽车主机厂,军工单位,智能化工厂
1.2 MCU

MCU ==> 微控制单元(Microcontroller Unit;MCU)

  • 中央处理器,指令处理单元
  • ROM 硬盘/存储空间
  • RAM 运行内存
  • MCU 可以认为是一个小型计算机,具备计算机的所有核心内容。
1.3 ARM 公司

ARM成立前的历史可追溯至45年前。1978年,由Chris Curry及Hermann Hauser共同创立Acorn Computers。这家新创公司获得建构及生产BBC Micro的权利。 这项英国政府计划的目标是让英国每间教室都设置电脑。Steve Furber教授及Sophie Wilson在这项计划中,设计出史上第一款ARM处理器ARM1。 [12]

ARM 主要进行芯片内核设计,提供给其他芯片制造商,生厂商,包括二级开发商,提供对应内核解决方案

  • Cortex-A 内核,高性能内核,更新速度极快。主要用于手机 SoC 芯片开发,例如高通,小米,苹果…
  • Cortex-R 内核,一般用于 MPU 实现,处理速度高,延时低,应用场景要求高稳定性,高可靠性。例如车辆控制 ECU 模块。
  • Cortex-M 内核,小型化,低功耗化芯片内核。主要用于 MCU 市场,主要版本有 Cortex-M3 Cortex-M4 Cortex-M7 Cortex-M0.
  • Cortex-X 内核,目前是 ARM 最新内核设计,主要用于 PC 和 移动端市场。

不同产品性能对比

不同产品性能对比

ARM架构对应的处理器家族

  • ARMv7 ==> Cortex-M 架构,目前市场主流 32 处理器架构。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.4 市场主流 32 芯片
  • 国内芯片
    • GD 兆易创新,国内占用率较高的 MCU 32 芯片。主要用于汽车,军工,智能化控制领域,同时和 STM 32 芯片兼容。
    • 乐鑫科技 ESP32 芯片,ESP32 性能较高,同时针对于通信设备和通信协议支持较多,包括 WiFi 蓝牙 Lora ZigBee。。。
    • 华大半导体,灵动微电子
    • 龙芯中科
    • 目前国家倡导使用国产芯片实现产品开发,从而提供国产芯片生存土壤,也避免国外卡脖子。
  • 国外芯片
    • ST 系列,意法半导体公司
    • Ti 协议,美国德州仪器公司,主要芯片是 DSP 数字信号处理芯片。
1.5 STM32 开发版概述

开发版概述

目前使用的开发版是基于 STM32F103ZET6 型号。

  • ST 意法半导体公司产品
  • M 使用 Cortex-M 内核
  • 32 当前 MCU 为 32 位芯片
  • F103
    • F1 ==> Cortex-M3 内核
    • 03 ==> F1 系列的型号,03 是增强型。
  • ZET6
    • Z ==> 引脚数目 144 引脚
    • E ==> 闪存存储器大小(Flash) 512 KB
    • T ==> 封装标准 LQFP 封装
    • 6 ==> 工作温度范围 -40 ~ 85 ℃

stm32编号规则

2. GPIO
2.1 GPIO 概述

GPIO,全称为 通用输入输出,是一种存在于集成电路(如微控制器、单板计算机等)上的数字信号引脚。它的核心特征是 “通用”,意味着这些引脚没有预先设定的单一功能(比如专门用于UART通信或I2C通信),其具体行为(作为输入还是输出)可以通过软件进行动态配置。

在 OpenHarmony Hi3861 中利用 GPIO 实现控制

  • LED 灯,BEEP 工作 ==> GPIO 输出信号控制
  • KEY ==> GPIO 输入信号控制
  • DHT11 ==> GPIO 输入输出状态转换,控制 + 数据读取、

对于 GPIO 而言

  • GPIO 方式 输入 or 输出
  • GPIO 电压情况,高电平 or 低电平
2.2 STM32F103ZET6 GPIO 相关内容

不同的 MCU 信号中,对应的 GPIO 数量不同,主要因素是对应 STM32 引脚数量

  • GD32F103C8T6 对应 GPIO 有两组分别是 GPIOA 和 GPIOB,每一组 16 个通用GPIO,可编程 GPIO 有 32 个
  • STM32F103ZET6 对应 GPIO 有七组 GPIOA ~ GPIOG,每一组 16 个通用GPIO,可编程 GPIO 有 16 * 7 = 112 个

硬件设计中的很多理念都遵循 2 进制思想,另外在硬件开发中,操作使用的二进制情况很多,需要重点掌握**【位操作】**相关内容

2.3 GPIO 开发流程
  • 原理图分析
    • 根据原理图,分析当前编程需要控制的引脚是哪一个,同时期望的现象需要当前 IO 对应工作状态。
  • 寄存器控制开发
    • 时钟使能,MCU 中所有的外部设备处于休眠状态。需要告知 MCU 当前外部设备需要工作,加入到 MCU 的执行周期中。
    • 根据原理图分析的 GPIO 工作模式,对应 GPIO 进行配置。
      • 明确 GPIO 分组
      • 明确 GPIO 引脚编号
      • 明确 GPIO 工作模式和高低电平状态。
      • 根据以上信息进行配置。
    • 根据业务所需,进行相关代码实现。控制高低电平完成 LED 的控制
2.4 GPIO 控制 LED 灯

LED 原理图分析

  • 对应引脚是 LED0 和 LED1
  • 当前 LED 对应 IO 引脚
    • IO 提供高电平,LED 灭
    • IO 提供低电平,LED 亮
  • 可以分析
    • GPIO 要求可以提供高低电平切换。
    • GPIO 对应输出模式。

引脚关系

  • LED0 ==> PB5
    • GPIO 分组 B 组中编号为 5 的引脚
  • LED1 ==> PE5
    • GPIO 分组 E 组中编号为 5 的引脚

2.5 GPIO 端口内部基本电路情况

在 STM32 中 GPIO 有八种工作模式

2.5.1. 浮空输入模式(Floating Input)
  • 原理:在这种模式下,GPIO 引脚没有接上拉电阻或下拉电阻,其电平状态完全取决于外部电路。引脚处于高阻抗状态,输入电流几乎为零。根据当前 IO 口分压来判断高低电平数据。
  • 应用场景:适用于外部信号已经有明确的驱动能力和电平状态的情况,比如连接按键,按键按下时直接将引脚接地,松开时引脚浮空,通过读取引脚电平判断按键状态。
2.5.2. 上拉输入模式(Pull - up Input)
  • 原理:GPIO 引脚内部连接了上拉电阻,当外部电路没有对引脚进行驱动时,引脚电平被上拉到高电平。如果外部电路将引脚拉低,那么引脚电平就为低电平。
  • 应用场景:常用于按键输入,当按键未按下时,引脚通过上拉电阻保持高电平;按键按下时,引脚接地变为低电平,避免了引脚浮空可能带来的电平不稳定问题。
2.5.3. 下拉输入模式(Pull - down Input)
  • 原理:与上拉输入模式相反,GPIO 引脚内部连接了下拉电阻,当外部电路没有对引脚进行驱动时,引脚电平被下拉到低电平。如果外部电路将引脚拉高,那么引脚电平就为高电平。
  • 应用场景:同样适用于按键输入等场景,当按键未按下时,引脚通过下拉电阻保持低电平;按键按下时,引脚接高电平。
2.5.4. 模拟输入模式(Analog Input)
  • 原理:该模式下,GPIO 引脚用于模拟信号的输入,内部的数字逻辑电路被断开,引脚直接连接到模拟信号处理模块,如 ADC(模拟 - 数字转换器)。
  • 应用场景:用于采集模拟信号,如温度传感器、压力传感器等输出的模拟电压信号,通过 ADC 将模拟信号转换为数字信号进行处理。
2.5.5. 开漏输出模式(Open - Drain Output)
  • 原理:在开漏输出模式下,GPIO 引脚内部的输出级只有 N 沟道 MOS 管,当输出为低电平时,MOS 管导通,引脚接地;当输出为高电平时,MOS 管截止,引脚处于高阻态,需要外部接上拉电阻才能输出高电平。
  • 应用场景:常用于实现线与功能I2C 总线等通信协议,多个开漏输出引脚可以连接在一起,只要有一个引脚输出低电平,总线就为低电平。
2.5.6. 推挽输出模式(Push - Pull Output)
  • 原理:推挽输出模式下,GPIO 引脚内部的输出级由 P 沟道 MOS 管和 N 沟道 MOS 管组成。当输出为高电平时,P 沟道 MOS 管导通,引脚输出高电平;当输出为低电平时,N 沟道 MOS 管导通,引脚输出低电平。
  • 应用场景:适用于直接驱动一些负载,如 LED 灯,能够提供较强的驱动能力。
2.5.7. 复用开漏输出模式(Alternate Function Open - Drain Output)
  • 原理:该模式下,GPIO 引脚的功能由片上外设控制,输出级采用开漏输出结构。与普通开漏输出模式类似,需要外部接上拉电阻才能输出高电平。
  • 应用场景:常用于一些通信协议和外设接口,如 SPI 总线的某些引脚、I2C 总线等,将 GPIO 引脚复用为外设的特定功能。
2.5.8. 复用推挽输出模式(Alternate Function Push - Pull Output)
  • 原理:此模式下,GPIO 引脚的功能由片上外设控制,输出级采用推挽输出结构,能够直接输出高电平和低电平。
  • 应用场景:常用于一些需要较强驱动能力的外设接口,如 UART 通信的发送引脚、PWM 信号输出等。

根据当前 LED 电路原理图分析,和需求的 GPIO 功能分析。当前对应 GPIO PB5 和 PE5 需要设置为推挽输出模式。

led概述

2.6 时钟使能【小重点】

时钟是当前 MCU 的执行能力,主要的核心参数/内容

  • 时钟频率:一般都是 MCU 和外部晶振提供,作为 MCU 处理任务的核心时钟参数,当前 STM32F103ZET6 芯片时钟是 72 MHz。芯片的运算速度可以认为是 13.88ns 时间周期执行一次计算
  • 时钟树:当前 MCU 内部的电路设计,将 MCU 的计算器能力提供多个时钟提供端口,将 MCU 执行能力提供给不同的功能模块,每一个模块都有固定的内部时钟管道。
    • 类似于水厂/热力公司,根据不同的区域管道,提供自来水/热力。

2.7 寄存器开发模式【重点】

根据 STM32 内核提供的标准库函数,利用寄存器方式对模块进行配置和使用。

寄存器就类似于拨码开关,根据官方要求和限制,需要提供拨码开关的不同形式来进行配置开发。

2.7.1 时钟使能,对应寄存器 RCC

RCC ==> Reset & Clock Control

根据原理分析引脚关系和时钟树分析对应时钟分配情况,当前需要通过 RCC 控制 APB2 使能(Enable) GPIOB 和 GPIOE 两个 GPIO 组时钟,从而满足执行操作。

rcc寄存器

需要提供给 RCC_APB2ENR 寄存器数据可以采用两种方式,分别为

  • 方式一: 直接赋值给寄存器数据 0x0000 0048

  • 方式二:

    RCC->APB2ENR |= (0x01 << 6); // 使能 GPIOE
    RCC->APB2ENR |= (0x01 << 3); // 使能 GPIOB
    
2.7.2 GPIO 对应引脚配置

根据原理图分析,对应引脚是 PB5 和 PE5,对应工作模式为 GPIO 推挽输出模式。利用 GPIO 寄存器对当前的 IO 引脚进行控制。

在 STM32 中的一组 GPIO 有 16 个 IO 口。内核将 16 个 IO 分为高低两组

  • 高位寄存器 8 ~ 15
  • 低位寄存器 0 ~ 7

因为多组 GPIO,在底层寄存器中,利用 GPIOx 提供不同的分组 GPIO 控制。例如 GPIOA,GPIOB…

gpio

当前 GPIOB ==> PB5 和 GPIOE ==> PE5 所需的工作模式为

  • 通用推挽输出模式

需要对当前寄存器中的 CNF5 和 MODE5 进行组合配置,可以提供数据为

  • 0001 ==> 推挽输出模式,速度 10 MHz
  • 0011 ==> 推挽输出模式,速度 50 MHz
  • 0010 ==> 推挽输出模式,速度 2 MHz
GPIOB->CRL |= (0x03 << 20); // GPIOB 组中 PB5 引脚配置为通用推挽输出模式,速度 50 MHz
GPIOE->CRL |= (0x03 << 20); // GPIOE 组中 PE5 引脚配置为通用推挽输出模式,速度 50 MHz
2.7.3 GPIO 引脚输出高低电平配置

通过 ODR 配置输出电平

14-GPIOx_ODR寄存器配置

  • LED 亮,GPIO对应就为低电平

    GPIOB->ODR &= ~(0x01 << 5);
    GPIOE->ODR &= ~(0x01 << 5);
    
  • LED 灭,GPIO对应就为高电平

    GPIOB->ODR |= (0x01 << 5);
    GPIOE->ODR |= (0x01 << 5);
    
2.7.4 代码实现
#include "stm32f10x.h"
/*
STM32 核心头文件,没有当前头文件无法完成项目开发!!!
stm32f10x.h 对应芯片系列为F10x ==> F101 F102 F103 F105 F107....
*/int main(void)
{/*1. 时钟使能需要将 MCU 时钟提供给 GPIOB 和 GPIOE对应寄存器是 RCC->APB2ENR*/RCC->APB2ENR |= (0x01 << 3); // 使能 GPIOB IO组RCC->APB2ENR |= (0x01 << 6); // 使能 GPIOE IO组/*2. 对应 GPIO 引脚功能配置,需要对 PB5 和 PE5 引脚统一配置为【通用推挽输出模式】对应寄存器是 GPIOx->CRLGPIOB->CRL &= ~(0x0F << 20);GPIOB->CRL 32位寄存器 0100 0100 【????】 0100 0100 0100 0100 01000x0F ==> 0000 1111 执行左移 20 位0000 1111 0000 0000 0000 0000 0000~(0x0F << 20)1111 0000 1111 1111 1111 1111 1111GPIOB->CRL &= ~(0x0F << 20);0100 0100 ???? 0100 0100 0100 0100 0100&	     1111 0000 1111 1111 1111 1111 11110100 0100 0000 0100 0100 0100 0100 0100*/// PB5 配置GPIOB->CRL &= ~(0x0F << 20);GPIOB->CRL |= (0x03 << 20); // 0011 ==> 通用推挽输出模式,速度 50 MHz// PE5 配置GPIOE->CRL &= ~(0x0F << 20);GPIOE->CRL |= (0x03 << 20); // 0011 ==> 通用推挽输出模式,速度 50 MHz/*3. 控制 GPIOx_ODR 寄存器,配置高低电平高电平 ==> LED 灭低电平 ==> LED 亮*/while (1){// LED0 亮 LED1 灭GPIOB->ODR &= ~(0x01 << 5);GPIOE->ODR |= (0x01 << 5);for (u32 i = 0; i < 10000000; i++) {}GPIOB->ODR |= (0x01 << 5);GPIOE->ODR &= ~(0x01 << 5);for (u32 i = 0; i < 10000000; i++) {}}
}
2.7.5 程序烧录和重启

编译

在这里插入图片描述

烧录

在这里插入图片描述

连接方式

在这里插入图片描述

编译和烧录成功提示

在这里插入图片描述

在这里插入图片描述

重启

3. GPIO 控制案例
3.1 Beep 蜂鸣器控制
3.1.1 BEEP 原理图分析

3.1.2 代码实现
  • 时钟使能,通过 RCC 对应 APB2ENR 控制 GPIOB 组时钟使能。
  • 利用 GPIOx 中的 CRH 控制 PB8 引脚工作状态
  • 控制 GPIOx 中的 ODR 寄存器,控制 MCU PB8 对外输出高低电平情况。

在这里插入图片描述

#include "stm32f10x.h"int main(void)
{// 1. GPIOB 对应 GPIO 组时钟使能RCC->APB2ENR |= (0x01 << 3);/*2. 配置 GPIOB CRH 寄存器,控制 PB8 引脚的工作模式所需工作模式为 【通用推挽输出模式】*/GPIOB->CRH &= ~(0x0F); // 清除对应 CNF8 MODE8 原本状态。GPIOB->CRH |= 0x03;    // PB8 对应通用推挽模式,速度 50 MHz/*3. 利用 ODR 控制高低电平,满足 BEEP 工作高电平 ==> BEEP 工作低电平 ==> BEEP 停止工作*/while (1){GPIOB->ODR |= (0x01 << 8);for (u32 i = 0; i < 10000000; i++) {}GPIOB->ODR &= ~(0x01 << 8);	for (u32 i = 0; i < 10000000; i++) {}	}
}
3.2 多文件编程

需要将开发中使用的设备进行模块化处理,方便后续组装 or 二开。一般情况下,模块内容都是对应 .h.c。代码模块名称对应当前模块名,例如 led, beep

流程

  • 新建文件添加到 Keil 项目中
  • 新建文件和保存

新文件配置添加到 Keil 项目中

目标文件选中

多文件案例

led.h

#ifndef _LED_H
#define _LED_H#include "stm32f10x.h"// RCC 对应时钟使能控制寄存器标志位
#define GPIOB_RCC_APB2_CLOCK_ENABLE (0x01 << 3)
#define GPIOE_RCC_APB2_CLOCK_ENABLE (0x01 << 6)// GPIOP 推挽输出模式,50 MHz 预设宏
#define Push_Pull_Out_50MHz (0x03)/**
* @brief 当前 STM32F103ZET6 开发板对应 LED0 和 LED1 配置
*      LED0 和 LED1 对应 GPIO 引脚,配置为【通用推挽输出模式】
*/
void Led_Init(void);/**
* @brief LED0 控制函数,根据提供的外部参数,控制当前 LED 亮灭
*
* @param flag flag 为 1 对应 LED0 亮,0 对应 LED0 熄灭
*/
void Led0_Ctrl(u8 flag);/**
* @brief LED1 控制函数,根据提供的外部参数,控制当前 LED 亮灭
*
* @param flag flag 为 1 对应 LED1 亮,0 对应 LED1 熄灭
*/
void Led1_Ctrl(u8 flag);#endif

led.c

#include "led.h"void Led_Init(void) 
{// 1. LED0 和 LED1 对应 GPIO 时钟使能RCC->APB2ENR |= GPIOB_RCC_APB2_CLOCK_ENABLE | GPIOE_RCC_APB2_CLOCK_ENABLE;// 2. PB5 和 PE5 通用推挽输出模式。速度 50 MHzGPIOB->CRL &= ~(0x0F << 20);GPIOB->CRL |= (Push_Pull_Out_50MHz << 20);GPIOE->CRL &= ~(0x0F << 20);GPIOE->CRL |= (Push_Pull_Out_50MHz << 20);
}void Led0_Ctrl(u8 flag)
{// 根据 Flag 控制当前 LED 工作情况/*【注意】 LED 要求 IO 引脚输出低电平灯亮,高电平灯灭*/if (flag){GPIOB->ODR &= ~(0x01 << 5);}else{GPIOB->ODR |= (0x01 << 5);}
}void Led1_Ctrl(u8 flag)
{if (flag){GPIOE->ODR &= ~(0x01 << 5);}else{GPIOE->ODR |= (0x01 << 5);}
}
3.3 非精准延时控制函数

利用 _NOP 函数实现。非精准延时控制

因为当前 STM32F103ZET6 对应时钟频率为 72MHz,MCU 执行一次任务时间为 13.88ns,利用特征实现【us 单位延时】和【ms 单位延时】控制。

_NOP 函数 当前 MCU 空闲一个执行任务周期,对应时间为 13.88889 ns。如果一个函数执行 72 次**_NOP 函数** ,可以任务当前函数的执行时间为 13.88889 ns * 72 == 1 us

delay.h

#ifndef _DELAY_H
#define _DELAY_H#include "stm32f10x.h"/**
* @brief 延时控制函数,对应的控制单位为 us 微秒
* 
* @param us 延时控制微秒数
*/
void Delay_us(u32 us);/**
* @brief 延时控制函数,对应的控制单位为 ms 毫秒
* 
* @param ms 延时控制毫秒数
*/
void Delay_ms(u32 ms);#endif

delay.c

#include "delay.h"void Delay_us(u32 us)
{/*根据 MCU 执行特征分析,任何一个任务执行都需要消耗周期时间while 循环控制和 us-- 实际上也存在一定的 MCU 执行周期占用当前延时控制【非精准控制】,存在一定的误差范围。*/while (us--) {/*一个 __NOP 函数占用 MCU 一次执行任务周期,对应时间为 13.8888 ns当前 Delay_us 单位控制对应 72 个 __NOP 函数,执行时间可以认为是 1 us*/__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();}
}void Delay_ms(u32 ms)
{Delay_us(ms * 1000);
}
3.4 Key 按键控制
3.4.1 原理图分析

在这里插入图片描述

在这里插入图片描述

  • 根据原理分析
    • KEY0 KEY1 KEY2 按键按下之后对应引脚电平为【低电平】,如果需要根据按键的电平信号进行 MCU 控制和操作,要求对应 MCU IO 引脚默认电平为【高电平】。
      • KEY0 ==> PE4 KEY1 ==> PE3 KEY0 ==> PE2
      • PE2 PE3 PE4 要求 GPIO 的工作模式为输入模式。
      • 同时为了满足电平切换可参考,可提取信息,对应为【上拉输入模式 高电平】
    • KEY_UP Or WK_UP 按键按下之后对应引脚电平为【高电平】,如果需要根据按键的电平信号进行 MCU 控制和操作,要求对应 MCU IO 引脚默认电平为【低电平】。
      • KEY_UP Or WK_UP ==> PA0
      • PA0 GPIO 的工作模式为输入模式。
      • 同时为了满足电平切换可参考,可提取信息,对应为【下拉输入模式 低电平】
  • 代码流程分析
    • 时钟使能【GPIOA】和【GPIOE】,通过 RCC 中的 APB2ENR 进行控制
    • 对应 PE2 PE3 PE4 配置为上拉输入模式
    • 对应 PA0 配置为下拉输入模式
    • 按键输入电平读取操作
3.4.2 开发流程

时钟使能

GPIO 配置

  • PA0 PE2 PE3 PE4 都是上拉/下拉输入模式
  • 具体上拉还是下拉,需要使用 ODR 寄存器配置输出高低电平,决定当时输入工作模式为上拉还是下拉
  • ODR = 1 ==> 上拉输入 ODR = 0 ==> 下拉输入

利用 ODR 寄存器配置高低电平,决定当前为上拉输入还是下拉输入

外部 KEY 按键之后,IO 口输入电平读取,读取 GPIOx_IDR 寄出去 (Input Data Register)

3.4.3 代码实现

key.h

#ifndef _KEY_H
#define _KEY_H#include "stm32f10x.h"#include "delay.h"#define GPIOA_RCC_APB2_CLOCK_ENABLE (0x01 << 2)
#define GPIOE_RCC_APB2_CLOCK_ENABLE (0x01 << 6)#define Pull_Up_Or_Down_Input (0x08)// 利用枚举类型描述按键按键标记数据
typedef enum key_value
{	KEY_0_VALUE,KEY_1_VALUE,KEY_2_VALUE,KEY_UP_VALUE,NO_KEY_PRESSED
} GL_Key_Value;/**
* @brief 当前开发板中按键初始化函数,配置 PA0 PE2 PE3 PE4 
*         所需的 GPIO 工作模式
*         PA0 ==> KEY_UP or WK_UP 下拉输入
*         PE2 ==> KEY2 上拉输入
*         PE3 ==> KEY1 上拉输入
*         PE4 ==> KEY0 上拉输入
*/
void Key_Init(void);/**
* @brief 获取当前开发板中,哪一个按键被按下
*
* @return 返回值是对应按键被按下的标记数据,对应类型为枚举 GL_Key_Value
*		类型
*/
u8 Key_GetValue(void);#endif

key.c

#include "key.h"void Key_Init(void)
{// 1. 时钟使能,GPIOA 和 GPIOERCC->APB2ENR |= GPIOA_RCC_APB2_CLOCK_ENABLE | GPIOE_RCC_APB2_CLOCK_ENABLE;/*2. GPIO 配置*//*2.1 PA0 下拉输入配置*/GPIOA->CRL &= ~(0x0F);GPIOA->CRL |= Pull_Up_Or_Down_Input;GPIOA->ODR &= ~(0x01); // 利用 ODR 低电平明确限制下拉输入/*2.2 PE2 PE3 PE4 上拉输入配置*/GPIOE->CRL &= ~(0x0FFF << 8);GPIOE->CRL |= (Pull_Up_Or_Down_Input << 16) | (Pull_Up_Or_Down_Input << 12)| (Pull_Up_Or_Down_Input << 8);GPIOE->ODR |= (0x07 << 2);  // 利用 ODR 高电平明确限制上拉输入
}u8 Key_GetValue(void)
{/*KEY0 【上拉输入模式 默认高电平】按键判断是否按下KEY0 ==> PE4 引脚0x01 << 4 ==> 0000 0001 << 4 0001 0000GPIOE->IDR & 0001 0000,如果结果为 0 表示,对应 IDR4 位置为 0,按键已按下。如果结果不为 0,表示 IDR4 位置为 1,按键尚未按下*/if (0 == (GPIOE->IDR & (0x01 << 4))){// 消抖Delay_ms(10);if (0 == (GPIOE->IDR & (0x01 << 4))){return KEY_0_VALUE;}}// KEY1 按键对应 PE3 引脚,操作同理 KEY0if (0 == (GPIOE->IDR & (0x01 << 3))){// 消抖Delay_ms(10);if (0 == (GPIOE->IDR & (0x01 << 3))){return KEY_1_VALUE;}}// KEY2 按键对应 PE2 引脚,操作同理 KEY0if (0 == (GPIOE->IDR & (0x01 << 2))){// 消抖Delay_ms(10);if (0 == (GPIOE->IDR & (0x01 << 2))){return KEY_2_VALUE;}}/*KEY_UP or WK_UP 按键对应 PA0 【下拉输入模式 默认低电平】GPIOA->IDR GPIOA 组输入电平高低寄存器。PA0 对应 IDR0GPIOA->IDR & 0x01 如果 KEY_UP 按下,对应 IDR0 为 1,当前可以简化代码 & 操作为0x01 & 0x01 ==> if 可以执行如果 KEY_UP 未按下,对应 IDR0 为 0,当前可以简化代码 & 操作为0x00 & 0x01 ==> 不满足 if 条件判断。*/if (GPIOA->IDR & 0x01){// 消抖Delay_ms(10);if (GPIOA->IDR & 0x01){return KEY_UP_VALUE;}}/*以上所有按键都未按下,返回 NO_KEY_PRESSED 告知外部。*/return NO_KEY_PRESSED;
}

测试 main 函数代码

#include "stm32f10x.h"#include "stdio.h"
#include "stdlib.h"
#include "string.h"#include "led.h"
#include "beep.h"
#include "delay.h"
#include "key.h"int main(void)
{// LED 模块初始化,完成时钟使能和 GPIO 配置Led_Init();// BEEP 模块初始化Beep_Init();// KEY 模块初始化Key_Init();u8 key_value = 0;// u8 flag = 1;while (1){key_value = Key_GetValue();if (KEY_0_VALUE == key_value){Led0_Ctrl(1);}else if (KEY_1_VALUE == key_value){Led0_Ctrl(0);}else if (KEY_2_VALUE == key_value){Beep_Ctrl(1);}else if (KEY_UP_VALUE == key_value){Beep_Ctrl(0);}Delay_ms(10);}
}
http://www.dtcms.com/a/508027.html

相关文章:

  • wordpress站点标题添加如何注册一个自己的公司
  • 台州企业网站搭建价格网站开发的交付文档
  • 橙色守护者:嘉顺达蓝海的危险品运输安全密码
  • 安全监控摄像头通过智能组网模块实现联网报警和远程管理的实践解析
  • AI时代的数据管理新范式:Git for Data让数据工程化
  • Linux中内核调用用户空间程序的实现
  • 建网站空间的详细说明网站备案怎么查询
  • 2025 兽用 mRNA 疫苗市场调研:58.7% CAGR 下,技术路线与投资前景深度分析
  • 关于 Qt5.x版本离线安装可以跳过登录但是实际离线仍需要登录 的解决方法
  • 什么时候会出现电源平面谐振?
  • php做网站常见实例新市网站建设
  • 【Vue知识点总结】style标签的 scoped 属性
  • 网站移动适配怎么做济南做网站互联网公司排名
  • authui!CLogonFrame::Create中的USER32!LoadImageW可以作为有效起始断点
  • Linux服务器编程实践50-TCP接收与发送缓冲区:SO_RCVBUF与SO_SNDBUF设置
  • 免费无版权图片素材网站中国制造网简介
  • 鸿蒙Next Test Kit:一站式自动化测试框架详解
  • 《微信小程序》第一章:开发前准备与配置
  • 实验二-决策树-葡萄酒
  • 用双语网站做seo会不会建设一个网站需要哪些员工
  • 专项智能练习(教学过程的规律)
  • 设计模式-创建型设计模式
  • 非关系型数据库(NoSQL)学习指南:从入门到实战
  • Endnote | word中参考文献段落对齐及悬挂缩进的设置
  • MCU硬件学习
  • SpringBoot教程(十九) | SpringBoot集成Slf4j日志门面(优化版)
  • 帮别人备案网站大连企业网站建设模板
  • 关于反向传播
  • --- 数据结构 AVL树 ---
  • 8、docker容器跨主机连接