电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【let'sdo|2026年第3期】过程贴:按键启停步进电机

共1条 1/1 1 跳转至页

【let'sdo|2026年第3期】过程贴:按键启停步进电机

助工
2026-11-14 15:47:48     打赏

【let'sdo|2026年第3期】过程贴:CubeMX2+CubeIDE2按键中断点灯(迎接变化)

https://forum.eepw.com.cn/thread/402317/1

上一篇体验了全新的CubeMX2+CubeIDE2按键中断点灯。

本篇在此基础上使用按键启停步进电机。

  • 步进电机:28BYJ-48

  • 驱动电路:ULN2003芯片的驱动板

image.png


image.png


驱动板的硬件连接如上图。

1、2、3、4 接STM32的4个GPIO口

5接GND

6、7 接5V VCC

ABCDE接步进电机。


驱动方式也很简单:依次给各个相(1、2、3、4)输入高电平信号就可以了。注意,当给某一相输入信号的时候,其他相要重新置0。也就是说,同一时刻只能保持有一个相为高电平。

大概相当于如下:

  while(1)
        {
        HAL_GPIO_WritePin(PA4_PORT, PA4_PIN, );
   	HAL_GPIO_WritePin(PB0_PORT, PB0_PIN, HAL_GPIO_PIN_RESET);
   	HAL_GPIO_WritePin(PC5_PORT, PC5_PIN, HAL_GPIO_PIN_RESET);
   	HAL_GPIO_WritePin(PC0_PORT, PC0_PIN, HAL_GPIO_PIN_RESET);

   	HAL_Delay(1);

   	HAL_GPIO_WritePin(PA4_PORT, PA4_PIN, HAL_GPIO_PIN_RESET);
   	HAL_GPIO_WritePin(PB0_PORT, PB0_PIN, );
   	HAL_GPIO_WritePin(PC5_PORT, PC5_PIN, HAL_GPIO_PIN_RESET);
   	HAL_GPIO_WritePin(PC0_PORT, PC0_PIN, HAL_GPIO_PIN_RESET);

   	HAL_Delay(1);

   	HAL_GPIO_WritePin(PA4_PORT, PA4_PIN, HAL_GPIO_PIN_RESET);
   	HAL_GPIO_WritePin(PB0_PORT, PB0_PIN, HAL_GPIO_PIN_RESET);
   	HAL_GPIO_WritePin(PC5_PORT, PC5_PIN, );
   	HAL_GPIO_WritePin(PC0_PORT, PC0_PIN, HAL_GPIO_PIN_RESET);

   	HAL_Delay(1);

   	HAL_GPIO_WritePin(PA4_PORT, PA4_PIN, HAL_GPIO_PIN_RESET);
   	HAL_GPIO_WritePin(PB0_PORT, PB0_PIN, HAL_GPIO_PIN_RESET);
   	HAL_GPIO_WritePin(PC5_PORT, PC5_PIN, HAL_GPIO_PIN_RESET);
   	HAL_GPIO_WritePin(PC0_PORT, PC0_PIN, );

   	HAL_Delay(1);
   	}



整体main.c代码如下(包含了3轴加速度读取):

#include "main.h"
#include "string.h"
#include <stdint.h>
#include <stdio.h>
#include <math.h>

char msg1[] = "Hello World!\r\n";
char msg2[] = "\r\n";
// 扫描得到7bit=0x19,8bit地址0x32
#define LIS3DH_ADDR_8BIT    (0x19 << 1)
#define LIS3DH_REG_WHO_AM_I 0x0F
#define LIS3DH_REG_CTRL1    0x20
#define LIS3DH_REG_CTRL4    0x23
#define LIS3DH_REG_OUT_XL   0x28

// 全局偏移变量
int16_t offset_x = 0;
int16_t offset_y = 0;
int16_t offset_z = 0;
uint8_t cal_done = 0;
#define CAL_SAMPLE_CNT 32  // 校准采样点数

volatile uint8_t ExtiDetected = 0; //USER按键中断检测


/**
 * @brief 读取LIS3DH WHO_AM_I
 */
hal_status_t LIS3DH_ReadID(hal_i2c_handle_t *hi2c, uint8_t *id)
{
hal_status_t ret;
uint8_t reg = LIS3DH_REG_WHO_AM_I;
ret = HAL_I2C_MASTER_Transmit(hi2c, LIS3DH_ADDR_8BIT, &reg, 1, 100);
if(ret != HAL_OK) return ret;
ret = HAL_I2C_MASTER_Receive(hi2c, LIS3DH_ADDR_8BIT, id, 1, 100);
return ret;
}

/**
 * @brief LIS3DH初始化:100Hz,XYZ使能,±2g高分辨率
 */
hal_status_t LIS3DH_Init(hal_i2c_handle_t *hi2c)
{
hal_status_t ret;
uint8_t buf[2];

// CTRL1: ODR=100Hz, X Y Z enable --> 0x57
buf[0] = LIS3DH_REG_CTRL1;
buf[1] = 0x57;
ret = HAL_I2C_MASTER_Transmit(hi2c, LIS3DH_ADDR_8BIT, buf, 2, 100);
if(ret != HAL_OK) return ret;

// CTRL4: ±2g, HR=1 --> 0x08
buf[0] = LIS3DH_REG_CTRL4;
buf[1] = 0x08;
ret = HAL_I2C_MASTER_Transmit(hi2c, LIS3DH_ADDR_8BIT, buf, 2, 100);
return ret;
}

/**
 * @brief 连续读取XYZ原始数据 6字节
 * @param raw_buf[6] XL,XH,YL,YH,ZL,ZH
 */
hal_status_t LIS3DH_ReadRawXYZ(hal_i2c_handle_t *hi2c, uint8_t *raw_buf)
{
hal_status_t ret;
// bit7=1 自动增量
uint8_t reg = 0x80 | LIS3DH_REG_OUT_XL;
ret = HAL_I2C_MASTER_Transmit(hi2c, LIS3DH_ADDR_8BIT, &reg, 1, 100);
if(ret != HAL_OK) return ret;
ret = HAL_I2C_MASTER_Receive(hi2c, LIS3DH_ADDR_8BIT, raw_buf, 6, 100);
return ret;
}

/**
 * @brief 打印ID
 */
void LIS3DH_PrintID_UART2(void)
{
hal_status_t ret;
uint8_t chip_id = 0;
char msg[64];
ret = LIS3DH_ReadID(mx_i2c1_i2c_gethandle(), &chip_id);
if(ret == HAL_OK)
{
snprintf(msg, sizeof(msg), "LIS3DH ID: 0x%02X, expect 0x33\r\n", chip_id);
}
else
{
snprintf(msg, sizeof(msg), "LIS3DH I2C read FAIL");
}
HAL_UART_Transmit(mx_usart2_uart_gethandle(), (uint8_t *)msg, strlen(msg), 100);
}

/**
 * @brief 读取XYZ并串口打印(mg单位)
 */
void LIS3DH_PrintXYZ_UART2(void)
{
hal_status_t ret;
uint8_t raw[6];
int16_t x_raw, y_raw, z_raw;
int16_t x, y, z;
char msg[128];

ret = LIS3DH_ReadRawXYZ(mx_i2c1_i2c_gethandle(), raw);
if(ret != HAL_OK)
{
snprintf(msg, sizeof(msg), "LIS3DH XYZ read error\r\n");
}
else
{
x_raw = (int16_t)((raw[1] << 8) | raw[0]);
y_raw = (int16_t)((raw[3] << 8) | raw[2]);
z_raw = (int16_t)((raw[5] << 8) | raw[4]);

// HR高分辨率模式:12bit,左对齐,必须右移4位!
x = x_raw >> 4;
y = y_raw >> 4;
z = z_raw >> 4;

// ±2g:1 LSB = 1mg
snprintf(msg, sizeof(msg), "ACC: X=%d mg, Y=%d mg, Z=%d mg\r\n", x, y, z);
}
HAL_UART_Transmit(mx_usart2_uart_gethandle(), (uint8_t *)msg, strlen(msg), 100);
}

/**
 * @brief 零点校准函数,调用前保持传感器水平平放
 */
void LIS3DH_CalibrateZero(void)
{
uint8_t raw[6];
int16_t x_raw, y_raw, z_raw;
int32_t sum_x = 0, sum_y = 0, sum_z = 0;

for(uint16_t i = 0; i < CAL_SAMPLE_CNT; i++)
{
// 等待读取成功
while(LIS3DH_ReadRawXYZ(mx_i2c1_i2c_gethandle(), raw) != HAL_OK);
x_raw = (int16_t)((raw[1] << 8) | raw[0]);
y_raw = (int16_t)((raw[3] << 8) | raw[2]);
z_raw = (int16_t)((raw[5] << 8) | raw[4]);

int16_t x = x_raw >> 4;
int16_t y = y_raw >> 4;
int16_t z = z_raw >> 4;

sum_x += x;
sum_y += y;
sum_z += z;
HAL_Delay(20);
}
// 求平均偏移;Z理想值是1000mg
offset_x = sum_x / CAL_SAMPLE_CNT;
offset_y = sum_y / CAL_SAMPLE_CNT;
offset_z = sum_z / CAL_SAMPLE_CNT - 1000;
cal_done = 1;
}

/**
 * @brief 读取并打印【校准后】XYZ,单位 mg
 */
void LIS3DH_PrintXYZ_Cal(void)
{
hal_status_t ret;
uint8_t raw[6];
int16_t x_raw, y_raw, z_raw;
int16_t x, y, z;
char msg[128];

ret = LIS3DH_ReadRawXYZ(mx_i2c1_i2c_gethandle(), raw);
if(ret != HAL_OK)
{
snprintf(msg, sizeof(msg), "LIS3DH XYZ read error, ret=%u\r\n", ret);
}
else
{
x_raw = (int16_t)((raw[1] << 8) | raw[0]);
y_raw = (int16_t)((raw[3] << 8) | raw[2]);
z_raw = (int16_t)((raw[5] << 8) | raw[4]);

// 减去偏移,得到校准值
x = (x_raw >> 4) - offset_x;
y = (y_raw >> 4) - offset_y;
z = (z_raw >> 4) - offset_z;

//snprintf(msg, sizeof(msg), "ACC: X=%d mg, Y=%d mg, Z=%d mg\r\n", x, y, z);
snprintf(msg, sizeof(msg), "%d,%d,%d,", x, y, z);
}
HAL_UART_Transmit(mx_usart2_uart_gethandle(), (uint8_t *)msg, strlen(msg), 100);
}


int main(void)
{
if (mx_system_init() != SYSTEM_OK)
{
return (-1);
}
else
{
LIS3DH_PrintID_UART2();
LIS3DH_Init(mx_i2c1_i2c_gethandle());
// 上电校准!【板子平放,不要晃动!】
LIS3DH_CalibrateZero();

while (1) {
   	//HAL_GPIO_TogglePin(PA5_PORT, PA5_PIN);
   	//HAL_UART_Transmit(mx_usart2_uart_gethandle(), msg1, strlen(msg1), 100);

   	for(int i=0;i<32;i++)   //每个数据块包含63帧加速度数据
   	{
   		if(i<31)
   		LIS3DH_PrintXYZ_Cal(); // 读取并发送一帧3轴加速度数据
  		else                   //最后一帧回车
   		HAL_UART_Transmit(mx_usart2_uart_gethandle(), (uint8_t *)msg2, strlen(msg2), 100);
   	}
   	//HAL_Delay(500);

   	if(ExtiDetected == 1)
   	{
   	HAL_GPIO_WritePin(PA4_PORT, PA4_PIN, HAL_GPIO_PIN_SET);
   	HAL_GPIO_WritePin(PB0_PORT, PB0_PIN, HAL_GPIO_PIN_RESET);
   	HAL_GPIO_WritePin(PC5_PORT, PC5_PIN, HAL_GPIO_PIN_RESET);
   	HAL_GPIO_WritePin(PC0_PORT, PC0_PIN, HAL_GPIO_PIN_RESET);

   	HAL_Delay(1);

   	HAL_GPIO_WritePin(PA4_PORT, PA4_PIN, HAL_GPIO_PIN_RESET);
   	HAL_GPIO_WritePin(PB0_PORT, PB0_PIN, HAL_GPIO_PIN_SET);
   	HAL_GPIO_WritePin(PC5_PORT, PC5_PIN, HAL_GPIO_PIN_RESET);
   	HAL_GPIO_WritePin(PC0_PORT, PC0_PIN, HAL_GPIO_PIN_RESET);

   	HAL_Delay(1);

   	HAL_GPIO_WritePin(PA4_PORT, PA4_PIN, HAL_GPIO_PIN_RESET);
   	HAL_GPIO_WritePin(PB0_PORT, PB0_PIN, HAL_GPIO_PIN_RESET);
   	HAL_GPIO_WritePin(PC5_PORT, PC5_PIN, HAL_GPIO_PIN_SET);
   	HAL_GPIO_WritePin(PC0_PORT, PC0_PIN, HAL_GPIO_PIN_RESET);

   	HAL_Delay(1);

   	HAL_GPIO_WritePin(PA4_PORT, PA4_PIN, HAL_GPIO_PIN_RESET);
   	HAL_GPIO_WritePin(PB0_PORT, PB0_PIN, HAL_GPIO_PIN_RESET);
   	HAL_GPIO_WritePin(PC5_PORT, PC5_PIN, HAL_GPIO_PIN_RESET);
   	HAL_GPIO_WritePin(PC0_PORT, PC0_PIN, HAL_GPIO_PIN_SET);

   	HAL_Delay(1);
   	}
   	else
   	{
       	HAL_GPIO_WritePin(PA4_PORT, PA4_PIN, HAL_GPIO_PIN_RESET);
       	HAL_GPIO_WritePin(PB0_PORT, PB0_PIN, HAL_GPIO_PIN_RESET);
       	HAL_GPIO_WritePin(PC5_PORT, PC5_PIN, HAL_GPIO_PIN_RESET);
       	HAL_GPIO_WritePin(PC0_PORT, PC0_PIN, HAL_GPIO_PIN_RESET);

HAL_Delay(5);
   	}

}
}
}



//中断回调函数
void HAL_EXTI_TriggerCallback(hal_exti_handle_t *hexti, hal_exti_trigger_t trigger)
{
/* Prevent unused argument compilation warning */
STM32_UNUSED(trigger);
if (hexti == mx_gpio_default_exti13_gethandle())
{
//ExtiDetected = 1;
ExtiDetected ^= 1;     按下按键,状态翻转
}
}


运行效果:

按下USER按钮:电机转动,

再次按下USER按钮:电机停止,

如此反复。

caccbde4bc3b1eb734ba66f1abfe731b.jpg



共1条 1/1 1 跳转至页

回复

匿名不能发帖!请先 [ 登陆 注册 ]