赞
踩
由于项目上需要用到无刷电机,一般的无刷电机驱动器又大又不方便,所以最后选择了航模上使用的无刷电调,当时只是刚好看到BLHeli_S电调,就直接下单了。
使用电调控制无刷电机,最大的问题就是电机保护和油门行程校准。第一,单片机在控制电调驱动无刷电机的时候就需要跳过电机保护;第二,油门行程校准由于不同的协议没有具体的介绍,手上又没有遥控器和飞控,光靠单片机算法模拟一个值一个值来试是很难的。
一开始我是用单片机定时器试,后面买了个pwm测试电调的模块,完全适配BLHeli_S电调,用示波器发现调速很简单,就是50hz的1ms高电平3s左右就解锁电机保护,1-2ms高电平代表最小油门和最大油门。
一、让BLHeli_S电调控制无刷电机动起来
使用单片机连接BLHeli_S电调,白色PWM信号线,黑色为信号端接地校准。
电调连接电池和无刷电机,电调买的时候会介绍支持的电池,我的支持2S-6S(1S代表串联一块3.7V电池),我用的3S电池(11.1V),红接电池正极,黑接电池负极,无刷电机三相没有顺序随便接到电调。
因为需要用到无线功能,单片机我使用的是esp-12F和Arduino开发,代码如下,记得改WIFI名字和密码。其他的单片机也是一样的,都是模拟遥控器关闭电机保护控制电机。这里用的是定时器,换成20ms循环delayMicroseconds( us );//微秒级延时函数电机控制会更平滑,这主要是analogWrite(pin,i)//i在0-255之间,高电平时间对应数字大小从低到高,对于1-2ms需要千分度的油门来说调节精度不够,但是如果想单片机控制无刷电机又要做其他事情,就只能用这个定时器了。
- #include <ESP8266WiFi.h>
- #include <WiFiUdp.h>
-
- #define motor0 2 //GPIO2
-
- const char ssid[] = "Redmi K40"; // your network SSID (name)
- const char pass[] = "12345679"; // your network password
- WiFiUDP Udp;
- unsigned int localPort = 2380;
- char incomingPacket[255];
- float rd = 0;
- int Data_length;
-
- void setup()
- {
- Wire.begin();
- Serial.begin(115200);
- WiFi.begin(ssid, pass);
- while (WiFi.status() != WL_CONNECTED)
- {
- delay(500);
- Serial.print(".");
- }
- Serial.println(WiFi.localIP());
- Udp.begin(localPort);//启动UDP监听本地端口
- pinMode(motor0, OUTPUT);
- digitalWrite(motor0, LOW);
- analogWrite(motor0, 13);
- }
-
- void loop()
- {
- Data_length = Udp.parsePacket(); //获取接收的数据的长度
- if (Data_length) //如果有数据那么Data_length不为0,无数据Data_length为0
- {
- int len = Udp.read(incomingPacket, 255); //读取数据,将数据保存在数组incomingPacket中
- if (len > 0) //为了避免获取的数据后面乱码做的判断
- {
- incomingPacket[len] = 0;
- }
- Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); //准备发送数据到目标IP和目标端口
- Udp.print("Receive data:"); //将数据receive data:放入发送的缓冲区
- if (len == 1) { rd = int(incomingPacket[0]) - 48; }//一位数控制速度
- Udp.println(rd); //将接收到的数据放入发送的缓冲区
- Udp.endPacket(); //向目标IP目标端口发送数据
- }
- analogWrite(motor0, 13+rd);//13-25,13解锁,25最大速度
- }
白线接GPIO2,黑线接GND。接好线后,需要先在Arduino标签栏->工具->串口监视器,看串口管理器的回复IP。
然后打开NetAssist(串口调试助手),连接同一WiFi,选择UDP协议,随便使用一个本地主机端口,打开端口,在远程主机里输入你刚刚看到的回复IP:2380,并且发送一个数字看能否收到回复。
收到回复后,在窗口发送的数字就是可以调节的50Hz的PWM波高电平时间。
默认高电平时间是1ms,因为解锁BLHeli_S电调的电机保护就是高电平1ms。
上电单片机后,连接电调,当听到嘀、嘀、嘀(3S电池响3声短),然后滴(短),滴~(稍长的一声),电机解锁成功。在窗口输入个位数1-9,电机就可以进入转速工作模式,输入0停止。
如果需要精确控制,下面这里代码控制速度更加精确。
- #include <ESP8266WiFi.h>
- #include <WiFiUdp.h>
-
- #define motor0 2 //GPIO2
-
- const char ssid[] = "Redmi K40"; // your network SSID (name)
- const char pass[] = "12345679"; // your network password
- WiFiUDP Udp;
- unsigned int localPort = 2380;
- unsigned int sendport = 2390;
- char incomingPacket[255];
- float rd = 0;
- int Data_length;
-
- void setup()
- {
- Wire.begin();
- Serial.begin(115200);
- WiFi.begin(ssid, pass);
- while (WiFi.status() != WL_CONNECTED)
- {
- delay(500);
- Serial.print(".");
- }
- Serial.println(WiFi.localIP());
- Udp.begin(localPort);//启动UDP监听本地端口
- pinMode(motor0, OUTPUT);
- digitalWrite(motor0, LOW);
- analogWrite(motor0, 13);
- }
-
- void loop()
- {
- Data_length = Udp.parsePacket(); //获取接收的数据的长度
- if (Data_length) //如果有数据那么Data_length不为0,无数据Data_length为0
- {
- int len = Udp.read(incomingPacket, 255); //读取数据,将数据保存在数组incomingPacket中
- if (len > 0) //为了避免获取的数据后面乱码做的判断
- {
- incomingPacket[len] = 0;
- }
- Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); //准备发送数据到目标IP和目标端口
- Udp.print("Receive data:"); //将数据receive data:放入发送的缓冲区
- if (len == 1) { rd = int(incomingPacket[0]) - 48; }//一位数控制速度
- Udp.println(rd); //将接收到的数据放入发送的缓冲区
- Udp.endPacket(); //向目标IP目标端口发送数据
- }
- delayMicroseconds(19000-rd*100);
- digitalWrite(motor0,LOW);//管脚写入函数
- delayMicroseconds(1000+rd*100);
- digitalWrite(motor0,HIGH);//管脚写入函数
- }
二、Keil使用BLHeli_S电调工程
多次尝试之后,发现就使用航模的电调和自己的工程完全不匹配,如果不想自己做无刷驱动,又想直接用上无刷驱动电调,那就只能编程了。
在网上也搜了关于BLHeli_S电调的Keil工程,但是发现资料很少,这里主要参考此博主的文章,然后说一下自己遇到的坑。
原文链接:https://blog.csdn.net/qq_41100189/article/details/119832506
按照博主的内容,去keil官网填一下几个空,就可以下载软件C51V961.EXE,在github下载BLHeli_S工程源代码,BLHeli_S /SiLabs文件夹里所有文件就是源代码。
Github下载代码时,压缩包解压总提示不可预料的压缩末端,下多次也是一样,没办法,新建文件BLHeli_S.asm用记事本把网页上的4000行代码全部粘贴进去,效果是一样的。
我看了自己电调芯片型号为EFM8BB21F16G,然后数了电调上引脚数20,那就是和博主一样的EFM8BB21F16G-QFN20。
至于引脚方案怎么确定是哪个?我是看了电调引脚接线和芯片引脚图的,我的电调接线方案就是J_,估计大部分BLHeli_S电调都是。
keil新建工程并选择此芯片,只导入了BLHeli_S.asm,按照博主更改代码取消3处注释,这里代码已经有区别了。
ESCNO EQU J_
MCU_48MHZ EQU 2
FETON_DELAY EQU 50
一点编译,很多错误。
看了一下代码,Github的代码已经更新了,和原来博主下载到的代码不一致,而找Github历史版本又不确定是哪一版,没办法自己改最新版代码的报错,最后如下导入5个文件,下载不了就新建文件复制代码保存效果一致。
由于只需要用到J.inc的引脚定义,删除所有其他硬件类型判断,例如
IF ESCNO == A_
$include (A.inc) ; Select pinout A
ENDIF
然后就可以编译成功。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。