论坛元老
 
- 积分
- 3347
- 金钱
- 3347
- 注册时间
- 2013-4-10
- 在线时间
- 333 小时
|
发表于 2018-1-4 19:14:08
|
显示全部楼层
本帖最后由 likunxue 于 2018-1-4 19:15 编辑
我给你一段起动代码,你可以自已完成其它的工作
/********************************************************************************************
函 数 名: 换相
调 用: YouGan_ComHandler(void)
参 数: 无
返 回 值: 无
********************************************************************************************/
void ComHandler(u8 Svev)
{
TIM1->CCER &= 0xfffff000;
TIM1->CCER |= MoB.CCER[Svev]; //写入PWM控制寄存器的输出状态
BLCD_GENGXINSHINENG; //产生更新事件COM,充许更新CCxE,CCxNE,CCxM
MoB.Signal = MoB.JianCeYouXiaoDianPing[Svev];//选择反电动势信号,检测电平
MoB.CommutPin = MoB.JIANCEXIAN[Svev]; //选择反电动势引脚
if(MoB.Signal != 0) BIT_ADM(TIM4->CCER,1) = 0; //CC1P 不反相输入上升沿捕获
else BIT_ADM(TIM4->CCER,1) = 1; //下降沿捕获
}
/******************************************************************************************
程序名称: 过零信号正确判断
调 用: GuoLingXinHaoPanDuan(u8 atx)
入口参数: 无
返 回 值: 0正确1 出错
*******************************************************************************************/
char GuoLingXinHaoPanDuan(void)
{
u8 BianMa,Bia,Cnt,BeforeCnt;
BianMa = ((GPIOB->IDR >> 6)&0x07); //得到反电动势代表的电机转子位置信息
BeforeCnt = 0;
for(Cnt = 10; Cnt > 0; Cnt --)
{
Bia = ((GPIOB->IDR >> 6)&0x07); //读取状态
if(Bia != BianMa){BianMa = Bia;BeforeCnt /= 2;} //过零不稳定
else{
BeforeCnt++;
if(BeforeCnt > 5)
{
if(BianMa == 5){MoB.OutBianMa = 0;return 5;} //正确编码5
if(BianMa == 4)
{
if(MoU.DIR ==0)MoB.OutBianMa = 1;else MoB.OutBianMa = 5;
return 4; //正确编码4
}
if(BianMa == 6)
{
if(MoU.DIR ==0)MoB.OutBianMa = 2;else MoB.OutBianMa = 4;
return 6; //正确编码6
}
if(BianMa == 2)
{
if(MoU.DIR ==0)MoB.OutBianMa = 3;else MoB.OutBianMa = 3;
return 2; //正确编码2
}
if(BianMa == 3)
{
if(MoU.DIR ==0)MoB.OutBianMa = 4;else MoB.OutBianMa = 2;
return 3; //正确编码3
}
if(BianMa == 1)
{
if(MoU.DIR ==0)MoB.OutBianMa = 5;else MoB.OutBianMa = 1;
return 1; //正确编码1
}
return 0; //编码错
}
}
}
return 0; //检测错
}
/*******************************************************************************************
函 数 名: 定时器4中断函数(无感驱动捕获方式获取过零信号)
调 用: 无
参 数: 无
反 回 值: 无
*******************************************************************************************/
void TIM4_IRQHandler(void)
{
if(BIT_ADM(TIM4->SR,1) == 1) //CC1捕获中断标记
{
u16 Cnt = TIM4->CCR1; //读取捕获值,其中包含速度信息
BIT_ADM(TIM4->SR,1) = 0; //清中断标志
if(TIM4->CNT > MoB.Commut10)
{
u8 BianMa = GuoLingXinHaoPanDuan(); //读取反电动势的编码信息
if(MoU.FsmStat == STATFORWARDRUN)
{
if((BianMa == 0)&&(TIM4->CNT >MoB.Period4))
{ //编码出错了
BLCD_SHIJIAN_OFF; //关闭电机
MoU.FsmStat = STATSTALL; //电机诸转了
}
else{
if(BianMa != MoB.BianMa)
{ //计算换相时间
MoB.Period4 -= MoB.Period4/2; //240度
MoB.Period4 += Cnt * 4; //240度
MoB.Period = MoB.Period4/4; //60度的时间
MoB.Commut20 = MoB.Period/3; //20度的时间
MoB.Commut15 = MoB.Period/4; //15度的时间
MoB.Commut10 = MoB.Period/12; //10度的时间
Cnt = MoB.Period - MoB.Commut20;
TIM4->CCR2 = Cnt; //更新换相时间
QFilter_lst(&Speed_LvBo,Cnt); //步进角度一阶滤波函数
MoB.BeforeFlag = 0xe5;
}
MoB.BianMa = BianMa; //当前编码值存副本
}
}
else{if(BianMa != 0)MoB.BianMa = BianMa;}//当前编码值存副本
}
}
if(BIT_ADM(TIM4->SR,2) == 1) //CC2IF(比较溢出中断)
{ //触发换相
BIT_ADM(TIM4->SR,2) = 0;
if((MoU.FsmStat == STATFORWARDRUN)&&(MoB.BeforeFlag == 0xe5))
{
MoB.OvFlag = 0; //清定时器溢出标志位
TIM4->CNT = 0; //清零计数器的值
TIM4->CCR2 = MoB.Period4; //下次换相时间设为60度
TIM1->CCER &= 0xfffff000;
TIM1->CCER |= MoB.CCER[MoB.OutBianMa]; //写入PWM控制寄存器的输出状态
BLCD_GENGXINSHINENG; //产生更新事件COM,充许更新CCxE,CCxNE,CCxM
MoB.Signal = MoB.JianCeYouXiaoDianPing[MoB.OutBianMa];//选择反电动势信号,检测电平
MoB.CommutPin = MoB.JIANCEXIAN[MoB.OutBianMa]; //选择反电动势引脚
if(MoB.Signal != 0) BIT_ADM(TIM4->CCER,1) = 0; //CC1P 不反相输入上升沿捕获
else BIT_ADM(TIM4->CCER,1) = 1; //下降沿捕获
MoB.count++; //计数器累加
MoB.BuJuSum += Speed_LvBo.Old_Dat; //时步角度累加
if(MoB.count >= 6) //2ms 事件(50*40 = 2000us)
{
MoU.ActualSpeed = SPEEDMULT/(MoB.BuJuSum /6); //计算当前电机速度
PI_MACRO(MoU.ActualSpeed);
MoB.BuJuSum = 0; //清零步距角累加器
MoB.count = 0; //清零步进角度累加计数器
}
MoB.BeforeFlag = 0; //清标志
}
MoB.ucCommutOkCn = 0; //清零编码出错统计次数
}
if(BIT_ADM(TIM4->SR,4) == 1) //CC4IF(比较溢出中断)
{
BIT_ADM(TIM4->SR,4) = 0;
MoB.OvFlag = 1; //溢出标志累加
if(MoU.FsmStat == STATFORWARDRUN)
{
BLCD_SHIJIAN_OFF; //关闭电机
MoU.FsmStat = STATSTALL; //电机诸转了
}
}
}
/******************************************************************************************
程序名称: 电机启动
调 用: BLDC_Start(void)
入口参数: 无
返 回 值: 无 BLCD_SHIJIAN_ON; //开启电机
*******************************************************************************************/
void BLDC_Start(void)
{
u8 BeforeCnt,ErrCnt,BeforeFlag,AfterFlag;
u16 ucCommutOkCnt = 0;
u16 BulTim;
BLCD_SHIJIAN_OFF; //关闭电机
LOOG_DISUMOSHI; //反电动势检测置低起动模式
delay_ms(100); //延时
PID_int(); //PID参数初始化
MoU.ActualSpeed = 0; //清零当前电机工作速度
MoB.OvFlag = 0; //置时器溢出标志位
MoB.count = 0; //速度初始化指针
MoB.BuJuSum = 0; //清零步距角累加和
MoB.BeforeFlag = 0; //清标志
DianJiFangXiang_Int(MoU.DIR); //初始化电机方向
LvBoShuJu_Int(&Speed_LvBo,8); //初始电机转速滤波系数
MoB.Uret = MoB.MinDianLiu; //写入最低电流
MoU.FsmStat = STATFORWARDSTART; //置电机为起动任力标志
ComHandler(0); //第一次定位AB导通,A+ B- C相关闭
BLCD_SHIJIAN_ON; //开启电机
while(1)
{
if(MoB.Uret >= MoB.QiDongDianLiu)break;
else{
MoB.Uret ++; //增加起动电流
delay_ms(1); //延时
}
}
delay_ms(30); //延时
//第二次定位
TIM4->CNT = 0; //清零计数器的值
TIM1->SR = 0; //清定时器4的所有中断标志
MoB.OvFlag = 0; //清定时器溢出标志位
MoB.BuJuSum = 0; //清零步距角累加器
MoB.count = 0; //清零步进角度累加计数器
MoB.BeforeFlag = 0; //清标志
MoB.Period4 = 0x1fff * 8; //初始化换相时间240度的时间
MoB.Period = MoB.Period4 / 4; //60度的时间
MoB.Commut20 = MoB.Period / 3; //20度的时间
MoB.Commut15 = MoB.Period / 4; //15度的时间
MoB.Commut10 = MoB.Period / 6; //10度的时间
ComHandler(1); //AC导通,A+ C- B相关闭
BIT_ADM(TIM4->DIER, 1) = 1; //定时器CC1E中断使能
BIT_ADM(TIM4->DIER, 2) = 1; //定时器CC2E中断使能
BIT_ADM(TIM4->DIER, 4) = 1; //定时器CC4E中断使能
BIT_ADM(TIM4->CR1,0) = 1; //开定时器TIM4
ErrCnt = 0;
while(1)
{
BeforeFlag = 0; //清过零稳定标志位
if(TIM4->CNT < MoB.Commut20 )
{ //如果当前电机位置没有超过20度电度角,需要进行过零前的电平信号检测
BeforeCnt = 0; //计数器清零
while(1)
{//读取过零信号(含去抖), 过零前
if(MEM_ADDR(MoB.CommutPin) == MoB.Signal)
{
BeforeCnt++; //计数器加1
if(BeforeCnt >= 16){BeforeFlag = 1; break;}//过零前信号稳定,置标志位,退出检测
}
else{
BeforeCnt /= 2;
if(TIM4->CNT > MoB.Commut15 )break;//过零信号错过,跳过
}
}
while(TIM4->CNT < MoB.Commut20); //延时到电机超过20度角时才进行过零后检测
}
BeforeCnt = 0; //计数器清零
AfterFlag = 0; //清过零电平稳定标志寄存器
BulTim = 0x1FFF;
while((MoB.OvFlag == 0)&&(TIM4->CNT < MoB.Period4))
{//读取过零信号, 过零后
if(MEM_ADDR(MoB.CommutPin) == MoB.Signal){if(BeforeCnt != 0)BeforeCnt--;} //过零前
else{//过零后,稳定
BeforeCnt++; //过零后电平信号稳定次数累加
if(BeforeCnt >= 16)
{
AfterFlag = 1;//置标过零后信号稳定标志,并退出
BulTim = TIM4->CNT;
break;
}
}
}
MoB.Period4 = BulTim * 8; //240度的时间
MoB.Period = MoB.Period4 / 4; //60度的时间
MoB.Commut20 = MoB.Period / 3; //20度的时间
MoB.Commut15 = MoB.Period / 4; //15度的时间
MoB.Commut10 = MoB.Period / 6; //10度的时间
BulTim = MoB.Period - MoB.Commut20; //得到当前次的换相时间
QFilter_lst(&Speed_LvBo,BulTim); //一阶滤波函数(动态调整滤波系数)
while(TIM4->CNT < BulTim); //过零后等待, 再换向(15度延迟)
MoB.OvFlag = 0; //清定时器溢出标志位
TIM4->CNT = 0; //清零计数器的值
TIM4->CCR2 = MoB.Period4; //下次换相时间设为60度
MoB.CurPhase++;
if(MoB.CurPhase >= 6)MoB.CurPhase = 0;
ComHandler(MoB.CurPhase); //6步无感换向
if(BeforeFlag && AfterFlag ) //换向稳定判断
{ //过零前后的检测电平稳定
if(++ ucCommutOkCnt >= 20 )
{
MoU.FsmStat = STATFORWARDRUN; //启动成功,切换到闭环置闭环控制标志
LOOG_GAOSUMOSHI; //高速模式
}
ErrCnt /= 2;
}
else{ //不稳定
ErrCnt++; //累加过零检测信号不稳定的次数
ucCommutOkCnt /= 2;
}
MoB.CntStart++; //总换相次数累加器加1
if((ErrCnt >= 120)||(MoB.CntStart > 800))
{
BLCD_SHIJIAN_OFF; //关闭电机
MoU.FsmStat = STATSTARTFAIL; //启动失败
}
if(MoU.FsmStat != STATFORWARDSTART)return;
}
}
|
|