RYMCU

金名的STM32F407单片机标准库开发(二)-点亮一个LED灯

kingmingnie 11 月前
# 金名的STM32F407标准库开发笔记 # RY-STM32F407 # STM32

金名的 STM32F407 单片机标准库开发(二)--点亮 LED 灯

​ 在 金名的STM32F407单片机标准库开发(一) 中我们编写了一段代码,相信即使是 C 语言大佬,初次看到这段代码也会很迷茫,无法理解这段代码的含义。确实,STM32 单片机的代码,尤其是涉及到硬件操作的部分,对于初学者来说可能会显得有些复杂。这是因为它涉及到对硬件寄存器的直接或间接操作,这与普通的 C 语言编程有很大的不同。对于初学者来说,这确实是一个挑战。不过,随着学习的深入,你会逐渐熟悉这些操作,并能够更好地理解和编写代码。接下来我们将一起学习 STM32 单片机的第一个外设——GPIO(General Purpose Input/Output,通用输入输出)外设。

一、什么是外设?

  在学习 GPIO 之前,首先需要澄清一个概念:什么是外设?

  如果你有《计算机组成原理》的背景,对外设这个术语应该不会陌生。不过,在单片机领域,外设的定义与传统计算机外设有所不同。在计算机中,外设指的是那些与计算机主机相连的外部设备,比如键盘、鼠标、显示器和打印机等,它们是计算机与外界交换信息的重要工具。

  而在单片机领域中,外设则指的是单片机内部集成的一系列功能模块。这些模块使得单片机能够与外部世界进行信息交互,并执行特定的任务。例如,ADC 模块可以将模拟信号转换为数字信号,UART 模块可以实现串行通信,而 GPIO 模块则提供了基本的输入输出功能。通过编程控制这些内部模块,单片机能够实现数据采集、信号处理、通信和用户交互等多种功能,从而在嵌入式系统和物联网设备中发挥关键作用。

二、什么是 GPIO?

  作为大多数人学习单片机时接触的第一个外设,GPIO(General Purpose Input/Output 通用输入输出)外设的重要性是不言而喻的。它是单片机开发最重要最基础的硬件资源之一,为单片机提供了与外部进行交互的数字接口。通过 GPIO 端口,开发者可以控制 LED 灯的亮灭、读取按钮的状态、驱动电机等,这些基本操作构成了单片机应用的基础。

  我们开发板所使用的 STM32F407VET6 芯片共有 100 个引脚,其中有 82 个引脚是 GPIO 端口,这些 IO 引脚分为五组,分别是 GPIOA~GPIOE,每组包含 16 个引脚。这些引脚输入模式下通常能够承受的电压范围是 0 到 3.3V,少数可以容忍 5V;而输出模式最大只能输出 3.3V。如图我们所使用的开发板引出了 75 个可用 IO 引脚。


RY-STM32F407开发板GPIO引脚布局

三、GPIO 的工作模式

  GPIO 外设通常包含多个引脚,每个引脚都可以被配置为输入或输出模式,以适应不同的应用场景。在输入模式下,GPIO 引脚可以作为数字信号的接收端,例如读取按钮的状态。而在输出模式下,GPIO 引脚则可以作为控制信号的发送端,用来驱动 LED 灯或其他电子元件。

GPIO 输入模式

  1. 浮空输入(Input Floating)
  • 引脚不连接内部上拉或下拉电阻,输入信号由外部电路决定。

  1. 上拉输入(Input with Pull-up)
  • 引脚内部连接一个上拉电阻到 Vcc,适用于外部开关或按键接地的情况。
  1. 下拉输入(Input with Pull-down)
  • 引脚内部连接一个下拉电阻到 GND,适用于外部开关或按键接 Vcc 的情况。
  1. 模拟输入(Analog Mode)

    • 引脚用作模拟信号输入,通常用于 ADC(模拟数字转换器)。

GPIO 输出模式

  1. 推挽输出(Push-Pull Output)

    • 引脚可以输出高电平(连接到 Vcc)和低电平(连接到 GND),适用于驱动 LED 或一般的数字电路。

推挽输出之“推”

推挽输出之“挽”
  1. 开漏输出(Open-Drain Output)

    • 引脚只能输出低电平(连接到 GND),高电平由外部上拉电阻决定。这种模式常用于 I2C 等通信协议。

开漏输出之“开”

开漏输出之“漏”
  1. 复用推挽输出(Alternate Function Push-Pull)
  • 引脚在复用功能(如 USART、SPI、I2C 等)和推挽输出之间切换。

复用推挽输出
  1. 复用开漏输出(Alternate Function Open-Drain)

    • 引脚在复用功能(如 USART、SPI、I2C 等)和开漏输出之间切换。

复用开漏输出

本章点亮 LED 灯使用 GPIO 的推挽输出模式,输入模式将在以后进行讲解。

四、配置 GPIO 点亮 LED

硬件准备

  使用外接 LED 灯进行实验演示,使用 GPIOC9 引脚,LED 灯引脚长正短负,我们使用母对母杜邦线将正极与开发板的 C9 连接,负极与 GND 连接。


LED连接示意

端口配置

单片机的所有外设资源时钟默认都是关闭的,在使用之前我们需要进行相应的初始化。

配置 STM32F407 的 GPIO 为推挽输出模式:

1. 使能 GPIO 的端口时钟,为 GPIO 外设提供心脏

  • 查阅芯片手册可知,所有 GPIO 外设的时钟都是由 AHB1 总线提供。
  • 通过 RCC(Reset and Clock Control)模块使能对应 GPIO 端口的时钟。

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
    

2. 配置 GPIO 点亮 LED

  • 进行 GPIO 初始化需要先了解都要配置哪些东西,打开 STM32f4xx_gpio.h 头文件,查看 GPIO 初始化结构体声明:

    /** 
       * @brief   GPIO Init structure definition  
       */ 
     typedef struct
     {
       uint32_t GPIO_Pin;              /*!< Specifies the GPIO pins to be configured.
                                            This parameter can be any value of @ref GPIO_pins_define */
     ​
       GPIOMode_TypeDef GPIO_Mode;     /*!< Specifies the operating mode for the selected pins.
                                            This parameter can be a value of @ref GPIOMode_TypeDef */
     ​
       GPIOSpeed_TypeDef GPIO_Speed;   /*!< Specifies the speed for the selected pins.
                                            This parameter can be a value of @ref GPIOSpeed_TypeDef */
     ​
       GPIOOType_TypeDef GPIO_OType;   /*!< Specifies the operating output type for the selected pins.
                                            This parameter can be a value of @ref GPIOOType_TypeDef */
     ​
       GPIOPuPd_TypeDef GPIO_PuPd;     /*!< Specifies the operating Pull-up/Pull down for the selected pins.
                                            This parameter can be a value of @ref GPIOPuPd_TypeDef */
     }GPIO_InitTypeDef;
    

    由此 GPIO_InitTypeDef 结构体可知在初始化中需要五个结构体成员。

  • 第一个 GPIO_Pin 选择要使用的引脚,从 stm32f4xx_gpio.h 的头文件中可知:

    /** @defgroup GPIO_pins_define 
       * @{
       */ 
     #define GPIO_Pin_0                 ((uint16_t)0x0001)  /* Pin 0 selected */
     #define GPIO_Pin_1                 ((uint16_t)0x0002)  /* Pin 1 selected */
     #define GPIO_Pin_2                 ((uint16_t)0x0004)  /* Pin 2 selected */
     #define GPIO_Pin_3                 ((uint16_t)0x0008)  /* Pin 3 selected */
     #define GPIO_Pin_4                 ((uint16_t)0x0010)  /* Pin 4 selected */
     #define GPIO_Pin_5                 ((uint16_t)0x0020)  /* Pin 5 selected */
     #define GPIO_Pin_6                 ((uint16_t)0x0040)  /* Pin 6 selected */
     #define GPIO_Pin_7                 ((uint16_t)0x0080)  /* Pin 7 selected */
     #define GPIO_Pin_8                 ((uint16_t)0x0100)  /* Pin 8 selected */
     #define GPIO_Pin_9                 ((uint16_t)0x0200)  /* Pin 9 selected */
     #define GPIO_Pin_10                ((uint16_t)0x0400)  /* Pin 10 selected */
     #define GPIO_Pin_11                ((uint16_t)0x0800)  /* Pin 11 selected */
     #define GPIO_Pin_12                ((uint16_t)0x1000)  /* Pin 12 selected */
     #define GPIO_Pin_13                ((uint16_t)0x2000)  /* Pin 13 selected */
     #define GPIO_Pin_14                ((uint16_t)0x4000)  /* Pin 14 selected */
     #define GPIO_Pin_15                ((uint16_t)0x8000)  /* Pin 15 selected */
     #define GPIO_Pin_All               ((uint16_t)0xFFFF)  /* All pins selected */
    
  • 第二个 GPIO_Mode 选择引脚的工作模式,从 stm32f4xx_gpio.h 的头文件中可知 STM32 的工作模式,在上文有所介绍:

typedef enum
 { 
   GPIO_Mode_IN   = 0x00, /*!< GPIO Input Mode */
   GPIO_Mode_OUT  = 0x01, /*!< GPIO Output Mode */
   GPIO_Mode_AF   = 0x02, /*!< GPIO Alternate function Mode */
   GPIO_Mode_AN   = 0x03  /*!< GPIO Analog Mode */
 }GPIOMode_TypeDef;
  • 第三个 GPIO_Speed 配置的是 GPIO 的频率,从 stm32f4xx_gpio.h 的头文件中可知 STM32F4 提供了四种速度模式:

    typedef enum
     { 
       GPIO_Low_Speed     = 0x00, /*!< Low speed    */
       GPIO_Medium_Speed  = 0x01, /*!< Medium speed */
       GPIO_Fast_Speed    = 0x02, /*!< Fast speed   */
       GPIO_High_Speed    = 0x03  /*!< High speed   */
     }GPIOSpeed_TypeDef;
     ​
     /* Add legacy definition */
     #define  GPIO_Speed_2MHz    GPIO_Low_Speed    
     #define  GPIO_Speed_25MHz   GPIO_Medium_Speed 
     #define  GPIO_Speed_50MHz   GPIO_Fast_Speed 
     #define  GPIO_Speed_100MHz  GPIO_High_Speed
    
  • 第四个是 GPIO_OType 配置输出类型:

    typedef enum
     { 
       GPIO_OType_PP = 0x00,
       GPIO_OType_OD = 0x01
     }GPIOOType_TypeDef;
    
  • 第五个是 GPIO_PuPd 配置引脚有无上下拉:

    typedef enum
     { 
       GPIO_PuPd_NOPULL = 0x00,
       GPIO_PuPd_UP     = 0x01,
       GPIO_PuPd_DOWN   = 0x02
     }GPIOPuPd_TypeDef;
    

那么配置 PC9 为推挽输出,速度为 100MHZ,只需要传入对应的参数即可。转换为代码为:

GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // 选择引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; // 推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; // 速度
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; // 推挽输出类型
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; // 不使用上下拉
    GPIO_Init(GPIOC, &GPIO_InitStructure);

3. 主函数中控制 LED 灯

  • 使用标准库提供的函数读写 GPIO 引脚的状态。
    // 配置PC9引脚输出高电平
     GPIO_SetBits(GPIOC, GPIO_Pin_9); 
     ​
     // 配置PC9引脚输出低电平
     GPIO_ResetBits(GPIOC, GPIO_Pin_9);  
     ​
     // 配置PC9引脚输出高电平
     GPIO_WriteBit(GPIOC, GPIO_Pin_9, 1);
     ​
     // 配置PC9引脚输出高电平
     GPIO_WriteBit(GPIOC, GPIO_Pin_9, 0);
    

以下是 main.c 完整代码:

#include "stm32f4xx.h"
 ​
 void delay_ms(u16 time)
 {    
    u16 i=0;  
    while(time--)
    {
       i=12000;  //自己定义
       while(i--) ;    
    }
 }
 ​
 ​
 int main(void)
 {
      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
      GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // 选择引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; // 推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; // 速度
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; // 推挽输出类型
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; // 不使用上下拉
    GPIO_Init(GPIOC, &GPIO_InitStructure);
 ​
     while (1)
     {
         // 配置PC9引脚输出高电平
         GPIO_SetBits(GPIOC, GPIO_Pin_9); 
         delay_ms(200);
         // 配置PC9引脚输出低电平
         GPIO_ResetBits(GPIOC, GPIO_Pin_9);  
         delay_ms(200);
         // 配置PC9引脚输出高电平
         GPIO_WriteBit(GPIOC, GPIO_Pin_9, 1);
         delay_ms(200);
         // 配置PC9引脚输出高电平
         GPIO_WriteBit(GPIOC, GPIO_Pin_9, 0);
         delay_ms(200);
     }
 }

效果如图:
ac2e15f41cc9f38f00d8ee63d94f88d0converted.gif

结语

  在本教程中,我们深入探讨了 STM32F407 单片机的 GPIO 外设,并成功实现了点亮 LED 灯的基本操作。通过详细的步骤和代码示例,我们不仅学习了 GPIO 的基本概念和工作模式,还掌握了如何配置 GPIO 引脚以及如何通过软件控制硬件输出。这些技能是嵌入式系统开发中不可或缺的,它们为我们打开了探索更复杂功能的大门。

  随着对 STM32 单片机编程的进一步学习,我们可以期待实现更多高级功能,如 PWM 控制、I2C 通信、SPI 通信等。这些功能将使我们能够构建更加复杂和强大的嵌入式系统,为各种应用提供支持。掌握 GPIO 的使用不仅是单片机学习的起点,也是成为一名优秀嵌入式系统开发者的基石。

  在未来的学习旅程中,我们将继续探索 STM32 单片机的更多外设和功能,不断扩展我们的知识边界,提升我们的技能水平。让我们携手并进,共同在嵌入式开发的海洋中乘风破浪,创造出更多令人惊叹的作品。

后发布评论

起飞