一、项目概述
本项目为宠物腹背理疗仪配套驱动板,基于PY32F002B单片机开发,核心功能是为理疗仪提供稳定的供电管理、理疗灯(红光+850nm红外)控制、人机交互(按键+数码管显示)及低功耗控制,适配中小型犬、成年猫的腹背理疗需求,可搭配充电宝或锂电池供电,实现居家便捷理疗。
项目核心适配硬件:118数码管(带闪电+%符号,0.25寸)、双路呼吸灯(对应660nm红光+850nm红外理疗灯)、Type-C充电接口、3.7V锂电池、2个实体按键(开关键+设置键),软件层面实现供电切换、电量检测、模式控制、低功耗唤醒等全流程功能,代码遵循模块化设计,兼顾稳定性与可维护性。

二、PY32F002B单片机外设资源说明
PY32F002B是普冉(Puya)推出的一款低成本、高性能8位/32位混合单片机,采用TSSOP20封装,核心外设资源完全匹配本项目需求,也是代码中所有外设调用的基础,重点资源如下(结合本项目实际使用场景说明):
-
时钟资源:内置HSI高速内部时钟(最高24MHz),支持时钟分频配置,本项目配置为24MHz,为所有外设提供稳定时钟。
-
GPIO端口:支持多组GPIO(PA、PB、PC),可配置为输入、输出、复用功能,本项目用于按键输入、数码管驱动、呼吸灯PWM输出、充电状态检测。
-
定时器:支持TIM1(高级定时器)、TIM14(通用定时器),其中TIM1用于输出双路PWM控制呼吸灯,TIM14用于1ms系统定时(实现按键扫描、数码管刷新、倒计时等)。
-
ADC模块:12位精度ADC,支持单次/连续采样,内置1.5V基准电压,本项目用于电池电压采样,进而计算电量百分比。
-
Flash存储:内置Flash,用于保存用户配置参数(呼吸灯工作时间、工作模式),实现掉电不丢失功能。
-
低功耗模式:支持STOP低功耗模式,可通过外部中断(按键)唤醒,降低设备待机功耗,延长锂电池续航。
-
中断控制器:支持外部中断(EXTI)、定时器中断,本项目用于按键唤醒、TIM14定时中断(系统计时)。
补充:本项目中单片机的核心外设调用逻辑------所有外设(GPIO、TIM、ADC等)均通过LL库(底层寄存器操作库)配置,代码中"LL_XXX"开头的函数均为单片机外设的底层操作函数,直接操作寄存器,效率高、占用资源少,适合低成本、低功耗场景。
三、main.h头文件解析
main.h作为整个项目的头文件,包含了系统宏定义、硬件引脚定义、结构体定义、外部函数声明四大核心内容,是main.c及其他模块代码的基础,所有全局变量、函数调用、硬件配置均依赖此头文件,以下逐部分解析(结合代码完整说明,适配不熟悉单片机的开发者)。
3.1 头文件基础配置
核心作用:防止头文件递归包含、引入所需的单片机底层库(LL库、HAL库),确保代码可正常编译,关键代码解析如下:
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
// 引入PY32F002B单片机底层LL库(核心,所有外设操作依赖)
#include "py32f002b_ll_rcc.h"
#include "py32f002b_ll_bus.h"
#include "py32f002b_ll_system.h"
#include "py32f002b_ll_cortex.h"
#include "py32f002b_ll_utils.h"
#include "py32f002b_ll_pwr.h"
#include "py32f002b_ll_gpio.h"
#include "py32f002b_ll_tim.h"
#include "py32f002b_ll_adc.h"
#include "py32f002b_hal_flash.h"
#include "py32f002b_ll_exti.h"
#include "py32f002b_ll_usart.h"
#include <stdbool.h>
#include <string.h>
#if defined(USE_FULL_ASSERT)
#include "py32_assert.h"
#endif /* USE_FULL_ASSERT */
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */
关键说明:
-
#ifndef __MAIN_H #define __MAIN_H #endif:头文件保护宏,防止多次引入同一头文件导致编译错误。 -
extern "C":兼容C++编译环境,确保C语言函数在C++环境中可正常调用(本项目为C语言开发,仅做兼容)。 -
LL库文件引入:
py32f002b_ll_xxx.h系列文件,是PY32F002B单片机的底层寄存器操作库,代码中所有"LL_XXX"开头的函数(如LL_GPIO_SetOutputPin)均来自这些库。
3.2 核心宏定义(项目配置核心,直接决定设备运行参数)
宏定义是代码中"可直接修改的配置项",无需修改函数逻辑,仅修改宏值即可调整设备功能,按功能分类解析如下:
3.2.1 系统状态与显示模式宏定义
/* ===================== 系统状态定义 ======================== */
//设置慢闪频率
#define LOW_FLASHPhase 500 //用于数码管闪烁提示(0.5s亮/0.5s灭,对应1Hz)
#define QUCK_FLASHPhase 50 //用户呼吸灯快闪模式(0.05s亮/0.05s灭,对应10Hz)
// 单片机工作模式:正常运行 / 低功耗休眠
#define SYS_STATE_SLEEP 0 // 低功耗休眠模式(关闭显示、PWM、ADC)
#define SYS_STATE_ACTIVE 1 // 正常工作模式
/* ===================== 显示模式定义 ======================== */
// 数码管当前显示什么内容
#define DISP_MODE_BATTERY 0 // 显示电池电量百分比(默认)
#define DISP_MODE_LED_MODE 1 // 显示呼吸灯当前模式(L1-L4)
#define DISP_MODE_TIMER_SET 2 // 显示呼吸灯定时时间(分钟)
#define DISP_MODE_COUNTDOWN 3 // 显示呼吸灯剩余工作时间(倒计时)
作用:用"数字常量"表示"状态",简化代码逻辑(如判断系统是否休眠,直接判断g_SystemState == SYS_STATE_SLEEP,比直接用0/1更易理解)。
3.2.2 呼吸灯模式与参数宏定义
/* ==================== 呼吸灯模式定义 ======================= */
#define LED_MODE_50_PERCENT 0 // 亮度 50% 常亮(对应L1)
#define LED_MODE_80_PERCENT 1 // 亮度 80% 常亮(对应L2)
#define LED_MODE_100_PERCENT 2 // 亮度 100% 常亮(对应L3)
#define LED_MODE_100_PERCENT_BLINK 3 // 100%亮度 + 10Hz 闪烁(对应L4)
#define LED_MODE_COUNT 4 // 呼吸灯总模式数
//呼吸灯百分比(对应PWM占空比,单位毫秒,数值越大亮度越高)
#define LED_PWM_L1 300 // 30%占空比(对应50%亮度)
#define LED_PWM_L2 500 // 50%占空比(对应80%亮度)
#define LED_PWM_L3 800 // 80%占空比(对应100%亮度)
#define LED_PWM_L4 999 // 99.9%占空比(对应100%亮度+闪烁)
关键说明:呼吸灯亮度由PWM占空比决定,宏定义中LED_PWM_L1~L4的数值,直接对应TIM1定时器输出PWM的占空比,修改这些数值可调整理疗灯亮度。
3.2.3 按键参数宏定义
/* ===================== 按键参数定义 ======================== */
#define KEY_LONG_PRESS_MS 1000 // 长按判定时间(1秒,长按开关键切换呼吸灯开关/休眠)
#define KEY_DEBOUNCE_MS 50 // 按键消抖时间(50ms,防止按键接触不良导致误触发)
#define KEY_DOUBLE_CLICK_MS 300 // 双击间隔(300ms内连续按2次为双击,本项目暂未使用)
作用:解决按键物理特性缺陷(如接触抖动),定义按键操作的判定标准,确保按键操作稳定。
3.2.4 ADC与电池参数宏定义
/* ===================== ADC检测参数定义 ======================== */
#define VREF_ADC 1500UL //使用内部基准1.5V电压进行ADC采样(PY32F002B内置)
//电池相关参数定义
#define V_BAT_FULL 4200 //设置满电电压(4.2V,3.7V锂电池标准满电电压)
#define V_BAT_LOW 3100 //设置欠压保护电压(3.1V,防止锂电池过放损坏)
/* ==================== 电池参数定义 ========================= */
#define VBAT_DIV_RATIO 3.55f // 电阻分压比(51K+20K,用于ADC采样电压换算)
#define VBAT_FULL_MV 4200 // 满电电压 4.2V(与V_BAT_FULL一致,冗余定义)
#define VBAT_EMPTY_MV 3100 // 低电保护电压 3.1V(与V_BAT_LOW一致)
#define VBAT_LOW_PERCENT 20 // 电量≤20%禁止开呼吸灯(本项目已去掉该限制)
// ================= 电压与充电优化宏定义 =================
#define ADC_FILTER_WINDOW 16 // ADC滤波窗口大小(16次采样取平均,降低采样噪声)
#define V_USB_THRESHOLD 4200 // USB判定阈值(mV),留50mV余量
#define CHARGING_TIMEOUT_H 8 // 充电超时时间(小时),防止充电芯片异常导致充不满
#define CHARGING_TIMEOUT_MS (CHARGING_TIMEOUT_H * 60 * 60 * 1000UL)
#define V_USB_PLUG_THRESHOLD 4300 // USB插入判定阈值(4.3V,区分USB供电与锂电池供电)
#define WAKEUP_KEY_MASK_MS 200 // 唤醒按键屏蔽时间(200ms,防止休眠唤醒误触发)
#define LUT_SIZE 11 // 锂电池放电曲线LUT表大小(用于电压换算电量百分比)
关键说明:
-
VREF_ADC 1500UL:PY32F002B内置1.5V基准电压,ADC采样时以此为基准,计算实际电池电压。 -
VBAT_DIV_RATIO 3.55f:电池电压通过电阻分压后输入ADC(避免电压过高损坏单片机),此值为分压比,用于将ADC采样值换算为实际电池电压。 -
ADC_FILTER_WINDOW 16:ADC采样16次取平均值,减少采样噪声,使电量显示更稳定。
3.2.5 硬件引脚定义(核心!关联代码与硬件)
此部分是代码与硬件连接的桥梁,定义了所有外设(按键、数码管、呼吸灯、ADC等)对应的单片机引脚,修改此部分需与硬件原理图完全一致,否则外设无法正常工作,关键定义如下:
/* ==================== 硬件引脚定义 ========================= */
// 开关机按键 K1 → PA0(GPIOA端口的0号引脚)
#define KEY_PWR_PIN LL_GPIO_PIN_0
#define KEY_PWR_PORT GPIOA
// 设置按键 K2 → PA1(GPIOA端口的1号引脚)
#define KEY_SET_PIN LL_GPIO_PIN_1
#define KEY_SET_PORT GPIOA
// 数码管5路驱动引脚 → PB4 PB3 PB2 PB1 PB0(GPIOB端口的0~4号引脚)
#define S1_PIN LL_GPIO_PIN_4
#define S1_PORT GPIOB
#define S2_PIN LL_GPIO_PIN_3
#define S2_PORT GPIOB
#define S3_PIN LL_GPIO_PIN_2
#define S3_PORT GPIOB
#define S4_PIN LL_GPIO_PIN_1
#define S4_PORT GPIOB
#define S5_PIN LL_GPIO_PIN_0
#define S5_PORT GPIOB
#define ALL_SEG_PINS (S1_PIN|S2_PIN|S3_PIN|S4_PIN|S5_PIN)
#define ALL_SEG_PORTS GPIOB
// 双路呼吸灯PWM → PA3 (pwm2)/ PA4(pwm1)(GPIOA端口3、4号引脚,复用为TIM1的PWM输出)
#define LED_PWM1_PIN LL_GPIO_PIN_4
#define LED_PWM1_PORT GPIOA
#define LED_PWM2_PIN LL_GPIO_PIN_3
#define LED_PWM2_PORT GPIOA
#define LED_PWM_TIM TIM1 // 呼吸灯PWM由TIM1定时器控制
#define LED_PWM_CH1 LL_TIM_CHANNEL_CH3 // PA4对应TIM1的CH3通道
#define LED_PWM_CH2 LL_TIM_CHANNEL_CH2 // PA3对应TIM1的CH2通道
//电压检测供电 PB5(GPIOB端口5号引脚,控制ADC电压检测的供电)
#define PWR_ADC_PIN LL_GPIO_PIN_5
#define PWR_ADC_PORT GPIOB
// 电池电压检测ADC → PA7(GPIOA端口7号引脚,复用为ADC采样引脚)
#define VBAT_ADC_PIN LL_GPIO_PIN_7
#define VBAT_ADC_PORT GPIOA
#define VBAT_ADC_CH LL_ADC_CHANNEL_4 // PA7对应ADC的4号通道
// 充电管理芯片LP4057状态引脚(检测充电状态)
#define CHRG_PIN LL_GPIO_PIN_1 // PC1=低 → 正在充电(GPIOC端口1号引脚)
#define CHRG_PORT GPIOC
#define FULL_PIN LL_GPIO_PIN_7 // PB7=高 → 电池充满(GPIOB端口7号引脚)
#define FULL_PORT GPIOB
/* ==================== 系统配置 ============================= */
#define AUTO_SLEEP_MS 10000 // 无操作10秒 → 自动休眠
#define FLASH_SAVE_ADDR 0x08003C00 // Flash存储地址(最后1K,用于保存参数)
补充说明:
-
LL_GPIO_PIN_0:表示GPIO引脚的编号,由LL库定义,对应单片机的物理引脚。 -
复用功能:如呼吸灯引脚(PA3、PA4),不仅是GPIO引脚,还复用为TIM1的PWM输出引脚,这也是代码中APP_TIM1_Init()函数配置的核心依据。
-
Flash存储地址
0x08003C00:PY32F002B的Flash总容量有限,此地址为Flash最后1K空间,用于保存用户配置(工作时间、模式),避免掉电丢失。
3.3 结构体类型定义(代码模块化的核心)
结构体用于"封装一组相关的数据",使代码更简洁、易维护,本项目核心结构体如下:
/* ==================== 结构体类型定义 ======================= */
/**
* @brief 按键状态机结构体
* @note 用于记录按键是否按下、按了多久、是否双击/长按
*/
typedef struct {
uint8_t state; // 按键当前状态 0=空闲 1=按下 2=等待双击
uint32_t press_tick; // 按键按下的时间点(对应g_SysTick)
uint32_t release_tick; // 按键松开的时间点(对应g_SysTick)
uint8_t click_count; // 记录点击次数(用于双击)
bool long_press; // 是否触发长按
} Key_Handle_t;
/**
* @brief 数码管段驱动结构体
* @note 5线数码管每次只亮一段 = 1个正极 + 1个负极
* @param a 正极IO编号(1~5 对应 S1~S5)
* @param c 负极IO编号(1~5 对应 S1~S5)
*/
typedef struct {
uint8_t a; // 正极
uint8_t c; // 负极
} Seg_t;
/**
* @brief Flash掉电存储结构体
* @note 关机后仍要保存的参数
*/
typedef struct {
uint16_t work_time; // 呼吸灯定时时间(分钟)
uint8_t led_mode; // 呼吸灯亮度模式
uint8_t crc; // 数据校验(防止数据出错)
} SaveData_t;
关键说明:
-
Key_Handle_t:用于实现按键状态机,记录按键的完整状态(按下、松开、长按等),避免按键误触发,代码中g_KeyPwr(开关键)、s_keySet(设置键)均为此类型。 -
Seg_t:适配5线数码管的驱动逻辑(每次仅点亮一段),通过"正极+负极"的组合,实现数码管数字、符号的显示,代码中SEG_DIG1_B、SEG_PERCENT等均为此类型。 -
SaveData_t:用于封装需要掉电保存的参数,写入Flash中,下次开机时读取,实现"参数记忆"功能(如用户设置的工作时间,关机后再次开机仍保留)。
3.4 外部全局变量与函数声明
核心作用:声明main.c中定义的全局变量和函数,使其他模块(若有)可调用这些变量和函数,确保代码模块化,关键内容如下:
/* ===================== 外部全局变量声明 ==================== */
// 这些变量在 main.c 中定义,头文件只做声明
extern uint8_t g_SystemState; // 系统状态:运行/休眠
extern uint8_t g_DispMode; // 显示模式:电量/灯模式/时间
extern uint32_t g_SysTick; // 系统毫秒计时(每1ms+1)
extern uint8_t g_BatPercent; // 电池电量百分比(0~100)
extern bool g_IsCharging; // 是否正在充电
extern bool g_IsFull; // 是否充满电
extern bool g_LedIsOn; // 呼吸灯是否开启
//锂电池放电曲线LUT表(典型值,可替换为实测数据)
extern const uint16_t BAT_LUT_VOLT[LUT_SIZE];
extern const uint8_t BAT_LUT_PERC[LUT_SIZE];
extern void APP_UART1_Init(void);
/* ===================== 外部函数声明 ======================== */
// 系统初始化
void APP_SystemClockConfig(void); // 配置系统时钟为24MHz
void APP_GPIO_Init(void); // 初始化所有GPIO(按键/数码管/PWM/ADC)
void APP_TIM1_Init(void); // 初始化TIM1 → 双路PWM驱动呼吸灯
void APP_TIM14_Init(void); // 初始化TIM14 → 1ms中断(扫描+计时)
void APP_ADC_Init(void); // 初始化ADC → 测量电池电压
uint16_t APP_ADC_GetValue(void); // 获取一次ADC采样值
// 数码管显示
void APP_Disp_Refresh(void); // 1ms刷新一次数码管(中断调用)
void APP_Disp_Update(void); // 更新要显示的数字内容
void APP_DriveSeg(Seg_t seg); // 驱动数码管的某一段
void APP_AllSegOff(void); // 关闭所有数码管段(休眠用)
// 功能控制
void APP_Key_Scan(void); // 按键扫描(10ms调用一次)
void APP_Vbat_Measure(void); // 测量电池电压并计算电量
void APP_Chrg_StatusCheck(void); // 检测是否充电/充满
void APP_LedControl(void); // 呼吸灯亮度/闪烁控制
void APP_EnterSleep(void); // 进入低功耗休眠模式
void APP_ExitSleep(void); // 退出休眠,恢复系统
void APP_SaveToFlash(void); // 保存参数到Flash(掉电不丢失)
void APP_LoadFromFlash(void); // 从Flash读取保存的参数
uint8_t APP_CalcBatPercent(uint16_t vbat_mv); //根据电池电压计算电量百分比(LUT线性插值)
// 错误处理
void APP_ErrorHandler(void); // 程序异常时进入死循环
关键说明:
-
extern关键字:表示变量/函数在其他文件(main.c)中定义,此处仅做声明,不能重复定义,否则会导致编译错误。 -
函数声明:所有在main.c中定义的函数(如APP_GPIO_Init()、APP_LedControl()),均需在此处声明,确保函数可被其他函数调用(如main()函数调用APP_SystemClockConfig())。
以上就是项目头文件的相关内容,篇幅优先,功能函数部分的介绍在下一篇文章中进行详细说明介绍了。