一、引言

GPIO,作为STM32中最常用最简单的外设,常用来作为按键输入、引脚输出等。其电子原理图我也看不懂,读者有兴趣的话可自行研究。但这不影响使用。

GPIO作为输入/输出各有四种工作模式:

输出:开漏输出,推挽输出,复用开漏输出,复用推挽输出

输入:模拟输入,浮空输入,上拉输入,下拉输入

至于每种工作方式之间的具体区别,我也没有仔细研究过,在后续介绍中会按照我自己的经验介绍各种模式的实际工作场景,以及配置方法。

二、基于标准固件库配置GPIO输出

1. 看原理图

本次测试内容为通过GPIO输出,点亮LED,蜂鸣器发声,我的开发板上有两个LED,一个蜂鸣器,相应引脚为:

LED0-->PF9, LED1-->PF10, BEEP-->PF8

连接方式为:

图中可看出,LED外部通过上拉电阻连接至3.3V电源,因此,若要使灯亮,相应引脚应拉低,使LED两边形成电势差,若要灯灭,相应引脚应拉高,使LED两边没有电势差

图中可看出,通过控制相应引脚,进而控制三极管的导通,使得蜂鸣器发声。NPN三极管基极电压增大,三极管导通,也即是,PF8引脚拉高,蜂鸣器发声,拉低,蜂鸣器不发声。

2. 添加工程文件

本次实验,需要用到GPIO、时钟,选择相应库函数,将其添加至工程中。按照之前所说,库函数放置在FWLIB文件路径中,也需添加进相应的Group中。在建立模板工程时,该路径下所有的库函数均可添加进工程,这样后续开发方便,但是编译慢,且占用内存大。

 添加好标准库后,还需要新建文件用来存储LED\BEEP的配置代码,我们将其放在HARDWARE文件夹中,Keil工程中同样需要添加Group

 我将每个模块的.c/.h文件分别放在了src/inc文件夹中,对于.h文件,需要添加编译路径

3. 编写代码

在LED.c中,代码如下:

#include "LED.h"

/*LED0: GPIO_PF9; LED1:GPIO_PF10*/
static GPIO_InitTypeDef LED_init_str =
{
    GPIO_Pin_9 | GPIO_Pin_10,
    GPIO_Mode_OUT,
    GPIO_Fast_Speed,
    GPIO_OType_PP,//推挽输出
    GPIO_PuPd_UP,
};

void LED_init(void)
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);//开启PortF时钟
    GPIO_Init(GPIOF,&LED_init_str);//初始化PortF

    LED0_OFF();
    LED1_OFF();//初始化后默认LED不亮
}

void LED0_ON(void)
{
    GPIO_ResetBits(GPIOF,GPIO_Pin_9);//开启LED0,将PF9拉低
}
void LED1_ON(void)
{
    GPIO_ResetBits(GPIOF,GPIO_Pin_10);//开启LED1,将PF10拉低
}
void LED0_OFF(void)
{
    GPIO_SetBits(GPIOF,GPIO_Pin_9);//关闭LED0,将PF9拉高
}
void LED1_OFF(void)
{
    GPIO_SetBits(GPIOF,GPIO_Pin_10);//关闭LED1,将PF10拉高
}

LED.h中,代码如下

#ifndef _LED_H_
#define _LED_H_
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"

extern void LED_init(void);
extern void LED0_ON(void);
extern void LED1_ON(void);
extern void LED0_OFF(void);
extern void LED1_OFF(void);

#endif

在Beep.c中,代码如下

#include "Beep.h"
/*BEEP: GPIO_PF8;*/
static GPIO_InitTypeDef BEEP_init_str =
{
    GPIO_Pin_8,
    GPIO_Mode_OUT,
    GPIO_Fast_Speed,
    GPIO_OType_PP,//推挽输出
    GPIO_PuPd_UP,
};
void BEEP_init(void)
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);//开启PORTF时钟

    GPIO_Init(GPIOF,&BEEP_init_str);//初始化相关引脚
}
void BEEP_ON(void)
{
    GPIO_SetBits(GPIOF,GPIO_Pin_8);//蜂鸣器发声,将PF8拉高
}
void BEEP_OFF(void)
{
    GPIO_ResetBits(GPIOF,GPIO_Pin_8);//蜂鸣器关闭,将PF8拉低
}

在Beep.h中,代码如下

#ifndef _BEEP_H_
#define _BEEP_H_
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"

extern void BEEP_init(void);
extern void BEEP_ON(void);
extern void BEEP_OFF(void);
#endif

 而后,便可在main.c中进行相关逻辑编写

#include "LED.h"
#include "Beep.h"

int main(void)
{
    int cnt = 0;
    {
        // Initinal Functions
        LED_init();
        BEEP_init();
    }

    while (1)
    {
        // LED & BEEP Test
        LED0_ON();
        LED1_ON();
        BEEP_ON();

        for(cnt = 0;cnt <=1000000;cnt++)
        {
           //delay, do nothing
        }

        LED0_OFF();
        LED1_OFF();
        BEEP_OFF();

    }
    
}

4. SYSTEM文件夹

 正点原子官方提供了SYSTEM文件夹,包括usart\delay\sys,可以给开发提供很多便利,也可以添加进工程

 

 

其中,usart文件夹为串口相关,后续再介绍,delay文件夹中利用系统滴答定时器(SysTick),实现了一些延时函数,sys文件夹中为位带操作,添加后,main.c文件中的代码便可修改为

#include "LED.h"
#include "Beep.h"
#include "Key.h"
#include "sys.h"
#include "delay.h"

int main(void)
{
    {
        // Initinal Functions
        delay_init(168);
        LED_init();
        BEEP_init();
        KEY_init();
    }

    while (1)
    {
        // LED & BEEP Test
        PF8 = 1;
        PF9 = 0;
        PF10 = 0;

        delay_ms(500);

        PF8 = 0;
        PF9 = 1;
        PF10 = 1;

    }
    
}

合理利用SYSTEM文件夹,会让代码变得更加方便。另外,关于位带操作,即通过宏定义与地址转换关系,直接使用宏定义对寄存器进行操作,而不需要调用库函数;直接将寄存器地址作为宏定义进行操作;具体可自行查阅资料。关于系统嘀嗒定时器,后续会单独写文章介绍。

三、基于CubeMx实现GPIO输出

上篇文章中提到,CubeMx作为图形化代码生成工具,简单明了的便能配置好外设驱动。如何使用CubeMx实现GPIO输出点亮LED呢?

打开上篇文章所建立的CubeMx工程,配置GPIO

而后便可生成代码。

在HAL库中

HAL_GPIO_TogglePin(): 翻转GPIO状态

HAL_Delay(): 使用SYSTICK实现毫秒盲等延时

注意:用户代码必须放在/* USER CODE BEGIN 3 *//* USER CODE END 3 */中间(手写的函数在区域4),否则会将用户原代码覆盖掉,宏定义、全局变量以及#include等预处理命令同理

而后便可编译烧录运行。

四、结语

GPIO是STM32最简单最基础最常用的外设,本文讲述了基于固件库、基于CubeMx软件的HAL对其的输出开发点亮LED,在标准固件库中,介绍了正点原子SYSTEM文件夹,合理运用该文件夹会让代码变得更加简介、便利。

关于GPIO输出、系统滴答定时器的内容回在后续文章中介绍 

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐