标题:
无刷无感电机过零检测单片机源程序
[打印本页]
作者:
Hanney
时间:
2018-3-30 09:18
标题:
无刷无感电机过零检测单片机源程序
附件中的源文件是无感三相电机零速定位,开环加速以前闭环控制(含过零检测的程序)
单片机源程序如下:
#include "hardware.h"
#include "bldc.h"
u16 Temp = 0;
volatile State_TypeDef State = Idle;
Task_TypeDef Task;
Flag_TypeDef Flag;
vu16 ADC_VALUE[ADC_NUMBER*ADC_BUFFER]={0};
u16 SysTime = 0; /* 系统时间 */
u8 Phase = 0; /* 通电绕组 */
u16 PwmDuty = 0; /* PWM占空比 */
u8 AlignRotorCount = 0; /* 电机启动时锁定转子的次数 */
u8 BlankingCount = 0; /* 消隐时长 */
//u8 ZeroBeforeCount = 0; /* 过零点之前的检测次数 */
u8 ZeroCrossCount = 0; /* 到达过零点的检测次数 */
u8 ZeroAcquireCount = 0; /* 进入到同步运行状态前的过零点次数 */
u16 CommutateTime = 0; /* 过零检测到到换向的时间 */
u16 AccelerateCommutateTime = 0; /* 电机加速的换向的时间 */
u16 AdcPotentiometer = 0; /* 电位器ADC转换结果 */
u16 AdcBEMF = 0; /* BEMF电压ADC转换结果 */
u16 AdcCurrent = 0; /* 电流放大器ADC转换结果 */
u16 AdcVbus = 0; /* 电源电压ADC转换结果 */
u16 ZeroVref = 0; /* 过零检测基准电压,等于电源电压的一半 */
u8 SpeedErrorCount = 0; /* 电机速度异常次数 */
u16 ZeroPeriod = 1000; /* 过零周期即60度换向时间 */
u16 MotorRpm = 0; /* 电机转速,单位RPM */
u16 AccelerateTime = 0; /* 电机加速运转的时间 */
//u16 PhaseAdvance = 0; /* 超前相位 */
u16 Current = 0; /* 电流值 */
u16 Iref = 0; /* 电流放大器输出偏置 */
#define MaxIX 999 //最大记录条数
vu16 BEMF_REC[MaxIX+1]={0}; // 反电动势记录
u16 ix = 0; // 记录下标
/********************************************************************************************
* Function Name : void Scan_Key(void)
* Description : 按键扫描程序,用于启动或者停止电机运转
* Input : 无
* Return : 无
*********************************************************************************************/
void Scan_Key(void)
{
if(Key_Status() == PRESS)
{
if(State == Idle)
{
while(Key_Status() != RELEASE);
State = Start;
}
else
{
while(Key_Status() != RELEASE);
State = Stop;
}
}
}
void Start_Motor(void)
{
Close_LED7();
Close_LED8();
Close_LED9();
Flag.AcquireZero = 0;
Flag.ZeroCross = 0;
SpeedErrorCount = 0;
AccelerateTime = 0;
AlignRotorCount = 3; /* 初始化电机转子定位次数 */
Update_PwmDuty((u32)ALIGN_ROTOR_PWM*FULL_DUTY/100);
Phase = 0;
Commutate();
TIM_CtrlPWMOutputs(TIM1, ENABLE);
State = AlignRotor;
SysTime = 0;
Task.AlignRotor = 0;
printf("Start AlignRotor !!!\n\r");
}
/********************************************************************************************
* Function Name : void AlignMotorRotor(void)
* Description : 转子定位程序
* Input : 无
* Return : 无
*********************************************************************************************/
void Align_MotorRotor(void)
{
if(AlignRotorCount > 0)
{
Phase = 0;
Commutate();
Update_PwmDuty((u32)ALIGN_ROTOR_PWM*FULL_DUTY/100);
AlignRotorCount --;
if (AlignRotorCount == 0)
{
Update_PwmDuty((u32)PWM_ACCELERATE_START*FULL_DUTY/100); //更新初始加速占空比
AccelerateCommutateTime = TIM2_FREQ*20/START_RPM/MOTOR_POLES; //设计初始加速时间参数
/* 启动TIM2,进入到加速状态 */
TIM2_Counter = 0;
Clear_TIM2_Update_IF();
Enable_TIM2_Update_IT();
Clear_TIM1_CC4_IF();
Enable_TIM1_CC4_IT();
State = Accelerate;
//State = Stop;
}
}
}
void Commutate(void)
{
Disable_AH();
Disable_AL();
Disable_BH();
Disable_BL();
Disable_CH();
Disable_CL();
switch(Phase)
{
case 0: /* AB相 */
{
//Disable_CH();
Enable_AH();
Enable_BL();
#if (DIRECTION == COUNTER_CLOCKWISE)
Flag.BemfEdge = FALLING;
Phase = 1;
#else
Flag.BemfEdge = RISING;
Phase = 5;
#endif
}
break;
case 1: /* AC相 */
{
Enable_AH();
//Disable_BL();
Enable_CL();
#if (DIRECTION == COUNTER_CLOCKWISE)
Flag.BemfEdge = RISING;
Phase = 2;
#else
Flag.BemfEdge = FALLING;
Phase = 0;
#endif
}
break;
case 2: /* BC相 */
{
//Disable_AH();
Enable_BH();
Enable_CL();
#if (DIRECTION == COUNTER_CLOCKWISE)
Flag.BemfEdge = FALLING;
Phase = 3;
#else
Flag.BemfEdge = RISING;
Phase = 1;
#endif
}
break;
case 3: /* BA相 */
{
Enable_BH();
//Disable_CL();
Enable_AL();
#if (DIRECTION == COUNTER_CLOCKWISE)
Flag.BemfEdge = RISING;
Phase = 4;
#else
Flag.BemfEdge = FALLING;
Phase = 2;
#endif
}
break;
case 4: /* CA相 */
{
//Disable_BH();
Enable_CH();
Enable_AL();
#if (DIRECTION == COUNTER_CLOCKWISE)
Flag.BemfEdge = FALLING;
Phase = 5;
#else
Flag.BemfEdge = RISING;
Phase = 3;
#endif
}
break;
case 5: /* CB相 */
{
Enable_CH();
//Disable_AL();
Enable_BL();
#if (DIRECTION == COUNTER_CLOCKWISE)
Flag.BemfEdge = RISING;
Phase = 0;
#else
Flag.BemfEdge = FALLING;
Phase = 4;
#endif
}
break;
default:
break;
}
Flag.ZeroCross = 0;
BlankingCount = BLANKING_COUNT;
ZeroCrossCount = 0;
}
void Stop_Running(void)
{
Disable_PwmOutput();
Clear_TIM1_CC4_IF();
Disable_TIM1_CC4_IT();
Clear_TIM2_Update_IF();
Disable_TIM2_Update_IT();
State = Idle;
if(Flag.FailedStart) /* 输出错误标志 */
{
Flag.FailedStart = 0;
printf("Error: Failed to start!!!\n\r");
}
if(Flag.CurrentHigh)
{
Flag.CurrentHigh = 0;
printf("Error: Current is too large!!!\n\r");
}
if(Flag.SpeedHigh)
{
Flag.SpeedHigh = 0;
printf("Error: Motor speed is too high !!!\n\r");
}
if(Flag.SpeedLow)
{
Flag.SpeedLow = 0;
printf("Error: Motor speed is too low !!!\n\r");
}
if(Flag.LostZero)
{
Flag.LostZero = 0;
printf("Error: Sensor error !!!\n\r");
}
printf("Motor stop !!!\n\r");
}
// ROUNDUP( INDIRECT("E7") * 20 / ( INDIRECT("D13")* B7*B7 / INDIRECT("F13") / INDIRECT("F13") + INDIRECT("F7") ) / INDIRECT("G7") ,0 )
void Accelerate_Motor(void) // 加速
{
u16 speed = 0; // 新的目标速度
u32 ct = 0; // 新的换向时间
speed = ((u32)AccelerateTime*AccelerateTime)/ACCELERATE_TIME; /* 计算新的目标速度 */
speed = ((u32)(END_RPM - START_RPM)*speed)/ACCELERATE_TIME;
speed += START_RPM;
ct = (u32)TIM2_FREQ*20/speed/MOTOR_POLES; /* 将速度转换为相应的换向时长 */
//ct = AccelerateCommutateTime*14/15-1;
if(ct > 65535) AccelerateCommutateTime = 65535;
else AccelerateCommutateTime = ct;
PwmDuty = ((u32)PWM_ACCELERATE_DELTA*AccelerateTime/ACCELERATE_TIME); /* 计算PWM增量 */
PwmDuty += (u16)((u32)PWM_ACCELERATE_START*FULL_DUTY/100); /* 更新PWM */
Update_PwmDuty(PwmDuty);
if((AccelerateCommutateTime <= TIM2_FREQ*20/ZERO_ACQUIRE_RPM/MOTOR_POLES)&& /* 开始捕获过零点 */
(Flag.AcquireZero == 0))
{
Flag.AcquireZero = 1;
ZeroAcquireCount = 0;
// Open_LED7();
}
if(AccelerateCommutateTime <= TIM2_FREQ*20/END_RPM/MOTOR_POLES) /* 加速到启动终止速度时,启动失败 */
{
State = Stop;
Flag.FailedStart = 1;
Open_LED6();
}
}
void Check_ZeroCrossing(void)
{
u16 t = 0;
if(BlankingCount > 0) /* 等待消隐 */
{
BlankingCount --;
return;
}
if((Flag.BemfEdge == FALLING)&&(AdcBEMF < ZeroVref)) /* 判断BEMF电压是否过零 */
ZeroCrossCount ++;
if((Flag.BemfEdge == RISING)&&(AdcBEMF > ZeroVref))
ZeroCrossCount ++;
//Open_LED7();
if (ZeroCrossCount > ZERO_SAMPLES-1) /* 达到预期的过零次数 */
{
BEMF_REC[ix] = AdcBEMF;
ix++;
if(ix>MaxIX) ix = 0;
//Open_LED8();
ZeroPeriod = TIM3_Counter; /* 从TIM3计数器读取2次过零点的周期 */
TIM3_Counter = 0;
t = ZeroPeriod >> 1; /* 计算30度换向时长 */
CommutateTime = ((u32)t * (30 - ADVANCE_ANGLE))/30; /* 超前相位补偿 */
if(CommutateTime > ZERO_CHECK_DELAY) /* ADC过零检测延迟补偿 */
CommutateTime -= ZERO_CHECK_DELAY;
else
CommutateTime = 1;
if (State == Running)
{
Flag.ZeroCross = 1;
Disable_TIM2_Update_IT();
TIM2->ARR = CommutateTime;
TIM2_Counter = 0;
Clear_TIM2_Update_IF();
Enable_TIM2_Update_IT();
Open_LED9(); // 标志着已经切换到闭环控制状态
}
else /* 电机加速到同步运转状态的判断 */
{
ZeroAcquireCount ++;
if(ZeroAcquireCount > ZERO_ACQUIRE_COUNT-1) /* 进入过零点同步状态 */
{
Flag.ZeroCross = 1;
Disable_TIM2_Update_IT();
Flag.AcquireZero = 0;
State = Running;
TIM2->ARR = CommutateTime; /* 更新TIM2定时换向 */
TIM2_Counter = 0;
Clear_TIM2_Update_IF();
Enable_TIM2_Update_IT();
// Open_LED9(); // 标志着已经从开环加速正在切换到闭环控制状态
}
}
}
}
/********************************************************************************************
* Function Name : void Get_MotorSpeed(void)
* Description : 计算电机速度程序
RPM = 60/((60°换向周期(秒)*6)*(极数/2)) = 20/(T*P)
* Input : 无
* Return : 无
*********************************************************************************************/
void Get_MotorSpeed(void)
{
static u16 t = 0;
t += ZeroPeriod; /* 计算2次60度换向周期的平均值 */
t = t >> 1;
MotorRpm = (u32)TIM2_FREQ*20/t/MOTOR_POLES; /* RPM = 60/((60°换向周期(秒)*6)*(极数/2)) = 20/(T*P) */
}
void Control_Speed(void)
{
u16 duty = 0;
duty = ((u32)AdcPotentiometer*FULL_DUTY)/4095; /* 将ADC转换结果线性转换为PWM的占空比 */
if(duty > PwmDuty) /* 逐渐调整PWM占空比,避免占空比调整步长太大导致电机失速 */
{
PwmDuty += 4;
if(PwmDuty > FULL_DUTY) PwmDuty = FULL_DUTY;
}
else if(duty < PwmDuty)
{
if(PwmDuty < 4) PwmDuty = 0;
else PwmDuty -= 4;
}
else return;
Update_PwmDuty(PwmDuty); /* 更新PWM占空比 */
}
/********************************************************************************************
* Function Name : void Monitor_Speed(void)
* Description : 电机失速监控程序
* Input : 无
* Return : 无
*********************************************************************************************/
void Monitor_Speed(void)
{
if(MotorRpm < MIN_SPEED) /* 检查电机速度是否过低 */
……………………
…………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
下载:
bldc.rar
(3.46 KB, 下载次数: 183)
2018-3-30 09:16 上传
点击文件名下载附件
过零检测
下载积分: 黑币 -5
作者:
DHuang
时间:
2018-4-19 21:03
正在做相关方向,参考一下,谢谢无私分享
作者:
mcu_mpu
时间:
2018-7-9 11:00
好东西,学习下。
作者:
mcu_mpu
时间:
2018-7-9 11:01
正在研究BLCD相关的东西,学习下。
作者:
kr123crg
时间:
2018-11-16 17:16
led是8位IO口吗?没太看懂你的
作者:
HZCHZC
时间:
2019-1-2 15:43
楼主可以提供电路图吗?
作者:
HZCHZC
时间:
2019-1-2 16:15
程序中的两个头文件在哪里呢?
作者:
bowaterbo
时间:
2020-2-10 22:51
正在做相关方向,参考一下,谢谢无私分享,如果有原理图配合程序那就更完美了。
作者:
YG0068
时间:
2021-9-28 14:05
请问楼主有头文件吗?
作者:
lnsfxycmz
时间:
2021-10-18 10:45
正要做这块,帮大忙了,非常感谢
作者:
kavin21513
时间:
2021-11-27 21:03
正在学习无刷驱动,谢谢分享
作者:
云游天
时间:
2022-1-7 18:14
有更完整源码吗?
作者:
hgy1013
时间:
2023-9-9 15:51
配上原理图就更完善了
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1