使用STM32操作独立按键控制 AT24C02 计数并用数码管显示

📅 2026/7/17 18:10:12 👁️ 阅读次数 📝 编程学习
使用STM32操作独立按键控制 AT24C02 计数并用数码管显示

一、项目概述

1.1 项目功能

基于 STM32F10x 单片机,结合4 独立按键、8 位共阴极数码管、AT24C02 IIC EEPROM、串口 1 打印实现带掉电保存的数值调节器:

  1. 上电自动读取 EEPROM 中存储的 0~255 数值,数码管百位、十位、个位实时显示;
  2. KEY1:进入设置模式;KEY2:数值 + 1;KEY3:数值 - 1;KEY4:退出设置模式;
  3. 数值限制区间0 ~ 255,超出边界串口提示;
  4. 每次修改数值自动写入 AT24C02,断电数据不丢失;
  5. 串口 9600 波特实时打印按键操作、数值、硬件检测状态;
  6. 硬件自检:上电循环检测 AT24C02,硬件异常持续打印报错,正常后进入主逻辑;
  7. 数码管动态消隐驱动,消除数字拖影,仅前 3 位显示 0~255,后 5 位熄灭。

1.2 硬件资源清单

表格

外设模块功能引脚资源
SysTick毫秒 / 微秒延时、系统时钟 72M内核定时器
4 独立按键模式切换、加减、确认退出GPIOA 上拉输入
8 位共阴极数码管动态扫描显示 0~255PB0~PB7 段选;PA4/PA5/PA6 位选译码
USART1串口调试打印PA9(TX)、PA10(RX)
AT24C02掉电存储数值,IIC 通信自定义 SCL/SDA 引脚,软件模拟 IIC
NVIC中断优先级分组 2系统中断配置

1.3 核心技术点

  1. 软件模拟标准 IIC 通信时序,兼容 AT24CXX 系列 EEPROM;
  2. 数码管动态扫描 + 段码消隐算法,解决残影问题;
  3. 独立按键松手检测 + 20ms 软件消抖,支持长按阻塞;
  4. EEPROM 上电自检、单字节读写,数据持久化;
  5. 状态机区分正常显示模式 / 参数设置模式
  6. 宏常量统一管理硬件地址、阈值、延时,便于移植修改。

二、工程文件分层说明

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_ADDR0AT24C02 内部存储地址,数值存在 0 号字节
DATA_MAX_VAL255计数最大值,单字节无符号上限
DATA_MIN_VAL0计数最小值
SCAN_DELAY_MS10主循环周期延时,控制按键扫描、刷新帧率
3.2 工具函数Num_To_Buf(u16 num, u8 buf[8])

功能:将 0~255 数字拆解为百位、十位、个位,填充数码管显示缓存,其余 5 位清零熄灭

  • 入参:num待转换数字;buf[8]8 位数码管显示缓存数组
  • 执行逻辑:
    1. 全部 8 位缓存置 0,默认熄灭;
    2. buf[2] = num / 100百位;buf[1] = (num%100)/10十位;buf[0] = num%10个位;
    3. 仅前 3 位存储有效数字,动态显示时只扫描前 3 位。
3.3 硬件初始化函数Hardware_Init()

统一初始化所有外设,集中管理硬件启动流程:

  1. SysTick 滴答定时器初始化(72MHz 系统时钟);
  2. NVIC 中断优先级分组 2 配置;
  3. 数码管硬件初始化SMG_Init()
  4. USART1 9600 波特串口初始化;
  5. 按键 GPIO 初始化KEY_Init()
  6. IIC 总线 + AT24C02 硬件初始化AT24CXX_Init()
3.4 EEPROM 硬件自检EEPROM_DeviceCheck()

阻塞式硬件检测,防止 EEPROM 接线异常导致程序卡死:

  1. 循环调用AT24CXX_CheckDevice()检测从机应答;
  2. 无应答:串口打印报错,500ms 重试;
  3. 检测通过:打印正常提示,退出自检进入业务循环。
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

变量说明

  1. disp_buf[8]:数码管显示缓存数组;
  2. keyVal:按键扫描返回值,无按键 = 0;
  3. num_val:全局计数值,0~255,与 EEPROM 实时同步;
  4. 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对应按键标识核心机制:状态机 + 松手阻塞消抖

  1. 静态变量key_state:1 = 空闲可检测按键,0 = 按键消抖锁定;
  2. 检测到低电平按键信号 → 20ms 软件消抖;
  3. 判断具体按键,进入while(KEYx==0)阻塞循环,必须松手才退出
  4. 松手后再延时 20ms 消抖,恢复空闲检测状态;
  5. 多按键同时按下仅识别优先级靠前按键(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)数码管硬件初始化
  1. 段选 PB0~PB7:推挽输出 50MHz,上电段码全 0(熄灭);
  2. 位选 PA4/PA5/PA6 (LSA/LSB/LSC):推挽输出,译码选择 8 位数码管;
  3. 初始化关闭所有位选,数码管全部熄灭,防止上电乱码。
3.3smg_display(u8 dat[],u8 scan_num)动态扫描显示函数
  • 入参:dat[]显示缓存;scan_num需要扫描的数码管位数(本项目传入 2,扫描前 3 位 0/1/2)
  • 消隐核心逻辑(解决动态扫描残影):
    1. 切换当前数码管位选;
    2. 先清空段码输出 0x00(消隐);