这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » NUCLEO-H533RE+LIS3DH+28BYJ-48实现四档转速实时识别

共1条 1/1 1 跳转至页

NUCLEO-H533RE+LIS3DH+28BYJ-48实现四档转速实时识别

菜鸟
2026-11-08 21:49:34     打赏

一、开箱

这次活动的必选物料一共三件,主控是三选一,我选了 NUCLEO-H533RE。

第一件是 NUCLEO-H533RE 开发板。它搭载的是 STM32H533RET6,Cortex-M33 内核,最高可以跑到

250MHz,板载 512KB Flash 和 272KB RAM。之所以特别关注内存大小,是因为后面要往板子上塞一个机器

学习模型——虽然 NanoEdge AI Studio 生成的模型通常只有几 KB,但推理时的输入缓冲区(768 个 float)

本身就要占掉 3KB 左右,内存宽裕一点,后面调试起来心里更踏实。这块板子还自带 ST-LINK 调试器、

一颗用户按键、一颗绿色 LED,以及一个把串口桥接成 USB 虚拟串口的通道,基本上"开箱即用",不需要

额外的下载器或者 USB 转串口模块。

第二件是 Grove 三轴数字加速度计,核心芯片是 LIS3DHTR。它是这个项目的"耳朵":量程可以在

±2g / ±4g / ±8g / ±16g 之间切换,通过 I2C 接口通信,芯片内部还集成了 32 级 FIFO 和一个温度

传感器。

第三件是齿轮步进电机驱动套件,包含一块 ULN2003 驱动板和一颗 28BYJ-48 减速步进电机。

驱动代码不是凭空写的,两个模块都有官方参考资料,基本是照着官方示例把 Arduino 版本的逻辑搬到 STM32 上就能直接使用。

Grove 齿轮步进电机驱动套件:https://wiki.seeedstudio.com/cn/Gear_Stepper_Motor_Driver_Pack/

规格书:https://mm.digikey.com/Volume0/opasdata/d220001/medias/docus/719/Gear_Stepper_Motor_Driver_Pack_Web.pdf

Grove 三轴数字加速度计(LIS3DH):Grove - 3-Axis Digital Accelerometer(±1.5g) | Seeed Studio Wiki

规格书:https://mm.digikey.com/Volume0/opasdata/d220001/medias/docus/452/114020121_Web.pdf

image.png

二、环境搭建:

本次的三个stm公司的软件都挺好用的,也基本不会遇到什么网络方面的下载问题

第一个是 STM32CubeMX。

第二个是 STM32CubeIDE。

这2个属于玩过stm32的基本都用过,本次也是完全不用额外安装,毕竟之前都已经下载过了。

第三个是 NanoEdge AI Studio,版本 5.2.0。这个倒是头一次使用 ,它同样是 ST 官网的免费工具,注册账号后即可下载。需要注意的是注册邮箱要填实际可用的,第一次打开后需要填个人秘钥,会自动发到注册邮箱之中

image.png

三、代码编写

接下来就是将wiki上的arduino驱动代码给移植到当前的stm32平台上,最后可以得到2个模块的驱动库,下面仅贴出移植后的接口

image.png

image.png

然后根据NUCLEO-H533RE引出的引脚定义,然后分配一下我们需要的外设和引脚,这里使用的是板上串口2来查看加速度计的数值,用iic1来驱动加速度计,并分配4个gpio来驱动电机

image.png

需要注意的是NanoEdge AI Studio要求"一个采样窗口一行":每行 256 个时间点,每个时间点 3 个轴,按 X0 Y0 Z0 X1 Y1 Z1…… 的顺序交错排列,一共 768 个数,用逗号分隔,行尾换行——这样一行就是一个完整的信号,导入软件时会自动识别成"3 轴 × 256 点"。另外,每类状态建议采够 100 行以上,并且分成两批采集,避免相邻窗口过于相似导致验证分数虚高。格式确定之后,就可以在 main.c 里动手写采集代码了。整体思路很简单:按一下用户按键,就采一类状态的数据,采完自动停机并轮换到下一类。


/* 4 种电机状态:半步间隔(us),0 = 停止不转 */
#define MOTOR_STATE_STOP_US        0U
#define MOTOR_STATE_SLOW_US        3000U
#define MOTOR_STATE_MED_US         2000U
#define MOTOR_STATE_FAST_US        1000U

/* 状态下标 */
#define CAPTURE_CLASS_STOP         0U
#define CAPTURE_CLASS_SLOW         1U
#define CAPTURE_CLASS_MED          2U
#define CAPTURE_CLASS_FAST         3U

/* 采集参数 */
#define CAPTURE_CLASS_COUNT        4U       /* 一共几类 */
#define CAPTURE_LINES              100U     /* 每类采多少行 */
#define CAPTURE_SAMPLES            256U     /* 每行采样点数(每轴) */
#define CAPTURE_ODR_HZ             400U     /* 采样率,和传感器 ODR 一致 */
#define CAPTURE_SETTLE_MS          500U     /* 采集前等电机稳定 */
#define CAPTURE_READY_TIMEOUT      20000U   /* 等数据就绪的轮询上限,防死等 */

static const uint16_t s_class_interval_us[CAPTURE_CLASS_COUNT] =
{
  MOTOR_STATE_STOP_US, MOTOR_STATE_SLOW_US,
  MOTOR_STATE_MED_US,  MOTOR_STATE_FAST_US
};

static const char *const s_class_name[CAPTURE_CLASS_COUNT] =
{
  "STOP", "SLOW", "MED", "FAST"
};
uint8_t who = 0U;
H3LIS331DL_ReadWhoAmI(&who);
printf("# WHO_AM_I = 0x%02Xrn", (unsigned)who);

H3LIS331DL_Init();

/* 正常模式 + ODR 400Hz + 三轴使能 */
H3LIS331DL_SelectDataRate(0x77);

/* BDU=1 + ±2g + 12 位高分辨率,1 LSB 正好是 1mg */
H3LIS331DL_SelectDataConfig(0x88);
static void Capture_Run(uint8_t class_idx)
{
  /* 1) 设置电机状态:停止档断电,其余档连续转动 */
  if (class_idx == CAPTURE_CLASS_STOP)
  {
    Stepper_Stop();
  }
  else
  {
    Stepper_StartHalfSteps(2000000000, s_class_interval_us[class_idx]);
  }

  printf("# CAPTURE START class=%u (%s) interval=%uus lines=%urn",
         (unsigned)class_idx, s_class_name[class_idx],
         (unsigned)s_class_interval_us[class_idx], (unsigned)CAPTURE_LINES);

  BSP_LED_On(LED_GREEN);              /* 点亮 = 正在采集 */
  HAL_Delay(CAPTURE_SETTLE_MS);       /* 等转速稳定,跳过启动瞬态 */

  /* 2) 逐行采集,每行 256 个点 × 3 轴 */
  for (line = 0U; line < CAPTURE_LINES; line++)
  {
    for (i = 0U; i < CAPTURE_SAMPLES; i++)
    {
      int16_t x = 0, y = 0, z = 0;
      uint8_t ready = 0U;
      uint32_t guard = 0U;

      /* 等传感器出新样本,采样节奏由 ODR 决定 */
      do
      {
        (void)H3LIS331DL_DataReady(&ready);
        guard++;
      } while ((ready == 0U) && (guard < CAPTURE_READY_TIMEOUT));

      if (ready == 0U)              /* 传感器异常,中止本轮 */
      {
        printf("# ERROR: sensor not ready, abortedrn");
        Stepper_Stop();
        BSP_LED_Off(LED_GREEN);
        return;
      }

      (void)H3LIS331DL_ReadRaw(&x, &y, &z);
      x = Capture_DecodeAxis(x);    /* 12 位左对齐解码,单位 mg */
      y = Capture_DecodeAxis(y);
      z = Capture_DecodeAxis(z);

      if (i == (CAPTURE_SAMPLES - 1U))
      {
        printf("%d,%d,%drn", (int)x, (int)y, (int)z);   /* 行尾换行 */
      }
      else
      {
        printf("%d,%d,%d,", (int)x, (int)y, (int)z);
      }
    }
  }

  /* 3) 收尾:停机、断电、复位按键标志 */
  Stepper_Stop();
  BSP_LED_Off(LED_GREEN);
  BspButtonState = BUTTON_RELEASED;
}
uint8_t class_idx = CAPTURE_CLASS_STOP;   /* 下一次要采的状态 */

while (1)
{
  if (BspButtonState == BUTTON_PRESSED)
  {
    BspButtonState = BUTTON_RELEASED;

    Capture_Run(class_idx);               /* 采完一类 */

    class_idx = (uint8_t)((class_idx + 1U) % CAPTURE_CLASS_COUNT);
    printf("# next: %srn", s_class_name[class_idx]);
  }
}

编译通过,下载烧录,然后就是将加速度计用胶带贴到电机上面,然后开始采集数据,这里使用的是微软商店中下载的串口助手,毕竟可以直接将接收到的数据保存到文件中,比较方便。此处我们计划采集4中电机的

状态,分别是停止,慢速,中速,快速4中,采集完数据我们就可以得到motor_stop.txt ,motor_slow.txt,motor_mid.txt,motor_fast.txt4份用于训练模型的数据。

image.png

image.png

四,模型训练

打开NanoEdge AI Studio,新建一个Classify 工程,并选择3轴加速度,选择NUCLEO-H533RE板卡,可以直接填充ram,falsh大小,随后将4组训练数据添加上去

image.png

然后就可以开始训练了,这里是训练了2个多小时,然后就暂停了,因为训练到现在模型已经可以使用了,可以看到得分非常高,接近100分,再往下训练也得不到更加有价值的结果了

image.png

image.png

最后将训练好的模型下载下来,最重要的是其中的.a和.h文件,我们将其加入到工程的连接文件之中,稍微修改一下之前的采集代码,这次采集后的数据不用直接打印,而是将调用api,用加速度数据来算出电机当前的

状态,用户交互方面依旧保留,每按一次按键在停止-慢速-中速-快速4个状态循环,随后编译下载来看看成果

image.png

image.png

image.png

image.png

可以看到,效果非常哇塞啊,也算是完成了该活动的基础目标了

五,心得体会

本次也是幸运的再一次入围eepw的活动,接触到了之前完全没接触过的模型训练,受益匪浅啊








关键词: NUCLEO-H533RE     LIS3DH     28BY    

共1条 1/1 1 跳转至页

回复

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