应用——基于 51 单片机的多功能嵌入式系统

基于 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()

cpp 复制代码
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()

cpp 复制代码
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()

cpp 复制代码
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 串口初始化
cpp 复制代码
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 串口接收中断
cpp 复制代码
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初始化
cpp 复制代码
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中断服务函数
cpp 复制代码
void timer0_handler(void) interrupt 1
{
    // 重新加载定时器初值
    TH0 = g_i >> 8;
    TL0 = g_i;
    
    // P2.1引脚电平翻转(用于蜂鸣器控制)
    P2 ^= (1 << 1);
}

4. DS18B20温度传感器模块

4.1 复位时序
cpp 复制代码
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 温度读取流程
cpp 复制代码
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控制模块

cpp 复制代码
// 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: 温度读取 (进入连续读取模式)

四、系统工作流程

  1. 初始化阶段

    • 串口初始化(波特率9600)

    • LED初始化

    • 定时器0初始化

  2. 主循环

    cpp 复制代码
    while(1)
    {
        if(pos != 0)  // 接收到数据
        {
            delay(0x0FFF);  // 短延时确保数据完整
            
            ret = parse();  // 解析数据
            if(ret != 0)    // 解析成功
            {
                do_handler(ret);  // 执行功能
                
                if(ret != 4)  // 非温度读取功能需回复
                {
                    callback();  // 发送响应
                }
            }
            pos = 0;  // 清空接收位置
        }
    }
  3. 中断处理

    • 串口接收中断:将数据存入缓冲区

    • 定时器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

六、注意事项

  1. 硬件连接

    • DS18B20数据线连接P3.7

    • LED连接P2口(低电平有效)

    • 蜂鸣器连接P2.1

    • 数码管连接其他IO口(代码中已注释)

  2. 特殊处理

    • 温度读取功能(功能码4)不发送响应,而是进入连续读取模式

    • 蜂鸣器控制通过修改全局变量g_i改变频率

    • 接收缓冲区大小为32字节,需防止溢出

  3. 调试建议

    • 使用串口调试助手发送协议帧

    • 注意校验和计算

    • 温度读取需要1秒转换时间

七、总结

本系统展示了8051单片机在嵌入式控制中的典型应用,涵盖了:

  • 自定义通信协议设计

  • 多中断协同工作

  • 外设驱动开发(LED、蜂鸣器、数码管、温度传感器)

  • 模块化编程思想

通过解析通信协议,系统实现了灵活的远程控制功能,具有良好的扩展性,可以方便地添加新的功能模块。

相关推荐
广药门徒2 小时前
为什么访问一地址存16bits的存储芯片需要字节对齐?为什么访问外部Flash需要字节对齐?——深入理解STM32 FMC的地址映射机制
stm32·单片机·嵌入式硬件
jh10_2 小时前
嵌入式硬件DAY5(ARM汇编)
汇编·arm开发·嵌入式硬件
亦复何言??2 小时前
DreamWaQ - 基于隐式地形想象的鲁棒四足机器人运动学习
学习·机器人
lkbhua莱克瓦242 小时前
CSS盒子模型:网页布局的基石与艺术
前端·css·笔记·javaweb
国科安芯2 小时前
尺寸约束下商业卫星编码器系统的抗辐照MCU性能边界研究
运维·单片机·嵌入式硬件·安全·安全威胁分析
Qaz555666912 小时前
网络安全笔记(第一二天)
笔记·安全·web安全
天天开心a2 小时前
Vue.js 基础教程笔记(一):Vue入门与环境搭建
前端·javascript·vue.js·笔记·前端框架
后来后来啊2 小时前
2026.1.18学习笔记
笔记·学习
wdfk_prog2 小时前
[Linux]学习笔记系列 -- [drivers][base]core
linux·笔记·学习