用STC15W4K做了个同步整流电调,可以转起来了。
MOS管用6个IRF7832,MOS驱动用的NCP5181,STC15W4K 有6个可控制死区的PWM,实现同步整流比较简单。目前采用ADC在PWM OFF过0检测,当然现在就是学习一下,接下来打算借鉴别人的做法,在PWM大于50%时在PWM ON过0检测,稍后拍个视频和大家分享一下,等弄的差不多了和大家分享代码。没有启动算法,10%占空比直接启动,目前没发现启动失败,同步整流响应很快,特别是减速,瞬间速度就下来了 用stm32比较容易 方便在PWM ON 50%处检测,stc不知道有没有这样的功能 http://v.youku.com/v_show/id_XOTI3NzQ0NDE2.html
目前只是串口控制 foxpro2005 发表于 2015-4-5 23:06
用stm32比较容易 方便在PWM ON 50%处检测,stc不知道有没有这样的功能
我目前在PWM OFF快结束启动ADC检测,当然转换必须在下一个PWM上升沿来到之前转换完毕,用定时器控制ADC,即在PWM上升中断来到时启动定时器,定时35us后启动ADC(PWM22.8kHz,43us每周期,ADC只占用5us就够了),我想PWM ON检测方法是一样的,但是需要控制好过0检测电阻网路的切换,我就是用了ST 的那个过0检测方法,启动即可拉到闭环(如果25ms内无换向要强制换向),很意外,我想这主要归功于同步整流,不需要经过二极管续流产生压降,过0可以很精确。 嗯,刚看了一下视频效果,还不错,给你点个赞 本帖最后由 STCunio 于 2015-4-7 13:26 编辑
littlem 发表于 2015-4-6 09:48
我目前在PWM OFF快结束启动ADC检测,当然转换必须在下一个PWM上升沿来到之前转换完毕,用定时器控制ADC, ...
请问用PWM ON 50%实现电阻网络的过零检测的方法?有没有资料?ST 的那个过0检测方法能具体说一下吗? STCunio 发表于 2015-4-7 13:24
请问用PWM ON 50%实现电阻网络的过零检测的方法?有没有资料?ST 的那个过0检测方法能具体说一下吗? ...
http://wenku.baidu.com/link?url=suZ_aoP15jj_Tg1lTLufefMdcfaAB708uvfUltv-XtvoRqLi-lk0jWxQ4hy3Fuj8Wng_JQ2Gsdr9NKRyGChwkTcC15riFG2gsAnvR7N6-se
我就是看了这个做的,用15W4K做电调 感觉还是可以的,PWM中断也可当定时器用,比如堵转时长检测,甚至PPM信号检测 对楼主的方式很感兴趣,期待分享原理图和源码,谢谢!{:3_59:} 顶一下 最近就想做电调 对15系列也比较感兴趣 希望楼主早日完工 开源 这段时间工作忙,闲了继续,完善好了一定会和大家分享,谢谢支持! LZ也可以先贴代码,大家来完善,不需要一个人战斗。
//*****************************************说明************************************************
//本程序为STC15W4K系列单片机驱动无感BLDC电调程序,作者:河南有色地质七队 马腾飞
//晶振频率35MHz,驱动MOS的PWM频率位27.45kHz
//采用全NMOS IRF7832(20A/30V)半桥驱动芯片FAN5109,PWM单输入,带输出使能控制
//本电调为采用同步驱动方式,续流不经二极管,启动即可检测到反电动势,进入闭环运行,在占空比小于50%时,使用ADC在PWM OFF进行过零检测
//占空比大于50%时在PWM ON进行过零检测,切换自如不会发生抖动,低速、高速性能都比较好
//在调试时发现同步续流方式利于启动,而且响应极快,特别是减速性能,速度可以瞬间下降(程序中设置占空比变化延时,经实测占空比如果突变
//会MOS半桥驱动一起烧)
//电调输入电压不得超过15V,否则会烧,这是由FAN5109决定的,但其性能比较优越,驱动电流大,死区只有几十ns。
//PPM信号 1.1ms高电平启动,2ms最大油门,油门信号丢失或不合法1s后开始降低输出功率直至到停止,该过程持续2s.
//有过零换向延时,但没有过零检测,因为刚开始设计时没有设计此部分电路,不过可方便添加
//**********************************************************************************************
#include <stc15.h> //用STC官方头文件
#include <intrins.h>
sbit Phase_A = P2^1; //PWM模块PWM3
sbit Phase_B = P2^2; //PWM模块PWM4
sbit Phase_C = P2^3; //PWM模块PWM5
sbit EN_A_MOS_DRV=P3^7; //控制A相的半桥驱动使能:1:使能MOS驱动器MOS由PWM控制;0:上下MOS均断开,该相悬浮
sbit EN_B_MOS_DRV=P4^2; //控制B相的半桥驱动使能:1:使能MOS驱动器MOS由PWM控制;0:上下MOS均断开,该相悬浮
sbit EN_C_MOS_DRV=P4^4; //控制C相的半桥驱动使能:1:使能MOS驱动器MOS由PWM控制;0:上下MOS均断开,该相悬浮
sbit LED =P0^4;
sbit INT1=P3^3; //PPM信号控制
#define uchar unsigned char
#define uintunsigned int
uchar Duty_Current;
uchar Duty_Set;
uchar AD_Sample_Delay; //ADC采样延时,避开消磁阶段采样干扰
uchar Commutaion_Time_Interval; //换向时间间隔
uchar PWM_ADC_Sampling; //1:PWM ON采集反电动势 0:PWM OFF采集反电动势
uchar Step; //换向序号
uchar Commutaion_Delay; //换向延时计数变量
uchar V_Mid; //中点电压存放变量
uchar Dly;
uint Base_Timer; //以PWM7中断为节拍的计数存储变量
uint Elec_Period; //一个完整电周期计数值,该值×PWM周期(36.43us)即为一个电周期时长
uint Elec_Period_temp; //中间累加变量
uint PPM_Timeout; //PPM信号计数器溢出计数
uint PPM_HighLevel; //PPM信号高电平计数,值×0.34us=高电平时长
uint PPM_LowLevel; //PPM信号低电平计数,值×0.34us=高电平时长
bit You_Can_Start; //BLDC启动指令标志,1:启动条件具备需要启动;0:需要停止运行
bit Already_Start; //BLDC状态标志,1:已启动;0:停机状态
bit Falling_Edge; //侦测反电动势边沿标志,1:迎接下降沿;0:迎接上升沿
bit Cross_Zero; //反电动势过零标志1:检测到过零事件后置1;0:换向完成后才置0
bit Signal_Lost;
bit Signal_Ready;
bit PPM_High_Overflow;
bit PPM_LOW_Overflow;
#define CYCLE 255 // cycle 8位PWM
#define EN_PHASE_A_PWM_OUTPUT PWMCR=0x82 // 硬件接PWM3
#define EN_PHASE_B_PWM_OUTPUT PWMCR=0x84 // 硬件接PWM4
#define EN_PHASE_C_PWM_OUTPUT PWMCR=0x88 // 硬件接PWM5
#define Startup_Duyt_Cycle 15//启动占空比15/256=6%
#define Location_Duyt_Cycle 4//转子定位占空比
#define Start_Commutaion_Delay 18//启动换向延时(仅用于启动,先填一个数/6=每次换向延时)
#define DISABLE_OUTPUT_ALL PWMCR=0x00,EN_A_MOS_DRV=0,EN_B_MOS_DRV=0,EN_C_MOS_DRV=0,Phase_A=0,Phase_B=0,Phase_C=0,PWMIF=0 //关闭所有MOS输出清除中断标志
#define ADC_FLAG 0x10 //ADC转换标志
#define Delay_5_Degrees Elec_Period/72 //过0延时5° 后换向, 即25°进角
#define Delay_10_Degrees Elec_Period/36 //过0延时10°后换向, 即20°进角
#define Delay_15_Degrees Elec_Period/24 //过0延时15°后换向, 即15°进角
#define Delay_20_Degrees Elec_Period/18 //过0延时20°后换向, 即10°进角
#define Delay_25_Degrees Elec_Period/14 //过0延时25°后换向, 即5° 进角
void Delay1ms() //@35MHz
{
unsigned char i, j;
_nop_();
i = 34;
j = 0;
do
{
while (--j);
} while (--i);
}
void Delay_ms(uint delay)
{ uint i;
for(i=0;i<delay;i++)
{
Delay1ms();
}
}
void IO_Initial()
{
Phase_A=0;
Phase_B=0;
Phase_C=0;
Delay1ms();
P2 |=0x70;//456 输出高电平,由于IO口要设置为开漏模式 ,因此实际是HIGH Z
P2M0 = 0x7e;//PWM 123强上拉,456开漏
P2M1=0x70;
P3M0=0x80;
P3M1=0x00;//P3.7推挽,为PWM输出做准备
P4M0=0x14;//P4.2 P4.4推挽,为PWM输出做准备
P4M1=0x00;
EN_A_MOS_DRV=1; //使能所有MOS半桥驱动
EN_B_MOS_DRV=1;
EN_C_MOS_DRV=1;
}
void PWM_Initial()
{
PWMCFG=0x0e;//PWM3/4/5初始电平为高
P_SW2|= 0x80;
PWMC=CYCLE; //设定PWM Cycle
PWMCKS=0x04; //35M主频,设定PWM频率为27.45k
PWM3T2L=255;
PWM4T2L=255;
PWM5T2L=255;
PWM7T2L=255;//PWM7仅用于提供中断
P_SW2&=0x7f;
}
void PWM_Duty_Cycle_Control(uchar PWM_Value)
{ P_SW2=0x80;
PWM3T1L=PWM_Value; //第一次反转
PWM4T1L=PWM_Value; //第一次反转
PWM5T1L=PWM_Value; //第一次反转
P_SW2=0x00;
}
void ADC_Init()
{
P1ASF = 0X3c; // 开通P1.2-P1.5 AD输入口
ADC_RES=0;
ADC_CONTR =0xE0;//打开ADC电源,设置90个时钟转换一次
}
void Commutation()
{
if(Step<5)
Step++;
else
Step=0;
switch(Step)
{
case 0: //AB
EN_C_MOS_DRV=0;
Phase_C=1; //断开C相
_nop_();
_nop_();
EN_PHASE_A_PWM_OUTPUT;
Phase_B=0;//打开B低端
EN_A_MOS_DRV=1;
EN_B_MOS_DRV=1;
ADC_CONTR = 0XE2; // 选择P1.2作为ADC输入即C相电压,未开始转换
Falling_Edge=1;
break;
case 1: //AC
EN_B_MOS_DRV=0;
Phase_B=1; //断开B相
_nop_();
_nop_();
EN_PHASE_A_PWM_OUTPUT;
Phase_C=0;//打开C低端
EN_A_MOS_DRV=1;
EN_C_MOS_DRV=1;
ADC_CONTR = 0XE3; // 选择P1.3作为ADC输入即C相电压,未开始转换
Falling_Edge=0;
break;
case 2: //BC
EN_A_MOS_DRV=0;
Phase_A=1; //断开A相
_nop_();
_nop_();
EN_PHASE_B_PWM_OUTPUT;
Phase_C=0;
EN_B_MOS_DRV=1;
EN_C_MOS_DRV=1;
ADC_CONTR = 0XE4; // 选择P1.4作为ADC输入即C相电压,未开始转换
Falling_Edge=1;
break;
case 3: //BA
EN_C_MOS_DRV=0;
Phase_C=1;
_nop_();
_nop_();
EN_PHASE_B_PWM_OUTPUT;
Phase_A=0;//打开A低端
EN_A_MOS_DRV=1;
EN_B_MOS_DRV=1;
ADC_CONTR = 0XE2; // 选择P1.2作为ADC输入即C相电压,未开始转换
Falling_Edge=0;
break;
case 4: //CA
EN_B_MOS_DRV=0;
Phase_B=1; //断开B相
_nop_();
_nop_();
EN_PHASE_C_PWM_OUTPUT;
Phase_A=0;//打开A低端
EN_C_MOS_DRV=1;
EN_A_MOS_DRV=1;
ADC_CONTR = 0XE3; // 选择P1.3作为ADC输入即C相电压,未开始转换
Falling_Edge=1;
break;
case 5: //CB
EN_A_MOS_DRV=0;
Phase_A=1; //断开A相
_nop_();
_nop_();
EN_PHASE_C_PWM_OUTPUT;
Phase_B=0;//打开A低端
EN_C_MOS_DRV=1;
EN_B_MOS_DRV=1;
ADC_CONTR = 0XE4; // 选择P1.4作为ADC输入即C相电压,未开始转换
Falling_Edge=0;
break;
default:break;
}
AD_Sample_Delay=0;
Base_Timer=0;
}
void Locate_Rotator()//定位函数第一步C+ A+ B- 第二步C+ A-
{
DISABLE_OUTPUT_ALL;//首先关闭所有MOS输出和PWM中断
PWMCR=0x8A;//C+ A+
Phase_B=0; //B-
_nop_();
_nop_();
EN_A_MOS_DRV=1;
EN_B_MOS_DRV=1;
EN_C_MOS_DRV=1;
Delay_ms(60);
EN_B_MOS_DRV=0;
EN_PHASE_C_PWM_OUTPUT;//C+
_nop_();
_nop_();
Phase_A=0; //A-
Delay_ms(50);
_nop_();
_nop_();
}
uchar ADC() //ADC,采样可重入函数
{ ADC_CONTR|=0x08;
_nop_();
_nop_();
_nop_();
_nop_();
while (!(ADC_CONTR & ADC_FLAG));//等待ADC转换完成
ADC_CONTR&=0xE7;
return ADC_RES;
}
void Zero_Crossing_Detection_PWM_OFF()
{ADC();
if(Falling_Edge==1&&ADC_RES<0x01)
{ LED=~LED;
Elec_Period_temp+=Commutaion_Time_Interval;
Commutaion_Time_Interval=0;//每次过0都清0,记录每次过0时间间隔
Cross_Zero=1;
if(Step==5)//每个换向间隔相加得到整个电周期时间,电周期除以一定数值可以得到延时角度,实际是对时间滤波,这样稳定性好
{ Elec_Period=Elec_Period_temp;
Elec_Period_temp=0;
}
}
if(Falling_Edge==0&&ADC_RES>0x01)
{
Elec_Period_temp+=Commutaion_Time_Interval;
Commutaion_Time_Interval=0;
Cross_Zero=1;
if(Step==5)//每个换向间隔相加得到整个电周期时间,电周期除以一定数值可以得到延时角度,实际是对时间滤波,这样稳定性好
{ Elec_Period=Elec_Period_temp;
Elec_Period_temp=0;
}
LED=~LED;
}
}
void Zero_Crossing_Detection_PWM_ON()
{ADC();
if(Falling_Edge==1&&ADC_RES<V_Mid)
{LED=~LED;
Elec_Period_temp+=Commutaion_Time_Interval;
Commutaion_Time_Interval=0;
Cross_Zero=1;
if(Step==5)//每个换向间隔相加得到整个电周期时间,电周期除以一定数值可以得到延时角度,实际是对时间滤波,这样稳定性好
{ Elec_Period=Elec_Period_temp;
Elec_Period_temp=0;
}
}
if(Falling_Edge==0&&ADC_RES>V_Mid)
{
Elec_Period_temp+=Commutaion_Time_Interval;
Commutaion_Time_Interval=0;
Cross_Zero=1;
if(Step==5)//每个换向间隔相加得到整个电周期时间,电周期除以一定数值可以得到延时角度,实际是对时间滤波,这样稳定性好
{ Elec_Period=Elec_Period_temp;
Elec_Period_temp=0;
}
LED=~LED;
}
}
void T1_Init()
{
AUXR &= 0xBF; //12T
TMOD &= 0x0F;
TL1 = 0; //2.1ms
TH1 = 0; //
TF1 = 0;//中断标志清0
ET1=1;//开T1中断
}
void INT1_Init()
{
IE1 = 0; // 清除外中断1标志位
EX1 = 1; // INT1 Enable
IT1 = 0; //1:下降沿中断;0:上升沿下降沿均中断
}
void Startup_Motor()
{
Duty_Current=Duty_Set=Startup_Duyt_Cycle;
PWM_Duty_Cycle_Control(Duty_Current);
PWM_ADC_Sampling=0;
Elec_Period_temp=0;
DISABLE_OUTPUT_ALL; //启动前关闭MOS输出清除中断标志,完成启动电桥初始化
Step=5;//进行入换向函数会执行Step=1的接通顺序,这是根据转子定位函数确定的启动顺序不能更改
Base_Timer=0;//已PWM中断时间间隔及次数为基准的变量,起到定时或延时作用
Elec_Period=Start_Commutaion_Delay; //初始启动换向延时,提高启动一次成功率
P_SW2=0x80;
PWM7CR=0x05;//开启PWM7T1反转匹配中断
PWM7T1L=Duty_Current/2+80;
P_SW2=0x00;
Commutation();//启动和PWM中断中都调用此函数,虽然为不可重入函数,但只在启动时调用一次,运行时全部由中断调用,应该不会发生不可预知错误
Already_Start=1;//已启动标志,如果启动失败,由于有强制换向环节最终马达会正常运行
}
void Stop_Motor()
{
while(1)//占空比逐渐减少至0,实现迅速减速,占空比瞬间大幅变化,MOS和半桥驱动都会挂
{Duty_Current--;
PWM_Duty_Cycle_Control(Duty_Current);
Delay_ms(1);
if(Duty_Current==1)
break;
}
P_SW2=0x80;
PWM7CR=0x00;//关闭PWM7中断
P_SW2=0x00;
Duty_Set=Duty_Current=Location_Duyt_Cycle;//恢复到转子定位PWM duty cycle
PWM_Duty_Cycle_Control(Duty_Current);
PWM_ADC_Sampling=0;
Locate_Rotator();
Elec_Period_temp=0;
Already_Start=0;//已经停止
}
void Signal_Check()// 信号异常检测函数
{
if(PPM_HighLevel<2625||PPM_HighLevel>6125||PPM_LowLevel>58333)//H0.9ms/H2.1ms/L20ms
{
PPM_Timeout++;//如果进入溢出了,一次溢出约22ms
if(PPM_Timeout==990)//约1S后
{
Signal_Lost=1;
Dly=2000/Duty_Set;
}
}
if(PPM_HighLevel>=2625&&PPM_HighLevel<=6125&&PPM_LowLevel<=58333)//高电平时长小于2.1ms低电平时长小于20ms认为信号恢复正常
{
PPM_Timeout=0;
Signal_Lost=0;
}
}
void Main()
{
IO_Initial();
PWM_Initial();
ADC_Init(); // 初始化ADC
T1_Init();
Duty_Set=Duty_Current=Location_Duyt_Cycle;
PWM_Duty_Cycle_Control(Duty_Current);
Locate_Rotator();
IP2=0x04; //PWM为优先级1
EA =1;
PPM_HighLevel=3209;
Signal_Ready=0;
Delay_ms(500);
INT1_Init();
while(1)
{ while(1) //信号检测
{
if(PPM_HighLevel<2625||PPM_HighLevel>3208||PPM_LowLevel>58333)
{
LED=~LED;//LED以0.1S频率闪烁
Delay_ms(100);
}
if(PPM_HighLevel>=2625&&PPM_HighLevel<=3208&&PPM_LowLevel<=58333)//高电平时长小于2.1ms低电平时长小于20ms认为信号恢复正常
{
LED=~LED;//LED以0.4S频率闪烁
Delay_ms(400);
Signal_Ready=1;
}
if(PPM_HighLevel>3208&&Signal_Ready==1)break;
}
while(1)//主循环
{
Delay_ms(1);
if(Duty_Set<Duty_Current)Duty_Current--;
if(Duty_Set>Duty_Current)Duty_Current++;
if(Duty_Set==Duty_Current)_nop_();
PWM_Duty_Cycle_Control(Duty_Current);
Signal_Check();
if(Signal_Lost)//信号丢失,
{
Delay_ms(Dly);
Duty_Set--;
if(Duty_Set<3)
{
Stop_Motor();//执行停机程序
LED=1;
PPM_HighLevel=3209;
Signal_Ready=0;
PPM_Timeout=0;
Signal_Lost=0;
break;
}
}
if(!Signal_Lost&&!PPM_Timeout)//如果信号未丢失未超时
{
if(PPM_HighLevel>3208)//1.100-2.100ms
{
You_Can_Start=1; //可以启动了
if(Already_Start)
{Duty_Set=(PPM_HighLevel-3208)/12;
if(Duty_Set>=252)
Duty_Set=252;//限制最大占空比不得超过252/256=98.4%,其实最大也无所谓,只是为了安全起见
if(Duty_Set<=5)
Duty_Set=5; //限制最小占空比
}
}
else
{
You_Can_Start=0;//要停止了
}
if(You_Can_Start==1&&Already_Start==0){Startup_Motor();LED=0;}
if(You_Can_Start==0&&Already_Start==1){Stop_Motor();LED=1;}
}
}
}
}
void INT1_ISR() interrupt 2 using 2
{ TR1 = 0;
if(INT1)//上升沿记录低电平计数
{PPM_High_Overflow=0;
if(!PPM_LOW_Overflow)PPM_LowLevel = ((uint)TH1 << 8) + TL1;//上升沿来临如果之前无溢出才记录
else PPM_LowLevel=65535;//溢出则赋最大值
TL1 = 0;
TH1 = 0;
TR1 = 1;//T1在INT1高电平时可开始计数
}
else//下降沿记录高电平计数
{PPM_LOW_Overflow=0;
if(!PPM_High_Overflow)PPM_HighLevel = ((uint)TH1 << 8) + TL1;//下降沿来临如果之前无溢出才记录
else PPM_HighLevel=65535; //溢出则赋最大值
TL1 = 0;
TH1 = 0;
TR1 = 1;//T1在INT1高电平时可开始计数
}
}
void T1_ISR() interrupt 3 using 2//低电平或高电平时间溢出都进入中断
{
if(!INT1)
{PPM_LOW_Overflow=1;
PPM_LowLevel=65535;
}
if(INT1)
{PPM_High_Overflow=1;
PPM_HighLevel=65535;
}
}
void PWM_ISR() interrupt 22 using 1 //在中断中完成ADC过零检测和沿时换向
{
Base_Timer++;
Commutaion_Time_Interval++;
AD_Sample_Delay++;
if(Cross_Zero)
{AD_Sample_Delay=0;//过0检测到换向完成前值都为0,期间不进行过0检测
Commutaion_Delay++;
if(Commutaion_Delay==Delay_20_Degrees)
{
Commutaion_Delay=0;
Commutation();
Cross_Zero=0;
}
}
if(AD_Sample_Delay>=2)//换向后PWM第二次中断时开始过0采样,避免换向瞬间消磁干扰
{
switch(PWM_ADC_Sampling)
{
case 0: Zero_Crossing_Detection_PWM_OFF();//在PWM OFF过零采样
break;
case 1: Zero_Crossing_Detection_PWM_ON(); //在PWM ON 过零采样
break;
default:break;
}
}
if(Step==2&&!Commutaion_Delay)//每个完整换向周期 只执行一次当STEP=2时,
{if(Duty_Current<0x80)//占空比小于0.5再PWM OFF采样
{P2 |=0x70; //456 输出高电平 由于开漏模式无法输出高电平实际为Hi-Z,相当于断开
PWM_ADC_Sampling=0;
P_SW2=0x80;
PWM7T1L=Duty_Current/2+80; //第一次翻转
P_SW2=0x00;
}
else //占空比大于0.5改为PWM ON 采样
{ P2 &=0x8f; //456 输出低电平 三相分压电阻接地 初始化ADC分压采样
PWM_ADC_Sampling=1;
P_SW2=0x80;
PWM7T1L=Duty_Current/4; //第一次翻转
P_SW2=0x00;
ADC_CONTR = 0XE5;//切换到中点采样通道
V_Mid= ADC()/2; //采集中点电压,需要除以2
ADC_CONTR = 0XE4;//采样完毕后切换到原通道
}
}
if(Base_Timer>=1000)//约36ms,无换向堵转了,强制换相
{
Elec_Period=Start_Commutaion_Delay;
Commutaion_Delay=0;
Duty_Set=Duty_Current=Startup_Duyt_Cycle; //以启动低占空比换相
PWM_Duty_Cycle_Control(Duty_Current);
Commutation();
Cross_Zero=0;
}
PWMIF=0;//清除PWM中断标志,
}
在keil里是对齐的,不知贴上来怎么乱了,原理图晚上回家发吧。本人不是电子专业,也不从事电子专业,只因爱好业余时间学习一下,所以程序编写肯定有很多不规范地方和不好的习惯,还请大家指教。目前来看性能是可以的也比较稳定,可以小于10%的较低占空比带负载启动(用手捏住也能稳定启动),运行时响应极快,可瞬间加速或减速;PPM油门信号由一片STC404as产生,没有试验过通用航模遥控器信号,准备买个遥控器和接收机试验一下,那个信号丢失保护功能,可能不符合实际情况,只求模仿,大家可以完善。 说明一下,原来MOS驱动用的是 NCP5181 说实话性能不错,但不知为什么 单品机中互补PWM明明设置了死区(是100%肯定足够的死区),可某些情况还是会导致上下MOS直通,郁闷了,无奈换了单PWM输入的 FAN5109 这个死区是固定的 只需要输入一路PWM即可,带输出使能可用于同步续流也就是其中一相是可以悬浮的。 再次强调 同步续流有很大优势,这是我没想到的,根部不需要启动算法,这是我试验的结果。以前做的数控电源也是用同步整流BUCK,效率奇高。 PPM 信号处理没有用PCA捕获, 而是用了 外部中断 加定时器 ,感觉系统占用时间反而少,如果用PCA需要操作 long型数数据,中断占用时间可能会更多(绝对不能影响过0采样和换向的及时性),只是猜测还没有验证。 用PCA捕捉 和 外中断+定时器 来读PPM信号一样的,都是unsigned int变量,并且一般几ms~10ms中断一次,占CPU时间基本可以忽略了。 LZ贴了程序,这个给100个赞先!
我会帮忙测试,众人拾柴吧。。。 谢谢! 这就是开源的乐趣,一起努力吧 原理图这是,没有过流检测暂时 速度大于1w转,崩溃。
采用AD同步采样,过零点分辨率低(最小时间为1个PWM周期)。
速度过快时,换向时间就差不多1个PWM周期。 也想搞电机控制方面的,收藏了,谢谢 zhonghua_li 发表于 2015-11-27 11:16
速度大于1w转,崩溃。
采用AD同步采样,过零点分辨率低(最小时间为1个PWM周期)。
速度过快时,换向时间就 ...
确实是,速度不可能太快,太快用示波器看,过零很不稳,波形抖动。不过带载后还是很稳定的。 真很好 收藏了。。以后能看看。。。 foxpro2005 发表于 2015-4-5 23:06
用stm32比较容易 方便在PWM ON 50%处检测,stc不知道有没有这样的功能
大哥,我刚接触电调不久,想自己做个电调,也看了ST的那个PWM采样,就是要同步PWM采样的话我用定时器的比较输出中断,在电平翻转的时候产生中断采样,就是ST 的比较输出那里调的不好,不知道大神有没有关于定时器比较输出的相关资料或代码,小弟在此感激不尽 本帖最后由 foxpro2005 于 2016-6-8 15:32 编辑
makeflyeasy 发表于 2016-6-8 10:43
大哥,我刚接触电调不久,想自己做个电调,也看了ST的那个PWM采样,就是要同步PWM采样的话我用定时器的比 ...
下面是定时器TIM1或TIM8的配置代码:
<code>
/**
* @briefTIMx(高级定时器TIM1或TIM8)模块初始化
* @paramhwPulse - 占空比
* @retval None
*/
static void TIMER_Config(uint16_t hwPulse)
{
TIM_TimeBaseInitTypeDefTIM_TimeBaseStructure;
TIM_OCInitTypeDefTIM_OCInitStructure;
TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
/* TIMx时基单元配置 ------------------------------------------------------*/
TIM_TimeBaseStructure.TIM_Prescaler = BLDCM_TIM_PSC - 1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = BLDCM_PWM_PERIOD - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(BLDCM_TIMER, &TIM_TimeBaseStructure);
/* TIMx比较输出单元配置 --------------------------------------------------*/
/* 刚开始时互补通道先关闭, 这样在没有产生换相之前互补通道就不会有高电平输出 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 正向参考波形
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;// TIM_OutputState_Enable
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;// TIM_OutputNState_Enable
TIM_OCInitStructure.TIM_Pulse = hwPulse;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; // TIM_OCIdleState_Reset
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset; // TIM_OCNIdleState_Reset
//TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 反向参考波形
//TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;// TIM_OutputState_Enable
//TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;// TIM_OutputNState_Enable
//TIM_OCInitStructure.TIM_Pulse = hwPulse;
//TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
//TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
//TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
//TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;
TIM_OC1Init(BLDCM_TIMER, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(BLDCM_TIMER, TIM_OCPreload_Enable); // TIMx->CCR1预装使能
TIM_OC2Init(BLDCM_TIMER, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(BLDCM_TIMER, TIM_OCPreload_Enable); // TIMx->CCR2预装使能
TIM_OC3Init(BLDCM_TIMER, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(BLDCM_TIMER, TIM_OCPreload_Enable); // TIMx->CCR3预装使能
/* TIMx->CC4通道用于触发ADC1的注入通道组转换 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; // 反向参考波形
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = hwPulse >> 1; // 在PWM脉冲宽度的50%处触发
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC4Init(BLDCM_TIMER, &TIM_OCInitStructure);
TIM_OC4PreloadConfig(BLDCM_TIMER, TIM_OCPreload_Enable); // TIMx->CCR4预装使能
/* TIMx比较输出控制单元配置 ----------------------------------------------*/
TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Disable; // OSSR 当定时器不工作时, 输出0
TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Disable; // OSSI 当定时器不工作时, 输出0
TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF;
TIM_BDTRInitStructure.TIM_DeadTime = BLDCM_PWM_DEAD_TIME;
TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;
TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_Low; // 低电平有效
TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; // TIM_AutomaticOutput_Disable;
TIM_BDTRConfig(BLDCM_TIMER, &TIM_BDTRInitStructure);
/* TIMx模块控制 ----------------------------------------------------------*/
// 使用COM事件同步更新寄存器,需要CCxE,CCxNE,OCxM预装载
// 开启捕获/比较使能寄存器TIMx->CCERx的CCxE,CCxNE的位预装功能
// 开启捕获/比较模式寄存器TIMx->CCMRx的OCxM,的位预装功能
TIM_CCPreloadControl(BLDCM_TIMER, ENABLE);
/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
// 本项目中使用了TIM2的OC1比较匹配来产生TRGI信号来触发COM事件换相更新
// 捕获/比较控制更新选择, TIMx->CR2.CCUS配置
TIM_SelectCOM(BLDCM_TIMER, ENABLE); // 更新选择: COM位或TRGI的上升沿
// 触发源选择, 为了避免发生错误, TIMx->SMCR.TS的配置, 要在TIMx->SMCR.SMS=000的时候配置
TIM_SelectInputTrigger(BLDCM_TIMER, TIM_TS_ITR1); // 选择内部触发源TIM2连接到TIM1, 见STM32参考手册P237
/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
//TIM_SelectSlaveMode(BLDCM_TIMER, TIM_SlaveMode_Reset);
/* 在启动计数前, 产生一次更新事件以初始化有预装载的寄存器 */
//TIM_GenerateEvent(BLDCM_TIMER, TIM_EventSource_Update);
/* TIMx中断配置 */
TIM_ClearITPendingBit(BLDCM_TIMER, TIM_IT_Update |
TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4 |
TIM_IT_COM | TIM_IT_Trigger | TIM_IT_Break);
//TIM_ITConfig(BLDCM_TIMER, TIM_IT_COM, ENABLE); // TIM_IT_Break, 改由需要的时候再来开启
/* TIMx计数使能 */
TIM_Cmd(BLDCM_TIMER, ENABLE);
/* TIMx主输出使能 */
TIM_CtrlPWMOutputs(BLDCM_TIMER, ENABLE);
}
</code>
foxpro2005 发表于 2016-6-8 15:31
下面是定时器TIM1或TIM8的配置代码:
/**
谢谢大哥,真是及时雨啊,感激不尽 littlem 发表于 2015-5-5 17:01
这段时间工作忙,闲了继续,完善好了一定会和大家分享,谢谢支持!
顶,楼主威武 仔细看了你的程序没有看到同步整流在那里实现,难到是通过FAN5109实现的吗?
仔细看了你的程序没有看到同步整流在那里实现,难到是通过FAN5109实现的吗? FAN5109是单输入电桥驱动芯片,上下管互补驱动,同时具有使能功能,同步整流正是通过它实现 学习 好玩 littlem 发表于 2017-12-19 21:10
FAN5109是单输入电桥驱动芯片,上下管互补驱动,同时具有使能功能,同步整流正是通过它实现 ...
非电子专业做得比电子专业还厉害!佩服 厉害,兴趣爱好是巨大动力。 牛逼,不得不顶 学习,谢谢!!! 谢谢分享!好好补补无刷电调~ 参考lz的程序终于成功了,非常感谢!
页:
[1]