基于51单片机的蓝牙控制舵机程序

一、项目概述

本项目使用STC89C52单片机通过HC-05蓝牙模块控制SG90舵机,实现远程角度调节功能。系统支持通过手机APP或蓝牙调试工具发送指令,控制舵机在0-180°范围内精确转动,适用于智能家居、机器人控制等场景。

二、系统架构

graph TD A[手机APP/蓝牙调试器] -->|蓝牙指令| B[HC-05模块] B -->|UART串口| C[STC89C52单片机] C -->|PWM信号| D[SG90舵机] C -->|状态指示| E[LED指示灯] C -->|用户交互| F[按键控制] D -->|机械运动| G[执行机构]

三、硬件设计

1. 元件清单

元件名称 型号/规格 数量 功能说明
主控芯片 STC89C52RC 1 系统控制核心
蓝牙模块 HC-05 1 蓝牙通信(主从模式可切)
舵机 SG90 1 180°旋转执行机构
晶振 11.0592MHz 1 系统时钟
电阻 10kΩ, 1kΩ 若干 上拉/限流
电容 30pF, 10μF 若干 晶振/复位
LED 红色/绿色 2 状态指示
按键 轻触开关 2 手动控制
电源 5V DC 1 系统供电
杜邦线 公对母/母对母 若干 连接线

2. 硬件连接

模块 引脚 单片机引脚 说明
HC-05 TXD P3.0 (RXD) 蓝牙数据发送
RXD P3.1 (TXD) 蓝牙数据接收
VCC 5V 电源正极
GND GND 电源负极
SG90舵机 VCC 5V 电源正极
GND GND 电源负极
SIG P1.0 控制信号线
LED 红色 P2.0 蓝牙连接状态
绿色 P2.1 舵机动作状态
按键 K1(设置) P3.2 进入设置模式
K2(确认) P3.3 确认选择

四、软件设计

1. 主程序流程图

graph TD A[系统初始化] --> B[蓝牙模块初始化] B --> C[舵机初始化] C --> D[串口通信设置] D --> E[主循环] E --> F{有蓝牙指令?} F -->|是| G[解析指令] G --> H[控制舵机] H --> I[更新状态] I --> E F -->|否| J{有按键按下?} J -->|是| K[处理按键] K --> E J -->|否| E

2. 核心代码实现

(1) 头文件与宏定义

#include <reg52.h>
#include <intrins.h>
#include <string.h>

// 引脚定义
sbit SERVO = P1^0;     // 舵机信号线
sbit LED_BT = P2^0;     // 蓝牙状态灯
sbit LED_ACT = P2^1;    // 舵机动作灯
sbit KEY_SET = P3^2;    // 设置按键
sbit KEY_OK = P3^3;     // 确认按键

// 蓝牙指令定义
#define CMD_ANGLE_PREFIX "ANG:"  // 角度指令前缀
#define CMD_STOP "STOP"          // 停止指令
#define CMD_SWEEP "SWEEP"        // 扫动指令

// 舵机参数
#define SERVO_MIN_ANGLE 0      // 最小角度
#define SERVO_MAX_ANGLE 180    // 最大角度
#define SERVO_MID_ANGLE 90      // 中间角度
#define SERVO_PERIOD 20        // PWM周期(ms)
#define SERVO_MIN_PULSE 500    // 最小脉宽(us)
#define SERVO_MAX_PULSE 2500   // 最大脉宽(us)

// 全局变量
unsigned int servo_angle = SERVO_MID_ANGLE;  // 当前角度
bit bt_connected = 0;         // 蓝牙连接状态
unsigned char rx_buffer[16];  // 串口接收缓冲区
unsigned char rx_index = 0;   // 接收索引

(2) 串口通信与蓝牙控制

// 串口初始化(9600bps, 11.0592MHz)
void UART_Init() {
    SCON = 0x50;        // 模式1, 允许接收
    TMOD |= 0x20;       // 定时器1模式2
    TH1 = 0xFD;         // 9600波特率
    TL1 = 0xFD;
    TR1 = 1;            // 启动定时器1
    ES = 1;             // 允许串口中断
    EA = 1;             // 开总中断
}

// 串口发送字符
void UART_SendChar(char c) {
    SBUF = c;
    while (!TI);
    TI = 0;
}

// 串口发送字符串
void UART_SendString(char *str) {
    while (*str) {
        UART_SendChar(*str++);
    }
}

// 串口中断服务函数
void UART_ISR() interrupt 4 {
    if (RI) {
        RI = 0;
        char c = SBUF;
        
        // 回车或换行表示指令结束
        if (c == '\r' || c == '\n') {
            if (rx_index > 0) {
                rx_buffer[rx_index] = '\0';  // 字符串结束符
                Process_Command(rx_buffer);  // 处理指令
                rx_index = 0;
            }
        } 
        // 存储有效字符
        else if (rx_index < sizeof(rx_buffer) - 1) {
            rx_buffer[rx_index++] = c;
        }
    }
}

(3) 舵机控制

// 微秒级延时
void delay_us(unsigned int us) {
    while (us--) {
        _nop_(); _nop_(); _nop_(); _nop_();
        _nop_(); _nop_(); _nop_(); _nop_();
    }
}

// 毫秒级延时
void delay_ms(unsigned int ms) {
    unsigned int i, j;
    for (i = 0; i < ms; i++)
        for (j = 0; j < 114; j++);
}

// 设置舵机角度(0-180)
void Set_Servo_Angle(unsigned int angle) {
    // 角度限幅
    if (angle < SERVO_MIN_ANGLE) angle = SERVO_MIN_ANGLE;
    if (angle > SERVO_MAX_ANGLE) angle = SERVO_MAX_ANGLE;
    
    // 计算脉宽(us)
    unsigned int pulse = SERVO_MIN_PULSE + 
                        (unsigned long)(angle) * 
                        (SERVO_MAX_PULSE - SERVO_MIN_PULSE) / 180;
    
    // 设置PWM信号
    SERVO = 1;
    delay_us(pulse);
    SERVO = 0;
    
    // 更新状态
    servo_angle = angle;
    LED_ACT = ~LED_ACT;  // 动作指示灯闪烁
    
    // 发送确认信息
    char msg[20];
    sprintf(msg, "ANG:%d OK\r\n", angle);
    UART_SendString(msg);
}

// 舵机扫动演示
void Servo_Sweep() {
    for (int i = 0; i <= 180; i += 10) {
        Set_Servo_Angle(i);
        delay_ms(100);
    }
    for (int i = 180; i >= 0; i -= 10) {
        Set_Servo_Angle(i);
        delay_ms(100);
    }
    Set_Servo_Angle(SERVO_MID_ANGLE);
}

(4) 指令处理

// 处理蓝牙指令
void Process_Command(char *cmd) {
    // 角度控制指令: ANG:90
    if (strstr(cmd, CMD_ANGLE_PREFIX)) {
        int angle = atoi(cmd + strlen(CMD_ANGLE_PREFIX));
        Set_Servo_Angle(angle);
    }
    // 停止指令: STOP
    else if (strcmp(cmd, CMD_STOP) == 0) {
        Set_Servo_Angle(servo_angle);  // 保持当前位置
        UART_SendString("STOPPED\r\n");
    }
    // 扫动指令: SWEEP
    else if (strcmp(cmd, CMD_SWEEP) == 0) {
        Servo_Sweep();
        UART_SendString("SWEEP DONE\r\n");
    }
    // 未知指令
    else {
        UART_SendString("INVALID CMD\r\n");
    }
}

(5) 主程序

void main() {
    // 初始化
    UART_Init();
    LED_BT = 0;
    LED_ACT = 0;
    Set_Servo_Angle(SERVO_MID_ANGLE);  // 初始位置
    
    // 蓝牙连接检测
    UART_SendString("AT+NAME=Sweeper\r\n");  // 设置蓝牙名称
    delay_ms(500);
    UART_SendString("AT+PSWD=1234\r\n");     // 设置配对密码
    
    // 主循环
    while (1) {
        // 检测蓝牙连接状态
        if (RI) {
            if (SBUF == 'C') {  // 连接成功标志
                bt_connected = 1;
                LED_BT = 1;  // 蓝牙连接指示灯亮
            }
        }
        
        // 按键处理
        if (KEY_SET == 0) {
            delay_ms(20);
            if (KEY_SET == 0) {
                // 进入设置模式
                UART_SendString("SET MODE\r\n");
                while (KEY_SET == 0);  // 等待释放
            }
        }
        
        // 低功耗模式
        if (!bt_connected) {
            PCON |= 0x01;  // 进入IDLE模式
        }
    }
}

五、系统优化

1. 多舵机控制扩展

// 多舵机控制结构
typedef struct {
    unsigned int angle;
    unsigned int min_pulse;
    unsigned int max_pulse;
    unsigned char pin;
} Servo_TypeDef;

Servo_TypeDef servos[2] = {
    {90, 500, 2500, P1^0},  // 舵机1
    {90, 500, 2500, P1^1}   // 舵机2
};

// 设置多舵机角度
void Set_Multi_Servo_Angle(unsigned char id, unsigned int angle) {
    if (id >= 2) return;
    
    Servo_TypeDef *s = &servos[id];
    if (angle < 0) angle = 0;
    if (angle > 180) angle = 180;
    
    unsigned int pulse = s->min_pulse + 
                        (unsigned long)(angle) * 
                        (s->max_pulse - s->min_pulse) / 180;
    
    // 设置PWM信号
    s->pin = 1;
    delay_us(pulse);
    s->pin = 0;
    
    s->angle = angle;
}

2. 位置记忆功能

// 保存位置到EEPROM
void Save_Position(unsigned char id, unsigned int angle) {
    IapEraseSector(0x2000);  // 擦除扇区
    IapProgramByte(0x2000, id);
    IapProgramByte(0x2001, angle >> 8);
    IapProgramByte(0x2002, angle & 0xFF);
}

// 从EEPROM读取位置
unsigned int Read_Position(unsigned char id) {
    if (IapReadByte(0x2000) == id) {
        return (IapReadByte(0x2001) << 8) | IapReadByte(0x2002);
    }
    return 90;  // 默认位置
}

3. 安全保护机制

// 舵机过载保护
void Safe_Servo_Control(unsigned int angle) {
    // 检查角度变化率
    static unsigned int last_angle = 90;
    if (abs(angle - last_angle) > 30) {
        // 大角度变化,分步执行
        int step = (angle > last_angle) ? 1 : -1;
        for (int i = last_angle; i != angle; i += step) {
            Set_Servo_Angle(i);
            delay_ms(20);
        }
    } else {
        Set_Servo_Angle(angle);
    }
    last_angle = angle;
    
    // 检查连续工作时间
    static unsigned long work_time = 0;
    if (work_time > 30000) {  // 30秒连续工作
        Set_Servo_Angle(90);   // 回到中位
        delay_ms(1000);        // 休息1秒
        work_time = 0;
    } else {
        work_time += 20;  // 每次操作约20ms
    }
}

参考代码 基于51单片机蓝牙控制舵机程序 www.youwenfan.com/contentcns/182549.html

六、测试与调试

1. 测试工具

  • 蓝牙调试助手:安卓APP(如"蓝牙调试器")

  • 串口调试工具:PC端(如"XCOM")

  • 示波器:检测PWM信号质量

  • 逻辑分析仪:分析通信协议

2. 测试用例

测试项 输入指令 预期结果 实际结果
角度设置 ANG:0 舵机转到0°
ANG:90 舵机转到90°
ANG:180 舵机转到180°
边界值 ANG:-10 舵机转到0°
ANG:200 舵机转到180°
特殊功能 SWEEP 舵机0-180°往复运动
STOP 舵机停止在当前位置
连续控制 快速发送多个角度 舵机平滑移动 ⚠️ 需优化

3. 常见问题解决

问题现象 可能原因 解决方案
舵机不转动 电源不足 使用独立电源供电
信号线接触不良 检查接线
脉宽计算错误 用示波器检查PWM信号
蓝牙连接失败 模块未进入AT模式 按住按键上电进入AT模式
配对密码错误 确认密码为1234
地址错误 扫描正确MAC地址
角度控制不精确 定时器精度不足 使用12MHz晶振提高精度
机械间隙 软件补偿或机械调整
系统频繁复位 电源干扰 增加滤波电容
看门狗未喂狗 在长延时中喂狗

七、项目扩展

1. 添加语音控制

// 语音识别模块(如LD3320)接口
void Voice_Control() {
    if (voice_cmd == "打开") {
        Set_Servo_Angle(90);
    } else if (voice_cmd == "关闭") {
        Set_Servo_Angle(0);
    } else if (voice_cmd == "最大") {
        Set_Servo_Angle(180);
    }
}

2. 添加物联网功能

// 通过ESP8266连接云平台
void IoT_Upload() {
    char cmd[50];
    sprintf(cmd, "AT+CIPSTART=\"TCP\",\"api.thingspeak.com\",80");
    UART_SendString(cmd);
    
    // 发送HTTP请求
    sprintf(cmd, "GET /update?api_key=XXX&field1=%d\r\n", servo_angle);
    UART_SendString(cmd);
}

3. 添加手势控制

// 通过MPU6050检测手势
void Gesture_Control() {
    if (gesture == GESTURE_UP) {
        Set_Servo_Angle(servo_angle + 10);
    } else if (gesture == GESTURE_DOWN) {
        Set_Servo_Angle(servo_angle - 10);
    }
}

八、使用注意事项

  1. 电源管理

    • 舵机工作时电流可达200mA,需独立供电

    • 使用1000μF电容滤波

    • 避免与单片机共用电源

  2. 信号质量

    • 舵机信号线长度不超过30cm

    • 使用屏蔽线或双绞线

    • 避免在PWM信号附近布置电源线

  3. 机械安装

    • 舵机支架需牢固固定

    • 避免机械限位超出0-180°范围

    • 添加橡胶垫减少振动噪音

  4. 软件优化

    • 使用定时器中断生成PWM

    • 添加软件滤波消除抖动

    • 实现看门狗防止死机

九、项目总结

本系统实现了基于51单片机的蓝牙控制舵机功能,具有以下特点:

  1. 通过HC-05蓝牙模块实现无线控制

  2. 支持0-180°精确角度调节

  3. 提供多种控制方式(APP/按键)

  4. 实现特殊功能(扫动演示、位置记忆)

  5. 具备安全保护机制

posted @ 2026-03-23 09:31  小前端攻城狮  阅读(11)  评论(0)    收藏  举报