2.APM32-GPIO-按键检测

2.APM32-GPIO-按键检测

效果展示

GPIO-按键状态判断之扫描式

硬件原理图

LED模块

LED电路

该电路和流水灯中的一样就不再赘述。

按键模块

按键电路
由该原理图可知,按键按下时按键输出低电平,为了检测按键输出的高低电平所以APM32的GPIO要设置为输入模式,同时为了防止外部干扰,GPIO模式可设置成上拉模式,也可以在电路原理图上加一个上拉电阻,这样当按键没按下时就呈现高电平。

注意该电路有短路的危险,当IO不小心设置为输出模式,输出高电平并且按下按键容易造成短路并且烧毁IO口,为了解决这个问题可以在按键的一端接上限流电阻。

蜂鸣器模块

蜂鸣器电路
该电路使用NPN三极管控制蜂鸣器,当PB13端口输出高电平时三极管导通,蜂鸣器响,输出低电平,三极管截止,蜂鸣器关闭。R13为下拉电阻,使PB13端口默认电压为低电平,LL4148为续流电阻,由于蜂鸣器是电感性元件,所以当三极管处于截止状态时需要二极管LL4148进行续流,否则可能会烧毁器件。

源代码

LED源代码

LED的源代码和流水灯中的一样就不再赘述。

蜂鸣器源代码

#ifndef __BSP_BEEP_H__
#define __BSP_BEEP_H__
/* 包含头文件 ----------------------------------------------------------------*/
#include "apm32f10x_gpio.h"
#include "apm32f10x_rcm.h"


/**
 * @brief BEEP-->PB13
 */

#define BEEP_RCM_CLOCK_GPIO RCM_APB2_PERIPH_GPIOB
#define BEEP_GPIO_PORT GPIOB
#define BEEP_GPIO_PIN GPIO_PIN_13

// 打开蜂鸣器
#define BEEP_ON GPIO_SetBit(BEEP_GPIO_PORT, BEEP_GPIO_PIN)
// 关闭蜂鸣器
#define BEEP_OFF GPIO_ResetBit(BEEP_GPIO_PORT, BEEP_GPIO_PIN)
// 翻转蜂鸣器状态
#define BEEP_TOGGLE                             \
    {                                           \
        BEEP_GPIO_PORT->ODATA ^= BEEP_GPIO_PIN; \
    }
/* 函数声明 ------------------------------------------------------------------*/
void BEEP_GPIO_Config(void);


#endif /* __BSP_BEEP_H__ */

#include "bsp_beep.h"

/**
 * @brief 板载蜂鸣器IO引脚初始化,
 *        如需修改引脚修改bsp_beep.h文件中宏定义即可
 */
void BEEP_GPIO_Config(void)
{
    // 定义IO硬件初始化结构体变量
    GPIO_Config_T GPIO_ConfigStruct;
    // 使能(开启)蜂鸣器引脚对应IO端口时钟
    RCM_EnableAPB2PeriphClock(BEEP_RCM_CLOCK_GPIO);
    // 配置蜂鸣器引脚为推挽输出模式
    GPIO_ConfigStruct.mode = GPIO_MODE_OUT_PP;
    // 配置蜂鸣器引脚
    GPIO_ConfigStruct.pin = BEEP_GPIO_PIN;
    // 配置蜂鸣器引脚速度
    GPIO_ConfigStruct.speed = GPIO_SPEED_2MHz;
    // 配置蜂鸣器引脚
    GPIO_Config(BEEP_GPIO_PORT, &GPIO_ConfigStruct);
    // 设置引脚输出为低电平,此时蜂鸣器不响
    GPIO_ResetBit(BEEP_GPIO_PORT, BEEP_GPIO_PIN);
}

按键源代码

#ifndef __BSP_KEY_H__
#define __BSP_KEY_H__

/* 包含头文件 ----------------------------------------------------------------*/
#include "apm32f10x_rcm.h"
#include "apm32f10x_gpio.h"

/* 宏定义 --------------------------------------------------------------------*/
/**
 * @brief PE7-->KEY4, PE8-->KEY3, PE9-->KEY2, PE10-->KEY1
 */
#define KEY_UP 0
#define KEY_DOWN 1

#define KEY1_GPIO_CLOCK RCM_APB2_PERIPH_GPIOE
#define KEY1_GPIO_PORT GPIOE
#define KEY1_GPIO_PIN GPIO_PIN_10
#define KEY1_DOWN_LEVEL 0 // 这边具体看原理图

#define KEY2_GPIO_CLOCK RCM_APB2_PERIPH_GPIOE
#define KEY2_GPIO_PORT GPIOE
#define KEY2_GPIO_PIN GPIO_PIN_9
#define KEY2_DOWN_LEVEL 0 // 这边具体看原理图

#define KEY3_GPIO_CLOCK RCM_APB2_PERIPH_GPIOE
#define KEY3_GPIO_PORT GPIOE
#define KEY3_GPIO_PIN GPIO_PIN_8
#define KEY3_DOWN_LEVEL 0// 这边具体看原理图

#define KEY4_GPIO_CLOCK RCM_APB2_PERIPH_GPIOE
#define KEY4_GPIO_PORT GPIOE
#define KEY4_GPIO_PIN GPIO_PIN_7
#define KEY4_DOWN_LEVEL 0 // 这边具体看原理图

/* 函数声明 ------------------------------------------------------------------*/
void KEY_GPIO_Config(void);
uint8_t KEY1_StateRead(void);
uint8_t KEY2_StateRead(void);
uint8_t KEY3_StateRead(void);
uint8_t KEY4_StateRead(void);

#endif /* __BSP_KEY_H__ */

/* 包含头文件 ----------------------------------------------------------------*/
#include "bsp_key.h"

/**
 * @brief 板载按键IO引脚初始化
 */
void KEY_GPIO_Config(void)
{
    GPIO_Config_T GPIO_ConfigStruct;

    // 开启KEY1、KEY2、KEY3、KEY4引脚时钟
    RCM_EnableAPB2PeriphClock(KEY1_GPIO_CLOCK);
    RCM_EnableAPB2PeriphClock(KEY2_GPIO_CLOCK);
    RCM_EnableAPB2PeriphClock(KEY3_GPIO_CLOCK);
    RCM_EnableAPB2PeriphClock(KEY4_GPIO_CLOCK);

    // 设定KEY1对应引脚IO为上拉输入模式,这边具体看是否需要上拉或下拉
    GPIO_ConfigStruct.mode = GPIO_MODE_IN_PU;
    // 设定KEY1对应引脚IO编号
    GPIO_ConfigStruct.pin = KEY1_GPIO_PIN;
    // 设定KEY1对应引脚IO操作速度
    GPIO_ConfigStruct.speed = GPIO_SPEED_2MHz;
    GPIO_Config(KEY1_GPIO_PORT, &GPIO_ConfigStruct);

    GPIO_ConfigStruct.pin = KEY2_GPIO_PIN;
    GPIO_Config(KEY2_GPIO_PORT, &GPIO_ConfigStruct);

    GPIO_ConfigStruct.pin = KEY3_GPIO_PIN;
    GPIO_Config(KEY3_GPIO_PORT, &GPIO_ConfigStruct);

    GPIO_ConfigStruct.pin = KEY4_GPIO_PIN;
    GPIO_Config(KEY4_GPIO_PORT, &GPIO_ConfigStruct);
}

/**
 * @brief 按键扫描延时,简单粗暴,不精确
 */
static void KEY_ScanDelay(void)
{
    uint32_t i, j;
    for (i = 0; i < 100; ++i)
        for (j = 0; j < 1000; ++j)
        {
        }
}

/**
 * @brief 读取按键KEY1的状态
 * @return uint8_t
 * @retval KEY_DOWN 按键按下
 *         KEY_UP   按键没按下
 */
uint8_t KEY1_StateRead(void)
{
    // 读取此时按键值并判断是否是被按下状态,如果是被按下状态进入函数内
    if (GPIO_ReadInputBit(KEY1_GPIO_PORT, KEY1_GPIO_PIN) == KEY1_DOWN_LEVEL)
    {
        // 延时一小段时间,消除抖动
        KEY_ScanDelay();
        // 延时时间后再来判断按键状态,如果还是按下状态说明按键确实被按下
        if (GPIO_ReadInputBit(KEY1_GPIO_PORT, KEY1_GPIO_PIN) == KEY1_DOWN_LEVEL)
        {
            // 等待按键弹开才退出按键扫描函数
            while (GPIO_ReadInputBit(KEY1_GPIO_PORT, KEY1_GPIO_PIN) == KEY1_DOWN_LEVEL)
                ;
            // 按键扫描完毕,确定按键被按下,返回按键被按下状态
            return KEY_DOWN;
        }
    }
    return KEY_UP;
}

/**
 * @brief 读取按键KEY2的状态
 * @return uint8_t
 * @retval KEY_DOWN 按键按下
 *         KEY_UP   按键没按下
 */
uint8_t KEY2_StateRead(void)
{
    // 读取此时按键值并判断是否是被按下状态,如果是被按下状态进入函数内
    if (GPIO_ReadInputBit(KEY2_GPIO_PORT, KEY2_GPIO_PIN) == KEY2_DOWN_LEVEL)
    {
        // 延时一小段时间,消除抖动
        KEY_ScanDelay();
        // 延时时间后再来判断按键状态,如果还是按下状态说明按键确实被按下
        if (GPIO_ReadInputBit(KEY2_GPIO_PORT, KEY2_GPIO_PIN) == KEY2_DOWN_LEVEL)
        {
            // 等待按键弹开才退出按键扫描函数
            while (GPIO_ReadInputBit(KEY2_GPIO_PORT, KEY2_GPIO_PIN) == KEY2_DOWN_LEVEL)
                ;
            // 按键扫描完毕,确定按键被按下,返回按键被按下状态
            return KEY_DOWN;
        }
    }
    return KEY_UP;
}

/**
 * @brief 读取按键KEY3的状态
 * @return uint8_t
 * @retval KEY_DOWN 按键按下
 *         KEY_UP   按键没按下
 */
uint8_t KEY3_StateRead(void)
{
    // 读取此时按键值并判断是否是被按下状态,如果是被按下状态进入函数内
    if (GPIO_ReadInputBit(KEY3_GPIO_PORT, KEY3_GPIO_PIN) == KEY3_DOWN_LEVEL)
    {
        // 延时一小段时间,消除抖动
        KEY_ScanDelay();
        // 延时时间后再来判断按键状态,如果还是按下状态说明按键确实被按下
        if (GPIO_ReadInputBit(KEY3_GPIO_PORT, KEY3_GPIO_PIN) == KEY3_DOWN_LEVEL)
        {
            // 等待按键弹开才退出按键扫描函数
            while (GPIO_ReadInputBit(KEY3_GPIO_PORT, KEY3_GPIO_PIN) == KEY3_DOWN_LEVEL)
                ;
            // 按键扫描完毕,确定按键被按下,返回按键被按下状态
            return KEY_DOWN;
        }
    }
    return KEY_UP;
}
/**
 * @brief 读取按键KEY4的状态
 * @return uint8_t
 * @retval KEY_DOWN 按键按下
 *         KEY_UP   按键没按下
 */
uint8_t KEY4_StateRead(void)
{
    // 读取此时按键值并判断是否是被按下状态,如果是被按下状态进入函数内
    if (GPIO_ReadInputBit(KEY4_GPIO_PORT, KEY4_GPIO_PIN) == KEY4_DOWN_LEVEL)
    {
        // 延时一小段时间,消除抖动
        KEY_ScanDelay();
        // 延时时间后再来判断按键状态,如果还是按下状态说明按键确实被按下
        if (GPIO_ReadInputBit(KEY4_GPIO_PORT, KEY4_GPIO_PIN) == KEY4_DOWN_LEVEL)
        {
            // 等待按键弹开才退出按键扫描函数
            while (GPIO_ReadInputBit(KEY4_GPIO_PORT, KEY4_GPIO_PIN) == KEY4_DOWN_LEVEL)
                ;
            // 按键扫描完毕,确定按键被按下,返回按键被按下状态
            return KEY_DOWN;
        }
    }
    return KEY_UP;
}

主程序

/**
 * @file main.c
 * @brief PE7-->KEY4, PE8-->KEY3, PE9-->KEY2, PE10-->KEY1
 */

/* 包含头文件 ----------------------------------------------------------------*/
#include "bsp_led.h"
#include "bsp_beep.h"
#include "bsp_key.h"
/* 私有类型定义 --------------------------------------------------------------*/
/* 私有宏定义 ----------------------------------------------------------------*/
/* 私有变量 ------------------------------------------------------------------*/
/* 扩展变量 ------------------------------------------------------------------*/
/* 私有函数原形 --------------------------------------------------------------*/
static void Delay(uint32_t time);

/**
 * @brief 主函数
 * @return 无
 */
int main(void)
{
    // 初始化板载LED灯
    LED_GPIO_Config();
    // 初始化板载蜂鸣器
    BEEP_GPIO_Config();
    // 初始化板载按键
    KEY_GPIO_Config();

    while (1)
    {
        if (KEY1_StateRead() == KEY_DOWN) // KEY1按下,蜂鸣器响,LED1翻转
        {
            BEEP_ON;
            LED1_TOGGLE;
        }
        if (KEY2_StateRead() == KEY_DOWN) // KEY2按下,蜂鸣器关闭,LED2翻转
        {
            BEEP_OFF;
            LED2_TOGGLE;
        }
        if (KEY3_StateRead() == KEY_DOWN) // KEY3按下,蜂鸣器响,LED3翻转
        {
            BEEP_ON;
            LED3_TOGGLE;
        }
        if (KEY4_StateRead() == KEY_DOWN) // KEY4按下,蜂鸣器关闭,LED1-3关闭
        {
            BEEP_OFF;
            LED1_OFF;
            LED2_OFF;
            LED3_OFF;
        }
        Delay(100);
    }
}

/**
 * @brief 简单粗暴的延时函数,不精确
 * @param time 延时时间设置
 */
static void Delay(uint32_t time)
{
    uint32_t i, j;

    for (i = 0; i < time; ++i)
    {
        for (j = 0; j < 10000; ++j)
        {
            // 空循环,什么都不做
        }
    }
}

代码分析

bsp_beep.h

#define BEEP_RCM_CLOCK_GPIO RCM_APB2_PERIPH_GPIOB

#define BEEP_GPIO_PORT GPIOB

#define BEEP_GPIO_PIN GPIO_PIN_13

这段代码是宏定义和流水灯中的一样都是为了方便程序的移植、维护和使用。

// 打开蜂鸣器
#define BEEP_ON GPIO_SetBit(BEEP_GPIO_PORT, BEEP_GPIO_PIN)
// 关闭蜂鸣器
#define BEEP_OFF GPIO_ResetBit(BEEP_GPIO_PORT, BEEP_GPIO_PIN)
// 翻转蜂鸣器状态
#define BEEP_TOGGLE                             \
    {                                           \
        BEEP_GPIO_PORT->ODATA ^= BEEP_GPIO_PIN; \
    }

这段代码也和流水灯中控制LED的代码差不多,无非就是换了名字和GPIO,具体也不再赘述。

bsp_beep.c

/**
 * @brief 板载蜂鸣器IO引脚初始化,
 *        如需修改引脚修改bsp_beep.h文件中宏定义即可
 */
void BEEP_GPIO_Config(void)
{
    // 定义IO硬件初始化结构体变量
    GPIO_Config_T GPIO_ConfigStruct;
    // 使能(开启)蜂鸣器引脚对应IO端口时钟
    RCM_EnableAPB2PeriphClock(BEEP_RCM_CLOCK_GPIO);
    // 配置蜂鸣器引脚为推挽输出模式
    GPIO_ConfigStruct.mode = GPIO_MODE_OUT_PP;
    // 配置蜂鸣器引脚
    GPIO_ConfigStruct.pin = BEEP_GPIO_PIN;
    // 配置蜂鸣器引脚速度
    GPIO_ConfigStruct.speed = GPIO_SPEED_2MHz;
    // 配置蜂鸣器引脚
    GPIO_Config(BEEP_GPIO_PORT, &GPIO_ConfigStruct);
    // 设置引脚输出为低电平,此时蜂鸣器不响
    GPIO_ResetBit(BEEP_GPIO_PORT, BEEP_GPIO_PIN);
}

蜂鸣器引脚初始化和流水灯中初始化LED一样,先是声明一个GPIO的结构体,打开GPIO对应的时钟,配置结构体,将结构体填入初始化函数中。

bsp_key.h

#define KEY_UP 0
#define KEY_DOWN 1

#define KEY1_GPIO_CLOCK RCM_APB2_PERIPH_GPIOE
#define KEY1_GPIO_PORT GPIOE
#define KEY1_GPIO_PIN GPIO_PIN_10
#define KEY1_DOWN_LEVEL 0 // 这边具体看原理图

KEY_UPKEY_DOWN两定义分别表示按键松开和按键按下。

#define KEY1_DOWN_LEVEL 0该定义表示按键按下,按键输出什么电平,若按键按下输出低电平这边就定义为0,输出高电平就定义为1,提高程序的移植性。

剩下的宏定义就和流水灯中类似,不在赘述。

bsp_key.c

/**
 * @brief 板载按键IO引脚初始化
 */
void KEY_GPIO_Config(void)
{
    GPIO_Config_T GPIO_ConfigStruct;

    // 开启KEY1、KEY2、KEY3、KEY4引脚时钟
    RCM_EnableAPB2PeriphClock(KEY1_GPIO_CLOCK);
    RCM_EnableAPB2PeriphClock(KEY2_GPIO_CLOCK);
    RCM_EnableAPB2PeriphClock(KEY3_GPIO_CLOCK);
    RCM_EnableAPB2PeriphClock(KEY4_GPIO_CLOCK);

    // 设定KEY1对应引脚IO为上拉输入模式,这边具体看是否需要上拉或下拉
    GPIO_ConfigStruct.mode = GPIO_MODE_IN_PU;
    // 设定KEY1对应引脚IO编号
    GPIO_ConfigStruct.pin = KEY1_GPIO_PIN;
    // 设定KEY1对应引脚IO操作速度
    GPIO_ConfigStruct.speed = GPIO_SPEED_2MHz;
    GPIO_Config(KEY1_GPIO_PORT, &GPIO_ConfigStruct);

    GPIO_ConfigStruct.pin = KEY2_GPIO_PIN;
    GPIO_Config(KEY2_GPIO_PORT, &GPIO_ConfigStruct);

    GPIO_ConfigStruct.pin = KEY3_GPIO_PIN;
    GPIO_Config(KEY3_GPIO_PORT, &GPIO_ConfigStruct);

    GPIO_ConfigStruct.pin = KEY4_GPIO_PIN;
    GPIO_Config(KEY4_GPIO_PORT, &GPIO_ConfigStruct);
}

上述代码是初始化按键相关GPIO的,和流水灯中初始化LED相关GPIO只有GPIO_ConfigStruct.mode = GPIO_MODE_IN_PU;不同,其他都是一样的。

GPIO_ConfigStruct.mode = GPIO_MODE_IN_PU;表示设置GPIO为输入上拉模式。

在介绍其他函数之前,我们先来看下APM32标准库中读取电平的函数

GPIO_ReadInputBit()

我们先来看下该函数的源码。

/*!
 * @brief     Reads the specified input port pin
 *
 * @param     port: Select the GPIO port.
 *                  This parameter can be one of GPIOx( x can be from A to G).
 *
 * @param     pin : specifies pin to read.
 *                  This parameter can be one of GPIO_PIN_x( x can be from 0 to 15).
 *
 * @retval    The input port pin value
 */
uint8_t GPIO_ReadInputBit(GPIO_T* port, uint16_t pin)
{
    uint8_t ret;

    ret = (port->IDATA & pin) ?  BIT_SET : BIT_RESET;

    return ret;
}

从函数的注释可以知道

  • 这个函数功能是读取指定引脚输入的电平。

  • port可选GPIOA到GPIOG

  • pin可选GPIO_PIN_0到GPIO_PIN_15

ret = (port->IDATA & pin) ? BIT_SET : BIT_RESET;这个是C语言的三目运算符写法,是if else的一种简写,如果(port->IDATA & pin)为真,则ret=BIT_SET否则为BIT_RESET

我们在来看下APM32参考手册,第116页

GPIOx_IDATA寄存器

该寄存器的低16位用来储存GPIOx的输入数据,第y位对应GPIO_PIN_y。IDATA & pin这样的与运算就是读取GPIO_PIN_y的电压,0表示输入信号位低,1表示输入信号为高。

GPIO_ReadInputPort()

GPIO_ReadInputBit()是读取单个引脚的输入信号的,如果想读取GPIOx端口16个引脚的电压就要用GPIO_ReadInputPort(),我们来看下该函数的原代码。

/*!
 * @brief     Reads the specified GPIO input data port
 *
 * @param     port: Select the GPIO port.
 *                  This parameter can be one of GPIOx( x can be from A to G).
 *
 * @retval    GPIO input data port value
 */
uint16_t GPIO_ReadInputPort(GPIO_T* port)
{
    return ((uint16_t)port->IDATA);
}

这个函数的代码和GPIO_ReadInputBit()很像,就是少了与运算,直接将IDATA寄存器的值返回出去了。

看完上面两个函数我们继续看按键检测的代码,代码如下

/**
 * @brief 读取按键KEY1的状态
 * @return uint8_t
 * @retval KEY_DOWN 按键按下
 *         KEY_UP   按键没按下
 */
uint8_t KEY1_StateRead(void)
{
    // 读取此时按键值并判断是否是被按下状态,如果是被按下状态进入函数内
    if (GPIO_ReadInputBit(KEY1_GPIO_PORT, KEY1_GPIO_PIN) == KEY1_DOWN_LEVEL)
    {
        // 延时一小段时间,消除抖动
        KEY_ScanDelay();
        // 延时时间后再来判断按键状态,如果还是按下状态说明按键确实被按下
        if (GPIO_ReadInputBit(KEY1_GPIO_PORT, KEY1_GPIO_PIN) == KEY1_DOWN_LEVEL)
        {
            // 等待按键弹开才退出按键扫描函数
            while (GPIO_ReadInputBit(KEY1_GPIO_PORT, KEY1_GPIO_PIN) == KEY1_DOWN_LEVEL)
                ;
            // 按键扫描完毕,确定按键被按下,返回按键被按下状态
            return KEY_DOWN;
        }
    }
    return KEY_UP;
}

可以看到,在代码中我们先读取按键的状态,延时了一会又去读按键的状态,这是为什么?因为由于按键的物理特性,按键按下的一瞬间不可能就变成按下状态,在这个过程中按键会抖动,如下图

按键按下过程

等待按键到稳定状态我们再去读取它的电平,根据读取到的电平返回按键的状态是按下还是没按下。

其他几个按键的检测如法炮制即可。

注意这种按键检测的方式是阻塞的,很浪费MCU的资源,也有非阻塞的检测方式,后续再说。

main.c

/**
 * @file main.c
 * @brief PE7-->KEY4, PE8-->KEY3, PE9-->KEY2, PE10-->KEY1
 */

/* 包含头文件 ----------------------------------------------------------------*/
#include "bsp_led.h"
#include "bsp_beep.h"
#include "bsp_key.h"
/* 私有类型定义 --------------------------------------------------------------*/
/* 私有宏定义 ----------------------------------------------------------------*/
/* 私有变量 ------------------------------------------------------------------*/
/* 扩展变量 ------------------------------------------------------------------*/
/* 私有函数原形 --------------------------------------------------------------*/
static void Delay(uint32_t time);

/**
 * @brief 主函数
 * @return 无
 */
int main(void)
{
    // 初始化板载LED灯
    LED_GPIO_Config();
    // 初始化板载蜂鸣器
    BEEP_GPIO_Config();
    // 初始化板载按键
    KEY_GPIO_Config();

    while (1)
    {
        if (KEY1_StateRead() == KEY_DOWN) // KEY1按下,蜂鸣器响,LED1翻转
        {
            BEEP_ON;
            LED1_TOGGLE;
        }
        if (KEY2_StateRead() == KEY_DOWN) // KEY2按下,蜂鸣器关闭,LED2翻转
        {
            BEEP_OFF;
            LED2_TOGGLE;
        }
        if (KEY3_StateRead() == KEY_DOWN) // KEY3按下,蜂鸣器响,LED3翻转
        {
            BEEP_ON;
            LED3_TOGGLE;
        }
        if (KEY4_StateRead() == KEY_DOWN) // KEY4按下,蜂鸣器关闭,LED1-3关闭
        {
            BEEP_OFF;
            LED1_OFF;
            LED2_OFF;
            LED3_OFF;
        }
        Delay(100);
    }
}

/**
 * @brief 简单粗暴的延时函数,不精确
 * @param time 延时时间设置
 */
static void Delay(uint32_t time)
{
    uint32_t i, j;

    for (i = 0; i < time; ++i)
    {
        for (j = 0; j < 10000; ++j)
        {
            // 空循环,什么都不做
        }
    }
}

这段段代码很简单,先是初始化LED、BEEP、KEY,然后根据不同的按键按下做相应的事。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值