STM32 IO输入实验

实验内容

  • 使用Keil 5编写程序,要求在LED模块上按下相应按键后,按键对应的LED状态翻转。总共有四个按键:S1、S2、S3和S4,分别对应LED1、LED2、LED3和LED4。

实验目的

  • 了解按键的工作原理
  • 掌握STM32上的IO口作为输入端口的配置方法
  • 加深对编程思想理解

实验环境

实验所需硬件

序号 名称 数量 备注
1 电脑 1台 系统Windows7及以上
2 STM32底座模块 1个 ·
3 LED模块 1个 ·
4 ST-Link下载器 1个 ·
5 ST-Link下载器连接线 1根 ·
6 配套按键实验代码 1份 ·

实验所需软件

  • MDK5 安装步骤

  • ST-LINK 驱动安装步骤

  • Git 软件下载(可选)

ST-Link下载器 & ST-Link下载器连接线

STLink下载器

STM32底座:HIVE PRO STM32是一种基于STM32F103C8T6芯片的蜂巢底座。

STM32底座

LED模块:LED模块共有四个按键,4个LED灯,可供完成流水灯、按键处理等相关实验。按键的触发为低电平,LED灯低电平点亮。

LED模块

实验要求

  • 掌握STM32中通用IO作为输入口的配置方法。
  • 掌握按键编程的方法,能够编程读取按键的状态,并根据按键动作编程实现相关模块的控制。

实验原理

STM32的IO口作为输出在上一节IO口输出实验已经有了比较详细的介绍。这一节介绍STM32的IO口作为输入使用。本节是通过调用函数HAL_GPIO_ReadPin()来读取IO口的输入状态。了解了这点,就可以开始硬件设计和软件设计。

硬件设计

实验用到的硬件模块及原理图如下面图所示。本实验用到的是S1、S2、S3、S4按键,以及LED1、LED2、LED3、LED4。通过按键及LED的组合我们实现以下功能:按下S1灯LED1亮,再次按下熄灭;按下S2灯LED2亮,再次按下熄灭;按下S3灯LED3亮,再次按下熄灭;按下S4灯LED4亮,再次按下熄灭。

LED功能模块

电路连接原理图

实验步骤

0

① LED模块安装于STM32底座上。ST-Link连接底座与计算机,如下图:
安装模块

② 访问github,进入github界面后点击Code,Clone HTTPS安全链接,如下图所示:
操作步骤

③ 打开电脑终端,进入工作目录workspace (workspace 为工程文件夹所在目录):

cd workspace

④ 运行clone命令:

git clone https://github.com/aiotcom/eps.git

下载目录至指定文件夹下。
如果提示“command not found”表示电脑没有安装Git,请至Git官网下载。
如果电脑没有安装 Git 软件,也可以进入Github,点击 Code -> DownLoad ZIP 下载所有工程代码。如下图所示:
下载代码
如果电脑没有公网,可以进入D:\实验教程与代码 选择相应的代码。

⑤ 打开 Keil 5 工程软件,点击工具栏: ` Project -> Open Project,选择工程文件:STM32基础实验\2.IO输入实验\USER\KEY.uvprojx` 并打开。

打开工程
选择文件
如果没有安装该软件,请至Keil官网下载。

⑥ 工程启动后,点击 Rebuild 重新编译。如下图:

重新编译工程

⑦ 编译成功,如下图:

编译成功

⑧ 点击 Download 按钮下载程序,如下图所示:

下载程序

下载成功

⑨ 下载完成后,将USB线进行重连操作(即:将STLink的USB线从底座上取下,再重新接上)。

⑩ 观察操作实验:
按下按键S1,LED1被点亮,再次按下按键S1,LED1熄灭;
按下按键S2,LED2被点亮,再次按下按键S2,LED2熄灭;
按下按键S3,LED3被点亮,再次按下按键S3,LED3熄灭;
按下按键S4,LED4被点亮,再次按下按键S4,LED4熄灭。

代码讲解

① 程序目录结构,如下图。CORE文件夹为STM32内核代码,HALLIB文件文件夹为底层HAL库文件,我们主要关心,main.cHARDWARE中的代码。

程序目录结构

② main.c中进行硬件的初始化及整个代码的逻辑控制。

int main(void)
{
    static uint8_t key = 0;  
    HAL_Init();//初始化HAL库,为随后用到的HAL_Delay()函数提供时钟。
    LED_Init();//初始化LED灯控制的IO口	
    KEY_Init();//初始化按键输入的IO口

    while(1)
    {
        key = KEY_Scan();//获取按键      
        switch(key)
        {
            case S1_PRES:
                HAL_GPIO_TogglePin(LED_PORT,LED1_PIN);//S1 按下,翻转LED1灯状态
                break;
            case S2_PRES:
                HAL_GPIO_TogglePin(LED_PORT,LED2_PIN);//S2 按下,翻转LED2灯状态
                break;
            case S3_PRES:
                HAL_GPIO_TogglePin(LED_PORT,LED3_PIN);//S3 按下,翻转LED3灯状态
                break;
            case S4_PRES:
                HAL_GPIO_TogglePin(LED_PORT,LED4_PIN);//S4 按下,翻转LED4灯状态
                break;
            default:break;
        }
    }
}

③ LED.c为LED驱动代码,代码实现对LED灯控制的IO进行初始化设置IO口为推挽上拉模式,重点不要忘记使用能IO接口的时钟及设置输出的速度。

    void LED_Init(void)
    {
        GPIO_InitTypeDef GPIO_Initure;
        
        LED_IO_RCC();

        GPIO_Initure.Pin   = LED1_PIN|LED2_PIN|LED3_PIN|LED4_PIN;
        GPIO_Initure.Mode  = GPIO_MODE_OUTPUT_PP;//推挽输出
        GPIO_Initure.Pull  = GPIO_PULLUP;//上拉
        GPIO_Initure.Speed = GPIO_SPEED_HIGH;//高速
        HAL_GPIO_Init(LED_PORT,&GPIO_Initure);
            
        LED_OFF();//初始化完成全部LED灯灭
    }

④ key.c为LED模块上的按键驱动,Key_Init()中代码中设置IO口为上拉输入。

void KEY_Init(void)
{
    GPIO_InitTypeDef GPIO_Initure;

    KEY_IO_RCC();//使用IO端口时钟
    
    GPIO_Initure.Pin   = S1_PIN|S2_PIN;
    GPIO_Initure.Mode  = GPIO_MODE_INPUT;//输入
    GPIO_Initure.Pull  = GPIO_PULLUP;//上拉
    GPIO_Initure.Speed = GPIO_SPEED_LOW;//低速
    HAL_GPIO_Init(GPIOA,&GPIO_Initure);
        
    GPIO_Initure.Pin   = S3_PIN|S4_PIN;
    GPIO_Initure.Mode  = GPIO_MODE_INPUT;//输入
    GPIO_Initure.Pull  = GPIO_PULLUP;//上拉
    GPIO_Initure.Speed = GPIO_SPEED_LOW;//低速
    HAL_GPIO_Init(GPIOB,&GPIO_Initure);
}

⑤ 按键扫描代码。

    uint8_t KEY_Scan(void)
    {
        static uint8_t key_up=1;//按键松开标志
        
        /*在按键松开的情况,有按键按下*/
        if(key_up&&(S1_Read()==0||S2_Read()==0||S3_Read()==0||S4_Read()==0)){
            HAL_Delay(10);//如果有按键按下延时10个毫秒消抖。
            key_up=0;//按键己按下
            if(S1_Read()==0){
                return S1_PRES;//返回 S1 按下
            }
            else if(S2_Read()==0){
                return S2_PRES;//返回 S2 按下
            }
            else if(S3_Read()==0){
                return S3_PRES;//返回 S3 按下
            }          
            else if(S4_Read()==0){
                return S4_PRES;//返回 S4 按下
            }
        }
        else if(S1_Read()==1&&S2_Read()==1&&S3_Read()==1&&S4_Read()==1){
            /*按键全部松开了*/
            key_up=1;
            }    
        return 0;//无按键按下
    }

常见问题

  1. 弹出警告窗口,不能下载程序。

    • 请确认STLink驱动、STM32F103C8的DFP包是否安装。
    • STLink仿真器是否正常接入。
  2. 下载代码后程序没观察到实验现象。

    • 请重新上电,或者按下底座上的复位按键。
    • 模块没有安装稳妥。
  3. 按键按下后无反应。

    • 手指的发力点要在按键表面上。

实验思考

  1. 实现按键S1按下后,LED1亮1秒后熄灭。

  2. 实现按键S1按下后,LED1常亮,按键S2按键下LED1熄灭。