PY32F002B实践之二--宠物腹背理疗仪项目介绍及头文件解析

一、项目概述

本项目为宠物腹背理疗仪配套驱动板,基于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_BSEG_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())。

以上就是项目头文件的相关内容,篇幅优先,功能函数部分的介绍在下一篇文章中进行详细说明介绍了。

相关推荐
网域小星球4 小时前
C 语言从 0 入门(十四)|文件操作:读写文本、保存数据持久化
c语言·开发语言·文件操作·fopen·fprintf
网域小星球4 小时前
C 语言从 0 入门(七)|字符数组与字符串完整精讲|VS2022 高质量实战
c语言·开发语言·字符串·vs2022·字符数组
Jia ming4 小时前
C语言实现日期天数计算
c语言·开发语言·算法
浅时光_c6 小时前
12 指针
c语言·开发语言
爱编码的小八嘎6 小时前
C语言完美演绎7-11
c语言
爱编码的小八嘎6 小时前
C语言完美演绎7-9
c语言
范纹杉想快点毕业6 小时前
C语言全能实战教程
c语言·开发语言
ZK_H8 小时前
半导体工艺流程
java·c语言·开发语言·计算机网络·金融
网域小星球8 小时前
C语言从0入门(八)|函数基础:封装、调用与参数传递精讲
c语言·开发语言