stm32F103C8T6标准库按键点灯——输入模式
KEY_Scan函数第三个参数传递的是我按键按下后当前IO口的状态,比如说这个按键一端是连接的是PA0的IO口,另外一端接到VCC,然后PA0有下拉电阻,就是当我给单片机供电的时候,PA0的默认初始状态是低电平,当我此时按键按下,此时VCC之间通过开关流入到IO口,此时的IO口状态是高电平。所以在ON函数与OFF函数里面,当传递的第三个参数同为低电平逻辑或者高电平逻辑,ON里面的if执行的逻辑与O
目录
1.按键抖动
按键机械触点断开、闭合时,由于触点的弹性作用,按键开关不会马上稳定接通或一下子断开,使用按键时会产生图按键抖动说明图中的带波纹信号,需要用软件消抖处理滤波,不方便输入检测。可以利用电容充放电的延时,消除了波纹,从而简化软件的处理,软件只需要直接检测引脚的电平即可。
2.开发板按键原理图

板载上面的按键设计:
第一个按键电路中,当开关没有按下,此时PA0经过1k电阻,又经过4.7k电阻连接到地,4.7k电阻称之为下拉电阻。也就是PA0端口默认电平状态是低电平。
第三个按键电路中,当按键没有按下,4.7k电阻接的是3.3v,此时给IO口提供一个高电平,这个4.7k电阻称之为上拉电阻。也就是PC13端口默认电平状态是低电平。
2.1 输入模式简单理解
stm32内部可以设置4中输入模式
─ 输入浮空 :
─ 输入上拉
─ 输入下拉
上面这三种时候,只能是高电平低电平,比如说大于2.7V的时候就高电平,小于1.7V就是低电平。
─ 模拟输入 :可以具体输入一个电压值,比如说可以输入一个3.1V,3.2V,3.3V等等一个具体的值

当我们使用输入模式的时候,只有使用框框部分的,框框外面部分的一个开关是处于断开状态。
3. readme.txt
/***************************************************************************************************************/
【】程序介绍
-工程名称 :点亮LED灯之标准库写法版
-实验平台 :野火 STM32FC8T6-STM开发板
【 !】功能介绍:
控制GPIO引脚输出高低电平控制LED灯的亮灭,实现点灯的效果
【 !】实验操作:
1.编译并下载程序到开发板即可观察现象;
2.可以观察红、绿、蓝灯依次点亮然后再一起闪灭。
/****************************************************************************************************************/
【*】引脚分配
【*】 引脚分配
KEY1->PA0 按键按下为高电平 核心板板载默认下拉且硬件有消抖
KEY2->PC13 按键按下为高电平 核心板板载默认下拉且硬件有消抖
NRST->NRST 按键按下为低电平 核心板板载默认上拉且硬件有消抖
KEY3->PB15 按键按下为高电平 用户自定义按键需配置软件消抖且需要软件配置下拉
KEY4->PB6 按键按下为低电平 用户自定义按键需配置软件消抖且需要软件配置上拉
KEY5->PB7 按键按下为低电平 用户自定义按键需配置软件消抖且需要软件配置上拉
KEY6->PB8 按键按下为低电平 用户自定义按键需配置软件消抖且需要软件配置上拉
LED_R->LED1->PA1 核心板板载LED灯低电平亮
LED_G->LED2->PA2 核心板板载LED灯低电平亮
LED_B->LED3->PA3 核心板板载LED灯低电平亮
LED4->PB5 用户自定义LED灯低电平亮
LED5->PB13 用户自定义LED灯高电平亮
LED6->PB14 用户自定义LED灯高电平亮
/****************************************************************************************************************/
【*】程序描述:
<main.c>
1.初始化LED和KEY对应的GPIO,初始化LED和KEY端口
2.控制LED的亮灭
/****************************************************************************************************************/
4.配置key文件
1.在user创建key文件夹
2.在key里面分别创建一个.c文件和.h文件
其实在led文件夹里面将.c文件和.h文件复制到key文件来,将源文件和头文件名字更改一下。
3.将key.c源文件导入进来
key.c
/**
******************************************************************************
* @file bsp_gpio_key.c
* @author 作者
* @version v1.0
* @date 2026.4.3
* @brief 扫描按键函数接口
******************************************************************************
* @attention
*
* 版权声明
*
******************************************************************************
*/
#include "key/bsp_gpio_key.h"
/**
* @brief 初始化控制 KEY 的IO
* @param 无
* @retval 无
*/
void KEY_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct = { 0 };
/*****************************核心板载按键****************************************/
#if 1
RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK_PORT, ENABLE); //开启GPIOA 端口时钟
GPIO_SetBits(KEY1_GPIO_PORT, KEY1_GPIO_PIN); //设置PA1端口初始化1 让LED灭
// 配置引脚:选择GPIOA的Pin1
GPIO_InitStruct.GPIO_Pin = KEY1_GPIO_PIN;
// 配置输出速度:50MHz
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
// 配置工作模式:浮空输入模式
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStruct);
#endif
}
/***************************************END OF FILE *********************************************************/
工作模式定义的是浮空输入模式,因为板载按键有下拉电阻,默认的IO电平是低电平,所以不需要STM32内部设置的输入模式上拉和下拉去设置IO口默认电平状态,所以选择浮空输入模式。
key.h
#ifndef __BSP_GPIO_KEY_H
#define __BSP_GPIO_KEY_H
#include "stm32f10x.h"
/*定义连接GPIO端口,用户只需要修改下面代码即可改变控制的LED引脚 */
//KEY1
#define KEY1_GPIO_PORT GPIOA /* GPIO 端口 */
#define KEY1_GPIO_CLK_PORT RCC_APB2Periph_GPIOA /* GPIO 端口时钟 */
#define KEY1_GPIO_PIN GPIO_Pin_0 /* 对应PIN脚 */
void KEY_GPIO_Config(void);
#endif /*__bsp_gpio_led_H*/
在readme文件中看到,按键1是PA0控制,所以GPIO定义GPIOA,引脚定义GPIO_Pin_0
时钟端口是GPIOA。
5.LED文件
bsp_gpio_led.c
/**
******************************************************************************
* @file bsp_gpio_led.c
* @author 作者
* @version v1.0
* @date 2026.4.3
* @brief LED灯的函数接口
******************************************************************************
* @attention
*
* 版权声明
*
******************************************************************************
*/
#include "led/bsp_gpio_led.h"
/**
* @brief 初始化控制 LED 的IO
* @param 无
* @retval 无
*/
void LED_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct = { 0 };
#if 1
RCC_APB2PeriphClockCmd(R_LED1_GPIO_CLK_PORT, ENABLE); //开启GPIOA 端口时钟
GPIO_SetBits(R_LED1_GPIO_PORT, R_LED1_GPIO_PIN); //设置PA1端口初始化1 让LED灭
// 配置引脚:选择GPIOA的Pin1
GPIO_InitStruct.GPIO_Pin = R_LED1_GPIO_PIN;
// 配置输出速度:50MHz
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
// 配置工作模式:推挽输出
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(R_LED1_GPIO_PORT, &GPIO_InitStruct);
#endif
#if 1
RCC_APB2PeriphClockCmd(G_LED2_GPIO_CLK_PORT, ENABLE); //开启GPIOA 端口时钟
GPIO_SetBits(G_LED2_GPIO_PORT, G_LED2_GPIO_PIN); //设置PA2端口初始化1 让LED灭
// 配置引脚:选择GPIOA的Pin1
GPIO_InitStruct.GPIO_Pin = G_LED2_GPIO_PIN;
// 配置输出速度:50MHz
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
// 配置工作模式:推挽输出
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(G_LED2_GPIO_PORT, &GPIO_InitStruct);
#endif
#if 1
RCC_APB2PeriphClockCmd(B_LED3_GPIO_CLK_PORT, ENABLE); //开启GPIOA 端口时钟
GPIO_SetBits(B_LED3_GPIO_PORT, B_LED3_GPIO_PIN); //设置PA3端口初始化1 让LED灭
// 配置引脚:选择GPIOA的Pin1
GPIO_InitStruct.GPIO_Pin = B_LED3_GPIO_PIN;
// 配置输出速度:50MHz
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
// 配置工作模式:推挽输出
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(B_LED3_GPIO_PORT, &GPIO_InitStruct);
#endif
}
/**
* @brief 开启对应 LED 灯
* @param GPIOX : x可以是 A,B,C等
* @param GPIO_PIN: 待操作的PIN
* @param led_brightstatus LED灯亮时的状态
* @retval 无
*/
void LED_GPIO_ON(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, LED_TriggerLever led_brightstatus)
{
if (led_brightstatus == LED_LOW_TRIGGER)
{
GPIO_ResetBits(GPIOx, GPIO_Pin);
}
else
{
GPIO_SetBits(GPIOx, GPIO_Pin);
}
}
/**
* @brief 关闭对应 LED 灯
* @param GPIOX : x可以是 A,B,C等
* @param GPIO_PIN: 待操作的PIN
* @param led_brightstatus LED灯亮时的状态
* @retval 无
*/
void LED_GPIO_OFF(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, LED_TriggerLever led_brightstatus)
{
if (led_brightstatus == LED_LOW_TRIGGER)
{
GPIO_SetBits(GPIOx, GPIO_Pin);
}
else
{
GPIO_ResetBits(GPIOx, GPIO_Pin);
}
}
/***************************************END OF FILE *********************************************************/
bsp_gpio_led.h
#ifndef __bsp_gpio_led_H
#define __bsp_gpio_led_H
#include "stm32f10x.h"
/*定义连接GPIO端口,用户只需要修改下面代码即可改变控制的LED引脚 */
//LED1
#define LED1_GPIO_PORT GPIOA /* GPIO 端口 */
#define LED1_GPIO_CLK_PORT RCC_APB2Periph_GPIOA /* GPIO 端口时钟 */
#define LED1_GPIO_PIN GPIO_Pin_1 /* 对应PIN脚 */
//LED2
#define LED2_GPIO_PORT GPIOA /* GPIO 端口 */
#define LED2_GPIO_CLK_PORT RCC_APB2Periph_GPIOA /* GPIO 端口时钟 */
#define LED2_GPIO_PIN GPIO_Pin_2 /* 对应PIN脚 */
//LED3
#define LED3_GPIO_PORT GPIOA /* GPIO 端口 */
#define LED3_GPIO_CLK_PORT RCC_APB2Periph_GPIOA /* GPIO 端口时钟 */
#define LED3_GPIO_PIN GPIO_Pin_3 /* 对应PIN脚 */
/***************核心板载LED灯****************************************/
//R_LED
#define R_LED1_GPIO_PORT LED1_GPIO_PORT /* GPIO 端口 */
#define R_LED1_GPIO_CLK_PORT LED1_GPIO_CLK_PORT /* GPIO 端口时钟 */
#define R_LED1_GPIO_PIN LED1_GPIO_PIN /* 对应PIN脚 */
//G_LED
#define G_LED2_GPIO_PORT LED2_GPIO_PORT /* GPIO 端口 */
#define G_LED2_GPIO_CLK_PORT LED2_GPIO_CLK_PORT /* GPIO 端口时钟 */
#define G_LED2_GPIO_PIN LED2_GPIO_PIN /* 对应PIN脚 */
//B_LED
#define B_LED3_GPIO_PORT LED3_GPIO_PORT /* GPIO 端口 */
#define B_LED3_GPIO_CLK_PORT LED3_GPIO_CLK_PORT /* GPIO 端口时钟 */
#define B_LED3_GPIO_PIN LED3_GPIO_PIN /* 对应PIN脚 */
/***************用户自定义宏****************************************/
//R_LED
#define R_LED_ON_ONLY LED_GPIO_ON(R_LED1_GPIO_PORT, R_LED1_GPIO_PIN, LED_LOW_TRIGGER); \
LED_GPIO_OFF(G_LED2_GPIO_PORT, G_LED2_GPIO_PIN, LED_LOW_TRIGGER); \
LED_GPIO_OFF(B_LED3_GPIO_PORT, B_LED3_GPIO_PIN, LED_LOW_TRIGGER);
//G_LED
#define G_LED_ON_ONLY LED_GPIO_OFF(R_LED1_GPIO_PORT, R_LED1_GPIO_PIN, LED_LOW_TRIGGER); \
LED_GPIO_ON(G_LED2_GPIO_PORT, G_LED2_GPIO_PIN, LED_LOW_TRIGGER); \
LED_GPIO_OFF(B_LED3_GPIO_PORT, B_LED3_GPIO_PIN, LED_LOW_TRIGGER);
//B_LED
#define B_LED_ON_ONLY LED_GPIO_OFF(R_LED1_GPIO_PORT, R_LED1_GPIO_PIN, LED_LOW_TRIGGER); \
LED_GPIO_OFF(G_LED2_GPIO_PORT, G_LED2_GPIO_PIN, LED_LOW_TRIGGER); \
LED_GPIO_ON(B_LED3_GPIO_PORT, B_LED3_GPIO_PIN, LED_LOW_TRIGGER);
//B_G_B_LED全亮
#define RGB_LED_ALL_ON LED_GPIO_ON(R_LED1_GPIO_PORT, R_LED1_GPIO_PIN, LED_LOW_TRIGGER); \
LED_GPIO_ON(G_LED2_GPIO_PORT, G_LED2_GPIO_PIN, LED_LOW_TRIGGER); \
LED_GPIO_ON(B_LED3_GPIO_PORT, B_LED3_GPIO_PIN, LED_LOW_TRIGGER);
//B_G_B_LED全灭
#define RGB_LED_ALL_OFF LED_GPIO_OFF(R_LED1_GPIO_PORT, R_LED1_GPIO_PIN, LED_LOW_TRIGGER); \
LED_GPIO_OFF(G_LED2_GPIO_PORT, G_LED2_GPIO_PIN, LED_LOW_TRIGGER); \
LED_GPIO_OFF(B_LED3_GPIO_PORT, B_LED3_GPIO_PIN, LED_LOW_TRIGGER);
/* LED 灯亮时的IO电平 */
typedef enum {
LED_LOW_TRIGGER = 0,
LED_HIGH_TRIGGER = 1,
}LED_TriggerLever;
void LED_GPIO_Config(void);
void LED_GPIO_ON(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, LED_TriggerLever led_brightstatus);
void LED_GPIO_OFF(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, LED_TriggerLever led_brightstatus);
#endif /*__bsp_gpio_led_H*/
其中在.c源文件中
/**
* @brief 开启对应 LED 灯
* @param GPIOX : x可以是 A,B,C等
* @param GPIO_PIN: 待操作的PIN
* @param led_brightstatus LED灯亮时的状态
* @retval 无
*/
void LED_GPIO_ON(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, LED_TriggerLever led_brightstatus)
{
if (led_brightstatus == LED_LOW_TRIGGER)
{
GPIO_ResetBits(GPIOx, GPIO_Pin);
}
else
{
GPIO_SetBits(GPIOx, GPIO_Pin);
}
}
/**
* @brief 关闭对应 LED 灯
* @param GPIOX : x可以是 A,B,C等
* @param GPIO_PIN: 待操作的PIN
* @param led_brightstatus LED灯亮时的状态
* @retval 无
*/
void LED_GPIO_OFF(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, LED_TriggerLever led_brightstatus)
{
if (led_brightstatus == LED_LOW_TRIGGER)
{
GPIO_SetBits(GPIOx, GPIO_Pin);
}
else
{
GPIO_ResetBits(GPIOx, GPIO_Pin);
}
}
以及.h文件中枚举
/* LED 灯亮时的IO电平 */
typedef enum {
LED_LOW_TRIGGER = 0,
LED_HIGH_TRIGGER = 1,
}LED_TriggerLever;
在ON函数和OFF函数中,添加了第三个参数,这个参数是枚举类型,可以设置0和1,用来表示LED状态。
其中LED_TriggerLever 命名的含义:LED触发方式
LED:发光二极管
Trigger:触发
Lever:电平
led_brightstatus 命名的含义:LED点亮的状态
LED:发光二极管
bright:点亮
status:状态
这里定义了一个枚举类型,名字LED_TriggerLever,表示LED触发方式,然后在ON和OFF函数第三个参数,变量名是led_brightstatus,点亮时候的状态。
ON函数与OFF函数的理解:
当LED的逻辑状态是低电平点亮,高电平熄灭。
此时我在ON函数第三个参数传递LED_LOW_TRIGGER,if成立,执行IO口置0,LED点亮,逻辑正确
此时我在OFF函数第三个参数传递LED_LOW_TRIGGER,if成立,执行IO口置1,LED熄灭,逻辑正确
符合低电平点亮,高电平熄灭的逻辑。
当LED的逻辑状态是高电平点亮,低电平熄灭。
此时我在ON函数第三个参数传递LED_LOW_TRIGGER,if不成立,执行IO口置1,LED点亮,逻辑正确
此时我在OFF函数第三个参数传递LED_LOW_TRIGGER,if不成立,执行IO口置0,LED熄灭,逻辑正确
符合高电平点亮,低电平熄灭的逻辑
所以在ON函数与OFF函数里面,当传递的第三个参数同为低电平逻辑或者高电平逻辑,ON里面的if执行的逻辑与OFF里面的if执行的逻辑相反,ON里面的else执行的逻辑与OFF里面的else执行的逻辑相反就行。
6.key文件
bsp_gpio_key.c
/**
******************************************************************************
* @file bsp_gpio_key.c
* @author 作者
* @version v1.0
* @date 2026.4.3
* @brief 扫描按键函数接口
******************************************************************************
* @attention
*
* 版权声明
*
******************************************************************************
*/
#include "key/bsp_gpio_key.h"
#include "delay/bsp_delay.h"
/**
* @brief 初始化控制 KEY 的IO
* @param 无
* @retval 无
*/
void KEY_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct = { 0 };
/*****************************核心板载按键****************************************/
#if 1
RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK_PORT, ENABLE); //开启GPIOA 端口时钟
GPIO_SetBits(KEY1_GPIO_PORT, KEY1_GPIO_PIN); //设置PA1端口初始化1 让LED灭
// 配置引脚:选择GPIOA的Pin1
GPIO_InitStruct.GPIO_Pin = KEY1_GPIO_PIN;
// 配置输出速度:50MHz
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
// 配置工作模式:浮空输入模式
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStruct);
#endif
}
/**
* @brief 基础检测按键
* @param GPIOX : x可以是 A,B,C等
* @param GPIO_PIN: 待操作的PIN
* @param key_pressstatus:按键按下时IO电平状态
* @retval KEY_UP(没有触发按键)、KEY_DOWN(触发按键)
*/
KEY_Status KEY_Scan(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, KEY_TriggerLever key_pressstatus)
{
if (GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == key_pressstatus)
{
Rough_Delay_Ms(20);
while(GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == key_pressstatus);
Rough_Delay_Ms(20);
return KEY_DOWN;
}
else
{
return KEY_UP;
}
}
/***************************************END OF FILE *********************************************************/
bsp_gpio_key.h
#ifndef __BSP_GPIO_KEY_H
#define __BSP_GPIO_KEY_H
#include "stm32f10x.h"
/*定义连接GPIO端口,用户只需要修改下面代码即可改变控制的LED引脚 */
//KEY1
#define KEY1_GPIO_PORT GPIOA /* GPIO 端口 */
#define KEY1_GPIO_CLK_PORT RCC_APB2Periph_GPIOA /* GPIO 端口时钟 */
#define KEY1_GPIO_PIN GPIO_Pin_0 /* 对应PIN脚 */
/* 按键按下时的IO电平 */
typedef enum {
KEY_LOW_TRIGGER = 0,
KEY_HIGH_TRIGGER = 1,
}KEY_TriggerLever;
/* 按键的状态 */
typedef enum {
KEY_UP = 0,
KEY_DOWN = 1,
KEY_INIT = 2,
}KEY_Status;
void KEY_GPIO_Config(void);
KEY_Status KEY_Scan(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, KEY_TriggerLever key_pressstatus);
#endif /*__BSP_GPIO_KEY_H*/
其中以下部分代码的理解
/* 按键按下时的IO电平 */
typedef enum {
KEY_LOW_TRIGGER = 0,
KEY_HIGH_TRIGGER = 1,
}KEY_TriggerLever;
/* 按键的状态 */
typedef enum {
KEY_UP = 0,
KEY_DOWN = 1,
KEY_INIT = 2,
}KEY_Status;
/**
* @brief 基础检测按键
* @param GPIOX : x可以是 A,B,C等
* @param GPIO_PIN: 待操作的PIN
* @param key_pressstatus:按键按下时IO电平状态
* @retval KEY_UP(没有触发按键)、KEY_DOWN(触发按键)
*/
KEY_Status KEY_Scan(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, KEY_TriggerLever key_pressstatus)
{
if (GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == key_pressstatus)
{
Rough_Delay_Ms(20);
while(GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == key_pressstatus);
Rough_Delay_Ms(20);
return KEY_DOWN;
}
else
{
return KEY_UP;
}
}
KEY_Scan函数第三个参数传递的是我按键按下后当前IO口的状态,比如说这个按键一端是连接的是PA0的IO口,另外一端接到VCC,然后PA0有下拉电阻,就是当我给单片机供电的时候,PA0的默认初始状态是低电平,当我此时按键按下,此时VCC之间通过开关流入到IO口,此时的IO口状态是高电平。
所以我定义了按键按下后的枚举,KEY_LOW_TRIGGER = 0,KEY_HIGH_TRIGGER = 1。
当我在main函数去调用KEY_Scan函数的时候如下
while(1)
{
if (KEY_Scan(KEY1_GPIO_PORT, KEY1_GPIO_PIN, KEY_HIGH_TRIGGER) == KEY_DOWN)
{
LED_TOGGLE(R_LED1_GPIO_PORT, R_LED1_GPIO_PIN);
}
}
我的第三个参数传递的是KEY_HIGH_TRIGGER,然后进入到函数KEY_Scan里面
/**
* @brief 基础检测按键
* @param GPIOX : x可以是 A,B,C等
* @param GPIO_PIN: 待操作的PIN
* @param key_pressstatus:按键按下时IO电平状态
* @retval KEY_UP(没有触发按键)、KEY_DOWN(触发按键)
*/
KEY_Status KEY_Scan(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, KEY_TriggerLever key_pressstatus)
{
if (GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == key_pressstatus)
{
Rough_Delay_Ms(20);
while(GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == key_pressstatus);
Rough_Delay_Ms(20);
return KEY_DOWN;
}
else
{
return KEY_UP;
}
}
key_pressstatus是KEY_HIGH_TRIGGER,然后函数:
GPIO_ReadInputDataBit(GPIOx, GPIO_Pin)与key_pressstatus判断
GPIO_ReadInputDataBit(GPIOx, GPIO_Pin)这个函数是GPIO.c官方提供的
typedef enum
{ Bit_RESET = 0,
Bit_SET
}BitAction;
/**
* @brief Reads the specified input port pin.
* @param GPIOx: where x can be (A..G) to select the GPIO peripheral.
* @param GPIO_Pin: specifies the port bit to read.
* This parameter can be GPIO_Pin_x where x can be (0..15).
* @retval The input port pin value.
*/
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
uint8_t bitstatus = 0x00;
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GET_GPIO_PIN(GPIO_Pin));
if ((GPIOx->IDR & GPIO_Pin) != (uint32_t)Bit_RESET)
{
bitstatus = (uint8_t)Bit_SET;
}
else
{
bitstatus = (uint8_t)Bit_RESET;
}
return bitstatus;
}
这个函数的功能是判断当前IO口状态,GPIOX是GPIOA,GPIO_Pin是GPIO_Pin_0
这个函数里面有个if
if ((GPIOx->IDR & GPIO_Pin) != (uint32_t)Bit_RESET)
其中IDR是寄存器
这个if的!=左边的意思是:GPIOA端口,GPIO_Pin_0的电平状态
!= 右边的是0的意思,
因为GPIOA的pin0引脚有下拉电阻,默认电平状态是低电平,当开关按下,然后VCC通过开关到GPIOA的pin0引脚,此时的状态是1。
所以当开关按下,!=左边是1,右边是0,不相等的,判断成立,执行if,
if ((GPIOx->IDR & GPIO_Pin) != (uint32_t)Bit_RESET)
{
bitstatus = (uint8_t)Bit_SET;
}
return bitstatus;
此时bitstatus 获取的状态是Bit_SET,而Bit_SET是1,返回bitstatus。
while(1)
{
if (KEY_Scan(KEY1_GPIO_PORT, KEY1_GPIO_PIN, KEY_HIGH_TRIGGER) == KEY_DOWN)
{
LED_TOGGLE(R_LED1_GPIO_PORT, R_LED1_GPIO_PIN);
}
}
/**
* @brief 基础检测按键
* @param GPIOX : x可以是 A,B,C等
* @param GPIO_PIN: 待操作的PIN
* @param key_pressstatus:按键按下时IO电平状态
* @retval KEY_UP(没有触发按键)、KEY_DOWN(触发按键)
*/
KEY_Status KEY_Scan(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, KEY_TriggerLever key_pressstatus)
{
if (GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == key_pressstatus)
{
Rough_Delay_Ms(20);
while(GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == key_pressstatus);
Rough_Delay_Ms(20);
return KEY_DOWN;
}
else
{
return KEY_UP;
}
}
此时
if (GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == key_pressstatus)
当按键按下,等号左边返回的是1,等号右边的值是 KEY_HIGH_TRIGGER,也是1,成立的。
执行if里面的语句,if里面的语句
if (GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == key_pressstatus)
{
Rough_Delay_Ms(20);
while(GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == key_pressstatus);
Rough_Delay_Ms(20);
return KEY_DOWN;
}
有个while,这个是用来松手检测,如果我按键一直长按,会停在while里面,上面下面都有延时20ms的函数用来消抖,最后通过return 返回按键的状态。
while(1)
{
if (KEY_Scan(KEY1_GPIO_PORT, KEY1_GPIO_PIN, KEY_HIGH_TRIGGER) == KEY_DOWN)
{
LED_TOGGLE(R_LED1_GPIO_PORT, R_LED1_GPIO_PIN);
}
}
if成立执行
/**
* @brief 翻转对应 LED 灯
* @param GPIOX : x可以是 A,B,C等
* @param GPIO_PIN: 待操作的PIN
* @retval 无
*/
void LED_TOGGLE(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
GPIOx->ODR ^= GPIO_Pin;
}

不断的翻转R灯的引脚状态。
ODR寄存器能给指定的引脚设置1或者清除0操作。我需要执行不断的翻转IO口,就需要不断给当前IO口设置1和清除0操作。
最终在
while(1)
{
if (KEY_Scan(KEY1_GPIO_PORT, KEY1_GPIO_PIN, KEY_HIGH_TRIGGER) == KEY_DOWN)
{
LED_TOGGLE(R_LED1_GPIO_PORT, R_LED1_GPIO_PIN);
}
}
我按键按下,LED灯执行翻转的操作,按下亮,按一下灭。
在这个while(1)里面的函数KEY_Scan的第三个参数传递的是按键按下后的电平状态。
7.引脚配置

8.代码
8.1 main
/**
******************************************************************************
* @file main.c
* @author 作者
* @version v1.0
* @date 2026.4.3
* @brief 流水灯标准库写法
******************************************************************************
* @attention
*
* 版权声明
*
******************************************************************************
*/
#include "led/bsp_gpio_led.h"
#include "delay/bsp_delay.h"
#include "key/bsp_gpio_key.h"
#include "stm32f10x.h"
/**
* @brief 主函数
* @param 无
* @note 无
* @retval 无
*/
int main (void)
{
LED_GPIO_Config();
KEY_GPIO_Config();
while(1)
{
if (KEY_Scan(KEY1_GPIO_PORT, KEY1_GPIO_PIN, KEY_HIGH_TRIGGER) == KEY_DOWN)
{
LED_TOGGLE(R_LED1_GPIO_PORT, R_LED1_GPIO_PIN);
}
if (KEY_Scan(KEY2_GPIO_PORT, KEY2_GPIO_PIN, KEY_HIGH_TRIGGER) == KEY_DOWN)
{
LED_TOGGLE(G_LED2_GPIO_PORT, G_LED2_GPIO_PIN);
}
if (KEY_Scan(KEY3_GPIO_PORT, KEY3_GPIO_PIN, KEY_HIGH_TRIGGER) == KEY_DOWN)
{
LED_TOGGLE(B_LED3_GPIO_PORT, B_LED3_GPIO_PIN);
}
if (KEY_Scan(KEY4_GPIO_PORT, KEY4_GPIO_PIN, KEY_LOW_TRIGGER) == KEY_DOWN)
{
LED_TOGGLE(LED4_GPIO_PORT, LED4_GPIO_PIN);
}
if (KEY_Scan(KEY5_GPIO_PORT, KEY5_GPIO_PIN, KEY_LOW_TRIGGER) == KEY_DOWN)
{
LED_TOGGLE(LED5_GPIO_PORT, LED5_GPIO_PIN);
}
if (KEY_Scan(KEY6_GPIO_PORT, KEY6_GPIO_PIN, KEY_LOW_TRIGGER) == KEY_DOWN)
{
LED_TOGGLE(LED6_GPIO_PORT, LED6_GPIO_PIN);
}
}
}
其中KEY4,KEY5,KEY6函数第三个参数配置KEY_LOW_TRIGGER,低电平,按键按下IO口的状态是低电平。
8.2 key
8.2.1 bsp_gpio_key.c
/**
******************************************************************************
* @file bsp_gpio_key.c
* @author 作者
* @version v1.0
* @date 2026.4.3
* @brief 扫描按键函数接口
******************************************************************************
* @attention
*
* 版权声明
*
******************************************************************************
*/
#include "key/bsp_gpio_key.h"
#include "delay/bsp_delay.h"
/**
* @brief 初始化控制 KEY 的IO
* @param 无
* @retval 无
*/
void KEY_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct = { 0 };
/*****************************核心板载按键****************************************/
#if 1
RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK_PORT, ENABLE); //开启GPIOA 端口时钟
GPIO_SetBits(KEY1_GPIO_PORT, KEY1_GPIO_PIN); //设置PA0端口初始化1 让LED灭
// 配置引脚:选择GPIOA的Pin1
GPIO_InitStruct.GPIO_Pin = KEY1_GPIO_PIN;
// 配置输出速度:50MHz
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
// 配置工作模式:浮空输入模式
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStruct);
#endif
#if 1
RCC_APB2PeriphClockCmd(KEY2_GPIO_CLK_PORT, ENABLE); //开启GPIOA 端口时钟
GPIO_SetBits(KEY2_GPIO_PORT, KEY2_GPIO_PIN);
// 配置引脚:选择GPIOA的Pin1
GPIO_InitStruct.GPIO_Pin = KEY2_GPIO_PIN;
// 配置输出速度:50MHz
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
// 配置工作模式:浮空输入模式
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStruct);
#endif
/*****************************用户自定义扩展按键****************************************/
#if 1
RCC_APB2PeriphClockCmd(KEY3_GPIO_CLK_PORT, ENABLE);
GPIO_SetBits(KEY3_GPIO_PORT, KEY3_GPIO_PIN);
// 配置引脚:选择GPIOA的Pin1
GPIO_InitStruct.GPIO_Pin = KEY3_GPIO_PIN;
// 配置输出速度:50MHz
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
// 配置工作模式:下拉输入模式
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(KEY3_GPIO_PORT, &GPIO_InitStruct);
#endif
#if 1
RCC_APB2PeriphClockCmd(KEY4_GPIO_CLK_PORT, ENABLE);
GPIO_SetBits(KEY4_GPIO_PORT, KEY4_GPIO_PIN);
// 配置引脚:选择GPIOA的Pin1
GPIO_InitStruct.GPIO_Pin = KEY4_GPIO_PIN;
// 配置输出速度:50MHz
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
// 配置工作模式:上拉输入模式
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(KEY4_GPIO_PORT, &GPIO_InitStruct);
#endif
#if 1
RCC_APB2PeriphClockCmd(KEY5_GPIO_CLK_PORT, ENABLE);
GPIO_SetBits(KEY5_GPIO_PORT, KEY5_GPIO_PIN);
// 配置引脚:选择GPIOA的Pin1
GPIO_InitStruct.GPIO_Pin = KEY5_GPIO_PIN;
// 配置输出速度:50MHz
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
// 配置工作模式:上拉输入模式
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(KEY5_GPIO_PORT, &GPIO_InitStruct);
#endif
#if 1
RCC_APB2PeriphClockCmd(KEY6_GPIO_CLK_PORT, ENABLE);
GPIO_SetBits(KEY6_GPIO_PORT, KEY6_GPIO_PIN);
// 配置引脚:选择GPIOA的Pin1
GPIO_InitStruct.GPIO_Pin = KEY6_GPIO_PIN;
// 配置输出速度:50MHz
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
// 配置工作模式:上拉输入模式
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(KEY6_GPIO_PORT, &GPIO_InitStruct);
#endif
}
/**
* @brief 基础检测按键
* @param GPIOX : x可以是 A,B,C等
* @param GPIO_PIN: 待操作的PIN
* @param key_pressstatus:按键按下时IO电平状态
* @retval KEY_UP(没有触发按键)、KEY_DOWN(触发按键)
*/
KEY_Status KEY_Scan(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, KEY_TriggerLever key_pressstatus)
{
if (GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == key_pressstatus)
{
Rough_Delay_Ms(20);
while(GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == key_pressstatus);
Rough_Delay_Ms(20);
return KEY_DOWN;
}
else
{
return KEY_UP;
}
}
/***************************************END OF FILE *********************************************************/
按键1和按键2是板载的按键,按下后IO口状态是高电平,外接入了下拉电阻,所以配置输入浮空模式
按键3,按下后IO口状态是高电平,没有外接下拉电阻,所以配置下拉输入模式
按键4,5,6,按下后IO口状态是低电平,没有外接上拉电阻,所以需要配置上拉输入模式。
上下拉电阻用来初始化IO口状态,然后按键按下后,改变IO口状态。
8.2.2 bsp_gpio_key.h
#ifndef __BSP_GPIO_KEY_H
#define __BSP_GPIO_KEY_H
#include "stm32f10x.h"
/*定义连接GPIO端口,用户只需要修改下面代码即可改变控制的LED引脚 */
/**********************核心板载按键****************************************/
//KEY1
#define KEY1_GPIO_PORT GPIOA /* GPIO 端口 */
#define KEY1_GPIO_CLK_PORT RCC_APB2Periph_GPIOA /* GPIO 端口时钟 */
#define KEY1_GPIO_PIN GPIO_Pin_0 /* 对应PIN脚 */
//KEY2
#define KEY2_GPIO_PORT GPIOC /* GPIO 端口 */
#define KEY2_GPIO_CLK_PORT RCC_APB2Periph_GPIOC /* GPIO 端口时钟 */
#define KEY2_GPIO_PIN GPIO_Pin_13 /* 对应PIN脚 */
/**********************用户自定义按键****************************************/
//KEY3
#define KEY3_GPIO_PORT GPIOB /* GPIO 端口 */
#define KEY3_GPIO_CLK_PORT RCC_APB2Periph_GPIOB /* GPIO 端口时钟 */
#define KEY3_GPIO_PIN GPIO_Pin_15 /* 对应PIN脚 */
//KEY4
#define KEY4_GPIO_PORT GPIOB /* GPIO 端口 */
#define KEY4_GPIO_CLK_PORT RCC_APB2Periph_GPIOB /* GPIO 端口时钟 */
#define KEY4_GPIO_PIN GPIO_Pin_6 /* 对应PIN脚 */
//KEY5
#define KEY5_GPIO_PORT GPIOB /* GPIO 端口 */
#define KEY5_GPIO_CLK_PORT RCC_APB2Periph_GPIOB /* GPIO 端口时钟 */
#define KEY5_GPIO_PIN GPIO_Pin_7 /* 对应PIN脚 */
//KEY6
#define KEY6_GPIO_PORT GPIOB /* GPIO 端口 */
#define KEY6_GPIO_CLK_PORT RCC_APB2Periph_GPIOB /* GPIO 端口时钟 */
#define KEY6_GPIO_PIN GPIO_Pin_8 /* 对应PIN脚 */
/* 按键按下时的IO电平 */
typedef enum {
KEY_LOW_TRIGGER = 0,
KEY_HIGH_TRIGGER = 1,
}KEY_TriggerLever;
/* 按键的状态 */
typedef enum {
KEY_UP = 0,
KEY_DOWN = 1,
KEY_INIT = 2,
}KEY_Status;
void KEY_GPIO_Config(void);
KEY_Status KEY_Scan(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, KEY_TriggerLever key_pressstatus);
#endif /*__BSP_GPIO_KEY_H*/
8.3 LED
8.3.1 bsp_gpio_led.c
/**
******************************************************************************
* @file bsp_gpio_led.c
* @author 作者
* @version v1.0
* @date 2026.4.3
* @brief LED灯的函数接口
******************************************************************************
* @attention
*
* 版权声明
*
******************************************************************************
*/
#include "led/bsp_gpio_led.h"
/**
* @brief 初始化控制 LED 的IO
* @param 无
* @retval 无
*/
void LED_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct = { 0 };
/*****************************核心板载LED****************************************/
#if 1
RCC_APB2PeriphClockCmd(R_LED1_GPIO_CLK_PORT, ENABLE); //开启GPIOA 端口时钟
GPIO_SetBits(R_LED1_GPIO_PORT, R_LED1_GPIO_PIN); //设置PA1端口初始化1 让LED灭
// 配置引脚:选择GPIOA的Pin1
GPIO_InitStruct.GPIO_Pin = R_LED1_GPIO_PIN;
// 配置输出速度:50MHz
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
// 配置工作模式:推挽输出
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(R_LED1_GPIO_PORT, &GPIO_InitStruct);
#endif
#if 1
RCC_APB2PeriphClockCmd(G_LED2_GPIO_CLK_PORT, ENABLE); //开启GPIOA 端口时钟
GPIO_SetBits(G_LED2_GPIO_PORT, G_LED2_GPIO_PIN); //设置PA2端口初始化1 让LED灭
// 配置引脚:选择GPIOA的Pin1
GPIO_InitStruct.GPIO_Pin = G_LED2_GPIO_PIN;
// 配置输出速度:50MHz
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
// 配置工作模式:推挽输出
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(G_LED2_GPIO_PORT, &GPIO_InitStruct);
#endif
#if 1
RCC_APB2PeriphClockCmd(B_LED3_GPIO_CLK_PORT, ENABLE); //开启GPIOA 端口时钟
GPIO_SetBits(B_LED3_GPIO_PORT, B_LED3_GPIO_PIN); //设置PA3端口初始化1 让LED灭
// 配置引脚:选择GPIOA的Pin1
GPIO_InitStruct.GPIO_Pin = B_LED3_GPIO_PIN;
// 配置输出速度:50MHz
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
// 配置工作模式:推挽输出
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(B_LED3_GPIO_PORT, &GPIO_InitStruct);
#endif
/*****************************用户自定义LED*******************************/
#if 1
RCC_APB2PeriphClockCmd(LED4_GPIO_CLK_PORT, ENABLE);
GPIO_SetBits(LED4_GPIO_PORT, LED4_GPIO_PIN);
// 配置引脚:选择GPIOA的Pin1
GPIO_InitStruct.GPIO_Pin = LED4_GPIO_PIN;
// 配置输出速度:50MHz
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
// 配置工作模式:推挽输出
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(LED4_GPIO_PORT, &GPIO_InitStruct);
#endif
#if 1
RCC_APB2PeriphClockCmd(LED5_GPIO_CLK_PORT, ENABLE);
GPIO_ResetBits(LED5_GPIO_PORT, LED5_GPIO_PIN);
// 配置引脚:选择GPIOA的Pin1
GPIO_InitStruct.GPIO_Pin = LED5_GPIO_PIN;
// 配置输出速度:50MHz
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
// 配置工作模式:推挽输出
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(LED5_GPIO_PORT, &GPIO_InitStruct);
#endif
#if 1
RCC_APB2PeriphClockCmd(LED6_GPIO_CLK_PORT, ENABLE);
GPIO_ResetBits(LED6_GPIO_PORT, LED6_GPIO_PIN);
// 配置引脚:选择GPIOA的Pin1
GPIO_InitStruct.GPIO_Pin = LED6_GPIO_PIN;
// 配置输出速度:50MHz
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
// 配置工作模式:推挽输出
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(LED6_GPIO_PORT, &GPIO_InitStruct);
#endif
}
/**
* @brief 开启对应 LED 灯
* @param GPIOX : x可以是 A,B,C等
* @param GPIO_PIN: 待操作的PIN
* @param led_brightstatus LED灯亮时的状态
* @retval 无
*/
void LED_GPIO_ON(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, LED_TriggerLever led_brightstatus)
{
if (led_brightstatus == LED_LOW_TRIGGER)
{
GPIO_ResetBits(GPIOx, GPIO_Pin);
}
else
{
GPIO_SetBits(GPIOx, GPIO_Pin);
}
}
/**
* @brief 关闭对应 LED 灯
* @param GPIOX : x可以是 A,B,C等
* @param GPIO_PIN: 待操作的PIN
* @param led_brightstatus LED灯亮时的状态
* @retval 无
*/
void LED_GPIO_OFF(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, LED_TriggerLever led_brightstatus)
{
if (led_brightstatus == LED_LOW_TRIGGER)
{
GPIO_SetBits(GPIOx, GPIO_Pin);
}
else
{
GPIO_ResetBits(GPIOx, GPIO_Pin);
}
}
/**
* @brief 翻转对应 LED 灯
* @param GPIOX : x可以是 A,B,C等
* @param GPIO_PIN: 待操作的PIN
* @retval 无
*/
void LED_TOGGLE(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
GPIOx->ODR ^= GPIO_Pin;
}
/***************************************END OF FILE *********************************************************/
LED5和LED6是高电平点亮,所以需要用函数GPIO_ResetBits设置初始状态IO口,是低电平。如果是高电平,那么LED长脚接到IO口,短脚接入GND
LED1234是低电平点亮,所以需要函数GPIO_SetBits设置初始状态IO口,是高电平。
如果低电平点亮,那么LED短脚接入到IO口,长脚接VCC。
8.3.2 bsp_gpio_led.h
#ifndef __bsp_gpio_led_H
#define __bsp_gpio_led_H
#include "stm32f10x.h"
/*定义连接GPIO端口,用户只需要修改下面代码即可改变控制的LED引脚 */
//LED1
#define LED1_GPIO_PORT GPIOA /* GPIO 端口 */
#define LED1_GPIO_CLK_PORT RCC_APB2Periph_GPIOA /* GPIO 端口时钟 */
#define LED1_GPIO_PIN GPIO_Pin_1 /* 对应PIN脚 */
//LED2
#define LED2_GPIO_PORT GPIOA /* GPIO 端口 */
#define LED2_GPIO_CLK_PORT RCC_APB2Periph_GPIOA /* GPIO 端口时钟 */
#define LED2_GPIO_PIN GPIO_Pin_2 /* 对应PIN脚 */
//LED3
#define LED3_GPIO_PORT GPIOA /* GPIO 端口 */
#define LED3_GPIO_CLK_PORT RCC_APB2Periph_GPIOA /* GPIO 端口时钟 */
#define LED3_GPIO_PIN GPIO_Pin_3 /* 对应PIN脚 */
//LED4
#define LED4_GPIO_PORT GPIOB /* GPIO 端口 */
#define LED4_GPIO_CLK_PORT RCC_APB2Periph_GPIOB /* GPIO 端口时钟 */
#define LED4_GPIO_PIN GPIO_Pin_5 /* 对应PIN脚 */
//LED5
#define LED5_GPIO_PORT GPIOB /* GPIO 端口 */
#define LED5_GPIO_CLK_PORT RCC_APB2Periph_GPIOB /* GPIO 端口时钟 */
#define LED5_GPIO_PIN GPIO_Pin_13 /* 对应PIN脚 */
//LED6
#define LED6_GPIO_PORT GPIOB /* GPIO 端口 */
#define LED6_GPIO_CLK_PORT RCC_APB2Periph_GPIOB /* GPIO 端口时钟 */
#define LED6_GPIO_PIN GPIO_Pin_14 /* 对应PIN脚 */
/***************核心板载LED灯****************************************/
//R_LED
#define R_LED1_GPIO_PORT LED1_GPIO_PORT /* GPIO 端口 */
#define R_LED1_GPIO_CLK_PORT LED1_GPIO_CLK_PORT /* GPIO 端口时钟 */
#define R_LED1_GPIO_PIN LED1_GPIO_PIN /* 对应PIN脚 */
//G_LED
#define G_LED2_GPIO_PORT LED2_GPIO_PORT /* GPIO 端口 */
#define G_LED2_GPIO_CLK_PORT LED2_GPIO_CLK_PORT /* GPIO 端口时钟 */
#define G_LED2_GPIO_PIN LED2_GPIO_PIN /* 对应PIN脚 */
//B_LED
#define B_LED3_GPIO_PORT LED3_GPIO_PORT /* GPIO 端口 */
#define B_LED3_GPIO_CLK_PORT LED3_GPIO_CLK_PORT /* GPIO 端口时钟 */
#define B_LED3_GPIO_PIN LED3_GPIO_PIN /* 对应PIN脚 */
/***************用户自定义宏****************************************/
//R_LED
#define R_LED_ON_ONLY LED_GPIO_ON(R_LED1_GPIO_PORT, R_LED1_GPIO_PIN, LED_LOW_TRIGGER); \
LED_GPIO_OFF(G_LED2_GPIO_PORT, G_LED2_GPIO_PIN, LED_LOW_TRIGGER); \
LED_GPIO_OFF(B_LED3_GPIO_PORT, B_LED3_GPIO_PIN, LED_LOW_TRIGGER);
//G_LED
#define G_LED_ON_ONLY LED_GPIO_OFF(R_LED1_GPIO_PORT, R_LED1_GPIO_PIN, LED_LOW_TRIGGER); \
LED_GPIO_ON(G_LED2_GPIO_PORT, G_LED2_GPIO_PIN, LED_LOW_TRIGGER); \
LED_GPIO_OFF(B_LED3_GPIO_PORT, B_LED3_GPIO_PIN, LED_LOW_TRIGGER);
//B_LED
#define B_LED_ON_ONLY LED_GPIO_OFF(R_LED1_GPIO_PORT, R_LED1_GPIO_PIN, LED_LOW_TRIGGER); \
LED_GPIO_OFF(G_LED2_GPIO_PORT, G_LED2_GPIO_PIN, LED_LOW_TRIGGER); \
LED_GPIO_ON(B_LED3_GPIO_PORT, B_LED3_GPIO_PIN, LED_LOW_TRIGGER);
//B_G_B_LED全亮
#define RGB_LED_ALL_ON LED_GPIO_ON(R_LED1_GPIO_PORT, R_LED1_GPIO_PIN, LED_LOW_TRIGGER); \
LED_GPIO_ON(G_LED2_GPIO_PORT, G_LED2_GPIO_PIN, LED_LOW_TRIGGER); \
LED_GPIO_ON(B_LED3_GPIO_PORT, B_LED3_GPIO_PIN, LED_LOW_TRIGGER);
//B_G_B_LED全灭
#define RGB_LED_ALL_OFF LED_GPIO_OFF(R_LED1_GPIO_PORT, R_LED1_GPIO_PIN, LED_LOW_TRIGGER); \
LED_GPIO_OFF(G_LED2_GPIO_PORT, G_LED2_GPIO_PIN, LED_LOW_TRIGGER); \
LED_GPIO_OFF(B_LED3_GPIO_PORT, B_LED3_GPIO_PIN, LED_LOW_TRIGGER);
/* LED 灯亮时的IO电平 */
typedef enum {
LED_LOW_TRIGGER = 0,
LED_HIGH_TRIGGER = 1,
}LED_TriggerLever;
void LED_GPIO_Config(void);
void LED_GPIO_ON(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, LED_TriggerLever led_brightstatus);
void LED_GPIO_OFF(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, LED_TriggerLever led_brightstatus);
void LED_TOGGLE(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
#endif /*__bsp_gpio_led_H*/
8.4 延时
8.4.1bsp_delay.c
/**
******************************************************************************
* @file bsp_delay.c
* @author 作者
* @version v1.0
* @date 2026.4.3
* @brief 粗略阻塞延时函数接口
******************************************************************************
* @attention
*
* 版权声明
*
******************************************************************************
*/
#include "delay/bsp_delay.h"
/**
* @brief 粗略阻塞延时基本函数接口
* @param ncount:传入的计数值
* @note 软件延时函数,使用不同的系统时钟,延时不一样,还会存在函数调用以及其他计算损耗,只能粗略使用
* @retval 无
*/
void Rough_Delay(__IO uint32_t ncount)
{
for (uint32_t i = 0; i < ncount; i++)
{
__nop();
}
}
/**
* @brief 粗略阻塞延时基本函数接口 单位:US
* @param ncount:传入的计数值
* @note 软件延时函数,使用不同的系统时钟,延时不一样,还会存在函数调用以及其他计算损耗,只能粗略使用
* @retval 无
*/
void Rough_Delay_Us(__IO uint32_t time)
{
Rough_Delay(time);
}
/**
* @brief 粗略阻塞延时基本函数接口 单位:MS
* @param ncount:传入的计数值
* @note 软件延时函数,使用不同的系统时钟,延时不一样,还会存在函数调用以及其他计算损耗,只能粗略使用
* @retval 无
*/
void Rough_Delay_Ms(__IO uint32_t time)
{
Rough_Delay(time * 1000);
}
/**
* @brief 粗略阻塞延时基本函数接口 单位:S
* @param ncount:传入的计数值
* @note 软件延时函数,使用不同的系统时钟,延时不一样,还会存在函数调用以及其他计算损耗,只能粗略使用
* @retval 无
*/
void Rough_Delay_S(__IO uint32_t time)
{
Rough_Delay(time * 1000 * 1000);
}
8.4.2 bsp_delay_h
#ifndef __bsp_delay_H
#define __bsp_delay_H
#include "stm32f10x.h"
void Rough_Delay(__IO uint32_t ncount);
void Rough_Delay_Us(__IO uint32_t ncount);
void Rough_Delay_Ms(__IO uint32_t time);
void Rough_Delay_S(__IO uint32_t time);
#endif /*__bsp_delay_H*/
9.接线图


10 实验现象
STM32按键点灯
更多推荐



所有评论(0)