外设模块学习(3)——28BYJ-48步进减速电机
28BYJ-48 步进减速电机详解
一、概述
28BYJ-48 是一种常见的小型 永磁式单极步进电机,因为价格低廉、易于驱动、扭矩适中,经常作为入门学习电机控制和单片机实践的首选。它的型号含义是:
- 28:定子直径约 28mm;
- BYJ:表示永磁单极步进电机系列;
- 48:该系列中的具体型号编号,表示四拍和八拍都可以运行。
与普通直流电机不同,步进电机不是连续旋转的,而是每接收一个脉冲,按照设定的步距角“跳动”到下一个位置,因此非常适合需要精确控制角度和位置的场合。
二、关键概念
2.1 步距角
- 定义:电机转子每走一步时转过的角度。
- 28BYJ-48 电机的步距角为 5.625°。
2.2 步
- 指电机每响应一个控制脉冲时的最小转动单位。
- 步数多少,取决于电机本身的步距角和驱动方式。
2.3 拍
- 指绕组通电的方式。
- 常见模式有:
- 四拍整步驱动:每次点亮两个相邻绕组。电机本体每步转 11.25°。
- 八拍半步驱动:单相和双相交替通电。电机本体每步转 5.625°。
关系小结:
- 步距角决定了电机单步的角度;
- 拍决定了我们选择让电机每次走“大步”(整步)还是“小步”(半步);
- 步就是电机走出来的实际动作。
三、电机本体的步数
根据 28BYJ-48 的步距角:
- 整步驱动(四拍):每步 11.25° → 一圈 = 360 ÷ 11.25 = 32 步
- 半步驱动(八拍):每步 5.625° → 一圈 = 360 ÷ 5.625 = 64 步
因此,“电机本体一圈约 32 步”指的是采用 四拍整步驱动时的情况。如果改用八拍半步驱动,本体一圈就是 64 步。
四、减速齿轮组
28BYJ-48 并不是直接输出电机本体的轴,而是经过了一组 减速齿轮。
- 实际减速比 ≈ 1/63.68395(通常近似为 1/64)。
- 作用:降低转速、增加扭矩,使电机能驱动小型机械负载。
加上减速齿轮后,输出轴一圈所需的步数大幅增加:
-
整步驱动:
32×64≈2048 步/圈
-
半步驱动:
64×64≈4096 步/圈
五、驱动控制方式
28BYJ-48 一般通过 ULN2003 晶体管阵列驱动板连接到单片机(如 STM32),如下图所示。
控制方法就是让单片机的 4 个 IO 引脚按照一定的励磁顺序输出高低电平,从而依次给电机线圈通电。
- 四拍整步:控制简单,每步 11.25°(电机本体),输出轴约 2048 步/圈。
- 八拍半步:精度更高,每步 5.625°(电机本体),输出轴约 4076 步/圈。
在 STM32 程序中,只需要按照 励磁顺序表循环输出,就能让电机转动,并且通过控制步数来精确决定旋转角度。
六、控制原理
控制 28BYJ-28 就是控制它的 线圈通电顺序。常见的驱动方式有两种:
- 单相激励:一次只给一个线圈通电,省电但力矩小。
- 双相激励:同时给两个线圈通电,力矩大,转动更平稳。
- 半步模式:单相和双相交替,既保证力矩又能提高精度。
以半步模式为例,通电顺序如下(对应 IN1-IN4):
1 0 0 0
1 1 0 0
0 1 0 0
0 1 1 0
0 0 1 0
0 0 1 1
0 0 0 1
1 0 0 1
这 8 个状态循环一次,就是电机转动 8 步。
七、控制与 STM32 的结合
7.1 硬件连接
- 28BYJ-48 电机一般配套 ULN2003 晶体管驱动板使用。
- 电机的 5 根线接到驱动板,驱动板再接到 STM32 的 4 个 GPIO 引脚。
7.2 控制方式
- STM32 按照 励磁顺序表循环输出高低电平,驱动板放大电流,从而按步驱动电机。
- 选择整步还是半步模式,取决于励磁方式:
- 整步模式:每步走得大,输出轴约 2048 步一圈。
- 半步模式:每步走得细,输出轴约 4076 步一圈。
7.3 角度和圈数计算
- 需要电机转一整圈:输出 2048(整步)或 4096(半步)个脉冲;
- 需要电机转 90°:输出轴一圈步数 ÷ 4 → 512(整步)或 1024(半步)。
这样,你就可以精确地控制电机到达某个角度或转动指定圈数。
7.4 程序设计
- 定义一个数组存放步进电机的控制序列(如上面的 8 步)
- 依次循环输出序列到 GPIO
- 每输出一次延时一段时间,电机就转一步
- 通过改变延时长短,可以控制电机转速
- 通过控制循环次数,可以控制旋转角度
7.5 举例
- 如果需要电机正转一圈:
- 需要 4096 步
- 循环执行 4096 次控制序列即可
- 如果需要反转,则按逆序执行序列
八、基础案例——按键控制步进电机
8.1 项目概述
基于STM32F103C8T6微控制器,使用寄存器开发方式实现通过按键控制28BYJ-48步进电机的转动。
核心功能:
- 初始状态:电机停在0度位置
- 按键功能:每按一次,电机转动90度
- 循环逻辑:正转一周(0→90→180→270→360)后,自动反向,再反转一周(360→270→180→90→0),如此循环往复
8.2 硬件接线说明
外设模块 | 引脚连接 (STM32F103C8T6) | 接线细节 |
---|---|---|
ULN2003驱动板 | IN1 → PA0 IN2 → PA1 IN3 → PA2 IN4 → PA3 | 驱动板的4个控制信号输入端,连接到STM32的GPIO输出口 |
28BYJ-48电机 | 线圈A/B/A-/B- → ULN2003 OUT1~OUT4 公共端(COM) → 5V电源 | 电机线圈必须通过驱动板驱动,公共端需接外部5V电源 |
轻触按键 | 一端 → PB7 另一端 → GND | 按键一端接PB7,另一端接地。代码中已启用STM32内部上拉电阻 |
电源 | 5V/1A | 为ULN2003驱动板和步进电机供电,务必与STM32共地(GND) |
ST-Link V2 | SWDIO, SWCLK, GND, 3.3V | 严格对应引脚连接,为单片机提供调试和烧录接口 |
⚠️ 特别注意:
- 电机和驱动板的电源必须与STM32的GND连接在一起(共地),否则无法通信。
- 28BYJ-48电机的公共端(通常是红色线)必须接到5V电源,而不是3.3V。
8.3 核心代码
8.3.1 步进电机控制部分
#include "includes.h"uint8_t g_motorDir = 1; // 电机方向,1正转,0反转// 四相八拍通电顺序表
uint8_t stepSequence[8][4] ={{1, 0, 0, 0},{1, 1, 0, 0},{0, 1, 0, 0},{0, 1, 1, 0},{0, 0, 1, 0},{0, 0, 1, 1},{0, 0, 0, 1},{1, 0, 0, 1}};// 步进电机初始化
void STEPMOTOR_Init(void)
{// 使能GPIOA时钟RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;// 配置为推挽输出模式(50MHz)mode-11 cnf-00GPIOA->CRL &= ~(GPIO_CRL_CNF0 | GPIO_CRL_CNF1 | GPIO_CRL_CNF2 | GPIO_CRL_CNF3);GPIOA->CRL |= (GPIO_CRL_MODE0 | GPIO_CRL_MODE1 | GPIO_CRL_MODE2 | GPIO_CRL_MODE3);// 初始状态全部置低GPIOA->ODR &= ~(GPIO_ODR_ODR0 | GPIO_ODR_ODR1 | GPIO_ODR_ODR2 | GPIO_ODR_ODR3);
}// 步进电机运行函数
// dir: 1=正转, 0=反转; angle: 转动角度
void STEPMOTOR_Run(uint8_t dir, float angle)
{// 28BYJ-48实际每圈需要4096步(360/5.625=64 *64)// 90度 = 4096 / 4 = 1024步uint16_t totalSteps = (uint16_t)(angle * 4096 / 360);uint8_t stepIndex = 0;for (uint16_t i = 0; i < totalSteps; i++){// 清除当前输出GPIOA->ODR &= ~(GPIO_ODR_ODR0 | GPIO_ODR_ODR1 | GPIO_ODR_ODR2 | GPIO_ODR_ODR3);// 设置当前步的电平if (stepSequence[stepIndex][0])GPIOA->ODR |= GPIO_ODR_ODR0;if (stepSequence[stepIndex][1])GPIOA->ODR |= GPIO_ODR_ODR1;if (stepSequence[stepIndex][2])GPIOA->ODR |= GPIO_ODR_ODR2;if (stepSequence[stepIndex][3])GPIOA->ODR |= GPIO_ODR_ODR3;// 控制方向if (dir){stepIndex = (stepIndex + 1) % 8; // 正转}else{stepIndex = (stepIndex + 7) % 8; // 反转(避免负数)}Delay_ms(2); // 控制转速,可根据需要调整}// 停止后全部置低GPIOA->ODR &= ~(GPIO_ODR_ODR0 | GPIO_ODR_ODR1 | GPIO_ODR_ODR2 | GPIO_ODR_ODR3);
}
8.3.2 按键控制部分
// FileName:key.h#include "includes.h"uint8_t count = 0;/*** @brief 按键初始化(PB7,外部中断,下降沿触发)* @param void* @return void*/
void KEY_Init(void)
{// 1. 开启时钟(GPIOB和AFIO)RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; // 使能GPIOB时钟RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; // 使能AFIO时钟// 2. 配置GPIO工作模式(上拉输入,因为按键另一端接GND)GPIOB->CRL &= ~GPIO_CRL_MODE7; // MODE7=00(输入模式)GPIOB->CRL |= GPIO_CRL_CNF7_1; // CNF7=10(上拉/下拉输入)GPIOB->CRL &= ~GPIO_CRL_CNF7_0;GPIOB->ODR |= GPIO_ODR_ODR7; // 上拉(默认高电平)// 3. 配置AFIO复用映射(PB7 -> EXTI7)AFIO->EXTICR[1] &= ~AFIO_EXTICR2_EXTI7; // 清除原有映射AFIO->EXTICR[1] |= AFIO_EXTICR2_EXTI7_PB; // PB7映射到EXTI7// 4. 配置EXTI(下降沿触发,允许中断)EXTI->FTSR |= EXTI_FTSR_TR7; // 允许下降沿触发(按键按下)EXTI->RTSR &= ~EXTI_RTSR_TR7; // 禁止上升沿触发EXTI->IMR |= EXTI_IMR_MR7; // 允许EXTI7中断// 5. 配置NVIC(中断优先级和使能)NVIC_SetPriorityGrouping(3); // 全部使用抢占优先级NVIC_SetPriority(EXTI9_5_IRQn, 2); // 设置优先级(值越小优先级越高)NVIC_EnableIRQ(EXTI9_5_IRQn); // 使能EXTI9_5中断
}/*** @brief EXTI9_5中断服务函数(处理PB7中断)*/
void EXTI9_5_IRQHandler(void)
{// 检查是否是PB7触发的中断if (EXTI->PR & EXTI_PR_PR7){// 清除中断标志位(必须手动清除)EXTI->PR |= EXTI_PR_PR7;// 软件消抖Delay_ms(10);// 确认按键按下(PB7接GND,按下时为低电平)if (!(GPIOB->IDR & GPIO_IDR_IDR7)){// 步进电机控制// 转动90度STEPMOTOR_Run(g_motorDir, 90);count++;if (count > 4){// 切换方向g_motorDir = !g_motorDir;count = 0;}}}
}
8.4 完整代码获取
STM32F103C8T6 按键控制步进电机
笔者小白,能力有限,以上内容难免存在不足和纰漏,仅供参考,各位阅读时请带着批判性思维学习,遇到问题多查查。同时欢迎各位评论区批评指正。谢谢。