当前位置:   article > 正文

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

setphasevoltage

文章目录


前言

今天移植的内容,为定时器生在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

配置如下:

 三个通道均工作在模式1,极性为高电平

二、移植代码

1.添加代码

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

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

 初始化部分:

  由于都是stm32cubeMX根据需要生成的驱动代码,原代码对管脚初始化部分即可删除或屏蔽。

  1. // init hardware pins
  2. int BLDCDriver3PWM::init() {
  3. // PWM pins
  4. // pinMode(pwmA, OUTPUT);
  5. // pinMode(pwmB, OUTPUT);
  6. // pinMode(pwmC, OUTPUT);
  7. // if( _isset(enableA_pin)) pinMode(enableA_pin, OUTPUT);
  8. // if( _isset(enableB_pin)) pinMode(enableB_pin, OUTPUT);
  9. // if( _isset(enableC_pin)) pinMode(enableC_pin, OUTPUT);
  10. // sanity check for the voltage limit configuration
  11. if(!_isset(voltage_limit) || voltage_limit > voltage_power_supply) voltage_limit = voltage_power_supply;
  12. // Set the pwm frequency to the pins
  13. // hardware specific function - depending on driver and mcu
  14. params = _configure3PWM(pwm_frequency, pwmA, pwmB, pwmC);
  15. initialized = (params!=SIMPLEFOC_DRIVER_INIT_FAILED);
  16. return params!=SIMPLEFOC_DRIVER_INIT_FAILED;
  17. }

L6234使能部分

由于原理图的该芯片的en管脚为mcu统一管控,会影响到BLDCDriver3PWM::setPhaseState该函数,并且该函数只对 Trapezoid_120 、Trapezoid_150两种模式调制调用,貌似方波输出(该部分不是重点,没有深入,暂时忽略),BTN8982版是分开控制,或L6234版后续再改一版。

  1. // enable motor driver
  2. void BLDCDriver3PWM::enable(){
  3. // enable_pin the driver - if enable_pin pin available
  4. HAL_GPIO_WritePin(m0_en_GPIO_Port, m0_en_Pin, GPIO_PIN_SET);
  5. // set zero to PWM
  6. setPwm(0,0,0);
  7. }
  8. // disable motor driver
  9. void BLDCDriver3PWM::disable()
  10. {
  11. // set zero to PWM
  12. setPwm(0, 0, 0);
  13. // disable the driver - if enable_pin pin available
  14. HAL_GPIO_WritePin(m0_en_GPIO_Port, m0_en_Pin, GPIO_PIN_RESET);
  15. }
  1. // Set voltage to the pwm pin
  2. void BLDCDriver3PWM::setPhaseState(PhaseState sa, PhaseState sb, PhaseState sc) {
  3. // disable if needed
  4. if( _isset(enableA_pin) && _isset(enableB_pin) && _isset(enableC_pin) ){
  5. //该模式在 Trapezoid_120 Trapezoid_150里调用 由于三个引脚连在一起了,暂时屏蔽该功能
  6. // digitalWrite(enableA_pin, sa == PhaseState::PHASE_ON ? enable_active_high:!enable_active_high);
  7. // digitalWrite(enableB_pin, sb == PhaseState::PHASE_ON ? enable_active_high:!enable_active_high);
  8. // digitalWrite(enableC_pin, sc == PhaseState::PHASE_ON ? enable_active_high:!enable_active_high);
  9. }
  10. }

驱动层接入

将第一章节定时器配置生成的代码MX_TIM1_Init赋予给

void* _configure3PWM(long pwm_frequency,const int pinA, const int pinB, const int pinC),本例是将内容复制粘贴过来了 并全输出低电平,并且启动定时器

  1. void* _configure3PWM(long pwm_frequency,const int pinA, const int pinB, const int pinC) {
  2. // if (numTimerPinsUsed+3 > SIMPLEFOC_STM32_MAX_PINTIMERSUSED) {
  3. // SIMPLEFOC_DEBUG("STM32-DRV: ERR: too many pins used");
  4. // return (STM32DriverParams*)SIMPLEFOC_DRIVER_INIT_FAILED;
  5. // }
  6. if( !pwm_frequency || !_isset(pwm_frequency) ) pwm_frequency = _PWM_FREQUENCY; // default frequency 25khz
  7. else pwm_frequency = _constrain(pwm_frequency, 0, _PWM_FREQUENCY_MAX); // constrain to 50kHz max
  8. // center-aligned frequency is uses two periods
  9. pwm_frequency *=2;
  10. /* USER CODE BEGIN TIM1_Init 0 */
  11. /* USER CODE END TIM1_Init 0 */
  12. TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  13. TIM_MasterConfigTypeDef sMasterConfig = {0};
  14. TIM_OC_InitTypeDef sConfigOC = {0};
  15. TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
  16. /* USER CODE BEGIN TIM1_Init 1 */
  17. /* USER CODE END TIM1_Init 1 */
  18. htim1.Instance = TIM1;
  19. htim1.Init.Prescaler = 0;
  20. htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED3;
  21. htim1.Init.Period = SystemCoreClock/pwm_frequency;
  22. htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  23. htim1.Init.RepetitionCounter = TIM_1_RCR;
  24. htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  25. if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  26. {
  27. Error_Handler();
  28. }
  29. sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  30. if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
  31. {
  32. Error_Handler();
  33. }
  34. if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
  35. {
  36. Error_Handler();
  37. }
  38. sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  39. sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  40. if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  41. {
  42. Error_Handler();
  43. }
  44. sConfigOC.OCMode = TIM_OCMODE_PWM1;
  45. sConfigOC.Pulse = 0;
  46. sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  47. sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
  48. sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  49. sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
  50. sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
  51. if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  52. {
  53. Error_Handler();
  54. }
  55. if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  56. {
  57. Error_Handler();
  58. }
  59. if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
  60. {
  61. Error_Handler();
  62. }
  63. sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_ENABLE;
  64. sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSR_ENABLE;
  65. sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
  66. sBreakDeadTimeConfig.DeadTime = 10;
  67. sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
  68. sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
  69. sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
  70. if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
  71. {
  72. Error_Handler();
  73. }
  74. /* USER CODE BEGIN TIM1_Init 2 */
  75. __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,0);
  76. __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_2,0);
  77. __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_3,0);
  78. HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
  79. HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2);
  80. HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3);
  81. /* USER CODE END TIM1_Init 2 */
  82. HAL_TIM_MspPostInit(&htim1);
  83. return 0;
  84. }

 修改void _writeDutyCycle3PWM(float dc_a,  float dc_b, float dc_c, void* params)函数。

该函数的主要功能是根据相电压对于mos管的工作电压dc_bus的比率,设定pwm通道的TIMx_CCRx值,即完成pwm输出高电平的占空比。

  1. // function setting the pwm duty cycle to the hardware
  2. // - BLDC motor - 3PWM setting
  3. //- hardware speciffic
  4. void _writeDutyCycle3PWM(float dc_a, float dc_b, float dc_c, void* params){
  5. // transform duty cycle from [0,1] to [0,4095]
  6. //float pwm_range = SystemCoreClock/pwm_frequency;
  7. __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,_PWM_RANGE*dc_a);
  8. __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_2,_PWM_RANGE*dc_b);
  9. __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_3,_PWM_RANGE*dc_c);
  10. }

 三、调试

1、设定三相电压值

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

  1. extern "C" {
  2. // BLDCDriver3PWM driver = BLDCDriver3PWM(pwmA, pwmB, pwmC, Enable(optional));
  3. BLDCDriver3PWM driver = BLDCDriver3PWM(9, 5, 6, 8);
  4. void setup() {
  5. driver.voltage_power_supply = 24;
  6. // limit the maximal dc voltage the driver can set
  7. // as a protection measure for the low-resistance motors
  8. // this value is fixed on startup
  9. driver.voltage_limit = 0.8;
  10. driver.init();
  11. driver.enable();
  12. Serial.begin(115200);
  13. Serial.println("Motor ready!");
  14. Serial.println("Set target position [rad]");
  15. _delay(1000);
  16. }
  17. void loop() {
  18. driver.setPwm(3,6,5);
  19. }

 driver.voltage_limit = 0.8   由于本人使用的是5008高功率电机,相电阻很小,这里的限制一定要小,不然L6234发烫,电机工作也不正常。该值可以从小到大慢慢调,如果电机转不动或抖动,慢慢往上加。

 2、六相驱动调试

改动loop代码,让六相循环驱动起来,电机就会转起来了。

  1. void loop() {
  2. static int sixPhase_seq = 0;
  3. switch(sixPhase_seq%6)
  4. {
  5. case 0:{driver.setPwm(1,0,0);}break; //100
  6. case 1:{driver.setPwm(1,1,0);}break; //110
  7. case 2:{driver.setPwm(0,1,0);}break; //010
  8. case 3:{driver.setPwm(0,1,1);}break; //011
  9. case 4:{driver.setPwm(0,0,1);}break; //001
  10. case 5:{driver.setPwm(1,0,1);}break; //101
  11. }
  12. sixPhase_seq++;
  13. _delay(20);
  14. }

这代码里的1和0,代表输出三相的电压值,也体现了六桥通断的逻辑,如果是云台电机可将driver.voltage_limit设高一点,并将这里的1,设定高一些数字。

simpleFoc 六相(移植成功)

总结

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/247925
推荐阅读
相关标签
  

闽ICP备14008679号