资讯详情

FOC和SVPWM的C语言代码实现【转载】

SVPWM这里解释了原理:https://blog.csdn.net/qlexcel/article/details/74787619#comments

现在开始分析C语言的代码(建议将代码复制到notepad 为方便读者实验,每个代码都是独立的子模块,复制到工程中即可编译操作:

一、配置高级定时器TIM1产生6路互补PWM,带刹车保护

详细配置代码如下,复制以下程序段main.c可直接输出到中间PWM波形(保证BKIN下拉),方便读者验证:

      
      
  1. static void TIM1_GPIO_Config( void)
  2. {
  3. GPIO_InitTypeDef GPIO_InitStructure;
  4. RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
  5. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);
  6. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9| GPIO_Pin_10 | GPIO_Pin_11; //CH1--A8 CH2--A9 CH3--A10 CH4-A11
  7. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 CH1N-B13 CH2N-B14 CH3N-B15 BKIN-B12
  8. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  9. GPIO_Init(GPIOA, &GPIO_InitStructure);
  10. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13| GPIO_Pin_14 | GPIO_Pin_15;
  11. GPIO_Init(GPIOB, &GPIO_InitStructure);
  12. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //BKIN-B12
  13. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  14. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  15. GPIO_Init(GPIOB, &GPIO_InitStructure);
  16. GPIO_PinLockConfig(GPIOA, GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 ); //住高侧IO口的配置寄存器,避免后面误修改
  17. }
  18. #define CKTIM ((u32)72000000uL) //主频
  19. #define PWM_PRSC ((u8)0) //TIM1分频系数
  20. #define PWM_FREQ ((u16) 15000) //PWM频率(Hz)
  21. #define PWM_PERIOD ((u16) (CKTIM / (u32)(2 * PWM_FREQ *(PWM_PRSC+1))))
  22. #define REP_RATE (1) //该参数可以调整电流环的刷新频率,刷新周期:(REP_RATE + 1)/(2*PWM_FREQ) 秒
  23. //因为电流环的采样是靠TIM1来触发的
  24. #define DEADTIME_NS ((u16)1000) //死区时间(ns),范围:0-3500
  25. #define DEADTIME (u16)((unsigned long long)CKTIM/2 * (unsigned long long)DEADTIME_NS/1000000000uL)
  26. static void TIM1_Mode_Config( void)
  27. {
  28. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  29. TIM_OCInitTypeDef TIM_OCInitStructure;
  30. TIM_BDTRInitTypeDef TIM1_BDTRInitStructure;
  31. NVIC_InitTypeDef NVIC_InitStructure;
  32. TIM_TimeBaseStructure.TIM_Period = PWM_PERIOD; //计数周期
  33. TIM_TimeBaseStructure.TIM_Prescaler = PWM_PRSC; //分频系数
  34. TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV2; //设置外部时钟TIM1ETR的滤波时间
  35. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned1; //中央对齐模式1,从0计数到 TIM_Period 然后开始减到0,循环
  36. TIM_TimeBaseStructure.TIM_RepetitionCounter = REP_RATE; //重复计数,就是重复溢出多少次才产生一个溢出中断(产生更新事件,用来触发ADC采样)
  37. TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
  38. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //配置为PWM模式1
  39. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //使能CHx的PWM输出
  40. TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; //互补输出使能,使能CHxN的PWM输出
  41. TIM_OCInitStructure.TIM_Pulse = 800; //设置跳变值,当计数器计数到这个值时,电平发生跳变
  42. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //CHx有效电平的极性为高电平(高侧)
  43. TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; //CHxN有效电平的极性为高电平(低侧)
  44. TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; //在空闲时CHx输出低(高侧), 调用TIM_CtrlPWMOutputs(TIM1, DISABLE)后就是空闲状态。
  45. TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set; //在空闲时CHxN输出高(低侧),打开低侧管子可以用来锁电机
  46. //TIM_OCIdleState 和 TIM_OCNIdleState不能同时为高
  47. TIM_OC1Init(TIM1, &TIM_OCInitStructure); //配置CH1
  48. TIM_OCInitStructure.TIM_Pulse = 800;
  49. TIM_OC2Init(TIM1, &TIM_OCInitStructure); //配置CH2
  50. TIM_OCInitStructure.TIM_Pulse = 800;
  51. TIM_OC3Init(TIM1, &TIM_OCInitStructure); //配置CH3
  52. //设置刹车特性,死区时间,锁电平,OSSI,OSSR状态和AOE(自动输出使能)
  53. TIM1_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; //MOE=1且定时器不工作时,CHx和CHxN的输出状态
  54. TIM1_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; //MOE=0且定时器不工作时,CHx和CHxN的输出状态(详情看用户手册,一般都是ENABLE,不用深究)
  55. TIM1_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1; //BDTR寄存器写保护等级,防止软件错误误写。
  56. TIM1_BDTRInitStructure.TIM_DeadTime = DEADTIME; //设置死区时间
  57. TIM1_BDTRInitStructure.TIM_Break = TIM_Break_Enable; //使能TIM1刹车输入(BKIN),要把BKIN引脚拉低才有PWM输出
  58. TIM1_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; //刹车输入(BKIN)输入高电平有效
  59. TIM1_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable; //刹车有效标志只能被软件清除,不能被自动清除
  60. TIM_BDTRConfig(TIM1, &TIM1_BDTRInitStructure);
  61. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //4个抢先级、4个子优先级
  62. /* Enable the TIM1 BRK Interrupt */
  63. NVIC_InitStructure.NVIC_IRQChannel = TIM1_BRK_IRQn;
  64. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  65. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  66. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  67. NVIC_Init(&NVIC_InitStructure);
  68. TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update); //使用TIM1的更新事件作为触发输出,这个输出可以触发ADC进行采样,电流环的采样
  69. TIM_ClearITPendingBit(TIM1, TIM_IT_Break); //清除刹车中断,BKIN输入导致的中断
  70. TIM_ITConfig(TIM1, TIM_IT_Break, ENABLE); //使能刹车中断
  71. TIM_CtrlPWMOutputs(TIM1, ENABLE); //PWM输出使能
  72. TIM_Cmd(TIM1, ENABLE); //使能TIM1
  73. }
  74. void TIM1_PWM_Init( void)
  75. {
  76. TIM1_GPIO_Config();
  77. TIM1_Mode_Config();
  78. }
  79. /*******************************************************************************
  80. * Function Name : TIM1_BRK_IRQHandler
  81. * Description : This function handles TIM1 Break interrupt request.
  82. *******************************************************************************/
  83. void TIM1_BRK_IRQHandler( void)
  84. {
  85. //关闭IGBT,并报错
  86. TIM_ClearITPendingBit(TIM1, TIM_IT_Break);
  87. }

1、配置TIM1的CH1--A8、CH2--A9、CH3--A10、CH4-A11、CH1N-B13、CH2N-B14、CH3N-B15、BKIN-B12

BKIN作为报警信号或者刹车信号的输入,当检测此信号时,TIM1的PWM会硬件上停止输出,实时性好,起到保护硬件电路的作用。

2、观察SVPWM的PWM波形是对称的:

正好配置TIM1为中央对齐模式1,在上面代码的配置中,载波周期为15KHz,TIM_Period(ARR)=2400,CH1的TIM_Pulse(CCR)=800。采用的PWM1模式,即CNT小于CCR时,输出有效电平,大于CCR小于ARR时,输出无效电平,又配置CHx的有效电平为高电平,CHxN的有效电平为高电平,则可以得到下面的PWM波形:

如果CHxN的有效电平是低电平,则输出的CHx和CHxN的波形是相同的。(可能CHx和CHxN有效电平的叫法相反)

3、配置CHx和CHxN空闲时的电平,调用TIM_CtrlPWMOutputs(TIM1, DISABLE)后,就进入空闲状态了,高侧没什么用,让空闲时低侧的管子导通,可以使相线连在一起,起到锁定的作用。

4、改变 REP_RATE 的值,可以更改TRGO信号输出的频率。因为相电流采样由TIM1的TRGO信号触发,故更改REP_RATE可以调整电流环的计算频率(每次相电流采样后,会进行一次FOC运算)。采样频率关系:(2*PWM_FREQ)/(REP_RATE + 1),如:当PWM_FREQ=15KHz,REP_RATE=0,则采样频率为30KHz。

5、TIM_OSSRState和TIM_OSSIState直接Enable就可以了,详情可以去看用户手册。

6、使用TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update);函数设置TRGO信号的产生源,TIM_TRGOSource_Update参数代表TIM1产生一次更新事件,就输出一次TRGO信号。TRGO信号用来触发相电流的采样。

当然也可以使用TIM1的CH4来触发相电流采样,参数为TIM_TRGOSource_OC4Ref  ,再打开CH4,并配置CH4的比较值,比如配置比较值为PWM_PERIOD-5。这样当CNT计数到PWM_PERIOD-5时就会触发相电流的ADC采样,这种方法比较灵活,可以合理设置CH4的比较值,来让相电流采样点避开开关噪声。

二、配置双ADC模式和规则组、注入组,其中注入组由TIM1的TRGO触发


 
   
      
  1. //A相电流采样
  2. #define PHASE_A_ADC_CHANNEL ADC_Channel_11
  3. #define PHASE_A_GPIO_PORT GPIOC
  4. #define PHASE_A_GPIO_PIN GPIO_Pin_1
  5. //B相电流采样
  6. #define PHASE_B_ADC_CHANNEL ADC_Channel_10
  7. #define PHASE_B_GPIO_PORT GPIOC
  8. #define PHASE_B_GPIO_PIN GPIO_Pin_0
  9. //读取散热器温度(过热保护)
  10. #define TEMP_FDBK_CHANNEL ADC_Channel_13
  11. #define TEMP_FDBK_CHANNEL_GPIO_PORT GPIOC
  12. #define TEMP_FDBK_CHANNEL_GPIO_PIN GPIO_Pin_3
  13. //读取总线电压值(过压、欠压保护)
  14. #define BUS_VOLT_FDBK_CHANNEL ADC_Channel_14
  15. #define BUS_VOLT_FDBK_CHANNEL_GPIO_PORT GPIOC
  16. #define BUS_VOLT_FDBK_CHANNEL_GPIO_PIN GPIO_Pin_4
  17. //读取电位器值,可以用来调速等
  18. #define POT1_VOLT_FDBK_CHANNEL ADC_Channel_12
  19. #define POT1_VOLT_FDBK_CHANNEL_GPIO_PORT GPIOC
  20. #define POT1_VOLT_FDBK_CHANNEL_GPIO_PIN GPIO_Pin_2
  21. //读取母线电流值(过流保护)
  22. #define BUS_SHUNT_CURR_CHANNEL ADC_Channel_15
  23. #define BUS_SHUNT_CURR_CHANNEL_GPIO_PORT GPIOC
  24. #define BUS_SHUNT_CURR_CHANNEL_GPIO_PIN GPIO_Pin_5
  25. //读取刹车电阻电流(刹车电阻过流保护)
  26. #define BRK_SHUNT_CURR_CHANNEL ADC_Channel_7
  27. #define BRK_SHUNT_CURR_CHANNEL_GPIO_PORT GPIOA
  28. #define BRK_SHUNT_CURR_CHANNEL_GPIO_PIN GPIO_Pin_7
  29. //备用通道
  30. #define AIN0_VOLT_FDBK_CHANNEL ADC_Channel_8
  31. #define AIN0_VOLT_FDBK_CHANNEL_GPIO_PORT GPIOB
  32. #define AIN0_VOLT_FDBK_CHANNEL_GPIO_PIN GPIO_Pin_0
  33. //备用导通
  34. #define AIN1_VOLT_FDBK_CHANNEL ADC_Channel_9
  35. #define AIN1_VOLT_FDBK_CHANNEL_GPIO_PORT GPIOB
  36. #define AIN1_VOLT_FDBK_CHANNEL_GPIO_PIN GPIO_Pin_1
  37. #define ADC1_DR_Address ((uint32_t)0x4001244C) //ADC数据寄存器地址
  38. #define BufferLenght 36
  39. volatile u32 ADC_DualConvertedValueTab[BufferLenght];
  40. volatile u16 ADC1_RegularConvertedValueTab[BufferLenght];
  41. volatile u16 ADC2_RegularConvertedValueTab[BufferLenght];
  42. static u16 hPhaseAOffset;
  43. static u16 hPhaseBOffset;
  44. void ADC_DMA_Init(void)
  45. {
  46. u8 bIndex;
  47. GPIO_InitTypeDef GPIO_InitStructure;
  48. ADC_InitTypeDef ADC_InitStructure;
  49. DMA_InitTypeDef DMA_InitStructure;
  50. NVIC_InitTypeDef NVIC_InitStructure;
  51. RCC_ADCCLKConfig(RCC_PCLK2_Div6); //ADCCLK = PCLK2/6=72M/6=12MHz,ADC最大频率不能超过14MHz
  52. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //DMA1
  53. RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
  54. RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
  55. RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA |
  56. RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOE, ENABLE);
  57. GPIO_StructInit(&GPIO_InitStructure); //Fills each GPIO_InitStruct member with its default value
  58. GPIO_InitStructure.GPIO_Pin = PHASE_A_GPIO_PIN;
  59. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  60. GPIO_Init(PHASE_A_GPIO_PORT, &GPIO_InitStructure);
  61. GPIO_InitStructure.GPIO_Pin = PHASE_B_GPIO_PIN;
  62. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  63. GPIO_Init(PHASE_B_GPIO_PORT, &GPIO_InitStructure);
  64. GPIO_InitStructure.GPIO_Pin = TEMP_FDBK_CHANNEL_GPIO_PIN;
  65. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  66. GPIO_Init(TEMP_FDBK_CHANNEL_GPIO_PORT, &GPIO_InitStructure);
  67. GPIO_InitStructure.GPIO_Pin = BUS_VOLT_FDBK_CHANNEL_GPIO_PIN;
  68. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  69. GPIO_Init(BUS_VOLT_FDBK_CHANNEL_GPIO_PORT, &GPIO_InitStructure);
  70. GPIO_InitStructure.GPIO_Pin = POT1_VOLT_FDBK_CHANNEL_GPIO_PIN;
  71. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  72. GPIO_Init(POT1_VOLT_FDBK_CHANNEL_GPIO_PORT, &GPIO_InitStructure);
  73. GPIO_InitStructure.GPIO_Pin = BUS_SHUNT_CURR_CHANNEL_GPIO_PIN;
  74. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  75. GPIO_Init(BUS_SHUNT_CURR_CHANNEL_GPIO_PORT, &GPIO_InitStructure);
  76. GPIO_StructInit(&GPIO_InitStructure);
  77. GPIO_InitStructure.GPIO_Pin = BRK_SHUNT_CURR_CHANNEL_GPIO_PIN;
  78. 标签: 传感器bc53a电流138电位器

    锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台