前言
一、定时器的配置
工作频率设定
二、移植代码
1.添加代码
2.修改代码,嫁接定时器
初始化部分:
L6234使能部分
驱动层接入
三、调试
1、设定三相电压值
2、六相驱动调试
今天移植的内容,为定时器生在pwm,能按矢量数据控制电机到相应的位置
通读了simpleFoc的代码,准备让定时器1生成的pwm波为20KHz,中心对齐模式3,三个通道均工作在模式1,极性为高电平,即TIMx_CNT < TIMx_CCRx时OCxREF信号为高,输出为高电平。
预设:20KHz,由于是中心对齐模式,周期即是常规设定的2倍,那么ARR=f_timer/(2*f_pwm)
f_timer: 即是定时器工作主频,未分频,即为72MHz
f_pwm: 即是要设定的pwm的频,20KHz
那么ARR=72000000/(2*20000) = 1800
配置如下:
由于原理图设计为pwm三通道驱动,即将BLDCDriver3PWM.cpp,BLDCDriver3PWM.h添加到编译工程即可,并新增两个文件stm32_mcu.cpp,stm32_mcu.h,为BLDCDriver3PWM作底层接口
由于都是stm32cubeMX根据需要生成的驱动代码,原代码对管脚初始化部分即可删除或屏蔽。
// init hardware pins
int BLDCDriver3PWM::init() {
// PWM pins
// pinMode(pwmA, OUTPUT);
// pinMode(pwmB, OUTPUT);
// pinMode(pwmC, OUTPUT);
// if( _isset(enableA_pin)) pinMode(enableA_pin, OUTPUT);
// if( _isset(enableB_pin)) pinMode(enableB_pin, OUTPUT);
// if( _isset(enableC_pin)) pinMode(enableC_pin, OUTPUT);
// sanity check for the voltage limit configuration
if(!_isset(voltage_limit) || voltage_limit > voltage_power_supply) voltage_limit = voltage_power_supply;
// Set the pwm frequency to the pins
// hardware specific function - depending on driver and mcu
params = _configure3PWM(pwm_frequency, pwmA, pwmB, pwmC);
initialized = (params!=SIMPLEFOC_DRIVER_INIT_FAILED);
return params!=SIMPLEFOC_DRIVER_INIT_FAILED;
}
由于原理图的该芯片的en管脚为mcu统一管控,会影响到BLDCDriver3PWM::setPhaseState该函数,并且该函数只对 Trapezoid_120 、Trapezoid_150两种模式调制调用,貌似方波输出(该部分不是重点,没有深入,暂时忽略),BTN8982版是分开控制,或L6234版后续再改一版。
// enable motor driver
void BLDCDriver3PWM::enable(){
// enable_pin the driver - if enable_pin pin available
HAL_GPIO_WritePin(m0_en_GPIO_Port, m0_en_Pin, GPIO_PIN_SET);
// set zero to PWM
setPwm(0,0,0);
}
// disable motor driver
void BLDCDriver3PWM::disable()
{
// set zero to PWM
setPwm(0, 0, 0);
// disable the driver - if enable_pin pin available
HAL_GPIO_WritePin(m0_en_GPIO_Port, m0_en_Pin, GPIO_PIN_RESET);
}
// Set voltage to the pwm pin
void BLDCDriver3PWM::setPhaseState(PhaseState sa, PhaseState sb, PhaseState sc) {
// disable if needed
if( _isset(enableA_pin) && _isset(enableB_pin) && _isset(enableC_pin) ){
//该模式在 Trapezoid_120 Trapezoid_150里调用 由于三个引脚连在一起了,暂时屏蔽该功能
// digitalWrite(enableA_pin, sa == PhaseState::PHASE_ON ? enable_active_high:!enable_active_high);
// digitalWrite(enableB_pin, sb == PhaseState::PHASE_ON ? enable_active_high:!enable_active_high);
// digitalWrite(enableC_pin, sc == PhaseState::PHASE_ON ? enable_active_high:!enable_active_high);
}
}
将第一章节定时器配置生成的代码MX_TIM1_Init赋予给
void* _configure3PWM(long pwm_frequency,const int pinA, const int pinB, const int pinC),本例是将内容复制粘贴过来了 并全输出低电平,并且启动定时器
void* _configure3PWM(long pwm_frequency,const int pinA, const int pinB, const int pinC) {
// if (numTimerPinsUsed+3 > SIMPLEFOC_STM32_MAX_PINTIMERSUSED) {
// SIMPLEFOC_DEBUG("STM32-DRV: ERR: too many pins used");
// return (STM32DriverParams*)SIMPLEFOC_DRIVER_INIT_FAILED;
// }
if( !pwm_frequency || !_isset(pwm_frequency) ) pwm_frequency = _PWM_FREQUENCY; // default frequency 25khz
else pwm_frequency = _constrain(pwm_frequency, 0, _PWM_FREQUENCY_MAX); // constrain to 50kHz max
// center-aligned frequency is uses two periods
pwm_frequency *=2;
/* USER CODE BEGIN TIM1_Init 0 */
/* USER CODE END TIM1_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
/* USER CODE BEGIN TIM1_Init 1 */
/* USER CODE END TIM1_Init 1 */
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED3;
htim1.Init.Period = SystemCoreClock/pwm_frequency;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = TIM_1_RCR;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
Error_Handler();
}
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_ENABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSR_ENABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 10;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM1_Init 2 */
__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);
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3);
/* USER CODE END TIM1_Init 2 */
HAL_TIM_MspPostInit(&htim1);
return 0;
}
修改void _writeDutyCycle3PWM(float dc_a, float dc_b, float dc_c, void* params)函数。
该函数的主要功能是根据相电压对于mos管的工作电压dc_bus的比率,设定pwm通道的TIMx_CCRx值,即完成pwm输出高电平的占空比。
// function setting the pwm duty cycle to the hardware
// - BLDC motor - 3PWM setting
//- hardware speciffic
void _writeDutyCycle3PWM(float dc_a, float dc_b, float dc_c, void* params){
// transform duty cycle from [0,1] to [0,4095]
//float pwm_range = SystemCoreClock/pwm_frequency;
__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,_PWM_RANGE*dc_a);
__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_2,_PWM_RANGE*dc_b);
__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_3,_PWM_RANGE*dc_c);
}
电机转到相应的位置,即说明驱动正常了。
extern "C" {
// BLDCDriver3PWM driver = BLDCDriver3PWM(pwmA, pwmB, pwmC, Enable(optional));
BLDCDriver3PWM driver = BLDCDriver3PWM(9, 5, 6, 8);
void setup() {
driver.voltage_power_supply = 24;
// limit the maximal dc voltage the driver can set
// as a protection measure for the low-resistance motors
// this value is fixed on startup
driver.voltage_limit = 0.8;
driver.init();
driver.enable();
Serial.begin(115200);
Serial.println("Motor ready!");
Serial.println("Set target position [rad]");
_delay(1000);
}
void loop() {
driver.setPwm(3,6,5);
}
driver.voltage_limit = 0.8 由于本人使用的是5008高功率电机,相电阻很小,这里的限制一定要小,不然L6234发烫,电机工作也不正常。该值可以从小到大慢慢调,如果电机转不动或抖动,慢慢往上加。
改动loop代码,让六相循环驱动起来,电机就会转起来了。
void loop() {
static int sixPhase_seq = 0;
switch(sixPhase_seq%6)
{
case 0:{driver.setPwm(1,0,0);}break; //100
case 1:{driver.setPwm(1,1,0);}break; //110
case 2:{driver.setPwm(0,1,0);}break; //010
case 3:{driver.setPwm(0,1,1);}break; //011
case 4:{driver.setPwm(0,0,1);}break; //001
case 5:{driver.setPwm(1,0,1);}break; //101
}
sixPhase_seq++;
_delay(20);
}
这代码里的1和0,代表输出三相的电压值,也体现了六桥通断的逻辑,如果是云台电机可将driver.voltage_limit设高一点,并将这里的1,设定高一些数字。
simpleFoc 六相(移植成功)
总结
本章从定时器的设置到电机能按六相位转动起来,基本为后续的开环,闭环控制作好了硬件基础。