萝莉Loli双向有刷电调源代码 SDCC 版本

STC51单片机控制电调驱动无刷电机代码 /70us进入一次。/*这是我用4个30A的电调控制4个1000kv无刷电机的单片机程序。//控制脉宽和占空比。 阅读详情
AI摘要

博主在git上找到一份原用keil51编译的萝莉Loli双向有刷电调源代码,因使用macos无法安装keil51,将其改成可用免费的sdcc编译的版本,还添加了makefile工具。介绍了编译方法,指出适用的mcu型号,最后贴出源代码和github链接。

在git上找到这一份代码,感谢原作者的分享。原来应该是使用keil51编译的,我是macos, 没法安装,于是改了一下,让它可以使用免费的sdcc编译。 修改的过程也进行了阅读理解和注释,加上了makefile小工具。

把原来的keil的语法改成了sdcc的写法,可以使用sdcc编译。

## 编译方法

1. 安装sdcc

2. 安装make和srecord工具

3. 运行make命令

4. 如果不安装make 工具, 也可以使用命令行编译:

sdcc LoliDualBrusedBiEsc.c -o LoliDualBrusedBiEsc.ihx

使用的mcu是STC15 系列的应该都可以, 只有需要6个IO就可以了, 两个IO输出,4个IO输出.

如STC15W104系列, 使用sdcc编译出来大约是1.3K , 选用2K flash的型号应该就可以了, 使用dip8/dfn8 最少的脚的都行。

源代码比较小,直接贴出来,大家copy下来保存即可, 用到的朋友,请点个赞吧。

github的链接:GitHub - aerror2/LoliDualBrushedBiEsc: Loli Dual Brushed Motor bidirectional ESC firmware

#include <8052.h>

#define u8 unsigned char
#define u16 unsigned int
#define NOP() __asm NOP __endasm

//----------------------------------------------------------
//STC15寄存器声明

// 将这些行:
// sfr P3M1=0xb1;
// sfr P3M0=0xb2;
// sfr AUXR=0x8e;
// sfr T2H=0xd6;
// sfr T2L=0xd7;
// sfr IE2=0xaf;

//----------------------------------------------------------
//引脚定义
// sbit A1=P3^0;
// sbit A2=P3^1;
// sbit B1=P3^2;
// sbit B2=P3^3;
// sbit IN1=P3^5;
// sbit IN2=P3^4;


// 改为:
__sfr __at(0xB1) P3M1;    // P3M1 寄存器
__sfr __at(0xB2) P3M0;    // P3M0 寄存器
__sfr __at(0x8E) AUXR;    // AUXR 寄存器
__sfr __at(0xD6) T2H;     // Timer2 高字节
__sfr __at(0xD7) T2L;     // Timer2 低字节
__sfr __at(0xAF) IE2;     // 中断使能寄存器2



// 改为:
__sbit __at(0xB0) P30;  // P3.0  
__sbit __at(0xB1) P31;  // P3.1
__sbit __at(0xB2) P32;  // P3.2
__sbit __at(0xB3) P33;  // P3.3
__sbit __at(0xB5) P35;  // P3.5
__sbit __at(0xB4) P34;  // P3.4

#define A1 P30	//电机信号输出A
#define A2 P31  //电机信号输出A
#define B1 P32 //电机信号输出B
#define B2 P33  //电机信号输出B

#define IN1 P35   //pwm 输入1
#define IN2 P34	//pwm 输入2



//----------------------------------------------------------
//软件PWM

u8 PWM_count;
u8 PWM_duty_A;
u8 PWM_duty_B;

u8 PWM_value;

//----------------------------------------------------------
//控制

u16 timer1,timer2;

u16 pulse;

u16 IN1_H_time,IN2_H_time;
// 将这些行:
// bit IN1_last,IN2_last;
// bit get_pulse1,get_pulse2;
// bit get_new;
// bit Direction_A,Direction_B;

// 改为:
unsigned char status_bits;
#define IN1_last    (status_bits & 0x01)    // 位0
#define IN2_last    (status_bits & 0x02)    // 位1
#define get_pulse1  (status_bits & 0x04)    // 位2
#define get_pulse2  (status_bits & 0x08)    // 位3
#define get_new     (status_bits & 0x10)    // 位4
#define Direction_A (status_bits & 0x20)    // 位5
#define Direction_B (status_bits & 0x40)    // 位6

// 设置位的宏
#define SET_IN1_last()    (status_bits |= 0x01)
#define SET_IN2_last()    (status_bits |= 0x02)
#define SET_get_pulse1()  (status_bits |= 0x04)
#define SET_get_pulse2()  (status_bits |= 0x08)
#define SET_get_new()     (status_bits |= 0x10)
#define SET_Direction_A() (status_bits |= 0x20)
#define SET_Direction_B() (status_bits |= 0x40)

// 清除位的宏
#define CLR_IN1_last()    (status_bits &= ~0x01)
#define CLR_IN2_last()    (status_bits &= ~0x02)
#define CLR_get_pulse1()  (status_bits &= ~0x04)
#define CLR_get_pulse2()  (status_bits &= ~0x08)
#define CLR_get_new()     (status_bits &= ~0x10)
#define CLR_Direction_A() (status_bits &= ~0x20)
#define CLR_Direction_B() (status_bits &= ~0x40)

int mix_x,mix_y;

//bit Direction_A,Direction_B;


int pulse1=150,pulse2=150;
u8 lose_A=20,lose_B=20;  //更新:上电默认处于失控状态,防止第一次信号检测错误


//----------------------------------------------------------
//混控设置
#define  mix_en 0  //关闭混控,两路独立
//bit mix_en=1;  //开启混控






void delay_ms(u16 ms)		//STC15 @12.000MHz
{
	u16 i;

	do{
	    i = 12000000 / 13022;
		
		NOP();NOP();NOP();
		
		while(--i)	;   
     }while(--ms);	
}

void delay_us(u8 us)		//@12.000MHz
{

	while(--us)
	{
		NOP();NOP();
	}
}

void shock( u8 n)    //震动发声
{
	u8 i;
	for(i=0;i<250;i++)
	{
		A1=0,A2=0;
		B1=0,B2=0;		
		delay_us(n);
		
		A1=1;B1=1;
		delay_us(n);
		
		A1=0;B1=0;		
		delay_us(n);
				
		A2=1;B2=1;
		delay_us(n);	
	}
	A1=0,A2=0;
	B1=0,B2=0;
	delay_us(n);
}


void main()
{
	
 	P3=0xF0;	      //上电关闭输出
 
	P3M0=0x0F;      //IO推挽输出
	
	delay_ms(400);
	
	shock(200);	//新增 上电音乐,表明正常工作
	shock(150);
	shock(100);
	
	
	IE=0x80;
	IE2=0x04;
	T2L=0xF6;T2H=0xFF;  //开启软件PWM
	AUXR=0x10;
// 定时器初值:
// T2H = 0xFF, T2L = 0xF6
// 16位初值 = 0xFFF6 = 65526
// 计数次数 = 65536 - 65526 = 10
// 在12T模式下的中断周期:
// 系统时钟:12MHz
// 在12T模式下,定时器时钟 = 12MHz ÷ 12 = 1MHz
// 中断周期 = 10 × (1/1MHz) = 10μs
// AUXR = 0x10 = 0001 0000 (二进制)
// 第3位(T2x12) = 0  12分频
// 第4位(T2C/T) = 0   ,T2C/T=0,内部时钟
// 第5位(T2R)=1 , 允许T2 运行

	
	while(1)
	{
		
		if(get_pulse1)
		{
			CLR_get_pulse1();
			
			pulse =IN1_H_time;			
			IN1_H_time=0;
			
			if(pulse >85 && pulse <215) //只受理合理舵量范围
			{
				timer1=0;
				
				if(pulse <105)pulse =105;
				if(pulse >195)pulse =195; 
				
				if(lose_A)lose_A--;  //丢信号重连保护
				else { SET_get_new(); pulse1=pulse; }
				
			}
			
		}
		
		if(get_pulse2)
		{
			CLR_get_pulse2();
			
			pulse =IN2_H_time;			
			IN2_H_time=0;
			
			if(pulse >85 && pulse <215)
			{
				timer2=0;
				
				if(pulse <105)pulse =105;
				if(pulse >195)pulse =195;		//舵量限幅 1050~1950	

				if(lose_B)lose_B--;  //丢信号重连保护
				else { SET_get_new(); pulse2=pulse; }
			}			
			
		}
		
		
		if(get_new)
		{
			CLR_get_new();
			
			if(mix_en)  //引脚高电平 使能混控
			{
				if(pulse2>152 || pulse2<148) //通道2为差向输入,中位死区
				{
					mix_x=pulse1 + pulse2 -150;  
					mix_y=pulse1 - pulse2 +150;	
				}
				else
				{
					mix_x=pulse1;   //通道1为同向输入,
					mix_y=pulse1;
				}
							
			}
			else        //引脚低电平 两通道独立
			{
				mix_x=pulse1;
				mix_y=pulse2;				
			}
			
			
			if(mix_x<105)mix_x=105;
			if(mix_x>195)mix_x=195;
			
			if(mix_y<105)mix_y=105;
			if(mix_y>195)mix_y=195;
			
// 理想电机特性:
// PWM占空比    转速
// 0%    →     0 RPM
// 20%   →     20% 最大转速  
// 50%   →     50% 最大转速
// 100%  →     100% 最大转速			
// 实际电机特性:
// PWM占空比    转速
// 0%    →     0 RPM
// 20%   →     0 RPM (静摩擦力未克服)
// 30%   →     5% 最大转速 (刚好克服静摩擦)
// 50%   →     45% 最大转速
// 100%  →     100% 最大转速
//
			//===========================================================
			// A路电机控制量计算 - 摩擦力补偿算法
			// mix_x取值范围:105-195(对应1050-1950μs)
			// 核心思想:通过非线性映射克服电机静摩擦力,实现平滑可控
			//===========================================================
			if(mix_x>=153 )       // A路正转区间:>=1530μs
			{
				//=======================================================
				// 正转摩擦力补偿公式:(mix_x-151)*100/44
				//=======================================================
				// 关键参数解析:
				// • mix_x-151:起始点偏移补偿
				//   - 151而非150(中位):提供1单位预加载
				//   - 当mix_x=153时:153-151=2 → 最小输出≠0
				//   - 避免在静摩擦阈值附近震荡
				//
				// • 除以44而非45:量程优化补偿  
				//   - 理论量程:195-150=45
				//   - 实际量程:195-151=44
				//   - 效果:将更多分辨率分配给低速区间
				//
				// • 乘以100:转换为百分比PWM占空比
				//
				// 补偿效果对比:
				// 遥控量  |  线性映射  |  补偿映射  |  实际转速响应
				// 153     |    6.7%    |   4.5%    |  立即缓慢启动
				// 160     |   22.2%    |  20.5%    |  平滑低速运行  
				// 180     |   66.7%    |  65.9%    |  稳定中速运行
				// 195     |   100%     |   100%    |  最高速运行
				PWM_duty_A= (mix_x-151)*100/44; // 补偿摩擦力的非线性映射
				CLR_Direction_A();        // 设置A路正转方向(A2输出PWM,A1保持低)
			}
			else if(mix_x<=147 )  // A路反转区间:<=1470μs
			{
				//=======================================================
				// 反转摩擦力补偿公式:(149-mix_x)*100/44
				//=======================================================
				// 对称性设计原理:
				// • 149-mix_x:反向起始点偏移
				//   - 149而非150:提供反向1单位预加载
				//   - 当mix_x=147时:149-147=2 → 最小反向输出≠0
				//   - 与正转形成完美对称的控制特性
				//
				// • 反向量程:149-105=44(与正转量程相同)
				//   - 保证正反转响应的一致性
				//   - 用户操作感受完全对称
				//
				// 反转补偿效果:
				// 遥控量  |  反转深度  |  PWM占空比  |  实际转速响应
				// 147     |     2      |    4.5%     |  立即缓慢反转
				// 140     |     9      |   20.5%     |  平滑低速反转
				// 120     |    29      |   65.9%     |  稳定中速反转  
				// 105     |    44      |    100%     |  最高速反转
				PWM_duty_A= (149-mix_x)*100/44; // 反转摩擦力补偿
				SET_Direction_A();        // 设置A路反转方向(A1输出PWM,A2保持低)
			}
			else                  // A路停止死区:1470-1530μs(60μs宽度)
			{
				//=======================================================
				// 死区设计的工程意义:
				//=======================================================
				// • 防止误触发:遥控杆中位附近的微小抖动不会导致电机转动
				// • 明确停止:提供清晰的"停止"状态,用户操作更确定
				// • 保护电机:避免正反转快速切换导致的电流冲击
				// • 节能设计:中位时完全关闭PWM输出
				PWM_duty_A=0;        // 完全停止输出,电机进入制动状态
			}
			
			//===========================================================
			// B路电机控制量计算(基于mix_y的值)
			// mix_y取值范围:105-195(对应1050-1950μs)
			//===========================================================
			if(mix_y>=153 )       // B路正转判断:>=1530μs(中位150+死区3)
			{
				// 正转PWM占空比计算:
				// (mix_y-151)*100/44 
				// 当mix_y=153时:(153-151)*100/44 = 4.5%
				// 当mix_y=195时:(195-151)*100/44 = 100%
				// 151是正转起始点,44是满量程范围(195-151)
				PWM_duty_B= (mix_y-151)*100/44; // 补偿摩擦力的非线性映射
				CLR_Direction_B();        // 设置B路正转方向(B2输出PWM)
			}
			else if(mix_y<=147 )  // B路反转判断:<=1470μs(中位150-死区3)
			{
				// 反转PWM占空比计算:
				// (149-mix_y)*100/44
				// 当mix_y=147时:(149-147)*100/44 = 4.5%  
				// 当mix_y=105时:(149-105)*100/44 = 100%
				// 149是反转起始点,44是满量程范围(149-105)
				PWM_duty_B= (149-mix_y)*100/44; // 反转时占空比递增
				SET_Direction_B();        // 设置B路反转方向(B1输出PWM)
			}
			else                  // B路停止区间:1470-1530μs(60μs死区)
			{
				PWM_duty_B=0;        // 停止输出,电机制动
			}
			
		}
		
		
	}
	
}

//10us 触发一次调用
//IN1_H_time 取值 0-255, 即0-2550us
//IN2_H_time 取值 0-255, 即0-2550us
//PWM_count 是0-100, 即每1000us 重置一次
//PWM_duty_A 和PWM_duty_B, 取值都是0-100,当PWM_count 小于PWM_duty_A/B时,管脚高电平,否则低
//软件PWM 1Khz
void T2_isr() __interrupt(12)
{

	
	if(IN1)					//通道1脉宽检测
	{
		SET_IN1_last();
		IN1_H_time++;
	}
	else 
	{
		if(IN1_last)  SET_get_pulse1();
		CLR_IN1_last();
	}
	
	if(IN2)					//通道2脉宽检测
	{
		SET_IN2_last();
		IN2_H_time++;
	}
	else 
	{
		if(IN2_last) SET_get_pulse2();
		CLR_IN2_last();
	}	
	
	
	PWM_count++;
	if(PWM_count==100) //100级分辨率
	{
		PWM_count=0;
		
		timer1++;
		if(timer1>500)//0.5S无信号保护
		{
			timer1=0; lose_A=30;
			
			pulse1=150; SET_get_new();		
		}
		
		timer2++;
		if(timer2>500)//0.5S无信号保护
		{
			timer2=0; lose_B=30;
			
			pulse2=150; SET_get_new();		
		}
	}
	
	
	//=======================================================================
	// PWM输出控制部分 - 每10μs执行一次(中断频率100kHz)
	// PWM周期:1ms(PWM_count从0计数到100)
	// PWM分辨率:100级(占空比精度1%)
	//=======================================================================
	
	// A路电机H桥PWM控制
	if(PWM_duty_A > PWM_count)    // PWM有效期间(高电平期间)
	{
		if(Direction_A)           // 方向控制:1=反转,0=正转
			A1=1;                 // 反转:A1高,A2保持低(由else分支控制)
		else 
			A2=1;                 // 正转:A2高,A1保持低(由else分支控制)
	}
	else A1=0,A2=0;              // PWM无效期间:A1、A2都为低电平(电机停止/刹车)
	
	// B路电机H桥PWM控制(逻辑与A路相同)
	if(PWM_duty_B > PWM_count)    // PWM有效期间(高电平期间)
	{
		if(Direction_B)           // 方向控制:1=反转,0=正转  
			B1=1;                 // 反转:B1高,B2保持低
		else 
			B2=1;                 // 正转:B2高,B1保持低
	}
	else B1=0,B2=0;              // PWM无效期间:B1、B2都为低电平(电机停止/刹车)

	
}

Makefile

CC = sdcc
stctool = stcgal
protocol = stc15
upload_port = /dev/tty.wchusbserial*

all: build

build:
	@mkdir -p build
	$(CC) LoliDualBrusedBiEsc.c -o build/LoliDualBrusedBiEsc.ihx
upload:
	$(stctool) -P $(protocol) -p $(upload_port) LoliDualBrusedBiEsc.ihx

clean:
	rm -f *.asm *.lst *.map *.mem *.rel *.rst *.sym *.lk *.hex *.ihx
	rm -rf build

萝丽双路双向电调 - B版源码.rar 萝丽双路双向电调 - B版源码 立即下载

相关推荐

开源遥控器萝丽遥控接收电调资料合集

集成单路有刷电调,无刷电调,遥控器改装,原版教程

LOLI遥控萝丽控制器开源项目的制作过程问题总结

前言 萝丽遥控器是一个国人项目,这一个项目主要是航模遥控器,接收机的组合,有着容易使用,成本低廉的特点,关键是功能还很完整。 当然是使用过程中我遇到了很多问题,这些问题并没有在网络上被列出所以这里进行总结希望能提供给其他人参考。 萝丽控制器电调资料合集 链接:https://pan.baidu.com/s/1R23THVEkKdnOa5l_pxuZog 提取码:82kv --来自百度网盘超级会员V6的分享 如何使用OLED替代LCD 这个应该使用OLED兼容固件,我试了一下,可以

arenascat的博客 1万+

Loli3:这个是萝莉3航模遥控器的开源项目,包含硬件电路及固件源码,原创作者“我爱萝丽爱萝莉”,原发于“模型中国”论坛,后来“模型中国”论坛消亡,作者遂转战于“模友之吧”,虽然萝莉4代从提出到现在已经有1年半了(2017年12月31日提出萝莉4代至今),但由于4代正式版一直难产当中,到目前为止最新版本仍然是3代,由于群(1群:272416403; 2群:556473744)里文件比较混乱,特将相关内容放于git上,奢望能统一管理源码。所以我随便选了个MIT吧。

萝莉3 介绍 这个是萝莉3航模遥控器的开源项目,包含硬件电路及固件源码,原创作者“我爱萝丽爱萝莉”,原发于“模型中国”论坛,后来“模型中国”论坛消亡,作者遂转战于“模友之吧”,虽然萝莉4代从提出到现在已经有1年半了(2017年12月31日提出萝莉4代至今),但由于4代正式版一直难产当中,到目前为止最新版本仍然是3代,由于群(1群:272416403; 2群:556473744)里文件比较混乱,特将相关内容放于git上,奢望能统一管理源码。所以我随便选了个MIT吧。托管于几个git仓库: 【这个是主仓库,其他的为备份,有事没事都不会在那几个仓库出现,所以有问题请在这个主仓库提交】 软件架构 软件架构说明 安装教程 xxx xxx xxx 使用说明 xxx xxx xxx 参与贡献 叉本仓库 新建Feat_xxx分支 提交代码 新建Pull Request 编码云特技 使用Rea

【无人机】无刷电调学习之路

无刷电调的设计学习

Maker_Li的博客 7711

关于萝莉三代控源码的通信部分解读.doc

因为做了个手机遥控App,又利用1元蓝牙pos机改2.4G转发器完成后,想兼容萝莉的三代6通道接收器,所以研究了一下萝莉的开源代码。关于萝莉三代控源码的通信部分解读,关于萝莉三代控源码的通信部分解读

【我爱萝丽爱萝丽】震撼发布!第三代航模遥控器 DIY教程(正式A版已更新!)遥控飞机,遥控直升机,遥控汽车 - Powered by Discuz!.pdf

萝莉遥控器

四合一高频头加入萝莉协议LUOLI接收机

需要 使用彩屏的遥控器系统版本2.3.10以上,配合lua调整接收机模式

飞盈佳乐(Flycolor )双向电调书说明书

251400-1131 V1.0 Magellan WP 80A 5-14S 双向电调中英文说明书.pdf

萝莉遥控乐高电机

改装乐高积木电机控制

yyandad的博客 7246

电调.rar_STC15F104W_stc 电调_stc15w 有刷电调_电调 开发_萝莉电调

基于stc15f104w超小单片机实现的有刷电调,可以输出5v电压, 可以搭配商用接收机使用

萝丽航模遥控器与接收的原理图DXP工程及keil程序源码和固件资料.zip

萝丽航模遥控器与接收的原理图DXP工程及keil程序源码和固件资料 12通道发射机原理图 12通道接收机原理图 8通接收PCB原理图工程 8通接收原理图.pdf 六_八通接收A10.5程序工程 六通接收机原理图.jpg 萝丽三代6通接送机A10.5源码.c 萝丽三代遥控器正式A版固件.hex 萝丽三代遥控器正式A版程序代码.rar 萝丽新版6通接收机A版固件.hex 萝丽新版6通接收机A版程序.c 萝丽旧版12通接收机兼容A版程序.c 萝丽旧版6通接收机兼容A版程序.c 萝莉三代新发射机正式版本原理图.pdf 遥控器以及六_12通接收原理图PCB

2021-12-22 nrf24 萝莉遥控

1/

weixin_44148981的博客 2031

萝莉3-单片机引脚定义、焊接图、原理图1

萝莉3-单片机引脚定义、焊接图、原理图1

STC51单片机27——控制无刷电机

STC单片机,控制无刷电机

fengyuzhe13的专栏 2129

萝莉三代8通接收电路图1

萝莉三代8通接收电路图此为非官方版本,仅供参考。官方版本出来后,以官方为准。

[追梦哥]萝莉三代原理图2

[追梦哥]萝莉三代原理图2

STC无刷电调技术分享

STC无刷电调技术分享

LevolutionL的博客 8785

萝丽双路双向电调 - B版固件(双路独立).rar

萝丽双路双向电调 - B版固件(双路独立)

上一篇: Futaba乐迪小飞象Frsky7通多协议接收机KA6说明书
下一篇: 使用python写一个虚拟的舵机模拟器
aerror
博客等级 码龄23年 393粉丝 193原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值