C/C++教程

BLDC控制实验:方波、霍尔、开环、定速、正转

本文主要是介绍BLDC控制实验:方波、霍尔、开环、定速、正转,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

本文记录博主学习BLDC控制软件的过程。

文章目录

  • 1 概述
  • 2 软件架构及工具链
    • 2.1 软件架构
    • 2.2 工具链
  • 3 底层代码生成
    • 3.1 时钟配置
    • 3.2 按键输入配置
    • 3.3 串口通信配置
    • 3.4 霍尔信号外部中断配置
    • 3.5 MOS管导通开关配置
  • 4 接口及配置代码
    • 4.1 系统定时器重装载值
    • 4.2 按键输入接口函数
    • 4.3 重定向printf函数
    • 4.4 霍尔信号状态函数
    • 4.5 MOS管导通控制函数
    • 4.6 电机启停函数
  • 5 应用层模型及代码生成
    • 5.1 基于模型设计(MBD)方案
    • 5.2 低频任务子系统
    • 5.3 霍尔中断子系统
    • 5.4 代码生成及调用
  • 6 总结

1 概述

本文是博主第一次做BLDC控制实验,内容只是写代码让BLDC转起来,而暂时不考虑其他复杂的需求。

控制的方法是比较简单的六步换相法。利用电机内部的霍尔传感器,通过参考电机厂家给出的二二导通换相表,生成方波来控制电机。第一次实验为了简化需求,只考虑开环、定速、正转的情况:

  • 开环:不考虑速度反馈,直接给PWM让电机转起来;
  • 定速:不考虑速度调节,换相的时候给的PWM都是相同的值;
  • 正转:只参考换相表中正转的部分,不考虑反转;

所以,实验目标为,通过按下开发板上的Key1按键使BLDC低速运转,按下Key2按键使BLDC停止运转。

本实验需要BLDC六步换相的理论作为知识储备。

2 软件架构及工具链

2.1 软件架构

博主根据自己的工作习惯和经验,制订出实验的软件架构如下:
在这里插入图片描述
其中,各个板块的含义如下:

  • ASW:应用层软件,包含电机控制策略和算法;
  • BSW:底层软件,包含驱动Stm32的寄存器配置;
  • Interface:接口层软件,为底层和应用层之间的接口函数;
  • UI:调试开发板所用的代码;

2.2 工具链

对于架构中不同的板块,博主也根据经验选择合适的工具链进行开发。

  • Matlab/Simulink:基于模型开发的利器,非常适用于应用层软件开发。首先在Simulink中创建控制策略的模型,再用Embedded Coder组件生成C代码;
  • CubeMX:ST公司开发的用于配置STM32的工具,通过配置时钟和外设引脚,可以生成标准的HAL库,可用于BSW代码的生成;
  • MDK:STM32的编译环境,用于编译、调试软件并下载到控制器中,Interface的手写代码也在其中完成;
  • 串口调试助手:用于监测程序运行过程中的一些变量值;

3 底层代码生成

本章节会结合原理图,研究配置CubeMX生成底层代码。

3.1 时钟配置

博主用的开发板是STM32F405RGT6,在CubeMX中将时钟源设置为外部晶振。
在这里插入图片描述
时钟数配置如下图。
在这里插入图片描述
由于后续的低频任务会运行在系统定时器中断里,所以这里需要留意一下系统定时器的频率为168MHz,也就是1秒钟计数168000000次。

3.2 按键输入配置

在本实验中,开发板上的按键是用于告诉单片机启动或停止电机的请求。开发板上焊接了5个按键模块,如下图。本实验只需要用SW1和SW2两个。
在这里插入图片描述
以SW1为例,它的左端接地,右端连接到单片机的PC13引脚,如下图。
在这里插入图片描述
所以在CubeMX中配置PC13引脚的模式为输入模式,并配置为上拉。
在这里插入图片描述
这样的配置表示,PC13引脚接收到低电平时,按键SW1被按下,接收到高电平时,按键SW1没有被按下。SW2的按键引脚配置类似。

3.3 串口通信配置

串口通信可以将单片机运行过程中的全局变量发送到PC上,然后通过串口调试助手读取信息,是一种验证问题的常规方式。

从原理图可以看出,PB10和PB11引脚是串口3发送和接收的引脚。
在这里插入图片描述
首先将串口模式设置为Asynchronous,也就是异步通信。
在这里插入图片描述
然后是一些参数设置,包括波特率、字长度等。这里的设置将和PC上的串口调试助手相对应。
在这里插入图片描述
最后是NVIC中断优先级设置,这里暂时设置为如下图。
在这里插入图片描述

3.4 霍尔信号外部中断配置

六步换相法控制BLDC需要根据霍尔传感器信号输入来判断导通哪些MOS管,因此需要配置3个引脚来分别接收A相,B相,C相三个霍尔信号。
在这里插入图片描述
从原理图中可以看出,PB6,PB7,PB8这三个引脚分别对应着A相,B相,C相,所以接下来需要在CubeMX中配置这三个引脚。以PB6为例,在CubeMX中如下。
在这里插入图片描述
在这里插入图片描述
首先,GPIO_EXTI表示用于GPIO的外部中断。GPIO mode配置成了上升或下降沿触发的外部中断,也就是说,当电机转动导致了霍尔信号变化的时候,会触发外部中断。这一点很重要,因为在该中断回调函数里,会执行换相逻辑。

3.5 MOS管导通开关配置

STM32通过控制引脚输出PWM或GPIO电平,来导通MOS管,从而实现了BLDC的换相控制。由于采用了H PWM-L ON的控制方式,上桥由PWM驱动,下桥由高低电平驱动。

以A相为例,原理图如下。左边的TIM1_CH是PWM,TIM1_CHN是高低电平。
在这里插入图片描述
然后顺藤摸瓜找到对应的引脚,TIM1_CH对应PA8,TIM1_CHN对应PB13。
在这里插入图片描述
接着就可以在CubeMX分别配置PWM输出和GPIO输出。
在这里插入图片描述
这里博主将上桥PWM配置为Up向上计数,重装载值为12000。也就是说后面进行输出比较的时候,范围是0~12000。
在这里插入图片描述
下桥的GPIO配置为推挽输出,初始为低电平。

以上配置完成后,就可以生成Keil工程了。

4 接口及配置代码

本章节会在Keil中手写一些代码,作为两方面用处。一方面是为应用层软件配置好输入输出接口函数,另一方面是调用Hal库函数对底层进一步配置。

4.1 系统定时器重装载值

在main文件的初始化代码段加上如下函数:

HAL_SYSTICK_Config(168000U);

该函数用于配置系统定时器重装载值为168000。结合前文将系统时钟配置为168MHz,重装载值配置为168000就意味着通过系统定时器产生1ms中断。在中断函数SysTick_Handler中将执行低频任务。

4.2 按键输入接口函数

在main文件中配置如下按键输入接口函数,调用该函数可以返回按键状态(1或0)。

// Get Key State
uint8_t Get_Key1State(void)
{
	return((uint8_t)(!HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13)));
}

uint8_t Get_Key2State(void)
{
	return((uint8_t)(!HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_0)));
}

博主习惯于将输入的接口函数以Get_开头,其实相当于封装了一层统一的命名,并简化传参。这里的Get函数中调用了Hal库的读取GPIO pin脚的函数,并对返回值取反,使得返回1代表按键按下,0代表按键没有按下。

4.3 重定向printf函数

在main文件中重新定义fputc 函数:

int fputc(int ch, FILE *f)
{
	HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xFFFF);
	return (ch);
}

通过这种方式,就可以用printf函数将全局变量打印到PC上。本文的实验比较简单,没有做UI上位机,就用串口调试助手查看电机运行的实时数据了。

4.4 霍尔信号状态函数

在main文件中配置霍尔信号状态接收函数,调用该函数可以返回霍尔传感器状态(1或0)。

// Get Hall State
uint8_t Get_HallAState(void)
{
	return HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6);
}

uint8_t Get_HallBState(void)
{
	return HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7);
}

uint8_t Get_HallCState(void)
{
	return HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8);
}

应用层调用霍尔信号状态函数可以获取当前的A,B,C三相的霍尔传感器状态,然后查阅换相表得到导通的MOS管。

4.5 MOS管导通控制函数

在main文件中配置MOS管导通控制函数,调用该函数可以设置MOS管的开关或者PWM。

// Mos
void Set_T1PWM(uint32_t PWMValue)
{
	__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,PWMValue);
}

void Set_T3PWM(uint32_t PWMValue)
{
	__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_2,PWMValue);
}

void Set_T5PWM(uint32_t PWMValue)
{
	__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_3,PWMValue);
}

void Set_T2Status(uint8_t State)
{
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13,(GPIO_PinState)State);
}

void Set_T4Status(uint8_t State)
{
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14,(GPIO_PinState)State);
}

void Set_T6Status(uint8_t State)
{
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15,(GPIO_PinState)State);
}

其中,T1,T3,T5是上桥,在CubeMX配置为定时器PWM,因此传入的是输出比较值;T2,T4,T6是下桥,配置为GPIO输出,因此传入0或1的状态,来控制导通与断开。这里传入的PWMValue是0~12000,因为CubeMX中配置重装载值为12000。

4.6 电机启停函数

在main文件中配置电机启停函数,调用该函数可以启动或停止定时器通道,从而达到启停电机的效果。

// Set_StartStopMotor
void Set_StartStopMotor(uint8_t State)
{
	if(State == 0) //Stop Motor
	{
		HAL_TIM_PWM_Stop(&htim1,TIM_CHANNEL_1);
		HAL_TIM_PWM_Stop(&htim1,TIM_CHANNEL_2);
		HAL_TIM_PWM_Stop(&htim1,TIM_CHANNEL_3);
	}
	else
	{
		HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
		HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2);
		HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3);
	}
	
}

Set函数会根据传入的State参数来判断调用Stop或是Start的Hal库函数。

5 应用层模型及代码生成

本实验的电机控制应用层软件采用Simulink建模并生成代码。

5.1 基于模型设计(MBD)方案

Matlab/Simulink软件的灵活性很强,可以定制化生成各式各样的代码。博主按照自己的建模习惯,制定了本小节的MBD方案,但不是Matlab/Simulink的唯一用法。

首先,将所有控制策略做在一个模型文件和数据字典中,命名为MotorControl,如下图所示。
在这里插入图片描述
数据字典中定义了枚举量、Signal对象等,并根据需要设定Storage Class和头文件。
在这里插入图片描述
模型的顶层调用了两个function-call子系统,分别对应系统定时器中断中运行的低频任务,和霍尔传感器外部中断中运行的换相任务。在代码生成的时候会生成SystickTask和HallExitTask两个函数。
在这里插入图片描述
下面博主会叙述自己设计的BLDC控制策略,如有不当之处,希望能够交流探讨。

5.2 低频任务子系统

本实验中的低频任务只做两件事,电机状态机建模、启动停止控制。输入为按键状态、霍尔中断标志位、霍尔传感器状态,输出为电机状态。

1)首先是按键输入监测,调用了Get_Key1State()接口函数,并通过延时两个周期判断产生了上升沿。
在这里插入图片描述
这部分做了两个延时,也就是,第一个周期Key1State为0,然后连续两个周期为1的情况时,视为一次启动电机的请求(StartMotorReq置为1)。

2)电机状态机,Stateflow中共有4个状态:Init,Start,Run,Stop。
在这里插入图片描述
电机状态机的输入为启动或停止电机的请求。默认进入Init初始化状态,如果产生了启动电机请求(StartMotorReq)则跳转到Start状态。如果霍尔中断标志位(HallExtiFlag)激活为1,则进入Run状态。当产生了停止电机请求(StopMotorReq),无论当前为Start状态还是Run状态都会跳入Stop状态。

每个状态进入时,都会输出MotorState,作为状态机外面的逻辑判断的依据。

3)电机启动的时候还未进入霍尔传感器引起的中断,在该状态中也需要进行启动时的换相函数。首先通过Get_HallXState函数获取三个霍尔传感器的状态,再通过移位进行组装合成。
在这里插入图片描述
A相左移2位,B相左移1位,C相不移位。例如A,B,C三相分别是1,0,1时,

HallState = (A << 2) + (B << 1) + C = 4 + 0 + 1 = 5

后面的模型会通过HallState 来判断哪些MOS管需要导通。
在这里插入图片描述
Switch的上下两路输入都用子系统,把6个Mos管的参数打包成一个Bus信号,子系统内容如下。
在这里插入图片描述
PWMValue的值在数据字典中定义为2000。这是因为本实验做开环定速旋转,设的过高或引起启动时的抖动。

模型中做了一连串的Switch模块,这里只截取了一部分。最后会调用Set函数来启动定时器,以及导通MOS管。
在这里插入图片描述

5.3 霍尔中断子系统

霍尔中断子系统中的模型中没有电机状态机的部分,其余的和5.2 低频任务子系统相似。但是有一点区别在于该子系统需要输出HallExtiFlag,也就是霍尔激活标志位,用于给低频任务子系统的状态机做跳转的判断。
在这里插入图片描述

5.4 代码生成及调用

将模型MotorControl.slx配置好Embedded Coder后,Ctrl + B生成代码。
在这里插入图片描述
顶层的两个子系统分别生成了HallExtiTask.c和SystickTask.c两个c文件,并且其中包含了同名的函数。这两个函数就是上文两个子系统对应的代码。
在这里插入图片描述
MotorControl.c中生成了一个初始化函数MotorControl_initialize(),用于将模型中定义的全局变量初始化为0。

将所有的C文件和头文件拷贝到Keil工程中,然后在三个地方分别调用。
1)在main函数中调用初始化函数MotorControl_initialize();
在这里插入图片描述
2)在系统定时器中断函数中调用SystickTask();
在这里插入图片描述
3)在霍尔传感器中断回调函数中调用HallExtiTask();
在这里插入图片描述
另外,调用函数需要加上对应的头文件,否则编译无法通过。

最后在Keil中编译软件,并通过ST-Link下载到单片机中。尝试按下按键1和按键2,验证是否可以启动和停止。

6 总结

博主第一次做电机控制实验,感觉还是很有意思的。后面会按照本文的方法论去继续研究BLDC的控制。

>>返回个人博客总目录

这篇关于BLDC控制实验:方波、霍尔、开环、定速、正转的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!