手把手移植 simpleFOC (四):pwm 六相 篇

文章目录

前言

一、定时器的配置

工作频率设定

二、移植代码

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

配置如下:

手把手移植 simpleFOC (四):pwm 六相 篇_第1张图片

 三个通道均工作在模式1,极性为高电平手把手移植 simpleFOC (四):pwm 六相 篇_第2张图片

二、移植代码

1.添加代码

由于原理图设计为pwm三通道驱动,即将BLDCDriver3PWM.cpp,BLDCDriver3PWM.h添加到编译工程即可,并新增两个文件stm32_mcu.cpp,stm32_mcu.h,为BLDCDriver3PWM作底层接口

2.修改代码,嫁接定时器

 初始化部分:

  由于都是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;
}

L6234使能部分

由于原理图的该芯片的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);
 
}

 三、调试

1、设定三相电压值

电机转到相应的位置,即说明驱动正常了。

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发烫,电机工作也不正常。该值可以从小到大慢慢调,如果电机转不动或抖动,慢慢往上加。

 2、六相驱动调试

改动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 六相(移植成功)

总结

本章从定时器的设置到电机能按六相位转动起来,基本为后续的开环,闭环控制作好了硬件基础。

你可能感兴趣的:(simpleFoc,无刷电机,六相位)