基于 51 单片机的多功能嵌入式系统代码分析笔记
一、项目概述
本项目是一个基于 8051 单片机的嵌入式系统,实现了 UART 通信、LED 控制、数码管显示、蜂鸣器频率控制、DS18B20 温度传感器读取等多种功能。系统采用模块化设计,通过自定义的通信协议接收命令并执行相应操作。
二、核心模块分析
1. 主程序模块 (main.c)
通信协议格式
协议帧结构:AA ADDR FUNC DATA1 DATA2 SUM BB 字节位置: 0 1 2 3 4 5 6 长度:固定 7 字节 字段说明: AA:帧头 (0xAA) ADDR:设备地址 (0x01) FUNC:功能码 (1-4) DATA1:数据1(数码管位选/功能参数) DATA2:数据2(LED状态/数码管段选/蜂鸣器频率) SUM:校验和(前5字节累加和) BB:帧尾 (0xBB)
主要函数分析
1.1 数据解析函数parse()
int parse(void) { int ret = 0; int i = 0; unsigned char sum = 0; // 检查帧头和帧尾 if (recv_buffer[0] == 0xAA && recv_buffer[6] == 0xBB) { // 检查设备地址 if(recv_buffer[1] == DEV_ADDRESS) { // 计算校验和 for(i = 0; i < 5; i++) { sum += recv_buffer[i]; } // 验证校验和 if(sum == recv_buffer[5]) { ret = recv_buffer[2]; // 返回功能码 } } } return ret; }功能:验证接收数据的合法性,提取功能码
1.2 功能执行函数do_handler()
void do_handler(unsigned int n) { switch (n) { case 1: led_show(recv_buffer[4]); // LED控制 break; case 2: digiter_show(recv_buffer[4]); // 数码管显示 break; case 3: beep_choose(recv_buffer[4]); // 蜂鸣器频率选择 break; case 4: ds18b20_printf(recv_buffer[4]); // 温度读取 break; default: break; } }1.3 响应回调函数callback()
void callback() { unsigned char send_buffer[10] = {0}; unsigned char sum = 0; int i = 0; memcpy(send_buffer, recv_buffer, 7); send_buffer[2] |= (1 << 7); // 设置响应标志位 // 重新计算校验和 if (send_buffer[0] == 0xAA && send_buffer[6] == 0xBB) { if(send_buffer[1] == DEV_ADDRESS) { for(i = 0; i < 5; i++) { sum += send_buffer[i]; } send_buffer[5] = sum; } } uart_sendbuffer(send_buffer, 7); // 发送响应 }2. 串口通信模块 (uart.c)
2.1 串口初始化
void uart_init(void) { // SCON: 串口控制寄存器 SCON &= ~(3 << 6); // 清除SM0, SM1位 SCON |= (1 << 6); // SM0=0, SM1=1 (模式1: 8位UART,波特率可变) SCON |= (1 << 4); // REN=1 (允许接收) // PCON: 电源控制寄存器 PCON &= ~(1 << 6); // SMOD0=0 PCON |= (1 << 7); // SMOD1=1 (波特率加倍) // TMOD: 定时器模式寄存器 TMOD &= ~(0x0F << 4); // 清除T1相关位 TMOD |= (1 << 5); // T1模式1 (16位定时器) // 波特率设置: 9600bps (SMOD=1) // 计算公式: 波特率 = (2^SMOD / 32) * (fosc / (256 - TH1)) TL1 = 232; // 重载值 TH1 = 232; // 定时器初值 TCON |= (1 << 6); // TR1=1 (启动定时器1) // IE: 中断使能寄存器 IE |= (1 << 7); // EA=1 (全局中断使能) IE |= (1 << 4); // ES=1 (串口中断使能) }2.2 串口接收中断
void uart_recvhandler(void) interrupt 4 { if ((SCON & (1 << 0)) == 1) // 检查RI标志位 { if(pos < 32) // 缓冲区未满 { recv_buffer[pos++] = SBUF; // 读取数据 recv_buffer[pos] = 0; // 字符串结束符 } SCON &= ~(1 << 0); // 清除RI标志 } }3. 定时器模块 (timer.c)
3.1 定时器0初始化
void timer0_init(void) { // TMOD配置 TMOD &= ~(0x0F << 0); // 清除T0相关位 TMOD |= (1 << 0); // T0模式1 (16位定时器) // 定时器初值 TH0 = g_i >> 8; // 高8位 TL0 = g_i; // 低8位 TCON |= (1 << 4); // TR0=1 (启动定时器0) // 中断使能 IE |= (1 << 7); // EA=1 IE |= (1 << 1); // ET0=1 (定时器0中断使能) }3.2 定时器0中断服务函数
void timer0_handler(void) interrupt 1 { // 重新加载定时器初值 TH0 = g_i >> 8; TL0 = g_i; // P2.1引脚电平翻转(用于蜂鸣器控制) P2 ^= (1 << 1); }4. DS18B20温度传感器模块
4.1 复位时序
int ds18b20_reset(void) { int t = 0; // 主机拉低总线480μs-960μs DQ_DOWN; delay10us(70); // 700μs // 主机释放总线 DQ_HIGH; delay10us(6); // 60μs // 等待DS18B20响应信号 while(DQ_CHECK && t < 30) // 检测低电平 { delay10us(1); t++; } if(t >= 30) return 0; // 超时失败 t = 0; // 等待DS18B20释放总线 while(!DQ_CHECK && t < 30) // 检测高电平 { delay10us(1); t++; } if(t >= 30) return 0; // 超时失败 return 1; // 复位成功 }4.2 温度读取流程
float get_temp(void) { unsigned char tl = 0; unsigned char th = 0; short t = 0; // 1. 发送温度转换命令 ds18b20_reset(); ds18b20_write(0xCC); // 跳过ROM ds18b20_write(0x44); // 温度转换 delaylms(1000); // 等待转换完成 // 2. 读取温度数据 ds18b20_reset(); ds18b20_write(0xCC); // 跳过ROM ds18b20_write(0xBE); // 读暂存器 tl = ds18b20_read(); // 低字节 th = ds18b20_read(); // 高字节 // 3. 计算温度值 t = th << 8; t |= tl; return t * 0.0625; // 12位精度,LSB = 0.0625°C }5. LED控制模块
// LED初始化:所有LED灭 void led_init(void) { P2 = 0xFF; // P2口高电平,LED灭(共阳接法) } // 显示指定LED(位操作) void led_show(unsigned int n) { P2 = ~n; // 取反,相应位为0的LED亮 }三、通信协议详细说明
协议帧示例:
控制LED: AA 01 01 00 0F SUM BB 解释: AA: 帧头 01: 设备地址 01: 功能码(LED控制) 00: 数据1(未使用) 0F: 数据2(二进制00001111,低4位LED亮) SUM: 校验和(0xAA+0x01+0x01+0x00+0x0F=0xBB) BB: 帧尾
功能码定义:
1: LED控制 (DATA2: LED状态,低4位有效)
2: 数码管显示 (DATA2: 显示内容)
3: 蜂鸣器控制 (DATA2: 频率选择1-5)
4: 温度读取 (进入连续读取模式)
四、系统工作流程
初始化阶段
串口初始化(波特率9600)
LED初始化
定时器0初始化
主循环
while(1) { if(pos != 0) // 接收到数据 { delay(0x0FFF); // 短延时确保数据完整 ret = parse(); // 解析数据 if(ret != 0) // 解析成功 { do_handler(ret); // 执行功能 if(ret != 4) // 非温度读取功能需回复 { callback(); // 发送响应 } } pos = 0; // 清空接收位置 } }中断处理
串口接收中断:将数据存入缓冲区
定时器0中断:产生蜂鸣器方波信号
五、关键配置参数
蜂鸣器频率对应表
#define HZ_200 63231 // 200Hz对应的定时器初值 #define HZ_400 64383 // 400Hz #define HZ_600 64767 // 600Hz #define HZ_800 64959 // 800Hz #define HZ_1000 65074 // 1000Hz
计算公式:TH0TL0 = 65536 - fosc/(12*freq),其中fosc=11.0592MHz
串口波特率计算
SMOD=1, TH1=232时: 波特率 = (2^1/32) × 11059200/(256-232) = 9600bps
六、注意事项
硬件连接
DS18B20数据线连接P3.7
LED连接P2口(低电平有效)
蜂鸣器连接P2.1
数码管连接其他IO口(代码中已注释)
特殊处理
温度读取功能(功能码4)不发送响应,而是进入连续读取模式
蜂鸣器控制通过修改全局变量g_i改变频率
接收缓冲区大小为32字节,需防止溢出
调试建议
使用串口调试助手发送协议帧
注意校验和计算
温度读取需要1秒转换时间
七、总结
本系统展示了8051单片机在嵌入式控制中的典型应用,涵盖了:
自定义通信协议设计
多中断协同工作
外设驱动开发(LED、蜂鸣器、数码管、温度传感器)
模块化编程思想
通过解析通信协议,系统实现了灵活的远程控制功能,具有良好的扩展性,可以方便地添加新的功能模块。