飞书文档https://x509p6c8to.feishu.cn/wiki/InUfwEeJNimqctkyW1mcImianLh
一、步进电机与直流电机:
1-1、什么是直流电机?
直流电机是最常见的电机类型。直流电动机通常只有两个引线,一个正极和一个负极。直流电机的转速控制主要依靠改变输入电压的大小来实现,电压越高,电机转速越快。
1-2、什么是步进电机?
步进电机是一种将电脉冲信号转换成相应角位移的电机,每个脉冲使电机转动一个固定的角度(步进角),它可以实现更精准的位置控制。
1-3、直流电机与步进电机的对比:
直流电机:
优点:价格低、控制方便
缺点:精确的位置控制相对困难,除非采用额外的编码器反馈。
步进电机:
优点:低速扭矩大,控制更精准;
缺点:成本相对高,转速相对较低。
二、思考?为什么STM32芯片引脚不能直接接步进电机或直流电机?但可以直接接舵机?
这要从舵机的构造说起,控制芯片+电机组成,stm32实际接的是控制芯片引脚,而不是电机本身。
而步进电机和直流电机内部是没有控制芯片的,如果使用stm32直接接电机,因为stm32芯片引脚驱动能力弱而驱动不起甚至损坏芯片,stm32每个IO的最大电流为40mA,一般步进电机跑起来可能需要几百mA到几A。
驱动能力可以理解为引脚的可以输出的力气,如果力气过小,当然推不动电机运行。
三、如何提升驱动能力呢?
下图就是应用三极管的开关功能,使芯片IO的驱动能力提高。
上图可以简单理解为三极管开关电路,通过控制输入口的电平高低,就可以控制后端电路的开启关闭。
四、直流电机的控制?
4-1、控制转/停
4-2、控制转速
直流电机的速度可以通过改变其输入电压来控制,使用单片机控制转速可以通过PWM控制。
PWM是一种通过发送一系列ON-OFF脉冲来调整输入电压平均值的技术。该平均电压与脉冲的宽度成正比,称为占空比。
占空比越高,施加到直流电机的平均电压就越高,从而导致电机速度增加。占空比越短,施加到直流电机的平均电压越低,导致电机速度降低。
下图显示了具有各种占空比和平均电压的PWM技术。
4-3、控制方向
前面我们都只是控制电机往一个方向转动,如果需要更换方向,就需要重新接线,那如果需要自动控制电机的正反转呢?这就需要升级下电路。
下面电路被称为H桥,是因为它使用四个晶体管连接,使示意图看起来像一个“H”。
为了控制直流电机的旋转方向,无需互换引线,可以使用称为H桥的电路。H桥是可以双向驱动电机的电子电路。H桥用于许多不同的应用中。最常见的应用之一是控制机器人中的电机。
如果需要使用多个三极管,一个一个连接太麻烦了,有没有更好的方式呢?当然有,L293D、L298、和课程用的TC118S都是集成H桥的芯片。
直流驱动芯片TC118S
https://item.szlcsc.com/89487.html
应用电路图
原理图:
新建工程,设置PB14 PB15为GPIO输出
修改IO名称为DC_AN1、DC_AN2,这里PB14命名应该是DC_AN1,PB15应该是DC_AN2,不过这个命名错不影响控制效果,只影响电机旋转方向,大家留意下即可。
方向控制:
main.c
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//正转
HAL_GPIO_WritePin(GPIOB,DC_AN1_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,DC_AN2_Pin,GPIO_PIN_RESET);
HAL_Delay(5000);
//停止
HAL_GPIO_WritePin(GPIOB,DC_AN1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,DC_AN2_Pin,GPIO_PIN_RESET);
HAL_Delay(5000);
//反转
HAL_GPIO_WritePin(GPIOB,DC_AN1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,DC_AN2_Pin,GPIO_PIN_SET);
HAL_Delay(5000);
//停止
HAL_GPIO_WritePin(GPIOB,DC_AN1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,DC_AN2_Pin,GPIO_PIN_RESET);
HAL_Delay(5000);
}
/* USER CODE END 3 */
速度控制:
如果需要对直流电机进行速度控制,我们可以使用PWM,我们可以在STM32CUBEMX中看到PB15是支持绑定TIM1_CH3N这个通道的
TIM1_CH3N与TIM1_CH3为互补输出,例如黄色是TIM1_CH3,TIM1_CH3N则为蓝色部分
|
设置完成后,IO变为黄色 |
我们在左侧设置TIM1的CH3N为PWM模式即可
需要注意的是: |
最终代码
main.c
/* USER CODE BEGIN 2 */
uint16_t pwm_value = 0; //占空比
HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_3); //开启PWM输出
HAL_GPIO_WritePin(GPIOB,DC_AN2_Pin,GPIO_PIN_RESET); //设置DC_AN2为低,只保持一个方向转动
/* USER CODE END 2 */
while (1)
{
/* USER CODE BEGIN 3 */
while (pwm_value < 150){
pwm_value++;
//修改比较值,修改占空比,占空比为pwm_value/500
__HAL_TIM_SetCompare(&htim1, TIM_CHANNEL_3, pwm_value);
HAL_Delay(10);
}
HAL_Delay(1000);
while (pwm_value){
pwm_value--;
__HAL_TIM_SetCompare(&htim1, TIM_CHANNEL_3, pwm_value);
HAL_Delay(10);
}
HAL_Delay(1000);
}
/* USER CODE END 3 */
参考工程:参考飞书文档
五、步进电机的控制?
右手法则
步进电机工作原理
步进电机的基本工作原理为:给一个或多个定子相位通电,线圈中通过的电流会产生磁场,而转子会与该磁场对齐;依次给不同的相位施加电压,转子将旋转特定的角度并最终到达需要的位置。
步进电机中间的转子是一个磁铁,周围线圈在通电时会形成磁场,然后把转子吸过来,如果周围线圈按照一定的顺序逐个通电断电时,转子就会被带动转起来。
电机类型
步进电机又分为单极性的步进电机和双极性的步进电机
其中左侧为单极性步进电机,右侧为双极性的步进电机。
单双极性是指一个步进电机里面有几种电流的流向 |
单级性电机驱动
下图是单极性步进电机整步旋转的过程,其中,在图示中分为5根线,分别为A、B、C、D和公共端(+),公共端需要一直通电, 剩下ABCD相中只要有一个相通电,即可形成回路产生磁场,图中的通电顺序为A->B->C->D,即可完成上图中的顺时针旋转, 如果想要逆时针旋转只需要将其倒序即可。
双极性的步进电机
下图是一个双极性的步进电机整步,步进顺序。 在第一步中:将A相通电,根据电磁铁原理,产生磁性,并且因异性相吸,所以磁场将转子固定在第一步的位置; 第二步:当A相关闭,B相通电时,转子会旋转90°; 第三步:B相关闭、A相通电,但极性与第1步相反,这促使转子再次旋转90°。 在第四步中:A相关闭、B相通电,极性与第2步相反。重复该顺序促使转子按90°的步距角顺时针旋转。
满步驱动:
单拍满步驱动 双拍满步驱动
半步驱动:
半步驱动的好处是提高分辨率,但是缺点是扭矩只有满步驱动的70%,当然,也可以通过优化线圈中电流大小,来提高半步驱动扭矩。
总结:
步距角:改变一次通电状态(或者说一个脉冲信号)电机转子对应转过的角度。θ=360°/(z*n),θ是步距角,z是转子齿数,n是工作拍数。
在非超载情况下,电机的转速和停止位置只取决于控制脉冲信号的频率和脉冲数;
脉冲数越多,转动角度越大;频率越高,转动速度越快(不能超过电机规定的最高频率)。
42步进电机
这里的42一般指电机的安装尺寸42mm*42mm,同理,还有28、35、57、60,一般来说尺寸和扭矩成正比
- 两相:2组线圈
- 步距角:每走一步的角度为1.8度
步进驱动芯片BDR6622T
https://item.szlcsc.com/769389.html
芯片框图
内部一个桥的框图:
控制:
半步模式:1-4步
满步模式:1-8步
有了上面的理论基础后
我们可以编写代码用全步或半步控制步进电机了,
接线说明
绿色A- |
参考代码如下
main.c
/* USER CODE BEGIN 0 */
void motor_run(uint8_t direction,uint8_t step){
if(direction == 0){
//正转
switch(step){
case 0:
HAL_GPIO_WritePin(AN1_GPIO_Port,AN1_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(BN1_GPIO_Port,BN1_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(AN2_GPIO_Port,AN2_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(BN2_GPIO_Port,BN2_Pin,GPIO_PIN_RESET);
break;
case 1:
HAL_GPIO_WritePin(AN1_GPIO_Port,AN1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(BN1_GPIO_Port,BN1_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(AN2_GPIO_Port,AN2_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(BN2_GPIO_Port,BN2_Pin,GPIO_PIN_RESET);
break;
case 2:
HAL_GPIO_WritePin(AN1_GPIO_Port,AN1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(BN1_GPIO_Port,BN1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(AN2_GPIO_Port,AN2_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(BN2_GPIO_Port,BN2_Pin,GPIO_PIN_SET);
break;
case 3:
HAL_GPIO_WritePin(AN1_GPIO_Port,AN1_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(BN1_GPIO_Port,BN1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(AN2_GPIO_Port,AN2_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(BN2_GPIO_Port,BN2_Pin,GPIO_PIN_SET);
break;
}
}else{
//反转
switch(step){
case 0:
HAL_GPIO_WritePin(AN1_GPIO_Port,AN1_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(BN1_GPIO_Port,BN1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(AN2_GPIO_Port,AN2_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(BN2_GPIO_Port,BN2_Pin,GPIO_PIN_SET);
break;
case 1:
HAL_GPIO_WritePin(AN1_GPIO_Port,AN1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(BN1_GPIO_Port,BN1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(AN2_GPIO_Port,AN2_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(BN2_GPIO_Port,BN2_Pin,GPIO_PIN_SET);
break;
case 2:
HAL_GPIO_WritePin(AN1_GPIO_Port,AN1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(BN1_GPIO_Port,BN1_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(AN2_GPIO_Port,AN2_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(BN2_GPIO_Port,BN2_Pin,GPIO_PIN_RESET);
break;
case 3:
HAL_GPIO_WritePin(AN1_GPIO_Port,AN1_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(BN1_GPIO_Port,BN1_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(AN2_GPIO_Port,AN2_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(BN2_GPIO_Port,BN2_Pin,GPIO_PIN_RESET);
break;
}
}
}
void runstep(){
uint8_t direction = 0;
int step = 500;
for(int i = 0;i < step ;i++){
motor_run(direction,i%4);
HAL_Delay(1);
}
HAL_GPIO_WritePin(AN1_GPIO_Port,AN1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(BN1_GPIO_Port,BN1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(AN2_GPIO_Port,AN2_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(BN2_GPIO_Port,BN2_Pin,GPIO_PIN_RESET);
}
/* USER CODE END 0 */
/* USER CODE BEGIN 2 */
runstep();
/* USER CODE END 2 */
//改变runstep()中的direction就是改变方向,改变step就是改变步数。
示例工程
参考飞书文档