一、项目概述
1.1 项目功能
基于 STM32F10x 单片机,结合4 独立按键、8 位共阴极数码管、AT24C02 IIC EEPROM、串口 1 打印实现带掉电保存的数值调节器:
- 上电自动读取 EEPROM 中存储的 0~255 数值,数码管百位、十位、个位实时显示;
- KEY1:进入设置模式;KEY2:数值 + 1;KEY3:数值 - 1;KEY4:退出设置模式;
- 数值限制区间
0 ~ 255,超出边界串口提示; - 每次修改数值自动写入 AT24C02,断电数据不丢失;
- 串口 9600 波特实时打印按键操作、数值、硬件检测状态;
- 硬件自检:上电循环检测 AT24C02,硬件异常持续打印报错,正常后进入主逻辑;
- 数码管动态消隐驱动,消除数字拖影,仅前 3 位显示 0~255,后 5 位熄灭。
1.2 硬件资源清单
表格
| 外设模块 | 功能 | 引脚资源 |
|---|---|---|
| SysTick | 毫秒 / 微秒延时、系统时钟 72M | 内核定时器 |
| 4 独立按键 | 模式切换、加减、确认退出 | GPIOA 上拉输入 |
| 8 位共阴极数码管 | 动态扫描显示 0~255 | PB0~PB7 段选;PA4/PA5/PA6 位选译码 |
| USART1 | 串口调试打印 | PA9(TX)、PA10(RX) |
| AT24C02 | 掉电存储数值,IIC 通信 | 自定义 SCL/SDA 引脚,软件模拟 IIC |
| NVIC | 中断优先级分组 2 | 系统中断配置 |
1.3 核心技术点
- 软件模拟标准 IIC 通信时序,兼容 AT24CXX 系列 EEPROM;
- 数码管动态扫描 + 段码消隐算法,解决残影问题;
- 独立按键松手检测 + 20ms 软件消抖,支持长按阻塞;
- EEPROM 上电自检、单字节读写,数据持久化;
- 状态机区分正常显示模式 / 参数设置模式;
- 宏常量统一管理硬件地址、阈值、延时,便于移植修改。
二、工程文件分层说明
plaintext
工程根目录 ├─ main.c 主业务逻辑(按键交互、显示、EEPROM读写、模式控制) ├─ key.h/.c 4路独立按键底层驱动 ├─ smg.h/.c 8位共阴极数码管动态扫描驱动 ├─ iic.h/.c 软件模拟IIC底层时序驱动 ├─ 24cxx.h 基于IIC封装AT24C02读写接口 ├─ SysTick.h 系统滴答定时器延时函数(ms/us) ├─ usart.h USART1串口初始化、printf重定向 └─ public.h 公共类型定义(u8/u16/u32)、硬件引脚宏定义三、各模块详细功能文档
模块 1:公共业务宏与常量定义(main.c 顶部)
3.1 业务宏说明
表格
| 宏名 | 数值 | 作用 |
|---|---|---|
| EEPROM_STORE_ADDR | 0 | AT24C02 内部存储地址,数值存在 0 号字节 |
| DATA_MAX_VAL | 255 | 计数最大值,单字节无符号上限 |
| DATA_MIN_VAL | 0 | 计数最小值 |
| SCAN_DELAY_MS | 10 | 主循环周期延时,控制按键扫描、刷新帧率 |
3.2 工具函数Num_To_Buf(u16 num, u8 buf[8])
功能:将 0~255 数字拆解为百位、十位、个位,填充数码管显示缓存,其余 5 位清零熄灭
- 入参:
num待转换数字;buf[8]8 位数码管显示缓存数组 - 执行逻辑:
- 全部 8 位缓存置 0,默认熄灭;
buf[2] = num / 100百位;buf[1] = (num%100)/10十位;buf[0] = num%10个位;- 仅前 3 位存储有效数字,动态显示时只扫描前 3 位。
3.3 硬件初始化函数Hardware_Init()
统一初始化所有外设,集中管理硬件启动流程:
- SysTick 滴答定时器初始化(72MHz 系统时钟);
- NVIC 中断优先级分组 2 配置;
- 数码管硬件初始化
SMG_Init(); - USART1 9600 波特串口初始化;
- 按键 GPIO 初始化
KEY_Init(); - IIC 总线 + AT24C02 硬件初始化
AT24CXX_Init()。
3.4 EEPROM 硬件自检EEPROM_DeviceCheck()
阻塞式硬件检测,防止 EEPROM 接线异常导致程序卡死:
- 循环调用
AT24CXX_CheckDevice()检测从机应答; - 无应答:串口打印报错,500ms 重试;
- 检测通过:打印正常提示,退出自检进入业务循环。
3.5 Main 主函数逻辑流程
flowchart TD A[外设统一初始化] --> B[循环检测AT24C02硬件] B --> C[上电读取EEPROM保存数值num_val] C --> D[进入while(1)死循环] D --> E[按键扫描key_scan(0)] E --> F{是否有按键按下} F --无--> G[填充显示缓存+刷新数码管] F --有--> H[switch按键分支处理] H --> H1[KEY1:set_mode=1 进入设置模式] H --> H2[KEY2:设置模式下数值+1,上限255,自动写EEPROM] H --> H3[KEY3:设置模式下数值-1,下限0,自动写EEPROM] H --> H4[KEY4:set_mode=0 退出设置模式] H1&H2&H3&H4 --> G G --> I[延时10ms,循环刷新] I --> D变量说明
disp_buf[8]:数码管显示缓存数组;keyVal:按键扫描返回值,无按键 = 0;num_val:全局计数值,0~255,与 EEPROM 实时同步;set_mode:模式状态标记,0 = 正常只读显示,1 = 可修改数值设置模式。
模块 2:按键驱动 key.c
2.1KEY_Init(void)
- 时钟:开启 KEY_PORT (GPIOA) 外设时钟;
- 引脚配置:KEY1/2/3/4 引脚配置为上拉输入 GPIO_Mode_IPU;
- 硬件逻辑:无按键时引脚高电平,按键按下拉低电平触发。
2.2u8 key_scan(u8 mode)独立按键扫描函数
参数:mode=0重置按键状态机;mode=1保持状态返回值:KEY_UNPRESS(0)无按键;KEY1_PRESS/KEY2_PRESS/KEY3_PRESS/KEY4_PRESS对应按键标识核心机制:状态机 + 松手阻塞消抖
- 静态变量
key_state:1 = 空闲可检测按键,0 = 按键消抖锁定; - 检测到低电平按键信号 → 20ms 软件消抖;
- 判断具体按键,进入
while(KEYx==0)阻塞循环,必须松手才退出; - 松手后再延时 20ms 消抖,恢复空闲检测状态;
- 多按键同时按下仅识别优先级靠前按键(KEY1>KEY2>KEY3>KEY4)。
模块 3:数码管驱动 smg.c
3.1 段码数组gsmg_code[17]
适配共阴极数码管标准段码,下标对应数字 0~15:0x3f(0),0x06(1),0x5b(2),0x4f(3),0x66(4),0x6d(5),0x7d(6),0x07(7),0x7f(8),0x6f(9)...
3.2SMG_Init(void)数码管硬件初始化
- 段选 PB0~PB7:推挽输出 50MHz,上电段码全 0(熄灭);
- 位选 PA4/PA5/PA6 (LSA/LSB/LSC):推挽输出,译码选择 8 位数码管;
- 初始化关闭所有位选,数码管全部熄灭,防止上电乱码。
3.3smg_display(u8 dat[],u8 scan_num)动态扫描显示函数
- 入参:
dat[]显示缓存;scan_num需要扫描的数码管位数(本项目传入 2,扫描前 3 位 0/1/2) - 消隐核心逻辑(解决动态扫描残影):
- 切换当前数码管位选;
- 先清空段码输出 0x00(消隐);