欢迎光临
我们一直在努力

stm32F103C8T6标准库实验项目——环境报警设备2

目录

  • 1.主函数
    • 1.1 main.h
    • 1.2 main.c
  • 2.LED
    • 2.1 bsp_gpio_led.h
    • 2.2 bsp_gpio_led.c
    • 2.3 app_led.h
    • 2.4 app_led.c
  • 3.定时器中断与外部中断
    • 3.1 bsp_systick.h
    • 3.2 bsp_systick.c
    • 3.3 stm32f10x_it.c
  • 4. 按键
    • 4.1 bsp_gpio_key.h
    • 4.2 bsp_gpio_key.c
    • 4.3 app_key.h
    • 4.4 app_key.c
  • 5.光敏传感器
    • 5.1 bsp_gpio_idr.h
    • 5.2 bsp_gpio_idr.c
    • 5.3 app_idr.h
    • 5.4 app_idr.c
  • 6.热敏传感器
    • 6.1 bsp_gpio_ntc.h
    • 6.2 bsp_gpio_ntc.c
    • 6.3 app_ntc.h
    • 6.4 app_ntc.c
  • 7.蜂鸣器
    • 7.1 bsp_gpio_beep.h
    • 7.2 bsp_gpio_beep.c
  • 8.粗略阻塞延时
    • 8.1 bsp_delay.h
    • 8.2 bsp_delay.c
  • 8.接线图
  • 9.实验现象

1.主函数

1.1 main.h

#ifndef _MAIN_H
#define _MAIN_H

#include "led/app_led.h"
#include "idr/app_idr.h"
#include "key/app_key.h"
#include "ntc/app_ntc.h"

#endif /*_MAIN_H*/

1.2 main.c

/**
******************************************************************************
* @file main.c
* @author 作者
* @version v1.0
* @date 2026.4.28
* @brief 环境报警设备标准库写法
******************************************************************************
* @attention
*
* 版权声明
*
******************************************************************************
*/

#include "main.h"
#include "led/bsp_gpio_led.h"
#include "systick/bsp_systick.h"
#include "idr/bsp_gpio_idr.h"
#include "key/bsp_gpio_key.h"
#include "ntc/bsp_gpio_ntc.h"
#include "beep/bsp_gpio_beep.h"
#include "stm32f10x.h"

/*
************************程序设计要求**********************************************************
* *
* 1.编译并下载程序到开发板即可观察现象; *
* 2.观察板载绿灯以500ms翻转状态。 *
* 3.改变光敏传感器周围的光照,来切换LED灯状态(100ms扫描一次) *
* 4.温度报警部分: *
* 设备状态(NTC检测) *
* 1>设备报警状态:核心板红灯常亮和蜂鸣器长响 *
* 2>设备正常状态:核心板红灯常灭和蜂鸣器不响 *
* 工作模式(按键切换) *
* 1>工作模式: *
* 1.设备上电后为“工作模式“ 核心板蓝灯长亮 *
* 2.当热敏触发,进入“设备报警状态” *
* 3.热敏触发条件恢复后,需手动长按KEY2解除报警,进入“设备正常状态” *
* 2>测试模式: *
* 1.设备切换为“测试模式“ 核心板蓝灯长灭 *
* 2.当热敏触发,进入“设备报警状态” *
* 3.热敏触发条件恢复后,自动解除报警,进入“设备正常状态” *
* 3>模式切换:在“设备正常状态”时按KEY1,可来回切换“工作模式”与“测试模式” *
* 注意:每一个功能不可阻塞过多影响其他功能 *
* *
* *
**********************************************************************************************

*/

/**
* @brief 主函数
* @param 无
* @note 无
* @retval 无
*/

int main (void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
LED_GPIO_Config();
IDR_GPIO_Config();
NTC_GPIO_Config();
BEEP_GPIO_Config();
KEY_Init();

ProgramRunLed_TaskInit(500);
Idr_TaskInit(100);
Key_TaskInit(20);
Ntc_TaskInit(30);
SysTick_Init();

while(1)
{
/* 程序正常指示灯 */
ProgramRunLed_Task();

/* 外界光照环境感应灯 */
Idr_Task();

/* 按键长按解除报警 */
Key_Task();

/* 环境报警器 */
Ntc_Task();
}
}

2.LED

2.1 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脚 */

/***************核心板载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*/

2.2 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

}

/**
* @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 *********************************************************/

2.3 app_led.h

#ifndef __APP_LED_H
#define __APP_LED_H

#include "stm32f10x.h"

/*定义连接GPIO端口,用户只需要修改下面代码即可改变控制的LED引脚 */
typedef struct
{
uint32_t cycle; //周期
int32_t timer; //时间
uint8_t flag; //标志
}Led_TaskInfo; /*LED任务信息*/

extern Led_TaskInfo program_run_led_task;

void ProgramRunLed_TaskReset(void);
void ProgramRunLed_TaskInit(uint32_t program_run_led_task_cycle);
void ProgramRunLed_Task(void);

#endif /*__APP_LED_H*/

2.4 app_led.c

/**
******************************************************************************
* @file App_led.c
* @author 作者
* @version v1.0
* @date 2026.4.3
* @brief LED灯应用层功能接口
******************************************************************************
* @attention
*
* 版权声明
*
******************************************************************************
*/

#include "led/app_led.h"
#include "led/bsp_gpio_led.h"

/*初始化 程序运行LED任务 变量*/
Led_TaskInfo program_run_led_task = { 0 };

/**
* @brief 程序正常运行指示灯 计数复位
* @param 无
* @retval 无
*/

void ProgramRunLed_TaskReset(void)
{
program_run_led_task.timer = program_run_led_task.cycle;
program_run_led_task.flag = 0;
}

/**
* @brief 程序正常运行指示灯 任务初始化
* @param program_run_led_task_cycle: 任务周期 单位ms(可修改系统节拍定时器)
* @retval 无
*/

void ProgramRunLed_TaskInit(uint32_t program_run_led_task_cycle)
{
program_run_led_task.cycle = program_run_led_task_cycle;
ProgramRunLed_TaskReset();
}

/**
* @brief 程序正常运行指示灯 任务
* @param 无
* @retval 无
*/

void ProgramRunLed_Task(void)
{
if (program_run_led_task.flag == 1)
{
LED_TOGGLE(G_LED2_GPIO_PORT, G_LED2_GPIO_PIN);
ProgramRunLed_TaskReset();
}
}
/***************************************END OF FILE *********************************************************/

3.定时器中断与外部中断

3.1 bsp_systick.h

#ifndef __BSP_SYSTICK_H
#define __BSP_SYSTICK_H

#include "stm32f10x.h"

void SysTick_Init(void);
void SysTick_CountPlus(void);
uint64_t SysTick_GetCount(void);
void SysTick_DelayMS(uint64_t time);
#endif /*__BSP_SYSTICK_H*/

3.2 bsp_systick.c

/**
******************************************************************************
* @file bsp_gpio_systick.c
* @author 作者
* @version v1.0
* @date 2026.4.23
* @brief 系统定时器函数接口
******************************************************************************
* @attention
*
* 版权声明
*
******************************************************************************
*/

#include "systick/bsp_systick.h"

static uint64_t systick_count = 0;
/**
* @brief 初始化 SysTick (默认使用ms中断)
* @param 无
* @note 无
* @retval 无
*/

void SysTick_Init(void)
{
/*
SystemCoreClock / 1000 1ms中断一次
SystemCoreClock / 100000 10us中断一次
SystemCoreClock / 1000000 1us中断一次
*/

if (SysTick_Config(SystemCoreClock / 1000)) //1ms中断一次
{
while(1); //初始化失败后一直死循环在这,也可方便debug排查
}

// SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭定时器
}

/**
* @brief sysTick 循环计数函数
* @param 无
* @note 在 SysTick 中断函数 SysTick_Handler()内调用
* @retval 无
*/

void SysTick_CountPlus(void)
{
systick_count++;
}

/**
* @brief 查询当前 sysTick 循环计数的计数值
* @param 无
* @note 无
* @retval 当前 sysTick 循环计数的计数值
*/

uint64_t SysTick_GetCount(void)
{
return systick_count;
}

/**
* @brief systick 查询寄存器延时函数接口
* @param time:传入计数值
* @note 使用时开启Systick和配置对应计时频率 延时完毕后关闭, SysTick_Config()里默认开启了中断,但暂未在 SysTick 中断函数 SysTick_Handler()的函数体内写内容
* @retval 无
*/

void SysTick_DelayMS(uint64_t time)
{
uint64_t tick_start = SysTick_GetCount();
while(SysTick_GetCount() tick_start < time);
}
/***************************************END OF FILE *********************************************************/

3.3 stm32f10x_it.c

/**
******************************************************************************
* @file GPIO/IOToggle/stm32f10x_it.c
* @author MCD Application Team
* @version V3.6.0
* @date 20-September-2021
* @brief Main Interrupt Service Routines.
* This file provides template for all exceptions handler and peripherals
* interrupt service routine.
******************************************************************************
* @attention
*
* Copyright (c) 2011 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/

/* Includes ——————————————————————*/
#include "stm32f10x_it.h"
#include "key/bsp_gpio_key.h"
#include "systick/bsp_systick.h"
#include "main.h"

/** @addtogroup STM32F10x_StdPeriph_Examples
* @{
*/

/** @addtogroup GPIO_IOToggle
* @{
*/

/* Private typedef ———————————————————–*/
/* Private define ————————————————————*/
/* Private macro ————————————————————-*/
/* Private variables ———————————————————*/
/* Private function prototypes ———————————————–*/
/* Private functions ———————————————————*/

/******************************************************************************/
/* Cortex-M3 Processor Exceptions Handlers */
/******************************************************************************/

/**
* @brief This function handles NMI exception.
* @param None
* @retval None
*/

void NMI_Handler(void)
{
}

/**
* @brief This function handles Hard Fault exception.
* @param None
* @retval None
*/

void HardFault_Handler(void)
{
/* Go to infinite loop when Hard Fault exception occurs */
while (1)
{
}
}

/**
* @brief This function handles Memory Manage exception.
* @param None
* @retval None
*/

void MemManage_Handler(void)
{
/* Go to infinite loop when Memory Manage exception occurs */
while (1)
{
}
}

/**
* @brief This function handles Bus Fault exception.
* @param None
* @retval None
*/

void BusFault_Handler(void)
{
/* Go to infinite loop when Bus Fault exception occurs */
while (1)
{
}
}

/**
* @brief This function handles Usage Fault exception.
* @param None
* @retval None
*/

void UsageFault_Handler(void)
{
/* Go to infinite loop when Usage Fault exception occurs */
while (1)
{
}
}

/**
* @brief This function handles SVCall exception.
* @param None
* @retval None
*/

void SVC_Handler(void)
{
}

/**
* @brief This function handles Debug Monitor exception.
* @param None
* @retval None
*/

void DebugMon_Handler(void)
{
}

/**
* @brief This function handles PendSV_Handler exception.
* @param None
* @retval None
*/

void PendSV_Handler(void)
{
}

/**
* @brief This function handles SysTick Handler.
* @param None
* @retval None
*/

void SysTick_Handler(void)
{
SysTick_CountPlus();
if (program_run_led_task.timer > 0x00)
{
program_run_led_task.timer;
if (program_run_led_task.timer == 0)
{
program_run_led_task.flag = 1;
}
}

if (idr_led_task.timer > 0x00)
{
idr_led_task.timer;
if (idr_led_task.timer == 0)
{
idr_led_task.flag = 1;
}
}
if (key_task.timer > 0x00)
{
key_task.timer;
if (key_task.timer == 0)
{
key_task.flag = 1;
}
}

if (alarm_task.timer > 0x00)
{
alarm_task.timer;
if (alarm_task.timer == 0)
{
alarm_task.flag = 1;
}
}
}

/******************************************************************************/
/* STM32F10x Peripherals Interrupt Handlers */
/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */
/* available peripheral interrupt handler's name please refer to the startup */
/* file (startup_stm32f10x_xx.s). */
/******************************************************************************/

/**
* @brief This function handles PPP interrupt request.
* @param None
* @retval None
*/

/*void PPP_IRQHandler(void)
{
}*/

/**
* @brief This function handles KEY1 interrupt request.
* @param None
* @retval None
*/

void KEY1_EXTI_IRQHANDLER(void)
{
if (EXTI_GetITStatus(KEY1_EXTI_LINE) == SET)
{
/* 切换模式 非报警状态下才可以切换模式 */
if (alarm_task.state == NTC_NORMAL)
{
/*当前是工作模式*/
if (alarm_task.mode == NTC_RUNNING)
{
/* 从工作模式切换到测试模式 */
Ntc_RunningSwitchTesting();
}

/*当前是测试模式*/
else if (alarm_task.mode == NTC_TESTING)
{
/*从测试模式切换到工作模式*/
Ntc_TestingSwitchRunning();
}
}
EXTI_ClearITPendingBit(KEY1_EXTI_LINE);
}

}

/**
* @}
*/

/**
* @}
*/

4. 按键

4.1 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脚 */

#define KEY1_EXTI_PortSource GPIO_PortSourceGPIOA /*端口源*/
#define KEY1_EXTI_PinSource GPIO_PinSource0 /*PIN脚源*/
#define KEY1_EXTI_LINE EXTI_Line0 /*外部中断线*/
#define KEY1_EXTI_IRQ EXTI0_IRQn /*外部中断向量号*/
#define KEY1_EXTI_IRQHANDLER EXTI0_IRQHandler /*中断处理函数*/

//KEY2
#define KEY2_GPIO_PORT GPIOC /* GPIO 端口 */
#define KEY2_GPIO_CLK_PORT RCC_APB2Periph_GPIOC /* GPIO 端口时钟 */
#define KEY2_GPIO_PIN GPIO_Pin_13 /* 对应PIN脚 */

#define KEY2_EXTI_PortSource GPIO_PortSourceGPIOC /*端口源*/
#define KEY2_EXTI_PinSource GPIO_PinSource13 /*PIN脚源*/
#define KEY2_EXTI_LINE EXTI_Line13 /*外部中断线*/
#define KEY2_EXTI_IRQ EXTI15_10_IRQn /*外部中断向量号*/
#define KEY2_EXTI_IRQHANDLER EXTI15_10_IRQHandler /*中断处理函数*/

/**********************用户自定义按键****************************************/
//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_GENERAL_TRIGGER = 2,
}KEY_TriggerLevel;

/* 按键的状态 */
typedef enum {
KEY_UP = 0,
KEY_DOWN = 1,
KEY_INIT = 2,
}KEY_Status;

/* 按键的事件类型 */
typedef enum {
EVENT_ATTONITY = 0, /* 空闲状态 */
EVENT_PRESS = 1, /* 按下状态 */
EVENT_SHORT = 2, /* 短按状态 */
EVENT_SHORT_RELEASE = 3, /* 短按释放状态 */
EVENT_LONG = 4, /* 长按状态 */
EVENT_LONG_RELEASE = 5, /* 长按释放状态 */
}KEY_Evnet;

/* 按键的点击类型 */
typedef enum {
KEY_NONE_CLICK = 0,
KEY_SINGLE_CLICK = 1, /*单击*/
KEY_DOUBLE_CLICK = 2, /*双击*/
KEY_LONG_CLICK = 3, /*按键长按*/
}KEY_ClickType;

/* 按键结构体 */
typedef struct
{
GPIO_TypeDef* GPIOx;
uint16_t GPIO_Pin;
KEY_TriggerLevel triggerLevel; /* 按下时电平状态 */
KEY_Status status; /* 按键的状态 */
uint64_t press_time; /* 按下时间 */
uint64_t release_time; /* 释放时间 */
KEY_Evnet evnet; /* 按键事件 */
KEY_ClickType clicktype; /* 按键点击类型 */
}KEY_Info;

extern KEY_Info key1_info;
extern KEY_Info key2_info;

void KEY_GPIO_Config(void);
KEY_Status KEY_Scan(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, KEY_TriggerLevel key_pressstatus);
void KeyLevel_Init(KEY_Info* key_info);
void KEY_Init(void);
KEY_Evnet KEY_SystickScan(KEY_Info* key_info);
#endif /*__BSP_GPIO_KEY_H*/

4.2 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"
#include "systick/bsp_systick.h"

KEY_Info key1_info = { KEY1_GPIO_PORT, KEY1_GPIO_PIN, KEY_GENERAL_TRIGGER, KEY_INIT, 0,0,EVENT_ATTONITY,KEY_NONE_CLICK};
KEY_Info key2_info = { KEY2_GPIO_PORT, KEY2_GPIO_PIN, KEY_GENERAL_TRIGGER, KEY_INIT, 0,0,EVENT_ATTONITY,KEY_NONE_CLICK};

/**
* @brief 配置 KEY 中断配置
* @param 无
* @retval 无
*/

void KEY_NVIC_Config()
{
// 定义一个 NVIC 结构体
NVIC_InitTypeDef nvic_initstauct = { 0 };

/* 开启 AFIO 相关时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

#if 1
/*配置中断源*/
nvic_initstauct.NVIC_IRQChannel = KEY1_EXTI_IRQ;
/*配置抢占优先级*/
nvic_initstauct.NVIC_IRQChannelPreemptionPriority = 1;
/*配置响应优先级*/
nvic_initstauct.NVIC_IRQChannelSubPriority = 0;
/*开启中断*/
nvic_initstauct.NVIC_IRQChannelCmd = ENABLE;

// 把配置写入硬件,生效
NVIC_Init(&nvic_initstauct);
#endif

#if 0
/*配置中断源*/
nvic_initstauct.NVIC_IRQChannel = KEY2_EXTI_IRQ;
/*配置抢占优先级*/
nvic_initstauct.NVIC_IRQChannelPreemptionPriority = 1;
/*配置响应优先级*/
nvic_initstauct.NVIC_IRQChannelSubPriority = 0;
/*开启中断*/
nvic_initstauct.NVIC_IRQChannelCmd = ENABLE;

// 把配置写入硬件,生效
NVIC_Init(&nvic_initstauct);
#endif
}

/**
* @brief 配置 KEY 模式
* @param 无
* @retval 无
*/

void KEY_Mode_Config(void)
{
/* 定义一个 EXTI 结构体 */
EXTI_InitTypeDef exti_initstauct = { 0 };
/* 开启 AFIO 相关时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

#if 1

/*选择中断信号源*/
GPIO_EXTILineConfig(KEY1_EXTI_PortSource, KEY1_EXTI_PinSource);

/* 1. 选择EXTI线0(对应PA0、PB0等引脚) */
exti_initstauct.EXTI_Line = KEY1_EXTI_LINE;
/* 2. 模式:中断模式 */
exti_initstauct.EXTI_Mode = EXTI_Mode_Interrupt;
/* 3. 触发:下降沿触发(按键按下常用) */
exti_initstauct.EXTI_Trigger = EXTI_Trigger_Falling;
/* 4. 开启外部中断 */
exti_initstauct.EXTI_LineCmd = ENABLE;

EXTI_Init(&exti_initstauct);
#endif

#if 0
/*选择中断信号源*/
GPIO_EXTILineConfig(KEY2_EXTI_PortSource, KEY2_EXTI_PinSource);
/* 1. 选择EXTI线0(对应PA0、PB0等引脚) */
exti_initstauct.EXTI_Line = KEY2_EXTI_LINE;
/* 2. 模式:中断模式 */
exti_initstauct.EXTI_Mode = EXTI_Mode_Interrupt;
/* 3. 触发:下降沿触发(按键按下常用) */
exti_initstauct.EXTI_Trigger = EXTI_Trigger_Falling;
/* 4. 开启外部中断 */
exti_initstauct.EXTI_LineCmd = ENABLE;

EXTI_Init(&exti_initstauct);
#endif

}

/**
* @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 0

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 0

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 0

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 0

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_TriggerLevel 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;
}
}

/**
* @brief 获取当前操作按键电平
* @param key_info: 操作按键的信息结构体
* @note 无
* @retval 当前操作按键的电平
*/

static uint8_t Get_KeyCurrentLevel(KEY_Info* key_info)
{
return GPIO_ReadInputDataBit(key_info->GPIOx, key_info->GPIO_Pin);
}

/**
* @brief 获取当前操作按键空闲/抬起后的电平
* @param key_info: 操作按键的信息结构体
* @note 无
* @retval 无
*/

void KeyLevel_Init(KEY_Info* key_info)
{
if (key_info->triggerLevel == KEY_GENERAL_TRIGGER)
{
/* 上电后程序启动短时间内默认按键未按,那么根据当前未按下电平,反推出按下的电平*/
/* 设置按键按下后电平状态是高电平 */
key_info->triggerLevel = Get_KeyCurrentLevel(key_info)? KEY_LOW_TRIGGER : KEY_HIGH_TRIGGER;

}
}

/**
* @brief 按键初始化
* @param 无
* @retval 无
*/

void KEY_Init(void)
{
/* 对应的 GPIO 配置 */
KEY_GPIO_Config();

/*按键电平初始化*/
//KeyLevel_Init(&key1_info);
KeyLevel_Init(&key2_info);

/* 配置KEY 中断配置 */
KEY_NVIC_Config();

/*配置 KEY 模式*/
KEY_Mode_Config();
}

/**
* @brief 使用定时器扫描方式获取当前操作按键的事件类型
* @param key_info: 操作按键信息的结构体
* @note 无
* @retval 按键事件类型
*/

KEY_Evnet KEY_SystickScan(KEY_Info* key_info)
{
uint64_t time_time = 0;
/* 读取按键GPIO电平状态 与 按下后GPIO电平状态一致*/
if (Get_KeyCurrentLevel(key_info) == key_info->triggerLevel)
{
key_info->status = KEY_DOWN;
}
else
{
key_info->status = KEY_UP;
}

switch(key_info->evnet)
{
case EVENT_ATTONITY: /* 上一个事件处于 空闲/无操作 时 */
if (key_info->status == KEY_DOWN)
{
key_info->evnet = EVENT_PRESS;
key_info->press_time = SysTick_GetCount();
}
break;

case EVENT_PRESS: /* 上一个事件处于 按键按下 时 */
if (key_info->status == KEY_DOWN)
{
time_time = SysTick_GetCount();
/*按下时间超过自定义长按时间 还继续按下时 属于长按*/
if (time_time key_info->press_time > 1000)
{
key_info->evnet = EVENT_LONG; /* 进入长按事件 */
}

}
else
{
key_info->evnet = EVENT_SHORT; /* 进入短按事件 */
}
break;

case EVENT_SHORT:
/*上一轮返回EVENT_SHORT,无进阶事件,重回EVENT_ATTONITY*/
key_info->evnet = EVENT_SHORT_RELEASE;

/*按键单击*/
//key_info->clicktype = KEY_SINGLE_CLICK;
break;

case EVENT_LONG:
if (key_info->status == KEY_DOWN)
{
key_info->evnet = EVENT_LONG; /* 保持长按事件 */
}
else
{
/*上一轮返回EVENT_LONG,无进阶事件,重回EVENT_ATTONITY*/
key_info->evnet = EVENT_LONG_RELEASE;

/*按键长击*/
// key_info->clicktype = KEY_LONG_CLICK;
}
break;

default:
key_info->evnet = EVENT_ATTONITY;
}
return key_info->evnet;
}
/***************************************END OF FILE *********************************************************/

4.3 app_key.h

#ifndef __APP_KEY_H
#define __APP_KEY_H

#include "stm32f10x.h"

/*定义连接GPIO端口,用户只需要修改下面代码即可改变控制的LED引脚 */
typedef struct
{
uint32_t cycle; //周期
int32_t timer; //时间
uint8_t flag; //标志
}Key_TaskInfo; /*按键任务信息*/

extern Key_TaskInfo key_task;

void Key_TaskReset(void);
void Key_TaskInit(uint32_t key_task_cycle);
void Key_Task(void);

#endif /*__APP_LED_H*/

4.4 app_key.c

/**
******************************************************************************
* @file App_key.c
* @author 作者
* @version v1.0
* @date 2026.4.3
* @brief 按键应用层功能接口
******************************************************************************
* @attention
*
* 版权声明
*
******************************************************************************
*/

#include "ntc/app_ntc.h"
#include "key/app_key.h"
#include "led/bsp_gpio_led.h"
#include "key/bsp_gpio_key.h"
#include "beep/bsp_gpio_beep.h"

/*初始化 按键任务 变量*/
Key_TaskInfo key_task = { 0 };

/**
* @brief 按键 计数复位
* @param 无
* @retval 无
*/

void Key_TaskReset(void)
{
key_task.timer = key_task.cycle;
key_task.flag = 0;
}

/**
* @brief 按键 任务初始化
* @param key_task_cycle: 任务周期 单位ms(可修改系统节拍定时器)
* @retval 无
*/

void Key_TaskInit(uint32_t key_task_cycle)
{
key_task.cycle = key_task_cycle;
Key_TaskReset();
}

/**
* @brief 按键 任务
* @param 无
* @retval 无
*/

void Key_Task(void)
{
if (key_task.flag == 1)
{
KEY_Evnet current_event;
current_event = KEY_SystickScan(&key2_info);

/* 长按释放 */
if (current_event == EVENT_LONG_RELEASE)
{
/*工作模式*/
if (alarm_task.mode == NTC_RUNNING)
{
/* 报警状态下才能解除 */
if (alarm_task.state == NTC_OVERHEAT)
{
/* 设备正常状态*/

/* 复位到正常状态 */
Ntc_ReleaseAlarm();
}
}
}

Key_TaskReset();
}
}
/***************************************END OF FILE *********************************************************/

5.光敏传感器

5.1 bsp_gpio_idr.h

#ifndef __BSP_GPIO_IDR_H
#define __BSP_GPIO_IDR_H

#include "stm32f10x.h"

/*定义连接GPIO端口,用户只需要修改下面代码即可改变控制的LED引脚 */

//idr_D0
#define IDR_GPIO_PORT GPIOA /* GPIO 端口 */
#define IDR_GPIO_CLK_PORT RCC_APB2Periph_GPIOA /* GPIO 端口时钟 */
#define IDR_GPIO_PIN GPIO_Pin_11 /* 对应PIN脚 */

void IDR_GPIO_Config(void);
BitAction IDR_Scan(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

#endif /*__BSP_GPIO_IDR_H*/

5.2 bsp_gpio_idr.c

/**
******************************************************************************
* @file bsp_gpio_idr.c
* @author 作者
* @version v1.0
* @date 2026.4.3
* @brief 光敏传感器的函数接口
******************************************************************************
* @attention
*
* 版权声明
*
******************************************************************************
*/

#include "idr/bsp_gpio_idr.h"

/**
* @brief 初始化控制 光敏传感器 的IO
* @param 无
* @retval 无
*/

void IDR_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct = { 0 };

/*****************************核心板载按键****************************************/

#if 1
/*开启GPIOA 端口时钟*/
RCC_APB2PeriphClockCmd(IDR_GPIO_CLK_PORT, ENABLE);

/*设置PA11端口初始化高电平*/
GPIO_SetBits(IDR_GPIO_PORT, IDR_GPIO_PIN);

// 配置引脚:选择GPIOA的Pin1
GPIO_InitStruct.GPIO_Pin = IDR_GPIO_PIN;
// 配置输出速度:50MHz
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
// 配置工作模式:浮空输入模式
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_Init(IDR_GPIO_PORT, &GPIO_InitStruct);
#endif

}
/**
* @brief 光敏传感检测
* @param GPIOX : x可以是 A,B,C等
* @param GPIO_PIN: 待操作的PIN
* @retval BitAction枚举类型 有两个成员Bit_SET = 1和Bit_RESET = 0
* @retval Bit_SET(外界光照弱)、Bit_RESET(外界光照强)
*/

BitAction IDR_Scan(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
if (GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == Bit_RESET)
{
return Bit_RESET;
}
else
{
return Bit_SET;
}
}

/***************************************END OF FILE *********************************************************/

5.3 app_idr.h

#ifndef __APP_IDR_H
#define __APP_IDR_H

#include "stm32f10x.h"

/*定义连接GPIO端口,用户只需要修改下面代码即可改变控制的LED引脚 */
typedef struct
{
uint32_t cycle; //周期
int32_t timer; //时间
uint8_t flag; //标志
char device_id[10]; //设备ID
}Idr_TaskInfo; /*光敏任务信息*/

extern Idr_TaskInfo idr_led_task;

void Idr_TaskReset(void);
void Idr_TaskInit(uint32_t idr_led_task_cycle);
void Idr_Task(void);

#endif /*__APP_IDR_H*/

5.4 app_idr.c

/**
******************************************************************************
* @file App_idr.c
* @author 作者
* @version v1.0
* @date 2026.4.3
* @brief 光敏传感器应用层功能接口
******************************************************************************
* @attention
*
* 版权声明
*
******************************************************************************
*/

#include "idr/app_idr.h"
#include "idr/bsp_gpio_idr.h"
#include "led/bsp_gpio_led.h"

/*初始化 光敏传感器任务 变量*/
Idr_TaskInfo idr_led_task = { 0 };

/**
* @brief 外界光照感应灯 计数复位
* @param 无
* @retval 无
*/

void Idr_TaskReset(void)
{
idr_led_task.timer = idr_led_task.cycle;
idr_led_task.flag = 0;
}

/**
* @brief 外界光照感应灯 任务初始化
* @param program_run_led_task_cycle: 任务周期 单位ms(可修改系统节拍定时器)
* @retval 无
*/

void Idr_TaskInit(uint32_t idr_led_task_cycle)
{
idr_led_task.cycle = idr_led_task_cycle;
Idr_TaskReset();
}

/**
* @brief 外界光照感应灯 任务
* @param 无
* @retval 无
*/

void Idr_Task(void)
{
if (idr_led_task.flag == 1)
{
/*光照强*/
if (IDR_Scan(IDR_GPIO_PORT, IDR_GPIO_PIN) == Bit_RESET)
{
LED_GPIO_OFF(LED4_GPIO_PORT, LED4_GPIO_PIN, LED_LOW_TRIGGER);
}
else/*光照弱*/
{
LED_GPIO_ON(LED4_GPIO_PORT, LED4_GPIO_PIN, LED_LOW_TRIGGER);
}

Idr_TaskReset();
}
}
/***************************************END OF FILE *********************************************************/

6.热敏传感器

6.1 bsp_gpio_ntc.h

#ifndef __BSP_GPIO_NTC_H
#define __BSP_GPIO_NTC_H

#include "stm32f10x.h"

/*定义连接GPIO端口,用户只需要修改下面代码即可改变控制的LED引脚 */

//NTC_D0
#define NTC_GPIO_PORT GPIOA /* GPIO 端口 */
#define NTC_GPIO_CLK_PORT RCC_APB2Periph_GPIOA /* GPIO 端口时钟 */
#define NTC_GPIO_PIN GPIO_Pin_12 /* 对应PIN脚 */

void NTC_GPIO_Config(void);
BitAction NTC_Scan(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

#endif /*__BSP_GPIO_NTC_H*/

6.2 bsp_gpio_ntc.c

/**
******************************************************************************
* @file bsp_gpio_ntc.c
* @author 作者
* @version v1.0
* @date 2026.4.3
* @brief 热敏传感器的函数接口
******************************************************************************
* @attention
*
* 版权声明
*
******************************************************************************
*/

#include "ntc/bsp_gpio_ntc.h"

/**
* @brief 初始化控制 光敏传感器 的IO
* @param 无
* @retval 无
*/

void NTC_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct = { 0 };

/*****************************核心板载按键****************************************/

#if 1
/*开启GPIOA 端口时钟*/
RCC_APB2PeriphClockCmd(NTC_GPIO_CLK_PORT, ENABLE);

/*设置PA12端口初始化高电平*/
GPIO_SetBits(NTC_GPIO_PORT, NTC_GPIO_PIN);

// 配置引脚:选择GPIOA的Pin12
GPIO_InitStruct.GPIO_Pin = NTC_GPIO_PIN;
// 配置输出速度:50MHz
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
// 配置工作模式:浮空输入模式
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_Init(NTC_GPIO_PORT, &GPIO_InitStruct);
#endif

}
/**
* @brief 热敏传感检测
* @param GPIOX : x可以是 A,B,C等
* @param GPIO_PIN: 待操作的PIN
* @retval BitAction枚举类型 有两个成员Bit_SET = 1和Bit_RESET = 0
* @retval Bit_SET(外界温度弱)、Bit_RESET(外界温度高)
*/

BitAction NTC_Scan(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
if (GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == Bit_RESET)
{
return Bit_RESET;
}
else
{
return Bit_SET;
}
}

/***************************************END OF FILE *********************************************************/

6.3 app_ntc.h

#ifndef __APP_NTC_H
#define __APP_NTC_H

#include "stm32f10x.h"

/* NTC运行时状态 */
typedef enum {
NTC_NORMAL = 0, //正常
NTC_OVERHEAT = 1, //过热
}Ntc_TempState;

/* NTC运行的模式 */
typedef enum {
NTC_RUNNING = 0, //工作模式
NTC_TESTING = 1, //测试模式
}Ntc_Mode;

/*定义连接GPIO端口,用户只需要修改下面代码即可改变控制的LED引脚 */
typedef struct
{
uint32_t cycle; //周期
int32_t timer; //时间
uint8_t flag; //标志
char device_id[10]; //设备ID
Ntc_TempState state; //运行状态
Ntc_Mode mode; //模式
}Ntc_TaskInfo; /*热敏任务信息*/

extern Ntc_TaskInfo alarm_task;

void Ntc_TaskReset(void);
void Ntc_TaskInit(uint32_t alarm_task_cycle);
void Ntc_Task(void);
void Ntc_TriggerAlarm(void);
void Ntc_ReleaseAlarm(void);
void Ntc_SetRunningMode(void);
void Ntc_SetTestingMode(void);
void Ntc_RunningSwitchTesting(void);
void Ntc_TestingSwitchRunning(void);

#endif /*__APP_NTC_H*/

6.4 app_ntc.c

/**
******************************************************************************
* @file App_ntc.c
* @author 作者
* @version v1.0
* @date 2026.4.3
* @brief 热敏传感器应用层功能接口
******************************************************************************
* @attention
*
* 版权声明
*
******************************************************************************
*/

#include "ntc/app_ntc.h"
#include "led/bsp_gpio_led.h"
#include "beep/bsp_gpio_beep.h"
#include "ntc/bsp_gpio_ntc.h"

/*初始化 热敏传感器报警任务 变量*/
Ntc_TaskInfo alarm_task = { 0 };

/**
* @brief 外界环境温度报警装置 计数复位
* @param 无
* @retval 无
*/

void Ntc_TaskReset(void)
{
alarm_task.timer = alarm_task.cycle;
alarm_task.flag = 0;
}

/**
* @brief 外界环境温度报警装置 任务初始化
* @param alarm_task_cycle: 任务周期 单位ms(可修改系统节拍定时器)
* @retval 无
*/

void Ntc_TaskInit(uint32_t alarm_task_cycle)
{
alarm_task.cycle = alarm_task_cycle;
Ntc_TaskReset();

/* 上电时候是不报警的状态 */
Ntc_ReleaseAlarm();

/*上电时候为工作模式 蓝灯常亮 */
Ntc_SetRunningMode();
}

/**
* @brief 外界环境温度报警装置 任务
* @param 无
* @retval 无
*/

void Ntc_Task(void)
{
if (alarm_task.flag == 1)
{
/* NTC扫描结果自动控制报警状态 */
//外界温度高
if (NTC_Scan(NTC_GPIO_PORT, NTC_GPIO_PIN) == Bit_RESET)
{
/* 设备报警状态 */
Ntc_TriggerAlarm();
}
else/*外界温度低*/
{
/*测试模式才能执行自动解除报警*/
if (alarm_task.mode == NTC_TESTING)
{
/* 设备正常状态 */
Ntc_ReleaseAlarm();
}
}
Ntc_TaskReset();
}
}

/**
* @brief 报警状态输出
* @param 无
* @retval Trigger:触发 Alarm:报警
*/

void Ntc_TriggerAlarm(void)
{
/* 红灯亮 */
LED_GPIO_ON(R_LED1_GPIO_PORT, R_LED1_GPIO_PIN, LED_LOW_TRIGGER);

/* 蜂鸣器报警 */
BEEP_GPIO_ON(BEEP_GPIO_PORT,BEEP_GPIO_PIN, BEEP_HIGH_TRIGGER);

/* 报警过热状态*/
alarm_task.state = NTC_OVERHEAT;
}

/**
* @brief 报警状态释放
* @param 无
* @retval Release:解除 Alarm:报警
*/

void Ntc_ReleaseAlarm(void)
{
/* 红灯灭 */
LED_GPIO_OFF(R_LED1_GPIO_PORT, R_LED1_GPIO_PIN, LED_LOW_TRIGGER);

/* 蜂鸣器解除报警 */
BEEP_GPIO_OFF(BEEP_GPIO_PORT,BEEP_GPIO_PIN, BEEP_HIGH_TRIGGER);

/* 解除报警状态,正常状态*/
alarm_task.state = NTC_NORMAL;
}

/**
* @brief 外界环境温度报警装置 切换到工作模式
* @param 无
* @retval Set:设置 Running: 运行 Mode:模式
*/

void Ntc_SetRunningMode(void)
{
/* 蓝灯亮 */
LED_GPIO_ON(B_LED3_GPIO_PORT, B_LED3_GPIO_PIN, LED_LOW_TRIGGER);

/* 工作模式 */
alarm_task.mode = NTC_RUNNING;
}

/**
* @brief 外界环境温度报警装置 切换到测试模式
* @param 无
* @retval Set:设置 Testing: 测试 Mode:模式
*/

void Ntc_SetTestingMode(void)
{
/* 蓝灯灭 */
LED_GPIO_OFF(B_LED3_GPIO_PORT, B_LED3_GPIO_PIN, LED_LOW_TRIGGER);

/* 测试模式 */
alarm_task.mode = NTC_TESTING;
}

/**
* @brief 外界环境温度报警装置 由工作模式切换到测试模式
* @param 无
* @retval Running:工作 Switch:选择 Testing: 测试
*/

void Ntc_RunningSwitchTesting(void)
{
/*当前是工作模式才能跳转到测试模式*/
if (alarm_task.mode == NTC_RUNNING)
{
/* 测试模式 */
Ntc_SetTestingMode();
}
}

/**
* @brief 外界环境温度报警装置 由测试模式切换到工作模式
* @param 无
* @retval Running:工作 Switch:选择 Testing: 测试
*/

void Ntc_TestingSwitchRunning(void)
{
/*当前是测试模式才能跳转到工作模式*/
if (alarm_task.mode == NTC_TESTING)
{
/* 工作模式 */
Ntc_SetRunningMode();
}
}

/***************************************END OF FILE *********************************************************/

7.蜂鸣器

7.1 bsp_gpio_beep.h

#ifndef __BSP_GPIO_BEEP_H
#define __BSP_GPIO_BEEP_H

#include "stm32f10x.h"

/*定义连接GPIO端口,用户只需要修改下面代码即可改变控制的LED引脚 */

//beep
#define BEEP_GPIO_PORT GPIOA /* GPIO 端口 */
#define BEEP_GPIO_CLK_PORT RCC_APB2Periph_GPIOA /* GPIO 端口时钟 */
#define BEEP_GPIO_PIN GPIO_Pin_6 /* 对应PIN脚 */

/* 蜂鸣器的IO电平 */
typedef enum {
BEEP_LOW_TRIGGER = 0,
BEEP_HIGH_TRIGGER = 1,
}BEEP_TriggerLever;

void BEEP_GPIO_Config(void);
void BEEP_GPIO_ON(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BEEP_TriggerLever beep_soundsstatus);
void BEEP_GPIO_OFF(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BEEP_TriggerLever beep_soundsstatus);
void BEEP_TOGGLE(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

#endif /*__bsp_gpio_beep_H*/

7.2 bsp_gpio_beep.c

/**
******************************************************************************
* @file bsp_gpio_beep.c
* @author 作者
* @version v1.0
* @date 2026.4.3
* @brief 蜂鸣器的函数接口
******************************************************************************
* @attention
*
* 版权声明
*
******************************************************************************
*/

#include "beep/bsp_gpio_beep.h"

/**
* @brief 初始化控制 蜂鸣器 的IO
* @param 无
* @retval 无
*/

void BEEP_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct = { 0 };

/*****************************用户自定义beep*******************************/
#if 1

RCC_APB2PeriphClockCmd(BEEP_GPIO_CLK_PORT, ENABLE);

GPIO_ResetBits(BEEP_GPIO_PORT, BEEP_GPIO_PIN);

// 配置引脚:选择GPIOA的Pin6
GPIO_InitStruct.GPIO_Pin = BEEP_GPIO_PIN;
// 配置输出速度:50MHz
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
// 配置工作模式:推挽输出
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(BEEP_GPIO_PORT, &GPIO_InitStruct);
#endif

}

/**
* @brief 开启蜂鸣器
* @param GPIOX : x可以是 A,B,C等
* @param GPIO_PIN: 待操作的PIN
* @param beep_soundsstatuss 蜂鸣器响时的状态
* @retval 无
*/

void BEEP_GPIO_ON(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BEEP_TriggerLever beep_soundsstatus)
{
if (beep_soundsstatus == BEEP_LOW_TRIGGER)
{
GPIO_ResetBits(GPIOx, GPIO_Pin);
}
else
{
GPIO_SetBits(GPIOx, GPIO_Pin);
}
}

/**
* @brief 关闭蜂鸣器
* @param GPIOX : x可以是 A,B,C等
* @param GPIO_PIN: 待操作的PIN
* * @param beep_soundsstatuss 蜂鸣器不响时的状态
* @retval 无
*/

void BEEP_GPIO_OFF(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BEEP_TriggerLever beep_soundsstatus)
{
if (beep_soundsstatus == BEEP_LOW_TRIGGER)
{
GPIO_SetBits(GPIOx, GPIO_Pin);
}
else
{
GPIO_ResetBits(GPIOx, GPIO_Pin);
}
}

/**
* @brief 翻转对应 蜂鸣器
* @param GPIOX : x可以是 A,B,C等
* @param GPIO_PIN: 待操作的PIN
* @retval 无
*/

void BEEP_TOGGLE(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
GPIOx->ODR ^= GPIO_Pin;
}
/***************************************END OF FILE *********************************************************/

8.粗略阻塞延时

8.1 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*/

8.2 bsp_delay.c

/**
******************************************************************************
* @file bsp_delay.c
* @author 作者
* @version v1.0
* @date 2026.4.19
* @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.接线图

在这里插入图片描述

9.实验现象

环境报警设备1

环境报警设备2

环境报警设备3

工作模式,蓝灯常亮 功能1,用手触摸热敏传感器检测到温度,会滴滴叫红灯常亮,长按KEY2后释放,解除报警关闭红灯

按下按键1,进入测试模式,蓝灯灭 功能2,用手触摸热敏传感器检测到温度,会滴滴叫同时红灯亮,当热敏传感器温度消失,自动解除报警和红灯灭

功能3,光敏传感器当有光照的时候,白灯灭,当没有光照的时候白灯亮,光控灯

赞(0)
未经允许不得转载:171主机测评 » stm32F103C8T6标准库实验项目——环境报警设备2
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址