遥控器与电调相关知识点整理

2024-05-05 07:32

本文主要是介绍遥控器与电调相关知识点整理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一,电调的控制方法——PWM

单片机输出1ms~2ms的方波脉冲,根据航模标准,PWM信号线的频率应该是50Hz,对应的每个周期总时长是20ms,输出到电调的油门线(控制线,也就是细细的,除了红的是接5V电源,黑的GND,另外那个就是数据线)。
如果是单向电调,1ms表示0%的油门,2ms表示100%的油门。如果是双向电调(有正、反转和刹车),标准1.5ms是0点,1ms是反向油门最大(100%油门),用于刹车或反转;2ms正向油门最大(100%油门),用于正转。
这是无线遥控模型比例控制的一个标准。对于其它电调也一样。注意,电调转速只与1ms~2ms的脉宽有关,与脉冲重复率无关。1~2ms的方波脉宽渐变过程对应油门的从小到大,从负到正的渐变。 脉宽的幅度2.5V~6V;所以3~5V工作电压的单片机都适用。

二,单片机解码PPM信号--深层了解遥控

无线遥控就是利用高频无线电波实现对模型的控制。如天地飞的的6通道2.4 GHz遥控器,一套200多块,具有自动跳频抗干扰能力,从理论上讲可以让上百人在同一场地同时遥控自己的模型而不会相互干扰。而且在遥控距离方面也颇具优势,2.4 GHz遥控系统的功率仅仅在100 mW以下,而它的遥控距离可以达到1km以上。
遥控器发射机、接收机原理

每个通道信号脉宽0~2ms,变化范围为1~2ms之间。1帧PPM信号长度为20ms,理论上最多可以有10个通道,但是同步脉冲也需要时间,模型遥控器最多9个通道。
PPM格式

PPM信号,是遥控控制和接收以及电调油门控制舵机控制的最最重要的信号,当然玩模拟器在电脑软件里练飞行时也离不开PPM信号。如果只是单纯玩也没有必要了解那么仔细,但作为的专业的知识帖知识点是有必要弄清楚的,甚至在开发航模遥控时,给微控制器编程都是要深入了解的。


PPM信号格式:


1、老标准:1~2毫秒是单个通道的总脉宽,其中低电平是固定的占0.3毫秒,高电平从0.7~1.7毫秒可变,脉宽越大油门越高。


2、新的标准:每个通道1~2毫秒脉宽,周期20毫秒,即高电平5V宽度为1毫秒代表低速(油门通道,舵机通道舵杆是打到一头的顶),那剩下的19毫秒是低电平0V;1.5毫秒低表舵机通道舵杆是打到中心位置,那剩下的18.5毫秒是低电平0V;2毫秒代表高速(油门通道,舵机通道舵杆是打到另一头的顶),那剩下的18毫秒是低电平0V,如图。这样,发射端每20毫秒发射一次,总共可以容纳10个比例通道(理论上)。在接收端,把每个通道分离出来,脉宽信号也是20毫秒更新一次。


3、对于双向电调,是以1.5毫秒脉冲宽度为停止点,1毫秒脉宽时反转最高速,2毫秒脉宽时正转最高速。

在接收端分离出各个通道的信号输出给被控对象:如电调,舵机等,是不是可以理解为,是PWM(脉宽调制)信号呢?可以这么说,不能简单地把接收输出的控制信号,理解为PWM信号,接收输出的单通信号可周期可以是18~22毫秒,或者16~25毫秒都可以认为是正常的,要求严格的是那个高电平的1~2毫秒的脉冲信号。


三,用STM32捕捉遥控器PWM信号并输出给无刷电调
1、单独读取遥控信号,串口输出所有通道的信号,看和遥控手势是否匹配;
2、单独控制电机转速,在一次启动里让转速变化,不要只用一个转速控制;
   3、综合起来,如果有问题,看看中断会不会有干扰、外部数据调用是否合理等待。

下面的解决办法(亲测可用),希望有帮助:
1、遥控信号
    用的也是天地飞A6的遥控,他的接收机各个通道高电平时间正好是错开的,所以我用了一片或门(或非门)将所有通道加在一起,形成下面的样子
  
    ===================
          GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Pin   = ppm_pin;
          GPIO_Init(ppm_gpio, &GPIO_InitStructure);
    ===================
          TIM_DeInit(TIM1);
        TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);
        TIM_TimeBaseInitStruct.TIM_Prescaler = 72-1;
        TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInitStruct.TIM_Period = 0xFFFF;
        TIM_TimeBaseInitStruct.TIM_ClockDivision = 0;
        TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
        TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStruct );

        TIM_ICStructInit(&TIM_ICInitStruct);
        TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
        TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;
        TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
        TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
        TIM_ICInitStruct.TIM_ICFilter = 0x00;
        TIM_ICInit(TIM1, &TIM_ICInitStruct );

        TIM_ClearFlag(TIM1,TIM_FLAG_CC1 );
        TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE);        
        TIM_ITConfig(TIM1, TIM_IT_Update, DISABLE);
        TIM_Cmd(TIM1, ENABLE);
  ====================
        NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
          NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;    
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;         
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;      
        NVIC_Init(&NVIC_InitStructure);
  ====================
rt_uint8_t ppm_step = 0;  
rt_uint8_t ppm_c = 0;         
rt_uint16_t buffer = 0;
rt_uint16_t channel[6];
void ppm_isr()
{        
  /* enter interrupt */
  rt_interrupt_enter();        //防止中断冲突        
        switch (ppm_step)
        {
        case 0:
                TIM1->SR &= 0XFFFC; //clear flag
                  TIM1->CNT = 0;
                  TIM1->CCER = 0X0003; //change to falling
                ppm_step = 1;
                break;
        case 1:
                TIM1->SR &= 0XFFFC; //clear flag
                  buffer = TIM1->CNT; 
                TIM1->CNT = 0;        
                  TIM1->CCER = 0X0001; //change to rising
                (buffer<2500)?(ppm_step=0):(ppm_step=2);
                break;
        case 2:
                  TIM1->SR &= 0XFFFC; //clear flag
                  channel[ppm_c] = TIM1->CNT; 
                    TIM1->CCER = 0X0003; //change to falling        
                ppm_step = 3;
                ppm_c++;
                if(ppm_c == 6)
                {
                        ppm_c = 0;
                        ppm_step = 0;
                        goto end;
                }
                break;
        case 3:
                  TIM1->SR &= 0XFFFC; //clear flag
                  TIM1->CNT = 0;
                  TIM1->CCER = 0X0001; //change to rising
                ppm_step = 2;
                break;
        default:
                ppm_c = 0;
                ppm_step = 0;
        }
  /* leave interrupt */
  end:rt_interrupt_leave();        
}

2、电机控制
void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);

    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;          //³¬Éù²¨ÐźÅÊäÈë
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Pin   = sona1_pin;
    GPIO_Init(sona_gpio, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_OD;                  //³¬Éù²¨²Ù×÷IO
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Pin   = sona2_pin;
    GPIO_Init(sona_gpio, &GPIO_InitStructure);
        

    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;                  //¶¨Ê±Æ÷pwmÊä³ö¹Ü½Å
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_6;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_7;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_1;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_6;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_7;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_8;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}

void TIM_Configuration(void)
{
        //TIM3 CH1,2  TIM3 CH3,4  TIM4 CH1234
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_OCInitTypeDef  TIM_OCInitStructure_pwm;

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3|RCC_APB1Periph_TIM4, ENABLE);

        TIM_DeInit(TIM3);
        TIM_DeInit(TIM4);
        TIM_TimeBaseStructure.TIM_Period = 20* 1000 -1;                
        TIM_TimeBaseStructure.TIM_Prescaler = 72-1;                
        TIM_TimeBaseStructure.TIM_ClockDivision =  0x00;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
        //TIM_TimeBaseStructure.TIM_Period = 20 * 1000 -1;                
        TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

        TIM_Cmd(TIM3, ENABLE);
        TIM_Cmd(TIM4, ENABLE);

        TIM_OCInitStructure_pwm.TIM_OCMode = TIM_OCMode_PWM1;
        TIM_OCInitStructure_pwm.TIM_OutputState = TIM_OutputState_Enable;
        TIM_OCInitStructure_pwm.TIM_Pulse = 0;
        TIM_OCInitStructure_pwm.TIM_OCPolarity = TIM_OCPolarity_High;

        TIM_OC1Init(TIM3, &TIM_OCInitStructure_pwm);
        TIM_OC2Init(TIM3, &TIM_OCInitStructure_pwm);
        TIM_OC3Init(TIM3, &TIM_OCInitStructure_pwm);
        TIM_OC4Init(TIM3, &TIM_OCInitStructure_pwm);

        TIM_OC1Init(TIM4, &TIM_OCInitStructure_pwm);
        TIM_OC2Init(TIM4, &TIM_OCInitStructure_pwm);
        TIM_OC3Init(TIM4, &TIM_OCInitStructure_pwm);
        TIM_OC4Init(TIM4, &TIM_OCInitStructure_pwm);

        TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
        TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
        TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);
        TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);
        TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);
        TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);
        TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable);
        TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable);
}

#define CH1 1
#define CH2 2
#define CH3 3
#define CH4 4
#define CH5 5
#define CH6 6
#define CH7 7
#define CH8 8

void updata_pwm(unsigned int channel, unsigned int pulse)
{
        if(pulse > 0xffff)pulse = 0xffff;
        
        switch(channel)
        {
                case 1:        TIM3->CCR1 = pulse;break;        
                case 2:        TIM3->CCR2 = pulse;break;
                case 3:        TIM3->CCR3 = pulse;break;
                case 4:        TIM3->CCR4 = pulse;break;
                case 8:        TIM4->CCR1 = pulse;break;        
                case 7:        TIM4->CCR2 = pulse;break;
                case 6:        TIM4->CCR3 = pulse;break;
                case 5:        TIM4->CCR4 = pulse;break;                                
                default:break;        
        }
}
==========================
        updata_pwm(CH1, 1000);
        updata_pwm(CH2, 1000);
        updata_pwm(CH3, 1000);
        updata_pwm(CH4, 1000);
        updata_pwm(CH5, 1000);
        updata_pwm(CH6, 1000);
        updata_pwm(CH7, 1000);
        updata_pwm(CH8, 1000);

这篇关于遥控器与电调相关知识点整理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/961129

相关文章

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

嵌入式软件工程师应聘知识点

嵌入式软件工程师应聘 修改浏览权限 | 删除 数据结构(C语言)部分常考的知识点: 1、局部变量能、全局变量和静态变量 2、堆和栈 3、Const、volatile、define、typedef的用途 4、链表(比如链表的插入、删除和排序) 5、排序(考查冒泡法的较多) 6、可重入函数 、malloc函数 7、指针(常考函数指针,函数指针,数组指针,指针数组和

RecastNavigation之Poly相关类

Poly分成正常的Poly 和 OffMeshPoly。 正常的Poly 又分成 原始的Poly 和 Detail化的Poly,本文介绍这两种。 Poly的边分成三种类型: 1. 正常边:有tile内部的poly与之相邻 2.border边:没有poly与之相邻 3.Portal边:与之相邻的是外部tile的poly   由firstLink索引 得到第一个连接的Poly  通

数据库期末复习知识点

A卷 1. 选择题(30') 2. 判断范式(10') 判断到第三范式 3. 程序填空(20') 4. 分析填空(15') 5. 写SQL(25') 5'一题 恶性 B卷 1. 单选(30') 2. 填空 (20') 3. 程序填空(20') 4. 写SQL(30') 知识点 第一章 数据库管理系统(DBMS)  主要功能 数据定义功能 (DDL, 数据定义语

SQL Server中,always on服务器的相关操作

在SQL Server中,建立了always on服务,可用于数据库的同步备份,当数据库出现问题后,always on服务会自动切换主从服务器。 例如192.168.1.10为主服务器,12为从服务器,当主服务器出现问题后,always on自动将主服务器切换为12,保证数据库正常访问。 对于always on服务器有如下操作: 1、切换主从服务器:假如需要手动切换主从服务器时(如果两个服务

相关网站

力扣  https://leetcode-cn.com/contest/weekly-contest-124

CALayer相关的属性

iOS开发UI篇—CAlayer层的属性 一、position和anchorPoint 1.简单介绍 CALayer有2个非常重要的属性:position和anchorPoint @property CGPoint position; 用来设置CALayer在父层中的位置 以父层的左上角为原点(0, 0)   @property CGPoint anchorPoint; 称为“定位点”、“锚点”

Avalonia 常用控件二 Menu相关

1、Menu 添加代码如下 <Button HorizontalAlignment="Center" Content="Menu/菜单"><Button.Flyout><MenuFlyout><MenuItem Header="打开"/><MenuItem Header="-"/><MenuItem Header="关闭"/></MenuFlyout></Button.Flyout></B

android的strings整理脚本

统一对String整理的工具,结构如下 代码 package com.owant.toollib;import java.io.BufferedReader;import java.io.File;import java.io.FileReader;import java.util.ArrayList;import java.util.List;import java.util

bootstrap和JS相关

下表列出了模态框中要用到事件。这些事件可在函数中当钩子使用。 bootstrap 显示隐藏div $('.show-info').click(function () {var show = $(this).data('show');if(show =='all'){$('#creative').show();$('#plan').show();$('#plan').attr('class','