一、项目概述
1.1 项目功
-
温度读取:使用DS18B20传感器实时采集温度
-
温度显示:通过数码管显示当前温度(精确到0.1℃)
-
温度设置:设置温度上限和下限值(范围:10~70℃)
-
温度控制:根据温度值控制LED指示灯
-
错误检测:设置参数校验和错误提示
1.2 硬件配置
-
主控芯片:STC15F2K60S2(51单片机)
-
温度传感器:DS18B20(单线数字温度传感器)
-
输出设备:
-
8位数码管显示
-
4个LED指示灯(L1、L2、L3、L4)
-
-
输入设备:矩阵按键(模式切换、参数调节)
二、系统工作原理
2.2 系统工作流程
TEXT1启动 → 初始化DS18B20 → 延时750ms
2 ↓
3读取温度值(t) → 显示处理 → Led状态控制
4 ↓
5按键输入 → 温度参数设置与验证
6 ↓
7循环执行
8
2.3 温度范围划分
| 范围 | 条件 | LED状态 | LED_Pwm | 说明 |
|---|---|---|---|---|
| 高于上限 | t > t_Set_OK[0] | L1亮 | 3 | 温度过高 |
| 正常范围 | t_Set_OK[1] ≤ t ≤ t_Set_OK[0] | L2亮 | 6 | 温度正常 |
| 低于下限 | t < t_Set_OK[1] | L3亮 | 9 | 温度过低 |
| 错误操作 | Error_Flag=1 | L4亮 | - | 设置参数错误 |
三、核心数据结构
3.1 全局变量声明
C1//温度相关变量
2float t; // 实时温度值
3unsigned char t_Set[2]={30,20}; // 设置缓存 [0]=上限,[1]=下限
4unsigned char t_Set_OK[2]={30,20}; // 生效参数 [0]=上限,[1]=下限
5
6//显示相关变量
7unsigned char Seg_Buf[8]={...}; // 数码管数据缓存
8unsigned char Seg_Point[8]={...}; // 小数点控制
9unsigned char Seg_Mode; // 0=显示模式,1=设置模式
10unsigned char Seg_Pos; // 数码管扫描位置
11unsigned int Seg_Slow; // 数码管更新速度控制
12
13//LED控制变量
14unsigned char ucLed[8]; // LED状态数组
15unsigned char Led_Pwm; // LED亮度等级(0-10)
16unsigned char Led_Num; // LED PWM计数
17
18//按键相关变量
19unsigned char Key_Val, Key_Down, Key_Up, Key_Old;
20unsigned char Key_Slow; // 按键减速计数
21bit Key_Flag; // 长按标志
22unsigned int Key_Tick; // 按键计时
23
24//错误与标志
25bit Seg_Star_Flag; // 闪烁标志(500ms翻转)
26bit Error_Flag; // 错误标志
27unsigned int Timer_500ms; // 500ms计时器
28
四、按键功能模块
4.1 按键映射表
| 按键值 | 功能 | 说明 |
|---|---|---|
| 12 | 模式切换 | 显示模式 ↔ 设置模式 |
| 13 | 参数切换 | 上限 ↔ 下限 |
| 14 | 参数增加 | t_Set[index]++ |
| 15 | 参数减少 | t_Set[index]– |
| 16 | 恢复默认 | 重置为初始值 |
4.2 按键处理逻辑
短按 (Key_Tick ≤ 500ms)
C1按键按下 → 立即执行一次操作 → 按键抬起结束
2
长按 (Key_Tick > 500ms)
C1按键按下 → 500ms后开始连续执行 → 按键抬起结束
2
按键消抖机制
C1// 消抖算法:只检测按键状态变化
2Key_Down = Key_Val & (Key_Val ^ Key_Old); // 下降沿(按下)
3Key_Up = ~Key_Val & (Key_Val ^ Key_Old); // 上升沿(抬起)
4Key_Old = Key_Val; // 保存状态
5
6// 减速:每10ms采样一次
7if(Key_Slow) return;
8Key_Slow = 1; // 置位减速标志
9
4.3 温度参数设置流程
TEXT1模式切换(K12) → Seg_Mode=1(进入设置)
2 ↓
3参数编辑 ← K14增加 / K15减少 / K13切换上下限 →
4 ↓
5确认保存(K12) → 参数校验
6 ├─ 通过 → t_Set_OK[index] = t_Set[index] → Seg_Mode=0 → Error_Flag=0
7 └─ 失败 → 恢复原值 → Error_Flag=1 → 点亮L4
8
4.4 参数校验条件 (第109行、132行、148行)
C1// 校验条件:三个都满足才能保存
2if (t_Set[t_Set_Detex] <= 70 && // ① 不超过70℃
3 t_Set[t_Set_Detex] >= 10 && // ② 不低于10℃
4 t_Set[0] > t_Set[1]) // ③ 上限 > 下限
5{
6 Error_Flag = 0;
7 t_Set_OK[t_Set_Detex] = t_Set[t_Set_Detex];
8}
9else
10{
11 Error_Flag = 1;
12 t_Set[t_Set_Detex] = t_Set_OK[t_Set_Detex]; // 恢复原值
13}
14
五、数码管显示模块
5.1 显示模式切换
模式0:温度显示 (第187-195行)
C1┌─────────────────────────┐
2│ [11] - [ ] [ ] [ ] [T1][T0].[T-1] [11] │
3│ "℃" 熄灭 熄灭 熄灭 十 个 0.1℃ "℃" │
4└─────────────────────────┘
5
6例如:25.3℃ 显示为
7Seg_Buf: [11, 10, 10, 10, 2, 5, 3, 11]
8 [℃, -, -, -, 2, 5, ., 3℃]
9
代码实现:
C1Seg_Point[5] = 1; // 小数点在第5位
2Seg_Buf[0] = 11; // 摄氏度符号
3Seg_Buf[4] = (unsigned char)t / 10 % 10; // 十位
4Seg_Buf[5] = (unsigned char)t % 10; // 个位
5Seg_Buf[6] = (unsigned int)(t*10) % 10; // 小数位
6Seg_Buf[7] = 11; // 摄氏度符号
7
模式1:参数设置 (第197-210行)
C1┌─────────────────────────┐
2│ [12] [ ] [ ] [Max10][Max0] [13] [Min10][Min0] │
3│ "H" - - 最大值十 最大个 "━" 最小值十 最小个 │
4└─────────────────────────┘
5
6其中:
7• [12] = "H" 表示模式提示
8• [13] = "━" 分隔符
9• 闪烁显示当前编辑项
10
闪烁实现 (第207-208行):
C1// 每500ms翻转一次(Seg_Star_Flag)
2// 选中项显示数字,未选中显示10(熄灭)
3Seg_Buf[3*t_Set_Detex+3] = Seg_Star_Flag ? t_Set[t_Set_Detex]/10%10 : 10;
4Seg_Buf[3*t_Set_Detex+4] = Seg_Star_Flag ? t_Set[t_Set_Detex]%10 : 10;
5
5.2 数码管扫描机制
C1定时器每1ms中断一次
2 ↓
3Seg_Pos循环 0→1→2→3→4→5→6→7→0
4 ↓
5每8ms显示一位数字(8×1ms)
6 ↓
7人眼看起来 8 位全部点亮(动态显示)
8
六、LED指示灯控制模块
6.1 LED与温度的对应关系
C1void Led_Proc()
2{
3 // ① 驱动等级设置
4 if(t > t_Set_OK[0]) Led_Pwm = 3; // 高温
5 if(t < t_Set_OK[1]) Led_Pwm = 9; // 低温
6 if(t_Set_OK[1] <= t <= t_Set_OK[0]) Led_Pwm = 6; // 正常
7
8 // ② LED亮度控制(PWM方式)
9 // ...LED亮度通过PWM占空比控制(1/3、1/2、9/10)
10}
11
6.2 LED点亮逻辑
| LED | 表示 | 点亮条件 |
|---|---|---|
| L1 | 高温告警 | ucLed[0] = (t > t_Set_OK[0]) ? 1 : 0 |
| L2 | 温度正常 | ucLed[1] = ((t >= t_Set_OK[1]) && (t <= t_Set_OK[0])) ? 1 : 0 |
| L3 | 低温告警 | ucLed[2] = (t < t_Set_OK[1]) ? 1 : 0 |
| L4 | 错误操作 | ucLed[3] = Error_Flag |
PWM亮度调节机制 (第268-272行)
C1// 0~9循环计数,PWM周期为10ms
2if(++Led_Num == 10) Led_Num = 0;
3
4// 根据Led_Pwm占空比决定亮度
5if(Led_Num < Led_Pwm) // 占空比 = Led_Pwm/10
6{
7 Led_Disp(Seg_Pos, ucLed[Seg_Pos]); // 点亮LED
8}
9// 否则 LED 自动熄灭
10
11// 例如:Led_Pwm=6 → 占空比60% → 亮度为满亮的60%
12
七、定时器中断处理
7.1 定时器初始化 (第231-241行)
C1void Timer0_Init(void) // 1ms中断一次 @12MHz
2{
3 AUXR &= 0x7F; // 12T模式
4 TMOD &= 0xF0; // 定时器0模式2
5 TL0 = 0x18; // 装载初值
6 TH0 = 0xFC; // 装载初值
7 TF0 = 0; // 清除溢出标志
8 TR0 = 1; // 启动定时器
9 ET0 = 1; // 使能中断
10 EA = 1; // 全局中断使能
11}
12
13// 中断周期 = (256-0xFC18)*12/12MHz = 1ms
14
7.2 定时器中断服务函数 (第244-273行)
TEXT1每1ms进入中断一次
2 ├─ Key_Slow++ (每10ms采样一次按键)
3 ├─ Seg_Slow++ (每500ms更新一次显示)
4 ├─ Seg_Pos++ (动态扫描8位数码管,每125μs一位)
5 ├─ Timer_500ms++ (500ms闪烁计时)
6 ├─ Key_Tick++ (长短按判断计时)
7 └─ Led_Num++ (PWM计数)
8
具体计时:
| 计时器 | 周期 | 用途 |
|---|---|---|
| Key_Slow | 10ms | 按键减速采样 |
| Seg_Slow | 500ms | 数码管温度更新 |
| Timer_500ms | 500ms | 闪烁翻转 |
| Led_Num | 10ms(0~9) | LED PWM |
| Seg_Pos | 8ms(0~7) | 数码管扫描 |
八、DS18B20单线通信协议简介
8.1 OneWire协议特点
-
通信线数:仅1条数据线
-
传输方式:半双工同步通信
-
总线空闲:上拉电阻保持高电平
-
数据表示:
-
逻辑1:主机释放线路,从机在~60μs内发送
-
逻辑0:主机拉低线路60μs+
-
8.2 DS18B20温度读取流程
TEXT1┌────────────────────────────────────────────────┐
2│ DS18B20温度读取流程 │
3└────────────────────────────────────────────────┘
4
5① 初始化Reset
6 主机拉低线路480μs → 释放线路 → 从机在15~60μs拉低60~240μs
7
8② ROM指令(跳过)
9 发送 0xCC 字节 → 跳过ROM匹配
10
11③ 启动转换
12 发送 0x44 字节 → DS18B20开始温度转换
13
14④ 等待转换完成
15 根据分辨率延时 (12bit分辨率约750ms)
16
17⑤ 读取温度
18 发送 0xBE 字节 → 读取Scratchpad寄存器 (9字节)
19 └─ 字节0(LSB) + 字节1(MSB) = 16bit温度值
20
21⑥ 温度处理
22 温度值 = (MSB<<8) | LSB
23 实际温度 = 温度值 * 0.0625
24
8.3 温度数据格式 (12bit分辨率)
TEXT1 高字节(MSB) 低字节(LSB)
2┌─────────────┐ ┌─────────────┐
3│ S S S ℃℃℃℃ │ │ 0.5 0.25 0.125 0.0625 │
4│─── ────── │ │ ────────────── │
5└─────────────┘ └─────────────┘
6 符号 整数部分 小数部分
7
8例如:25.3℃
9• 整数部分:25 = 0x19
10• 小数部分:0.3 ≈ 0x5(0x0101 = 0.3125℃)
11• MSB = 0x19, LSB = 0x50
12• 温度值 = 0x1950 = 6480
13• 实际温度 = 6480 * 0.0625 = 25.3℃
14
九、程序执行流程
9.1 主程序流程 (main函数)
C1main()
2 ├─ re_tempterure() // ① 初始化DS18B20并读取一次温度
3 ├─ Delay750ms() // ② 等待750ms确保系统稳定
4 ├─ System_Init() // ③ 初始化GPIO、LED、数码管等
5 ├─ Timer0_Init() // ④ 启动定时器中断
6 └─ while(1) // ⑤ 主循环
7 ├─ Key_proc() // 按键处理(10ms执行一次)
8 ├─ Seg_Proc() // 显示处理(500ms更新一次)
9 └─ Led_Proc() // LED控制(实时执行)
10
9.2 时序关系
TEXT1主线程 中断线程(1ms)
2├─ Key_proc() ┌─ Key_Slow++
3├─ Seg_Proc() ←→ ├─ Seg_Slow++
4├─ Led_Proc() ├─ Timer_500ms++
5├─ ...等待 ├─ Key_Tick++
6└─ 循环 ├─ Led_Num++
7 └─ Seg_Pos++
8
学习重点总结
核心知识点
单线通信协议:掌握OneWire基本时序
定时器中断:理解多个计时器共存的设计
动态扫描显示:8位数码管分时复用显示
按键处理:消抖、短按、长按区分
参数验证:设置值与生效值的分离设计
状态机编程:显示模式与设置模式切换
PWM调光:LED亮度调节方法
调试技巧
-
温度显示不对:检查
re_tempterure()函数和DS18B20通信 -
按键无响应:检查
Key_Read()和中断是否启用 -
数码管显示错乱:检查Seg_Buf数组索引和扫描位置
-
LED闪烁:检查PWM占空比和计时器频率
-
参数无法保存:检查校验条件是否满足(第109行)
代码框架参考
C1// 完整程序框架
2#include <...> // 头文件
3
4// 全局变量(见第3.1节)
5
6// 各模块函数
7void Key_proc(); // 按键处理
8void Seg_Proc(); // 显示处理
9void Led_Proc(); // LED控制
10void Timer0_Init(); // 定时器初始化
11void Timer0_Server(); // 定时器中断服务
12
13void main()
14{
15 // 初始化阶段
16 re_tempterure();
17 Delay750ms();
18 System_Init();
19 Timer0_Init();
20
21 // 主循环:定时中断驱动
22 while(1)
23 {
24 Key_proc(); // 键盘驱动
25 Seg_Proc(); // 显示更新
26 Led_Proc(); // LED控制
27 }
28}
29
快速参考表
LED状态对应表
TEXT1温度 L1(高温) L2(正常) L3(低温) L4(错误)
2t>30℃ ✓ ✗ ✗ ✗
320≤t≤30℃ ✗ ✓ ✗ ✗
4t<20℃ ✗ ✗ ✓ ✗
5参数错误 ✗ ✗ ✗ ✓
6
按键功能速查
TEXT1K12: 显示 ↔ 设置(模式切换)
2K13: 上限 ↔ 下限(参数切换)
3K14: 参数 ++ (增加)
4K15: 参数 -- (减少)
5K16: 恢复默认值
6
定时器分频表
TEXT1定时器 周期 用途
2Key_Slow 10ms 按键采样
3Seg_Slow 500ms 温度更新
4Timer_500ms 500ms 闪烁翻转
5Led_Num 1~10ms LED PWM
6Seg_Pos 1~8ms 数码管扫描
7