STM32通过PWM控制ESC30C电调

最近在搞一个水下推进器,这东西的控制其实跟四旋翼的螺旋桨控制差不多。但我也是第一次用STM32板子来控制电调驱动桨叶旋转,因此踩了很多坑。网上找了很多资料,但是很多都写的不是很清楚,这边稍微记录一下怎么解决。大家买来的电调可能会有所不同,但是总体的控制思路是一样的,所以我相信你看完我这篇文章之后肯定能直接上手了。

电调基础

这是我这次买的ESC30电调(具体链接戳这里)。这图已经很清楚了,上面的红黑两条粗线就是用来接电池(3S和4S的均可)的,你可以买一个接线端子然后把电源盒这两根线接一块。然后黑白二线是信号线,白线接的是信号,黑线接的是地。下面的白绿蓝三线就是接到你电机上用来控制的三相线,关于无刷电机内容我这边就不展开讲了。

这里再稍微补充一点,常用的航模电调的信号线应该是三根线(红白黑)。对应的,白线仍然接PWM信号,黑线接地,红线接电。
在这里插入图片描述
在你买来开始调试控制之前,请务必仔细看一下这个电调的相关参数,这很重要!常用的航模电调一般都是单向的,也就是只能单方向旋转,但是以我这个为例,这是双向电调。
在这里插入图片描述
主要看信号这一栏,可以总结的内容如下:

  1. PWM波控制(一般来说电调都是在50Hz下的PWM波进行控制的,也就是20ms);
  2. 中位停止(这里一般指的都是高电平的占空比)1.5ms,实际在1.475ms到1.525ms之间都是出于中位停止;
  3. 控制范围在1ms至2ms,其中由于死区存在,因此实际控制范围为1.1ms到1.9ms之间;
  4. 1.5ms到1.9ms出于正转,1.1ms到1.5ms出于反转。

官方给出的控制程序是基于Arduino的,可以简单参考一下:

#include <Servo.h>

byte servoPin = 9;
Servo servo;

void setup() {
	servo.attach(servoPin);

	servo.writeMicroseconds(1500); // send "stop" signal to ESC.
	delay(1000); // delay to allow the ESC to recognize the stopped signal
}

void loop() {
	int signal = 1700; // Set signal value, which should be between 1100 and 1900

	servo.writeMicroseconds(signal); // Send signal to ESC.
}

注意:电调使用之前是需要解锁的!你接上电源之后电调会响3声,然后解锁成功之后电调会再响2声,总共5声。解锁不成功是无法使用电调进行控制的。 因此我们参考上述代码(当然你可以问客服),可以得出结论,ESC30C的解锁方式就是在初始化之后先设定到中位信号,等待信号接收后(响两声)才能开始调速。

控制及调试方法

我是用STM32F7的开发板,使用HAL库进行编程调试的,实际上就是一个定时器输出PWM波的事(蛮简单的这里就只挑部分说)。但是这之中有很多需要注意的事项,很多细节不清楚真的很耽误时间和精力,这边简单说一下我调试的经验。

首先是在定时器中配置PWM波时,注意不要将其初始化为你的解锁信号,给他一个随机值,或者要么就不配置。因为电调解锁是在定时器以及PWM初始化之后才进行的,以我这个为例,1.5ms中位停止信号是它的解锁信号,那你就不能在配置PWM的时候一开始就将它配置为1.5ms,否则电调在开机三声之后只会在响一声,然后你的桨叶仍不会转。

	//配置PWM波
	TIM3_CH1Handler.OCMode = TIM_OCMODE_COMBINED_PWM1;	//PWM模式1,CNT < CCRx值时为有效电平
	TIM3_CH1Handler.OCPolarity = TIM_OCPOLARITY_HIGH;		//高电平为有效电平
	//TIM3_CH1Handler.Pulse = 15;		//此处不配置,否则电调无法完成解锁
	HAL_TIM_PWM_ConfigChannel(&TIM3_Handler, &TIM3_CH1Handler, TIM_CHANNEL_1);	//TIM3通道1配置,即PA6

其次,注意使用延时。开始时我并没有采用延时,导致的结果就是电调只哔了一声之后就是没有反应,后面在用示波器观察PWM波的时候发现自己初始化的PWM就直接一闪而过了,再查阅资料发现需要给电调接收解锁信号的时间。但是这个时间也是有讲究的,一开始我是用的是 delay_us()进行配置,问题无法解决,后来改用 delay_ms(1000) 也就是配置1s的时间,仍然有问题,后面把时间再次调大之后才最终听到两声哔,然后电机就开始转动了。因此如何把握这个解锁信号的接收时间很重要。

	//电调初始化,初始化脉宽随机
	TIM3_PWM_Init(199, 10799);
	delay_ms(1000);
	//电调解锁:1.给电调发送中位信号;2.延时等待解锁完成,延时时间t≥1.5s
	TIM_SetTIM3Compare(15);
	delay_ms(1500);

还有在使用过程中注意学会配合示波器检查自己配置的信号是否有问题。下面是我一开始初始化的1.5ms占空比的PWM波,周期20ms,幅值3.3V。
在这里插入图片描述
总结起来,整个过程中要注意:

  1. 电调一般来说都是在50Hz频率下进行控制的,控制范围大概是在1ms到2ms之间,当然视具体情况而定。
  2. 在接电源之后电调会响3声,如果你解锁成功,之后电调还会再响2声。但是如果电调只响了1声,大概就是电调已经接收到了你配置的信号,但是并没有解锁成功,此时就需要仔细检查一下自己的解锁部分代码有没有编写错误了。如果电调没有响,那就是连信号都没接收到,仔细检查一下自己的配线以及代码问题。
  3. 注意使用延时函数给电调一定的时间用来接收解锁信号,每个电调都有所不同,这个自己调整。
  4. 注意接地,电调的信号线接到控制板的信号输出端口,然后信号线的地线接到控制板的GND。
  5. 学会使用示波器来检查自己配置的信号。
  6. 不要接错线了!(我就是这样烧了一个我的电池的)
  • 20
    点赞
  • 135
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
/* This file is part of AutoQuad ESC32. AutoQuad ESC32 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AutoQuad ESC32 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with AutoQuad ESC32. If not, see . Copyright © 2011, 2012 Bill Nesbitt */ /* * pwm.c文件.此文件有2个功能,2个功能分别使用,不能同时使用 * 1、pwm in输入模式,pwm输入中断里,调用runNewInput函数 * 2、one wire通讯协议,pwm输入中断里,调用owEdgeDetect函数,来输入新的数据,调用owReset函数来复位1wire通讯 * */ #include "pwm.h" #include "timer.h" #include "run.h" #include "main.h" #include "ow.h" #include "stm32f10x_gpio.h" #include "stm32f10x_tim.h" #include "misc.h" static int16_t pwmMinPeriod; //timer1 ch1 pwm 输入最小周期 static int16_t pwmMaxPeriod; //timer1 ch1 pwm 输入最大周期 int16_t pwmMinValue; //timer1 ch2 pwm 输入最小周期 static int16_t pwmMaxValue; //timer1 ch2 pwm 输入最大周期 int16_t pwmLoValue; int16_t pwmHiValue; int16_t pwmMinStart; volatile uint32_t pwmValidMicros; //关闭输入捕获比较中断 1和2 void pwmIsrAllOff(void) { PWM_TIM->DIER &= (uint16_t)~(TIM_IT_CC1 | TIM_IT_CC2);//关闭中断 } //开启输入捕获比较中断 1和2 void pwmIsrAllOn(void) { PWM_TIM->CCR1; PWM_TIM->CCR2; PWM_TIM->DIER |= (TIM_IT_CC1 | TIM_IT_CC2);//允许捕获比较 1 2中断 } //开启捕获比较2中断 void pwmIsrRunOn(void) { uint16_t dier = PWM_TIM->DIER; dier &= (uint16_t)~(TIM_IT_CC1 | TIM_IT_CC2); dier |= TIM_IT_CC2;//允许捕获/比较2中断 PWM_TIM->CCR1; PWM_TIM->CCR2; PWM_TIM->DIER = dier; } //timer 1 void pwmInit(void) { GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; TIM_ICInitTypeDef TIM_ICInitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; pwmSetConstants(); // TIM1 channel 1 pin (PA.08) configuration GPIO_InitStructure.GPIO_Pin = PWM_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(PWM_PORT, &GPIO;_InitStructure); // Enable the TIM1 global Interrupt NVIC_InitStructure.NVIC_IRQChannel = PWM_IRQ; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC;_InitStructure); TIM_TimeBaseStructInit(&TIM;_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Prescaler = (PWM_CLK_DIVISOR-1); TIM_TimeBaseStructure.TIM_Period = 0xffff; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(PWM_TIM, &TIM;_TimeBaseStructure); TIM_ICInitStructure.TIM_Channel = PWM_CHANNEL; TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; TIM_ICInitStructure.TIM_ICFilter = 0x0; TIM_PWMIConfig(PWM_TIM, &TIM;_ICInitStructure); // Select the TIM Input Trigger: TI1FP1 // 滤波后的定时器输入1(TI1FP1) TIM_SelectInputTrigger(PWM_TIM, TIM_TS_TI1FP1); // Select the slave Mode: Reset Mode TIM_SelectSlaveMode(PWM_TIM, TIM_SlaveMode_Reset);//复位模式 // Enable the Master/Slave Mode TIM_SelectMasterSlaveMode(PWM_TIM, TIM_MasterSlaveMode_Enable); // TIM enable counter TIM_Cmd(PWM_TIM, ENABLE); pwmIsrAllOn(); } //timer1 TIM1_CC_IRQHandler中断 void PWM_IRQ_HANDLER(void) { uint16_t pwmValue; uint16_t periodValue; uint8_t edge; edge = !(PWM_TIM->SR & TIM_IT_CC2); periodValue = PWM_TIM->CCR1; //IO 输入PA8 周期 pwmValue = PWM_TIM->CCR2; //IO 输入(但是没有看到配置了使用哪个IO做为输入了) 脉宽长度 // look for good RC PWM input if (inputMode == ESC_INPUT_PWM && //PWM输入模式 periodValue >= pwmMinPeriod && periodValue = pwmMinValue && pwmValue <= pwmMaxValue //脉宽长度 ) { if (edge == 0) { pwmValidMicros = timerMicros; runNewInput(pwmValue); //PWM正确.输入 } } } void pwmSetConstants(void) { float rpmScale = p[PWM_RPM_SCALE]; pwmMinPeriod = p[PWM_MIN_PERIOD] = (int)p[PWM_MIN_PERIOD];//PWM最小周期 timer1 ch1 pwmMaxPeriod = p[PWM_MAX_PERIOD] = (int)p[PWM_MAX_PERIOD];//PWM最大周期 timer1 ch1 pwmMinValue = p[PWM_MIN_VALUE] = (int)p[PWM_MIN_VALUE]; //PWM最小周期 timer1 ch2 pwmMaxValue = p[PWM_MAX_VALUE] = (int)p[PWM_MAX_VALUE]; //PWM最大周期 timer1 ch2 pwmLoValue = p[PWM_LO_VALUE] = (int)p[PWM_LO_VALUE]; pwmHiValue = p[PWM_HI_VALUE] = (int)p[PWM_HI_VALUE]; pwmMinStart = p[PWM_MIN_START] = (int)p[PWM_MIN_START]; if (rpmScale PWM_RPM_SCALE_MAX) rpmScale = PWM_RPM_SCALE_MAX; p[PWM_RPM_SCALE] = rpmScale; } ESC32开源电调 源码与原理图,此源码采用RTT操作系统,CAN PWM操作方式 ,本人已用PWM方式成功驱动起来,CAN 暂且还没做测试。 此资料是 啊嘉 开源出来的,好资料不敢独享,稍加整理放到这与大家共享。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值