ULN2003A

步进电机驱动芯片 · STM32F103C8T6 · HAL库开发

7
达林顿通道数
500mA
单通道最大电流
50V
最大输出电压
5V
电机工作电压
01 / PRINCIPLE

传感器原理与功能

ULN2003A 高压大电流达林顿晶体管阵列驱动芯片

1.1 工作原理

ULN2003A 是一款高压、大电流达林顿晶体管阵列芯片,内部集成了 7 路 NPN 达林顿晶体管对。每路达林顿管由两个三极管级联组成,电流放大系数可达千倍以上,能够将微控制器输出的弱电流信号放大为足以驱动步进电机线圈的强电流信号。芯片内置 2.7kΩ 串联基极电阻,使其可直接与 TTL 或 5V CMOS 逻辑电平接口,无需额外驱动电路。每路输出端均集成 续流钳位二极管,当驱动感性负载(如步进电机线圈)时,可有效抑制线圈断电瞬间产生的反向感应电动势,保护芯片和电路安全。

⚡

电流放大

7路独立达林顿晶体管对,单通道持续电流500mA,峰值电流600mA,可直接驱动步进电机、继电器等感性负载。

🛡

续流保护

每路输出内置钳位续流二极管,共阴极接COM端,有效抑制步进电机线圈换向时产生的反向感应电动势。

🔌

逻辑兼容

内置2.7kΩ串联基极电阻,输入端可直接连接STM32的GPIO推挽输出,兼容TTL和5V CMOS电平,无需电平转换。

⚙

步进驱动

配合28BYJ-48步进电机,通过4路GPIO输出8拍半步励磁序列,实现4096步/圈的精确角度控制,支持正反转。

1.3 引脚定义

引脚号 引脚名称 功能描述 STM32连接
1IN1输入1 — 驱动A相线圈PB6
2IN2输入2 — 驱动B相线圈PB7
3IN3输入3 — 驱动C相线圈PB8
4IN4输入4 — 驱动D相线圈PB9
5-7IN5-IN7输入5-7 — 备用通道(本例未使用)—
8GND地 — 逻辑与功率共地GND
9COM钳位二极管公共端 — 接电机电源正极5V
10OUT7输出7 — 备用(本例未使用)—
11OUT4输出4 — 驱动D相线圈电机D端
12OUT3输出3 — 驱动C相线圈电机C端
13OUT2输出2 — 驱动B相线圈电机B端
14OUT1输出1 — 驱动A相线圈电机A端
15-16NC未连接—

28BYJ-48 步进电机参数

5.625°/64

步距角(输出轴)

1:64

减速比

4096

半步模式步数/圈

50Ω

线圈直流电阻

02 / APPEARANCE

模块外观展示

ULN2003A 驱动板与 28BYJ-48 步进电机实物外观

模块外观
模块整体外观
顶视图
模块顶视图
底面
模块底面
03 / SCHEMATIC

原理图与PCB封装

电路原理图设计与PCB封装布局

原理图
PCB封装
04 / CODE ANALYSIS

程序分析

STM32F103C8T6 · HAL库 · 步进电机驱动程序源码解析

4.1 主程序 (main.c)

系统时钟配置为72MHz(HSE 8MHz × PLL 9倍频)。主程序初始化GPIO、TIM1定时器、OLED显示屏和步进电机驱动,在主循环中通过方向标志位Flag控制电机正转到达MOTOR_STEP(4096步)后反转回到0,每50ms更新一次OLED显示当前方向和转动百分比。TIM1定时器中断每1ms调用一次StepperMotorTick()驱动步进电机走一步。

main.c — 主程序
/* 全局变量 */
uint32_t Time_Now;
_Bool Flag;                                   // 转动方向标志位

int main(void)
{
  HAL_Init();
  SystemClock_Config();                         // 72MHz系统时钟
  MX_GPIO_Init();                              // GPIO初始化
  MX_TIM1_Init();                               // TIM1定时器初始化
  HAL_TIM_Base_Start_IT(&htim1);               // 启动TIM1中断
  OLED_Init();                                 // OLED显示屏初始化
  StepperMotor_Init();                          // 步进电机引脚初始化

  while (1)
  {
    if(Flag == 0)
    {
      if(Motor_Num < MOTOR_STEP)
        StepperMotorCTL(FORWARD);             // 正转
      else
        Flag = 1;                          // 切换为反转
    }
    else
    {
      if(Motor_Num > 0)
        StepperMotorCTL(REVERSE);             // 反转
      else
        Flag = 0;                          // 切换为正转
    }

    if(HAL_GetTick() - Time_Now >= 50)           // 50ms更新一次OLED
    {
      OLED_Clear();                               // 清屏
      if(getStepperMotor() == FORWARD)
        OLED_CenterPrintf(12, "正转");
      else if(getStepperMotor() == REVERSE)
        OLED_CenterPrintf(12, "反转");
      OLED_CenterPrintf(36, "%d%%", (int)(Motor_Num/(float)(MOTOR_STEP)*100));
      OLED_Update();                             // 更新显示
      Time_Now = HAL_GetTick();                  // 更新时间戳
    }
  }
}

/* TIM1定时器中断回调函数 — 每1ms执行一次 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if(htim->Instance == htim1.Instance)
  {
    StepperMotorTick();                           // 驱动步进电机走一步
  }
}

4.2 步进电机驱动程序 (steppermotor.c/h)

使用4路GPIO(PB6-PB9)以推挽输出方式驱动ULN2003A的4路输入。采用8拍半步励磁序列,电机走4096步完成一圈(360°)。步进序列数组 Motor_Buf[8] 定义了8个励磁状态,通过 Motor_Num 对8取模循环输出。定时器每1ms调用一次 StepperMotorTick(),电机每步1ms,完成一圈约需4.096秒。

steppermotor.h — 引脚与宏定义
// 步进电机引脚定义
#define STEPPER_IN1_Port  GPIOB
#define STEPPER_IN1_Pin  GPIO_PIN_6
#define STEPPER_IN2_Port  GPIOB
#define STEPPER_IN2_Pin  GPIO_PIN_7
#define STEPPER_IN3_Port  GPIOB
#define STEPPER_IN3_Pin  GPIO_PIN_8
#define STEPPER_IN4_Port  GPIOB
#define STEPPER_IN4_Pin  GPIO_PIN_9

#define MOTOR_STEP  512*8     // 4096步 = 一圈

// 方向枚举
typedef enum {
  STOP,           // 电机停止
  FORWARD,        // 电机正转
  REVERSE          // 电机反转
} Dir;
steppermotor.c — 驱动核心实现
// 8拍半步励磁序列:A→AB→B→BC→C→CD→D→DA
uint8_t const Motor_Buf[8] = {0x01, 0x03, 0x02, 0x06, 0x04, 0x0c, 0x08, 0x09};

// GPIO引脚驱动函数 — 按位写入4路线圈状态
void MotorGpioWrite(uint8_t data)
{
  HAL_GPIO_WritePin(STEPPER_IN1_Port, STEPPER_IN1_Pin, GPIO_PIN_RESET);
  HAL_GPIO_WritePin(STEPPER_IN2_Port, STEPPER_IN2_Pin, GPIO_PIN_RESET);
  HAL_GPIO_WritePin(STEPPER_IN3_Port, STEPPER_IN3_Pin, GPIO_PIN_RESET);
  HAL_GPIO_WritePin(STEPPER_IN4_Port, STEPPER_IN4_Pin, GPIO_PIN_RESET);

  if (data & 0x01) HAL_GPIO_WritePin(STEPPER_IN1_Port, STEPPER_IN1_Pin, GPIO_PIN_SET);
  if (data & 0x02) HAL_GPIO_WritePin(STEPPER_IN2_Port, STEPPER_IN2_Pin, GPIO_PIN_SET);
  if (data & 0x04) HAL_GPIO_WritePin(STEPPER_IN3_Port, STEPPER_IN3_Pin, GPIO_PIN_SET);
  if (data & 0x08) HAL_GPIO_WritePin(STEPPER_IN4_Port, STEPPER_IN4_Pin, GPIO_PIN_SET);
}

// 定时器驱动步进函数 — 每1ms调用一次
void StepperMotorTick(void)
{
  if(Motor_Status == 1 && Motor_Num < MOTOR_STEP)
    Motor_Num++;                              // 正转步数+1

  if(Motor_Status == 2 && Motor_Num)
    Motor_Num--;                              // 反转步数-1

  if(Motor_Num == 0 || Motor_Num == MOTOR_STEP)
    Motor_Status = 0;                    // 到达极限停止

  if(Motor_Status)
    MotorGpioWrite(Motor_Buf[Motor_Num % 8]);   // 输出对应励磁状态
}

4.3 TIM1定时器配置 (tim.c)

TIM1定时器配置为基本定时器模式,预分频器 Prescaler=71,自动重装值 Period=999。STM32F103C8T6的TIM1挂载在APB2总线上,时钟频率为72MHz。定时器中断频率 = 72MHz / (71+1) / (999+1) = 1kHz,即每1毫秒产生一次更新中断,作为步进电机的步进时钟源。

tim.c — TIM1定时器初始化
TIM_HandleTypeDef htim1;

void MX_TIM1_Init(void)
{
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 71;                // 72MHz/(71+1) = 1MHz
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 999;                 // 1MHz/(999+1) = 1kHz = 1ms
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  HAL_TIM_Base_Init(&htim1);

  // 在MspInit中启用TIM1更新中断
  HAL_NVIC_SetPriority(TIM1_UP_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
}

/* 定时器中断频率计算:
   时钟源 = 72MHz (APB2)
   计数频率 = 72MHz / (71+1) = 1MHz
   中断频率 = 1MHz / (999+1) = 1kHz
   中断周期 = 1ms → 每步1ms */

4.4 励磁序列状态对照表

8拍半步励磁序列每个状态对应不同的线圈通电组合,逐步切换实现电机平滑转动。Motor_Num 对8取模循环输出对应状态。

步数 (Motor_Num%8) 序列值 二进制 IN1 (PB6) IN2 (PB7) IN3 (PB8) IN4 (PB9) 励磁相
00x010001●○○○A
10x030011●●○○AB
20x020010○●○○B
30x060110○●●○BC
40x040100○○●○C
50x0c1100○○●●CD
60x081000○○○●D
70x091001●○○●DA
05 / FLOWCHART

程序流程图

系统初始化 → 主循环(正反转控制 → OLED更新) → TIM1中断驱动步进

开始 系统初始化 HAL_Init / 时钟72MHz / GPIO / TIM1 外设初始化 OLED_Init / StepperMotor_Init 启动TIM1定时器中断 (1ms) while(1) Flag == 0? (正转方向?) 是 否 Motor_Num < MOTOR_STEP? Motor_Num > 0? 是 StepperMotorCTL(FORWARD) 否 Flag = 1 (切换反转) 是 StepperMotorCTL(REVERSE) 否 Flag = 0 (切换正转) HAL_GetTick() - Time_Now >= 50ms? 是 OLED_Clear / 显示正转或反转 显示转动百分比 / OLED_Update Time_Now = HAL_GetTick() 否 TIM1中断 (1ms) StepperMotorTick() 步数±1 → 输出Motor_Buf[Motor_Num%8] 中断返回 异步触发 每1ms一次
06 / INTERACTIVE

交互式动画演示

步进电机驱动仿真 — 实时模拟ULN2003A驱动28BYJ-48步进电机

ULN2003A 驱动板 + 步进电机

IN1
PB6
IN2
PB7
IN3
PB8
IN4
PB9

OLED 显示 + 数据仪表

停止
0%
0%
0 / 4096

动画说明

左侧为ULN2003A驱动板与28BYJ-48步进电机仿真。4个LED指示灯对应IN1-IN4(PB6-PB9)的GPIO输出状态,按8拍半步励磁序列循环点亮。电机转子按励磁序列逐步旋转,正转至100%后自动切换为反转。右侧OLED模拟屏显示当前方向(正转/反转)和转动百分比,仪表盘以弧形进度条实时显示步数进度(0-4096步=0%-100%)。定时器中断周期1ms/步,OLED更新间隔50ms。