【外设篇】STMG4芯片高级定时器互补通道三相驱动桥的STM32CubeMx配置(基础工程)
引言:本文主要介绍高级定时器的配置参数及如何配置三相全桥。内容包括:1.HAL库定时器函数,2.高级定时器的配置参数解析,3.三相全桥的配置及stm32cubemx设置,4.keil5代码解释
1.HAL库定时器函数
高级定时器(如STM32中的TIM1和TIM8)是功能强大的定时器模块,用于PWM、输入捕获、输出比较、编码器模式等高精度操作。HAL库提供了多种函数来操作高级定时器。这些函数分为初始化、控制、输入捕获、输出比较、PWM和中断等。
| 序号 | 当前任务用到的HAL库函数 | 作用 |
|---|---|---|
| 1 | TIM1->ARR = 8000 - 1; | 设置TIM1的ARR的值 |
| 2 | TIM1->CCR4 = 8000 - 2; | 设置TIM1_IN4的CCR值 |
| 3 | HAL_TIM_Base_Start( &htim1); | 启动TIM1 |
| 4 | HAL_TIM_PWM_Start( &htim1, TIM_CHANNEL_4); | 启动TIM1_IN4 |
| 5 | __HAL_TIM_SET_PRESCALER(TIM_HandleTypeDef *htim, uint32_t Prescaler); | 设置预分配PSC值 |
/*********************定时器**************************/
//初始化用的
HAL_TIM_Base_Init(TIM_HandleTypeDef *htim);
HAL_TIM_PWM_Init(TIM_HandleTypeDef *htim);
HAL_TIM_OC_Init(TIM_HandleTypeDef *htim);
HAL_TIM_IC_Init(TIM_HandleTypeDef *htim);
HAL_TIM_Encoder_Init(TIM_HandleTypeDef *htim, TIM_Encoder_InitTypeDef *sConfig);
HAL_TIMEx_MasterConfigSynchronization(TIM_HandleTypeDef *htim, TIM_MasterConfigTypeDef *sMasterConfig);
//启动暂停
HAL_TIM_Base_Start(TIM_HandleTypeDef *htim);
HAL_TIM_Base_Stop(TIM_HandleTypeDef *htim);
HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim);
HAL_TIM_Base_Stop_IT(TIM_HandleTypeDef *htim);
/********************PWM******************************/
//初始化
HAL_TIM_Base_Init(TIM_HandleTypeDef *htim);
HAL_TIM_PWM_Init(TIM_HandleTypeDef *htim);
HAL_TIM_OC_Init(TIM_HandleTypeDef *htim);
HAL_TIM_IC_Init(TIM_HandleTypeDef *htim);
HAL_TIM_Encoder_Init(TIM_HandleTypeDef *htim, TIM_Encoder_InitTypeDef *sConfig);
HAL_TIMEx_MasterConfigSynchronization(TIM_HandleTypeDef *htim, TIM_MasterConfigTypeDef *sMasterConfig);
//启动暂停
HAL_TIM_Base_Start(TIM_HandleTypeDef *htim);
HAL_TIM_Base_Stop(TIM_HandleTypeDef *htim);
HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim);
HAL_TIM_Base_Stop_IT(TIM_HandleTypeDef *htim);
//改变占空比
__HAL_TIM_SET_COMPARE(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t Compare);
/***********************输出比较**********************/
//初始化
HAL_TIM_OC_Init(TIM_HandleTypeDef *htim);
//启动暂停
HAL_TIM_OC_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
HAL_TIM_OC_Stop(TIM_HandleTypeDef *htim, uint32_t Channel);
HAL_TIM_OC_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
HAL_TIM_OC_Stop_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
/*********************输入捕获*********************/
//初始化
HAL_TIM_IC_Init(TIM_HandleTypeDef *htim);
//启动暂停
HAL_TIM_IC_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
HAL_TIM_IC_Stop(TIM_HandleTypeDef *htim, uint32_t Channel);
HAL_TIM_IC_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
HAL_TIM_IC_Stop_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
//读取捕获值
__HAL_TIM_GET_COMPARE(TIM_HandleTypeDef *htim, uint32_t Channel);
/******************编码器***********************/
//初始化
HAL_TIM_Encoder_Init(TIM_HandleTypeDef *htim, TIM_Encoder_InitTypeDef *sConfig);
//启动暂停
HAL_TIM_Encoder_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
HAL_TIM_Encoder_Stop(TIM_HandleTypeDef *htim, uint32_t Channel);
HAL_TIM_Encoder_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
HAL_TIM_Encoder_Stop_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
2.高级定时器的配置参数解析
2.1高级定时器框图
大家看到这个图不要害怕,实际上我们配置三相驱动桥,只需要用到其中一些配置即可,并且也需要根据这个图的参数,配置我们的stm32cubemx上的高级定时器参数,大家专注一下1.时钟源,2.控制器,3.时基单元,4.输出比较,5.重复计数器,其他的暂时没用到,后续使用到再详细学习。

2.2时钟源参数设置


时钟来源分为内部时钟internal Clock和外部时钟ETC,这里我建议直接使用内部时间即可,也就是APB总线上的时钟源,具体是哪个APB总线需要查看数据手册
2.3控制器选择
模式分为1.触发控制器,如本实验把TIM1_IN4设置为PWM不输出模式,作一个ADC的触发源;2.从模式控制器,3.编码器接口
2.4时基单元
1.预分配器PSC,范围是0~65535,2.自动重装载寄存器ARR,范围0~65535,3.那系统时钟进过PSC后,CNT计数器的时钟频率 = f / (PSC + 1)。
最终定时器溢出需要计数ARR+1个周期, 则溢出时间T = (ARR + 1)(PSC + 1)/ f
解释:(1)ARR +1 是因为在记了ARR次后,计数器满了,还需要一个时钟周期才溢出
(2)PSC + 1 是因为手册规定的。
2.5输入捕获

2.6捕获比较

2.7重复计算器
RCR = 0,则每过1个定时器周期,计数器记2次
RCR = 1,则每过1个定时器周期,计数器记1次
RCR = 2,则每过2个定时器周期,计数器记1次
RCR = 3,则每过3个定时器周期,计数器记1次
所以定时器溢出时间的计算,RCR也有影响
2.8输出比较
TIM1_CH1/TIM1_CH1N、TIM1_CH2/TIM1_CH2N、TIM1_CH1/TIM1_CH3N三个为PWM互补通道,TIM1_CH4为PWM不输出模式,用于给ADC作触发源
2.9刹车
下一节再说
3.三相全桥的配置及stm32cubemx设置
实验目标:配置三相驱动桥为互补输出,TIM1_IN4给ADC采样三相电流的触发源,在下一章内部比较+刹车+DAC级联配置再讲解刹车如何配置。
首先使用内部时钟,然后三个互补通道,一个PWM不输出


预分频值PSC,计数器的时钟频率 = f / (PSC + 1),不分频
计数模式,分为向上计数、向下计数、中央对齐计数,中央对齐:一个定时器周期内会计数两次
PWM抖动模式,可以提高PWM波的分辨率,咱们不用使能
自动重装载值ARR,范围0~65535,这里8000-1
内部时钟分频CKD,只能2分聘,或者4分频,这里2分频
重复计数器RCR,见2.7,这里设为1
自动重装载预装载,如果使能,在需要改变ARR值的时候,会提前在此定时器周期结束前改变,也就是有一定的缓冲作用,减少定时器误差;如果不使能,则在需要改变ARR值的时候,会在此定时器周期结束时改变,没有缓冲作用,误差就包含了操作ARR所花费的时间。因三相全桥不需要改变ARR值,故不使能自动重装载。


三个通道配置一样,PWM的模式1,通道4为ADC触发源,把他设为PWM模式2,占空比为8000-2,这样每次采用三相电流时,都在PMSM电机的 0 0 0位,较为准确,具体看欧拉电子吧,视频讲的明白。
因为刹车需要触发源,所以下一节咱们通过内部比较器将DAC模拟输出与ADC比较作为触发源,再说刹车功能
4.keil5代码解释
具体使用就是
再main函数初始化那加
//TIM1高级定时器
TIM1->ARR = 8000 - 1;
TIM1->CCR4 = 8000 - 2;
HAL_TIM_Base_Start( &htim1);
HAL_TIM_PWM_Start( &htim1, TIM_CHANNEL_4);
然后随便在哪用都行
TIM1->CCR1 = 0;
TIM1->CCR2 = 0;
TIM1->CCR3 = 0;
/**************************** 4.ADC+3.ABZ编码器+5.高级定时器+2.串口****************************/
void HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef *hadc)
{
static uint8_t cnt;
static uint8_t prev_state;
/* Prevent unused argument(s) compilation warning */
UNUSED(hadc);
if(hadc == &hadc1)
{
if(ADC_offset == 0)
{
cnt++;
adc1_in1 = hadc1.Instance->JDR1;//读取注入组三相电流
adc1_in2 = hadc1.Instance->JDR2;
adc1_in3 = hadc1.Instance->JDR3;
IA_Offset += adc1_in1;//10次累计再做平均,实习滤波,算出电流0点偏移量
IB_Offset += adc1_in2;
IC_Offset += adc1_in3;
if(cnt >= 10)
{
ADC_offset = 1;
IA_Offset = IA_Offset/10;
IB_Offset = IB_Offset/10;
IC_Offset = IC_Offset/10;
}
}
else
{
adc1_in1 = hadc1.Instance->JDR1 ;
adc1_in2 = hadc1.Instance->JDR2 ;
adc1_in3 = hadc1.Instance->JDR3 ;
rtU.ia = (adc1_in1 - IA_Offset)*0.00149025f;
rtU.ib = (adc1_in2 - IB_Offset)*0.00149025f;
rtU.ic = (adc1_in3 - IC_Offset)*0.00149025f;
//编码器读取ABZ
Enc_cnt = __HAL_TIM_GET_COUNTER(&htim3) ;
m_Theta = (Enc_cnt + amend_Theta)*2*PI/16384;
while(m_Theta >= 2*PI){m_Theta -= 2*PI;}
while(m_Theta < 0){m_Theta += 2*PI;}//角度归一化
//转速计算
m_speed = (m_Theta - m_Theta_delay)/0.0001;
m_Theta_delay = m_Theta;
//电角度、机械角度计算
e_Theta = m_Theta *pole_pairs;
while(e_Theta >= 2*PI){e_Theta -= 2*PI;}
while(e_Theta < 0){e_Theta += 2*PI;}//角度归一化
// 电角度0对齐
if(prev_state == 2 && state == 3) {
__HAL_TIM_SET_COUNTER(&htim3, 0);
e_Theta = 0;
}
prev_state = state;
//位置计算
m_positionfd = Position_Cal(m_prevTheta, m_Theta);
m_prevTheta = m_Theta;
//赋值给Simulink模型
rtU.FOC_state = 1;
rtU.PositionRef = 0;
rtU.PositionFd = m_positionfd;
rtU.theta = e_Theta;
rtU.torque_ref = 1;
FOC_Model_step();
if(state == 2){
TIM1->CCR1 = 0;
TIM1->CCR2 = 30;
TIM1->CCR3 = 100;
}
else{
TIM1->CCR1 = rtY.tABC[0];
TIM1->CCR2 = rtY.tABC[1];
TIM1->CCR3 = rtY.tABC[2];
}
// TIM1->CCR1 = rtY.tABC[0];
// TIM1->CCR2 = rtY.tABC[1];
// TIM1->CCR3 = rtY.tABC[2];
load_data[0] = rtU.ia;
load_data[1] = adc1_in1;
load_data[2] =IA_Offset;
load_data[3] = state;
load_data[4] = e_Theta;
memcpy(tempData, (uint8_t *)&load_data, sizeof(load_data));
HAL_UART_Transmit_DMA(&huart2,(uint8_t *)tempData,6*4);
}
}
/* NOTE : This function should not be modified. When the callback is needed,
function HAL_ADCEx_InjectedConvCpltCallback must be implemented in the user file.
*/
}
/**************************** 4.ADC+3.ABZ编码器+5.高级定时器+2.串口****************************/
结果:分别给三相桥0.5、0.375、0.625的占空比,计算三相电流(已重构为FOC使用的数据)

本章内容十分复杂,大家可以结合b站的欧拉电子和正点原子hal库视频理解
内容较多,难免出错,如有错误,感谢指正
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)