8. 无刷直流电机

您所在的位置:网站首页 自己做无刷电机视频教程大全 8. 无刷直流电机

8. 无刷直流电机

2024-07-17 18:01| 来源: 网络整理| 查看: 265

8.4.3.1. 编程要点¶

高级定时器 IO 配置

定时器时基结构体TIM_HandleTypeDef配置

定时器输出比较结构体TIM_OC_InitTypeDef配置

根据电机的换相表编写换相中断回调函数

根据定时器定义电机控制相关函数

bsp_motor_tim.h-宏定义¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88/* 电机控制定时器 */ #define MOTOR_TIM TIM8 #define MOTOR_TIM_CLK_ENABLE() __TIM8_CLK_ENABLE() extern TIM_HandleTypeDef htimx_bldcm; /* 累计 TIM_Period个后产生一个更新或者中断 当定时器从0计数到5599,即为5600次,为一个定时周期 */ #define PWM_PERIOD_COUNT (5600) #define PWM_MAX_PERIOD_COUNT (PWM_PERIOD_COUNT - 100) /* 高级控制定时器时钟源TIMxCLK = HCLK = 168MHz 设定定时器频率为=TIMxCLK/(PWM_PRESCALER_COUNT+1)/PWM_PERIOD_COUNT = 15KHz*/ #define PWM_PRESCALER_COUNT (2) /* TIM8通道1输出引脚 */ #define MOTOR_OCPWM1_PIN GPIO_PIN_5 #define MOTOR_OCPWM1_GPIO_PORT GPIOI #define MOTOR_OCPWM1_GPIO_CLK_ENABLE() __GPIOI_CLK_ENABLE() #define MOTOR_OCPWM1_AF GPIO_AF3_TIM8 /* TIM8通道2输出引脚 */ #define MOTOR_OCPWM2_PIN GPIO_PIN_6 #define MOTOR_OCPWM2_GPIO_PORT GPIOI #define MOTOR_OCPWM2_GPIO_CLK_ENABLE() __GPIOI_CLK_ENABLE() #define MOTOR_OCPWM2_AF GPIO_AF3_TIM8 /* TIM8通道3输出引脚 */ #define MOTOR_OCPWM3_PIN GPIO_PIN_7 #define MOTOR_OCPWM3_GPIO_PORT GPIOI #define MOTOR_OCPWM3_GPIO_CLK_ENABLE() __GPIOI_CLK_ENABLE() #define MOTOR_OCPWM3_AF GPIO_AF3_TIM8 /* TIM8通道1互补输出引脚 */ #define MOTOR_OCNPWM1_PIN GPIO_PIN_13 #define MOTOR_OCNPWM1_GPIO_PORT GPIOH #define MOTOR_OCNPWM1_GPIO_CLK_ENABLE() __GPIOH_CLK_ENABLE() #define MOTOR_OCNPWM1_AF GPIO_AF3_TIM8 /* TIM8通道2互补输出引脚 */ #define MOTOR_OCNPWM2_PIN GPIO_PIN_14 #define MOTOR_OCNPWM2_GPIO_PORT GPIOH #define MOTOR_OCNPWM2_GPIO_CLK_ENABLE() __GPIOH_CLK_ENABLE() #define MOTOR_OCNPWM2_AF GPIO_AF3_TIM8 /* TIM8通道3互补输出引脚 */ #define MOTOR_OCNPWM3_PIN GPIO_PIN_15 #define MOTOR_OCNPWM3_GPIO_PORT GPIOH #define MOTOR_OCNPWM3_GPIO_CLK_ENABLE() __GPIOH_CLK_ENABLE() #define MOTOR_OCNPWM3_AF GPIO_AF3_TIM8 #define TIM_COM_TS_ITRx TIM_TS_ITR3 // 内部触发配置(TIM8->ITR3->TIM5) /* 霍尔传感器定时器 */ #define HALL_TIM TIM5 #define HALL_TIM_CLK_ENABLE() __TIM5_CLK_ENABLE() extern TIM_HandleTypeDef htimx_hall; /* 累计 TIM_Period个后产生一个更新或者中断 当定时器从0计数到4999,即为5000次,为一个定时周期 */ #define HALL_PERIOD_COUNT (0xFFFF) /* 高级控制定时器时钟源TIMxCLK = HCLK / 2 = 84MHz 设定定时器频率为 = TIMxCLK / (PWM_PRESCALER_COUNT + 1) / PWM_PERIOD_COUNT = 10.01Hz 周期 T = 100ms */ #define HALL_PRESCALER_COUNT (128) /* TIM5 通道 1 引脚 */ #define HALL_INPUTU_PIN GPIO_PIN_10 #define HALL_INPUTU_GPIO_PORT GPIOH #define HALL_INPUTU_GPIO_CLK_ENABLE() __GPIOH_CLK_ENABLE() #define HALL_INPUTU_AF GPIO_AF2_TIM5 /* TIM5 通道 2 引脚 */ #define HALL_INPUTV_PIN GPIO_PIN_11 #define HALL_INPUTV_GPIO_PORT GPIOH #define HALL_INPUTV_GPIO_CLK_ENABLE() __GPIOH_CLK_ENABLE() #define HALL_INPUTV_AF GPIO_AF2_TIM5 /* TIM5 通道 3 引脚 */ #define HALL_INPUTW_PIN GPIO_PIN_12 #define HALL_INPUTW_GPIO_PORT GPIOH #define HALL_INPUTW_GPIO_CLK_ENABLE() __GPIOH_CLK_ENABLE() #define HALL_INPUTW_AF GPIO_AF2_TIM5 #define HALL_TIM_IRQn TIM5_IRQn #define HALL_TIM_IRQHandler TIM5_IRQHandler

使用宏定义非常方便程序升级、移植。如果使用不同的定时器IO,修改这些宏即可。

定时器复用功能引脚初始化

定时器复用功能引脚初始化¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43static void TIMx_GPIO_Config(void) { /*定义一个GPIO_InitTypeDef类型的结构体*/ GPIO_InitTypeDef GPIO_InitStructure; /*开启定时器相关的GPIO外设时钟*/ MOTOR_OCPWM1_GPIO_CLK_ENABLE(); MOTOR_OCNPWM1_GPIO_CLK_ENABLE(); MOTOR_OCPWM2_GPIO_CLK_ENABLE(); MOTOR_OCNPWM2_GPIO_CLK_ENABLE(); MOTOR_OCPWM3_GPIO_CLK_ENABLE(); MOTOR_OCNPWM3_GPIO_CLK_ENABLE(); /* 定时器功能引脚初始化 */ GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出模式 GPIO_InitStructure.Pin = MOTOR_OCNPWM1_PIN; HAL_GPIO_Init(MOTOR_OCNPWM1_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.Pin = MOTOR_OCNPWM2_PIN; HAL_GPIO_Init(MOTOR_OCNPWM2_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.Pin = MOTOR_OCNPWM3_PIN; HAL_GPIO_Init(MOTOR_OCNPWM3_GPIO_PORT, &GPIO_InitStructure); /* 通道 2 */ GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; GPIO_InitStructure.Pin = MOTOR_OCPWM1_PIN; GPIO_InitStructure.Alternate = MOTOR_OCPWM1_AF; HAL_GPIO_Init(MOTOR_OCPWM1_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.Pin = MOTOR_OCPWM2_PIN; GPIO_InitStructure.Alternate = MOTOR_OCPWM2_AF; HAL_GPIO_Init(MOTOR_OCPWM2_GPIO_PORT, &GPIO_InitStructure); /* 通道 3 */ GPIO_InitStructure.Pin = MOTOR_OCPWM3_PIN; GPIO_InitStructure.Alternate = MOTOR_OCPWM3_AF; HAL_GPIO_Init(MOTOR_OCPWM3_GPIO_PORT, &GPIO_InitStructure); }

定时器通道引脚使用之前必须设定相关参数,这选择复用功能,并指定到对应的定时器。 使用GPIO之前都必须开启相应端口时钟。在上面我们将TIM1的CH1、CH2和CH3配置为PWM模式, 我对其对应的互补输出通道配置为推挽输出模式,所以在三相六臂驱动电路中,对于下桥臂是始终开启的, 即这里我们使用的是H_PWM-L_ON调制方式。

电机控制定时器模式配置¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46static void TIM_Mode_Config(void) { // 开启TIMx_CLK,x[1,8] MOTOR_TIM_CLK_ENABLE(); /* 定义定时器的句柄即确定定时器寄存器的基地址*/ htimx_bldcm.Instance = MOTOR_TIM; /* 累计 TIM_Period个后产生一个更新或者中断*/ //当定时器从0计数到999,即为1000次,为一个定时周期 htimx_bldcm.Init.Period = PWM_PERIOD_COUNT - 1; // 高级控制定时器时钟源TIMxCLK = HCLK=216MHz // 设定定时器频率为=TIMxCLK/(TIM_Prescaler+1)=1MHz htimx_bldcm.Init.Prescaler = PWM_PRESCALER_COUNT - 1; // 采样时钟分频 htimx_bldcm.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; // 计数方式 htimx_bldcm.Init.CounterMode=TIM_COUNTERMODE_UP; // 重复计数器 htimx_bldcm.Init.RepetitionCounter=0; // 初始化定时器TIMx, x[1,8] HAL_TIM_PWM_Init(&htimx_bldcm); /*PWM模式配置*/ //配置为PWM模式1 TIM_OCInitStructure.OCMode = TIM_OCMODE_PWM1; TIM_OCInitStructure.Pulse = 0; // 默认必须要初始为0 TIM_OCInitStructure.OCPolarity = TIM_OCPOLARITY_HIGH; TIM_OCInitStructure.OCNPolarity = TIM_OCNPOLARITY_HIGH; TIM_OCInitStructure.OCIdleState = TIM_OCIDLESTATE_SET; TIM_OCInitStructure.OCNIdleState = TIM_OCNIDLESTATE_RESET; HAL_TIM_PWM_ConfigChannel(&htimx_bldcm,&TIM_OCInitStructure,TIM_CHANNEL_1); // 初始化通道 1 输出 PWM HAL_TIM_PWM_ConfigChannel(&htimx_bldcm,&TIM_OCInitStructure,TIM_CHANNEL_2); // 初始化通道 2 输出 PWM HAL_TIM_PWM_ConfigChannel(&htimx_bldcm,&TIM_OCInitStructure,TIM_CHANNEL_3); // 初始化通道 3 输出 PWM /* 配置触发源 */ HAL_TIMEx_ConfigCommutationEvent(&htimx_bldcm, TIM_COM_TS_ITRx, TIM_COMMUTATION_SOFTWARE); /* 开启定时器通道1输出PWM */ HAL_TIM_PWM_Start(&htimx_bldcm,TIM_CHANNEL_1); /* 开启定时器通道2输出PWM */ HAL_TIM_PWM_Start(&htimx_bldcm,TIM_CHANNEL_2); /* 开启定时器通道3输出PWM */ HAL_TIM_PWM_Start(&htimx_bldcm,TIM_CHANNEL_3); }

首先定义两个定时器初始化结构体,定时器模式配置函数主要就是对这两个结构体的成员进行初始化,然后通过相 应的初始化函数把这些参数写入定时器的寄存器中。有关结构体的成员介绍请参考定时器详解章节。

不同的定时器可能对应不同的APB总线,在使能定时器时钟是必须特别注意。高级控制定时器属于APB2, 定时器内部时钟是168MHz。

在时基结构体中我们设置定时器周期参数为PWM_PERIOD_COUNT(5600)-1,时钟预分频器设置为 PWM_PRESCALER_COUNT(2) - 1,频率为:168MHz/PWM_PERIOD_COUNT/PWM_PRESCALER_COUNT=15KHz, 使用向上计数方式。

在输出比较结构体中,设置输出模式为PWM1模式,通道输出高电平有效,设置脉宽为0。

触发源配置为软件触发。

最后使用HAL_TIM_PWM_Start函数开启计数器,使能PWM输出。

霍尔传感器定时器模式配置¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23static void hall_tim_init(void) { TIM_HallSensor_InitTypeDef hall_sensor_onfig; /* 基本定时器外设时钟使能 */ HALL_TIM_CLK_ENABLE(); /* 定时器基本功能配置 */ htimx_hall.Instance = HALL_TIM; htimx_hall.Init.Prescaler = HALL_PRESCALER_COUNT - 1; // 预分频 htimx_hall.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数 htimx_hall.Init.Period = HALL_PERIOD_COUNT - 1; // 计数周期 htimx_hall.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 时钟分频 hall_sensor_onfig.IC1Prescaler = TIM_ICPSC_DIV1; // 输入捕获分频 hall_sensor_onfig.IC1Polarity = TIM_ICPOLARITY_BOTHEDGE; // 输入捕获极性 hall_sensor_onfig.IC1Filter = 10; // 输入滤波 hall_sensor_onfig.Commutation_Delay = 0U; // 不使用延迟触发 HAL_TIMEx_HallSensor_Init(&htimx_hall,&hall_sensor_onfig); HAL_NVIC_SetPriority(HALL_TIM_IRQn, 0, 0); // 设置中断优先级 HAL_NVIC_EnableIRQ(HALL_TIM_IRQn); // 使能中断 }

关于霍尔传感器引脚的初始化代码这里不在讲解,具体代码请参考配套工程代码。 高级控制定时器属于APB1,定时器内部时钟是84MHz。 在时基结构体中我们设置定时器周期参数为PWM_PERIOD_COUNT(0xFFFF)-1,时钟预分频器设置为 PWM_PRESCALER_COUNT(128) - 1,频率为:84MHz/PWM_PERIOD_COUNT/PWM_PRESCALER_COUNT≈10Hz, ,计数器的溢出周期为100毫秒,这个时间要设置到电机正常旋转时足够一路霍尔传感器产生变化, 这样能方便后续速度控制时的计时功能,使用向上计数方式。因为任何一相霍尔传感器发生变化都需要换相, 所以输入捕获极性设置为双边沿触发。借助 TIMx_CR2 寄存器中的 TI1S 位, 可将通道1的输入滤波器连接到异或门的输出,从而将CH1、CH2和CH3这三个输入引脚组合在一起,如下图所示。 因此霍尔传感器必须使用定时器的CH1、CH2和CH3这3个通道,这样只要任意一相霍尔传感器状态发生变化都可以触发中断进行换相。 配置定时器的中断优先级,并使能全局定时器中断。

霍尔传感器使能¶ 1 2 3 4 5 6 7 8 9 10 11 12void hall_enable(void) { /* 使能霍尔传感器接口 */ __HAL_TIM_ENABLE_IT(&htimx_hall, TIM_IT_TRIGGER); __HAL_TIM_ENABLE_IT(&htimx_hall, TIM_IT_UPDATE); HAL_TIMEx_HallSensor_Start(&htimx_hall); LED1_OFF; HAL_TIM_TriggerCallback(&htimx_hall); // 执行一次换相 }

开启触发中断,开启更新中断,启动霍尔传感器,关闭LED1,LED1将用于电机堵转超时的指示灯, 所以在开启电机前好确保该指示灯是灭的。最后执行了一次换相,在HAL_TIM_TriggerCallback这个函数里面执行一次换相, 这是因为需要根据当前霍尔传感器的位置让电机旋转到下一个位置,同时时霍尔传感器状态也发生了变化, 这时才会到HAL_TIM_TriggerCallback中断回调函数里面执行换相,否则电机将有可能不能正常启动。

霍尔传感器触发换相¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim) { /* 获取霍尔传感器引脚状态,作为换相的依据 */ uint8_t step = 0; step = get_hall_state(); if(get_bldcm_direction() == MOTOR_FWD) { switch(step) { case 1: /* U+ W- */ __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_2, 0); // 通道 2 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM2_GPIO_PORT, MOTOR_OCNPWM2_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_3, 0); // 通道 1 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM1_GPIO_PORT, MOTOR_OCNPWM1_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_1, bldcm_pulse); // 通道 1 配置的占空比 HAL_GPIO_WritePin(MOTOR_OCNPWM3_GPIO_PORT, MOTOR_OCNPWM3_PIN, GPIO_PIN_SET); // 开启下桥臂 break; case 2: /* V+ U- */ __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_3, 0); // 通道 3 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM3_GPIO_PORT, MOTOR_OCNPWM3_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_1, 0); // 通道 1 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM2_GPIO_PORT, MOTOR_OCNPWM2_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_2, bldcm_pulse); // 通道 2 配置的占空比 HAL_GPIO_WritePin(MOTOR_OCNPWM1_GPIO_PORT, MOTOR_OCNPWM1_PIN, GPIO_PIN_SET); // 开启下桥臂 break; case 3: /* V+ W- */ __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_1, 0); // 通道 1 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM1_GPIO_PORT, MOTOR_OCNPWM1_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_3, 0); // 通道 1 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM2_GPIO_PORT, MOTOR_OCNPWM2_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_2, bldcm_pulse); // 通道 2 配置的占空比 HAL_GPIO_WritePin(MOTOR_OCNPWM3_GPIO_PORT, MOTOR_OCNPWM3_PIN, GPIO_PIN_SET); // 开启下桥臂 break; case 4: /* W+ V- */ __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_1, 0); // 通道 1 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM1_GPIO_PORT, MOTOR_OCNPWM1_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_2, 0); // 通道 1 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM3_GPIO_PORT, MOTOR_OCNPWM3_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_3, bldcm_pulse); // 通道 3 配置的占空比 HAL_GPIO_WritePin(MOTOR_OCNPWM2_GPIO_PORT, MOTOR_OCNPWM2_PIN, GPIO_PIN_SET); // 开启下桥臂 break; case 5: /* U+ V -*/ __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_3, 0); // 通道 3 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM3_GPIO_PORT, MOTOR_OCNPWM3_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_2, 0); // 通道 1 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM1_GPIO_PORT, MOTOR_OCNPWM1_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_1, bldcm_pulse); // 通道 1 配置的占空比 HAL_GPIO_WritePin(MOTOR_OCNPWM2_GPIO_PORT, MOTOR_OCNPWM2_PIN, GPIO_PIN_SET); // 开启下桥臂 break; case 6: /* W+ U- */ __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_2, 0); // 通道 2 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM2_GPIO_PORT, MOTOR_OCNPWM2_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_1, 0); // 通道 1 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM3_GPIO_PORT, MOTOR_OCNPWM3_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_3, bldcm_pulse); // 通道 3 配置的占空比 HAL_GPIO_WritePin(MOTOR_OCNPWM1_GPIO_PORT, MOTOR_OCNPWM1_PIN, GPIO_PIN_SET); // 开启下桥臂 break; } } else { switch(step) { case 1: /* W+ U- */ __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_2, 0); // 通道 2 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM2_GPIO_PORT, MOTOR_OCNPWM2_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_1, 0); // 通道 1 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM3_GPIO_PORT, MOTOR_OCNPWM3_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_3, bldcm_pulse); // 通道 3 配置的占空比 HAL_GPIO_WritePin(MOTOR_OCNPWM1_GPIO_PORT, MOTOR_OCNPWM1_PIN, GPIO_PIN_SET); // 开启下桥臂 break; case 2: /* U+ V -*/ __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_3, 0); // 通道 3 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM3_GPIO_PORT, MOTOR_OCNPWM3_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_2, 0); // 通道 1 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM1_GPIO_PORT, MOTOR_OCNPWM1_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_1, bldcm_pulse); // 通道 1 配置的占空比 HAL_GPIO_WritePin(MOTOR_OCNPWM2_GPIO_PORT, MOTOR_OCNPWM2_PIN, GPIO_PIN_SET); // 开启下桥臂 break; case 3: /* W+ V- */ __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_1, 0); // 通道 1 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM1_GPIO_PORT, MOTOR_OCNPWM1_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_2, 0); // 通道 1 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM3_GPIO_PORT, MOTOR_OCNPWM3_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_3, bldcm_pulse); // 通道 3 配置的占空比 HAL_GPIO_WritePin(MOTOR_OCNPWM2_GPIO_PORT, MOTOR_OCNPWM2_PIN, GPIO_PIN_SET); // 开启下桥臂 break; case 4: /* V+ W- */ __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_1, 0); // 通道 1 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM1_GPIO_PORT, MOTOR_OCNPWM1_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_3, 0); // 通道 1 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM2_GPIO_PORT, MOTOR_OCNPWM2_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_2, bldcm_pulse); // 通道 2 配置的占空比 HAL_GPIO_WritePin(MOTOR_OCNPWM3_GPIO_PORT, MOTOR_OCNPWM3_PIN, GPIO_PIN_SET); // 开启下桥臂 break; case 5: /* V+ U- */ __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_3, 0); // 通道 3 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM3_GPIO_PORT, MOTOR_OCNPWM3_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_1, 0); // 通道 1 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM2_GPIO_PORT, MOTOR_OCNPWM2_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_2, bldcm_pulse); // 通道 2 配置的占空比 HAL_GPIO_WritePin(MOTOR_OCNPWM1_GPIO_PORT, MOTOR_OCNPWM1_PIN, GPIO_PIN_SET); // 开启下桥臂 break; case 6: /* U+ W- */ __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_2, 0); // 通道 2 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM2_GPIO_PORT, MOTOR_OCNPWM2_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_3, 0); // 通道 1 配置为 0 HAL_GPIO_WritePin(MOTOR_OCNPWM1_GPIO_PORT, MOTOR_OCNPWM1_PIN, GPIO_PIN_RESET); // 关闭下桥臂 __HAL_TIM_SET_COMPARE(&htimx_bldcm, TIM_CHANNEL_1, bldcm_pulse); // 通道 1 配置的占空比 HAL_GPIO_WritePin(MOTOR_OCNPWM3_GPIO_PORT, MOTOR_OCNPWM3_PIN, GPIO_PIN_SET); // 开启下桥臂 break; } } }

获取霍尔传感器引脚状态,根据厂家给出的真值表进行换相。将上桥臂采用PWM输出,下桥臂直接输出高电平。 即为H_PWM-L_ON模式。将变量update设置为0,最好生成COM事件触发换相事件,将配置写入。

霍尔传感器更新回调¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (update++ > 1) // 有一次在产生更新中断前霍尔传感器没有捕获到值 { printf("堵转超时\r\n"); update = 0; LED1_ON; // 点亮LED1表示堵转超时停止 /* 堵转超时停止 PWM 输出 */ hall_disable(); // 禁用霍尔传感器接口 stop_pwm_output(); // 停止 PWM 输出 } }

因为霍尔传感器没变化一次都会进HAL_TIM_TriggerCallback函数将update设置为0,并且会产生更新中断进入 HAL_TIM_PeriodElapsedCallback函数将update加一,那么如果update大于1就说明没有进入HAL_TIM_TriggerCallback 函数,直接进入HAL_TIM_PeriodElapsedCallback函数,这就说明电机是堵转了,并且已经至少堵转了100毫秒, 这里我们认为堵转超时停止PWM的输出和禁用霍尔传感器。

main函数¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58int main(void) { __IO uint16_t ChannelPulse = PWM_MAX_PERIOD_COUNT/10; uint8_t i = 0; /* 此处省略其他初始化函数 */ /* 电机初始化 */ bldcm_init(); while(1) { /* 扫描KEY1 */ if( Key_Scan(KEY1_GPIO_PORT, KEY1_PIN) == KEY_ON) { /* 使能电机 */ set_bldcm_speed(ChannelPulse); set_bldcm_enable(); } /* 扫描KEY2 */ if( Key_Scan(KEY2_GPIO_PORT, KEY2_PIN) == KEY_ON) { /* 停止电机 */ set_bldcm_disable(); } /* 扫描KEY3 */ if( Key_Scan(KEY3_GPIO_PORT, KEY3_PIN) == KEY_ON) { /* 增大占空比 */ ChannelPulse += PWM_MAX_PERIOD_COUNT/10; if(ChannelPulse > PWM_MAX_PERIOD_COUNT) ChannelPulse = PWM_MAX_PERIOD_COUNT; set_bldcm_speed(ChannelPulse); } /* 扫描KEY4 */ if( Key_Scan(KEY4_GPIO_PORT, KEY4_PIN) == KEY_ON) { if(ChannelPulse


【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3