基于51单片机的航模遥控器6通道接收机程序

一、系统概述

基于STC89C52RC单片机(8位,11.0592MHz晶振),实现6通道航模遥控器接收机功能。通过PPM信号解析(脉冲位置调制)接收遥控器发送的6通道控制指令,解析各通道脉宽后,输出6路PWM信号驱动舵机或电调,支持失控保护和信号指示。系统采用外部中断+定时器实现高精度时序控制,适用于固定翼飞机、多旋翼无人机等航模设备。

二、硬件设计

2.1 核心组件选型

模块 型号/参数 功能说明
主控 STC89C52RC(8KB Flash,512B RAM) PPM信号解析、PWM生成、通道数据处理
接收机模块 2.4G PPM输出模块(如FlySky FS-iA6B) 接收遥控器信号,输出6通道PPM信号(1路信号线)
舵机/电调 6路标准舵机(如SG90,1-2ms脉宽) 执行俯仰、横滚、油门、方向等控制
指示灯 LED(红/绿) 信号状态指示(绿:正常,红:失控)
电源 5V/2A DC(或航模电池+LM7805) 为单片机、接收机模块、舵机供电(注意舵机需独立电源)

2.2 硬件连接图

复制代码
+-------------------+          +-------------------+          +-------------------+  
|  2.4G接收机模块   |          |   STC89C52RC      |          |   6路舵机/电调     |  
|  PPM输出 → P3.2(INT0)|◄---------| 外部中断0(下降沿触发)|          |  PWM1→P1.0, PWM2→P1.1 |  
|  VCC → 5V          |          |  P1.0~P1.5 → PWM输出 |          |  ... PWM6→P1.5      |  
|  GND → GND         |          |  P3.3 → 状态LED(红)|          +-------------------+  
+-------------------+          |  P3.4 → 状态LED(绿)|          +-------------------+  
                                 |  VCC → 5V, GND→GND  |          |    电源模块        |  
                                 +-------------------+          |  5V/2A → 各模块     |  
                                                                 +-------------------+

关键说明

  • PPM信号:6通道PPM总周期20ms,每个通道脉冲宽度0.5-2ms(对应控制量0-100%),通道间间隔0.3-0.5ms,同步间隔>2ms。

  • PWM输出:6路独立PWM,周期20ms,脉宽1-2ms(舵机标准),由单片机定时器生成。

三、软件设计(Keil C51)

3.1 开发环境

  • IDE:Keil μVision5(C51编译器)

  • 晶振:11.0592MHz(确保定时器计时精度)

  • 通信协议:PPM(6通道,20ms周期)

3.2 核心原理

  1. PPM解析 :通过外部中断0(INT0) 捕获PPM信号下降沿,用定时器0计时,计算相邻下降沿的时间间隔(即脉宽),根据同步间隔区分6个通道。

  2. PWM生成 :用定时器1产生20ms周期中断,在中断中更新6路PWM输出(通过IO口模拟PWM,或直接用硬件PWM,51单片机需软件模拟)。

  3. 失控保护:若超过20ms未接收到PPM信号(同步间隔丢失),输出预设安全脉宽(如油门0%,舵机中位)。

3.3 核心代码实现

3.3.1 头文件与全局变量
c 复制代码
#include <reg52.h>
#include <intrins.h>

// ==================== 引脚定义 ====================
#define PPM_INPUT P3_2    // PPM信号输入(INT0,下降沿触发)
#define LED_GREEN P3_4    // 信号正常指示灯(绿)
#define LED_RED P3_3      // 失控指示灯(红)
#define PWM_PORT P1       // PWM输出端口(P1.0~P1.5对应6通道)

// ==================== 全局变量 ====================
unsigned int ppm_pulse[6] = {1500, 1500, 1000, 1500, 1500, 1500};  // 6通道脉宽(us,默认中位/油门最小)
unsigned int last_edge_time = 0;  // 上次下降沿时间(us,由定时器计数)
unsigned char channel = 0;        // 当前解析通道(0-5)
unsigned int sync_time = 0;        // 同步间隔(us)
bit signal_lost = 0;              // 信号丢失标志(1=失控)

// 定时器0:计时(1us计数,11.0592MHz下,机器周期1.085us,需校准)
unsigned int timer0_count = 0;    // 定时器0溢出计数
3.3.2 定时器0初始化(1us计时基准)
c 复制代码
// 定时器0初始化(模式1,16位计数,11.0592MHz下,1us≈1计数)
void Timer0_Init() {
    TMOD |= 0x01;  // 模式1(16位计数)
    TH0 = 0;       // 初始值0
    TL0 = 0;
    ET0 = 1;       // 允许定时器0中断
    EA = 1;        // 开总中断
    TR0 = 1;       // 启动定时器0
}
3.3.3 外部中断0初始化(PPM下降沿捕获)
c 复制代码
// 外部中断0初始化(下降沿触发,解析PPM)
void INT0_Init() {
    IT0 = 1;  // 下降沿触发
    EX0 = 1;  // 允许INT0中断
    EA = 1;   // 开总中断
}
3.3.4 PPM信号解析(外部中断0服务函数)
c 复制代码
// 外部中断0服务函数(PPM下降沿触发,计算脉宽)
void INT0_ISR() interrupt 0 {
    unsigned int current_time, pulse_width;
    
    // 1. 计算当前时间(us):定时器0溢出次数*65536 + 当前计数值
    current_time = (timer0_count * 65536) + (TH0 << 8 | TL0);
    
    // 2. 计算脉宽(us):当前时间 - 上次下降沿时间
    pulse_width = current_time - last_edge_time;
    last_edge_time = current_time;
    
    // 3. 判断通道:同步间隔>2000us(6通道PPM同步间隔约2-3ms)
    if (pulse_width > 2000) {  // 同步间隔,重置通道计数
        channel = 0;
        signal_lost = 0;  // 信号正常
        LED_GREEN = 0;    // 绿灯亮
        LED_RED = 1;      // 红灯灭
    } else {  // 通道脉冲
        if (channel < 6) {
            ppm_pulse[channel] = pulse_width;  // 存储脉宽(us)
            channel++;
        }
        // 通道数异常(>6),标记信号丢失
        if (channel > 6) {
            signal_lost = 1;
        }
    }
}
3.3.5 定时器0中断(计时溢出处理)
c 复制代码
// 定时器0中断服务函数(1us计数,处理溢出)
void Timer0_ISR() interrupt 1 {
    timer0_count++;  // 每65536us溢出一次,计数+1
    TH0 = 0;         // 重装初值0
    TL0 = 0;
}
3.3.6 PWM生成(定时器1中断,20ms周期)
c 复制代码
// 定时器1初始化(20ms周期,用于PWM生成)
void Timer1_Init() {
    TMOD |= 0x10;  // 模式1(16位计数)
    TH1 = (65536 - 20000) / 256;  // 20ms@11.0592MHz:20000us/1.085us≈18432,TH1=65536-18432=47104=0xB800
    TL1 = (65536 - 20000) % 256;  // 0x00
    ET1 = 1;       // 允许定时器1中断
    EA = 1;        // 开总中断
    TR1 = 1;       // 启动定时器1
}

// 定时器1中断服务函数(20ms周期,更新6路PWM)
void Timer1_ISR() interrupt 3 {
    static unsigned int pwm_count[6] = {0};  // 各通道PWM计数(us)
    unsigned char i;
    
    // 1. 重装定时器1初值(20ms)
    TH1 = (65536 - 20000) / 256;
    TL1 = (65536 - 20000) % 256;
    
    // 2. 若信号丢失,输出安全脉宽(油门0%,舵机中位1.5ms)
    if (signal_lost) {
        ppm_pulse[0] = 1500;  // 副翼中位
        ppm_pulse[1] = 1500;  // 升降中位
        ppm_pulse[2] = 1000;  // 油门最小
        ppm_pulse[3] = 1500;  // 方向中位
        ppm_pulse[4] = 1500;  // 辅助1中位
        ppm_pulse[5] = 1500;  // 辅助2中位
        LED_GREEN = 1;        // 绿灯灭
        LED_RED = 0;          // 红灯亮
    }
    
    // 3. 更新各通道PWM输出(1-2ms脉宽,20ms周期)
    for (i=0; i<6; i++) {
        if (pwm_count[i] < ppm_pulse[i]) {  // 高电平(脉宽内)
            PWM_PORT |= (1 << i);  // 对应IO口置1
        } else {  // 低电平(剩余周期)
            PWM_PORT &= ~(1 << i);  // 对应IO口置0
        }
        pwm_count[i] += 20;  // 每20ms周期,计数+20(单位us,简化计算)
        if (pwm_count[i] >= 20000) pwm_count[i] = 0;  // 20ms周期重置
    }
}
3.3.7 主函数
c 复制代码
void main() {
    // 初始化
    Timer0_Init();  // 定时器0(计时)
    Timer1_Init();  // 定时器1(PWM周期)
    INT0_Init();    // 外部中断0(PPM输入)
    
    // 初始状态:灯灭
    LED_GREEN = 1;
    LED_RED = 1;
    
    while (1) {
        // 主循环可添加其他功能(如通道数据转发、低电量检测等)
        // 示例:通过串口打印通道脉宽(需添加串口代码)
        // printf("Ch1:%d, Ch2:%d, Ch3:%d, Ch4:%d, Ch5:%d, Ch6:%d\r\n", 
        //        ppm_pulse[0], ppm_pulse[1], ppm_pulse[2], ppm_pulse[3], ppm_pulse[4], ppm_pulse[5]);
    }
}

参考代码 基于51单片机航模遥控器6通道接收机程序 www.youwenfan.com/contentcst/182670.html

四、关键问题与解决方案

4.1 PPM信号解析精度

  • 问题:51单片机定时器精度有限(11.0592MHz下,机器周期≈1.085us),脉宽计算误差大。

  • 解决

  • 定时器0溢出计数+当前计数值 计算总时间(如current_time = timer0_count*65536 + (TH0<<8|TL0));

  • 软件校准:通过示波器测量实际脉宽,调整pulse_width计算公式(如乘以0.92修正误差)。

4.2 多通道同步丢失

  • 问题:信号干扰导致通道计数错误(如少计或多计通道)。

  • 解决

  • 严格判断同步间隔>2000us才重置通道计数;

  • 限制通道数channel<6,超6则标记signal_lost

4.3 舵机抖动

  • 问题:PWM脉宽波动导致舵机抖动。

  • 解决

  • ppm_pulse进行软件滤波(如取5次平均值);

  • 限制脉宽变化率(如每次变化不超过50us)。

五、测试与验证

5.1 硬件连接

  • 2.4G接收机PPM输出接P3.2(INT0),VCC/GND接5V/地;

  • 6路舵机信号线接P1.0~P1.5,舵机电源接独立5V/2A电源(避免干扰单片机)。

5.2 功能测试

  1. 信号接收:遥控器开机,推动摇杆,用示波器测量P1.0~P1.5的PWM脉宽,应与摇杆位置对应(0.5-2ms)。

  2. 失控保护:断开接收机天线,观察LED由绿变红,舵机输出安全脉宽(油门0%,中位)。

  3. 抗干扰:在2.4G信号弱的环境(如空旷场地)测试,确保无失控。

六、总结

基于51单片机实现了6通道航模接收机,核心是PPM信号解析(外部中断+定时器计时)和多路PWM生成(定时器中断模拟)。通过模块化设计,可扩展更多通道(如8通道)或数字输出(如LED指示通道状态),满足不同航模控制需求。

相关推荐
bu_shuo8 小时前
嵌入式硬件工程师VS单板硬件工程师
嵌入式硬件·电子工程师·单板硬件
llilian_168 小时前
选择北斗导航卫星信号模拟器注意事项总结 北斗导航卫星模拟器 北斗导航信号模拟器
功能测试·单片机·嵌入式硬件·测试工具·51单片机·硬件工程
Yyq130208696828 小时前
MH2457,‌国产 32 位屏驱 MCU‌芯片,支持‌1080P 高清显示‌与‌以太网通信‌,广泛应用于两轮车仪表盘及工控屏等领域
单片机·嵌入式硬件
爱吃程序猿的喵9 小时前
南邮计科电工电子实验B《RLC串联谐振电路》实验报告
单片机·嵌入式硬件
独小乐9 小时前
009.中断实践之实现按键测试|千篇笔记实现嵌入式全栈/裸机篇
linux·c语言·驱动开发·笔记·嵌入式硬件·arm
XINVRY-FPGA10 小时前
XC7VX690T-2FFG1157I Xilinx AMD Virtex-7 FPGA
arm开发·人工智能·嵌入式硬件·深度学习·fpga开发·硬件工程·fpga
bubiyoushang88812 小时前
利用STM32实现Modbus通信(RTU从机方案)
stm32·单片机·嵌入式硬件
cmpxr_12 小时前
【单片机】常用设计模式
单片机·嵌入式硬件·设计模式
杰杰桀桀桀12 小时前
4*4无时延矩阵键盘(非阻塞)--附代码链接
stm32·单片机·嵌入式硬件·矩阵·计算机外设·无时延矩阵键盘