目录
CubeMX基本配置
drv8301控制模式(3pwm?6pwm?死区时间设置?)
SVPWM理论推导
HALL接口设置以及旋转速度获取原理
FOC开环控制主要分为三步:第一,角度自增;第二,Park逆变换;第三,SVPWM计算出下个周期要写入的占空比Ta,Tb,Tc
验证SVPWM模块也非常简单,串口打印出来应该是个比较标准的马鞍波(我是20k频率,可供参考)
如果角度改变太快会造成波形有不同程度的失真,不过是正常现象,角度变化改小点就可以了
CubeMX基本配置
使用STM32外设情况如下:
TIM1高级定时器CH1-CH3输出三路互补的PWM信号,设置为中央对齐模式,同时CH4配置为PWM generation no output用于触发ADC采样,具体原因可以看这篇博客:foc配置篇——ADC注入组使用定时器触发采样的配置_定时器触发adc采样_jdhfusk的博客-CSDN博客
据我测试Center Align Mode1和Center Align Mode2没啥很大的区别,定时器Update中断触发位置都是在中间的时刻,但最后我采用的是在ADC采集完成的回调函数中进行FOC运算,所以配置成什么模式就更无所谓了。
这里就提一句比较推荐使用高级定时器TIM1和TIM8来做PWM输出,因为只有他俩是挂在168M下的,而且具有互补输出功能,在频率比较高的情况下,占空比不至于过小。
ADC配置如下,随意看看就行,没啥很特别的
初始化代码如下:
void MOTOR1_PWM_Init(void)
{
//PWM初始化
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_3);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1,0);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2,0);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3,0);
//通道4触发ADC采样
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_4);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_4,3900);
//开启ADC注入转换
HAL_ADCEx_InjectedStart_IT(&hadc1);
}
drv8301控制模式(3pwm?6pwm?死区时间设置?)
一开始采样3PWM控制,但是这个模式不灵活的地方在于,DRV8301是通过DTC引脚到地的电阻值设置死区时间的,而怨种队友一开始坚定认为用了很好的MOS管,就只接了0欧电阻(相当于50ns死区时间)。推荐6PWM模式,配置简单,死区时间设置很方便,而且DRV8301默认就是6PWM控制,省了一步寄存器更改配置
死区时间计算理论上为 MOS管关断时间(看芯片手册) + 单片机IO口翻转时间(对于F4来说10ns左右)当然,理论计算出来后最好还要留一点裕量
我一开始没怎么考虑死区时间问题,于是电机转起来的声音非常惨绝人寰。排查了很久代码的问题,最后锁定了死区时间问题
实际调试时发现,死区时间过小,电机会有尖锐的噪声,死区时间过大,采样电流会隐隐看到有些不连续,严重时就像这样(神似马鞍波)
这个时候我们就可以考虑适当调小死区时间,效果好的时候就是这样啦
SVPWM理论推导
彻底吃透SVPWM如此简单 - 知乎 (zhihu.com)
这里推荐直接看这篇文章,至于代码网上有很多,但关键在于理解以下几个问题:
为什么要选择中心对其模式?
Uq的实际含义是什么?
以及采集总线电压到底有什么作用?
我一开始配置单片机外设的时候也没考虑过总线电压采集,其实如果电压比较稳定没有波动的话给个定值完全ok
HALL接口设置以及旋转速度获取原理
首先选择HALL接口模式,选择时钟源及合适的分频系数,以得到最大计数器周期,该周期长于传感器上两次变化的间隔时间
Input Filter 其实是为了抗干扰,因为会有电磁干扰进入引脚,就相当于按键的多次计数软件滤波
三个引脚二配置为内部上拉模式,当然在硬件电路上加上拉电阻也可以的。如果不上拉是无法获取到稳定的电平信号的(本人惨痛教训,曾经直接把三根信号线接到示波器上看,只有几十mV的电平,当时还以为是电机坏了)
下面来到本篇重点了,就是到底如何根据霍尔信号推算当前的电角度?
霍尔传感器分为60°安装方式和120°安装方式,但是仔细观察下面这张图就会发现,本质的区别不大。对于HALL接口模式下,三个信号异或,只要有一路信号发生跳变单片机就会进入输入捕获中断,也就是每隔60电角度就可以在触发中断里得到准确的电角度值
对于120°安装时,信号在0-2PI内变换6次,顺序是5-4-6-2-3-1
而60°安装时,信号改变顺序是4-6-7-3-1-0
但这里存在一个问题,就是我们需要根据TIM2->CCR1捕获值来计算角速度吗?
由于我把FOC的运算放在ADC注入组的中断里,所有如果把角速度计算放在霍尔中断,但是在adc中断里算电角度会有严重的延迟误差,每次校准时会有一个很明显的突变发生
如果把计算角速度的公式放在adc中断里就能得到一个很平滑的曲线
文章来源:https://www.toymoban.com/news/detail-607961.html
话不多说直接上代码文章来源地址https://www.toymoban.com/news/detail-607961.html
/**
* 函数功能: 霍尔传感器回调函数
* 输入参数: @htim,霍尔传感器接口定时器
* 返 回 值: 无
* 说 明:霍尔信号发生跳变后进入这个中断,只做角度矫正
*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
uint8_t hall_read_temp;
if(htim == &htim2)
{
hall_read_temp = HALL_GetPhase();
if(hall_read_temp==0x05)
{
hall_angle = 0.0f+PHASE_SHIFT_ANGLE;
}
else if(hall_read_temp==0x04)
{
hall_angle = (PI/3.0f)+PHASE_SHIFT_ANGLE;
}
else if(hall_read_temp==0x06)
{
hall_angle = (PI*2.0f/3.0f)+PHASE_SHIFT_ANGLE;
}
else if(hall_read_temp==0x02)
{
hall_angle = PI+PHASE_SHIFT_ANGLE;
}
else if(hall_read_temp==0x03)
{
hall_angle = (PI*4.0f/3.0f)+PHASE_SHIFT_ANGLE;
}
else if(hall_read_temp==0x01)
{
hall_angle = (PI*5.0f/3.0f)+PHASE_SHIFT_ANGLE;
}
if(hall_angle<0.0f)
{
hall_angle += 2.0f*PI;
}
else if(hall_angle>(2.0f*PI))
{
hall_angle -= 2.0f*PI;
}
}
}
void FOC_ControllerTask(void)
{
//最先计算霍尔角度,其次电流,然后送入SVPWM计算
static uint8_t hall_phase,hall_phase_last;
static uint16_t hall_count;
hall_phase = HALL_GetPhase();
if(hall_phase == hall_phase_last)
{
hall_count++;
if(hall_count > 2000)
{
hall_count = 0;
hall_angle_add = 0;
}
}
else
{
hall_angle_add = (float)PI/3.0f/hall_count;
hall_count = 0;
hall_phase_last = hall_phase;
}
hall_angle = _normalizeAngle(hall_angle + hall_angle_add);
}
到了这里,关于STM32 HAL库基于DRV8301的FOC开环速度控制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!