51单片机项目实战:用LCD12864自制一个温湿度计(带中文界面和自定义图标)
51单片机实战:打造智能温湿度监测仪(LCD12864中文界面+自定义图标全解析)
你是否想过用几块钱的单片机打造一个既实用又有科技感的桌面小设备?今天我们就用STC89C52单片机、LCD12864屏幕和DHT11传感器,实现一个带中文界面和自定义图标的温湿度监测仪。这个项目不仅能巩固你的单片机编程基础,还能掌握混合显示、图形自定义等进阶技能。
1. 硬件选型与电路设计
1.1 核心器件特性对比
我们先来看关键器件的选型要点:
| 器件 | 型号 | 工作电压 | 接口方式 | 关键特性 |
|---|---|---|---|---|
| 单片机 | STC89C52RC | 3.3-5.5V | 并行/串行 | 8K FlashROM,32个IO口 |
| LCD显示屏 | LCD12864 | 5V | 串行模式 | 支持GB2312字库,128x64分辨率 |
| 温湿度传感器 | DHT11 | 3-5.5V | 单总线 | 湿度±5%RH,温度±2℃精度 |
提示:LCD12864建议选用带中文字库的型号(如ST7920控制器),可省去字库芯片
1.2 电路连接示意图
典型接线方案如下:
// 51单片机引脚定义 sbit DHT11_PIN = P1^0; // 温湿度传感器数据线 sbit LCD_RS = P2^6; // LCD寄存器选择 sbit LCD_EN = P2^7; // LCD使能端 sbit LCD_PSB = P2^3; // 并行/串行模式选择(0:串行)实际连接时需注意:
- DHT11的数据线需要上拉电阻(4.7KΩ)
- LCD的V0引脚接电位器调节对比度
- 串行模式下只需连接SID、SCLK两根信号线
2. 中文显示原理与实现
2.1 字库调用机制
带中文字库的LCD12864内部存储了GB2312标准汉字(共7445个),每个汉字对应两个字节的区位码。例如"温"字的显示流程:
- 发送0x80设置显示地址
- 发送0xCEC2("温"的GB2312编码)
- 控制器自动从字库提取16x16点阵数据
显示混合内容的典型代码:
void ShowTemp(float temp) { LCD_SendCmd(0x80); // 第一行起始地址 LCD_SendData(0xCE); // "温" LCD_SendData(0xC2); LCD_SendData(':'); LCD_SendNumber(temp); // 自定义数字显示函数 LCD_SendData(0xA1); // ℃符号 LCD_SendData(0xE6); }2.2 自定义字符设计
除了标准汉字,我们还可以通过CGRAM定义5x8点阵的自定义图标:
// 定义水滴图标 unsigned char waterDrop[] = { 0x04, 0x04, 0x0A, 0x0A, 0x11, 0x11, 0x20, 0x1F }; void CreateCustomChar() { LCD_SendCmd(0x40); // 设置CGRAM地址 for(int i=0; i<8; i++) { LCD_SendData(waterDrop[i]); } }使用时通过LCD_SendData(0x00)调用第一个自定义字符。
3. 温湿度数据采集处理
3.1 DHT11通信协议解析
DHT11采用单总线协议,典型读取时序:
- 主机拉低总线18ms后释放
- 传感器响应80us低电平+80us高电平
- 40位数据格式:湿度整数+湿度小数+温度整数+温度小数+校验和
关键读取代码:
unsigned char ReadByte() { unsigned char data = 0; for(int i=0; i<8; i++) { while(!DHT11_PIN); // 等待50us低电平结束 Delay40us(); data <<= 1; if(DHT11_PIN) data |= 1; while(DHT11_PIN); // 等待高电平结束 } return data; }3.2 数据滤波算法
为提高显示稳定性,可采用滑动平均滤波:
#define FILTER_LEN 5 float tempBuffer[FILTER_LEN]; float FilterTemp(float newVal) { static int index = 0; float sum = 0; tempBuffer[index++] = newVal; if(index >= FILTER_LEN) index = 0; for(int i=0; i<FILTER_LEN; i++) { sum += tempBuffer[i]; } return sum/FILTER_LEN; }4. 系统整合与优化技巧
4.1 主程序架构设计
推荐采用模块化编程结构:
main.c ├─ 系统初始化 ├─ 定时器配置(1s中断) ├─ 主循环 ├─ 读取传感器(DHT11_Read) ├─ 数据处理(FilterTemp) ├─ 界面刷新(RefreshLCD)定时中断服务函数示例:
void Timer0_ISR() interrupt 1 { static unsigned int count = 0; TH0 = 0x3C; // 50ms定时 TL0 = 0xB0; if(++count >= 20) { // 1s更新 count = 0; needRefresh = 1; } }4.2 常见问题排查
- 显示乱码:检查字库编码是否正确,接线是否松动
- 数据读取失败:测量电源电压,确认上拉电阻正常
- 屏幕闪烁:优化刷新频率,避免频繁全屏刷新
实际调试中发现,DHT11对时序要求严格,延时代码需用示波器校准。建议将关键函数放在RAM中运行以提高速度:
#pragma OT(4, SPEED) void DHT11_Read() { // 严格时序要求的代码 }5. 功能扩展方向
完成基础功能后,可以尝试:
- 增加历史数据存储(使用24C02 EEPROM)
- 添加蜂鸣器报警功能
- 开发上位机通信接口(通过CH340G转USB)
- 设计3D打印外壳
一个实用的优化是添加温湿度限值提示:
void CheckLimit(float temp, float humi) { if(temp > 30.0) { LCD_SendCmd(0x90); // 第二行 LCD_SendString("高温警告!"); } }通过这个项目,你不仅能掌握51单片机的实际应用,还能深入理解嵌入式系统的设计思路。当看到自己制作的设备稳定显示"温度:26.5℃ 湿度:45%"时,那种成就感绝对值得投入这些时间。
