模块用法与加速度计采集数据
在上一个开箱贴中我们介绍了开发板以及各个模块,本贴主要来分享各个模块的功能与用法,以及如何接线,进行引脚分配,与开发板进行协作完成本次活动。
我这边使用MX2+vscode+st扩展进行开发,这套开发环境轻量便捷,在大模型的帮助下可提升开发效率。
整个工程基于 STM32CubeMX2 生成的 CMake 工程,工具链为 GNU Arm Embedded 14.3.1,所有外设都使用寄存器级 HAL 接口,便于移植和理解。
1. 项目一览
组件型号作用
| 主控 | NUCLEO-C562RE / STM32C562RE | Cortex-M33,主频 144 MHz,512 KB Flash / 128 KB RAM |
| 步进电机 | 28BYJ-48(5 线四相) | 执行机构 |
| 电机驱动 | ULN2003 驱动板 | 3.3 V 逻辑控制 5 V 电机线圈 |
| 加速度计 | LIS3DHTR | 采集电机振动,I2C,0x19 / 0x18 |
| 显示屏 | SSD1306 OLED 128×64 | 显示电机状态、AI 结果与置信度 |
| 按键 | PC13 板载按键 | 控制电机启停 |
| 串口 | USART2(PA2/PA3) | 921600 输出原始加速度窗口 |
| AI | NanoEdge AI Studio 分类库 | 2 类:RUN / STOP |
关键参数:
步进:8 拍半步,2 ms/半步,4096 半步/圈,约 8.2 秒一圈
采样:LIS3DHTR 100 Hz,±2 g 高分辨率,原始 16 位输出
窗口:256 点 × 3 轴 = 768 个值,约 2.56 秒一个窗口
串口:每行 768 个整数,空格分隔,CRLF 结尾,无表头

因其串口助手显示宽度的限制,被排挤到多行。实际每次传输768个数据。
2. 系统结构

数据流可以概括为:
LIS3DHTR 以 100 Hz 采样电机三轴加速度;
每 256 个采样点组成一个窗口(约 2.56 秒);
窗口数据一边以文本行形式从 USART2 发出,用于数据集采集;
同时转换成 float 数组送入 NanoEdge AI 分类模型;
在128*64的oled中,第4页显示电机运行状态,第6页显示模型分类结果和置信度。
3. 硬件连接
3.1 引脚分配

MCU 引脚信号模式连接
| PC0 | IN1 | 推挽输出 | ULN2003 IN1 |
| PC1 | IN2 | 推挽输出 | ULN2003 IN2 |
| PC2 | IN3 | 推挽输出 | ULN2003 IN3 |
| PC3 | IN4 | 推挽输出 | ULN2003 IN4 |
| PC13 | KEY | 输入,下拉,EXTI13 上升沿 | 板载按键 |
| PB6 | I2C1_SCL | AF4,开漏,上拉 | OLED SCL + LIS3DHTR SCL |
| PB7 | I2C1_SDA | AF4,开漏,上拉 | OLED SDA + LIS3DHTR SDA |
| PA2 | USART2_TX | AF7 | ST-LINK 虚拟串口 RX |
| PA3 | USART2_RX | AF7 | ST-LINK 虚拟串口 TX |
3.2 电源注意事项
ULN2003 驱动板建议使用 5 V 独立供电,并与主控 共地。28BYJ-48 单相电流约 200~300 mA,不建议使用开发板上的5V为驱动板进行供电
OLED 和 LIS3DHTR 使用 3.3 V 即可。
I2C 总线上两个器件共用 PB6/PB7,模块自带上拉即可,不需要硬件上配置4.7k上拉电阻;CubeMX2 中也配置了内部上拉。
3.3 I2C 地址
器件7 位地址8 位写地址说明
| SSD1306 | 0x3C | 0x78 | 地址由模块固定 |
| LIS3DHTR | 0x19 | 0x32 | SDO 悬空/接高;SDO 接 GND 时为 0x18 |
注意:STM32C5 HAL 的 I2C 接口要求传入 左移一位后的 8 位地址,所以代码中写0x3C << 1 = 0x78、0x19 << 1 = 0x32。
4. 步进电机模块
4.1 ULN2003 与 28BYJ-48
28BYJ-48 是 5 线四相减速步进电机,内部线圈公共端接 5 V,四相 A/B/C/D 由 ULN2003 灌电流驱动。MCU 的 PC0~PC3 接 ULN2003 的 IN1~IN4,逻辑高电平导通对应相。
方向相反时,交换电机与驱动板之间的任意两根线即可,不需要改代码。
4.2 半步序列
驱动采用 8 拍半步,运行更平滑:
拍IN1IN2IN3IN4十六进制
| 1 | 1 | 0 | 0 | 0 | 0x01 |
| 2 | 1 | 1 | 0 | 0 | 0x03 |
| 3 | 0 | 1 | 0 | 0 | 0x02 |
| 4 | 0 | 1 | 1 | 0 | 0x06 |
| 5 | 0 | 0 | 1 | 0 | 0x04 |
| 6 | 0 | 0 | 1 | 1 | 0x0C |
| 7 | 0 | 0 | 0 | 1 | 0x08 |
| 8 | 1 | 0 | 0 | 1 | 0x09 |
代码中用 HAL_GPIO_WriteMultipleStatePin() 一次更新四个引脚,保证相位切换的原子性。
4.3 驱动接口
void Stepper_Init(void); // 断线圈,复位状态 void Stepper_SetSpeed(uint32_t ms); // 半步周期,1~50 ms void Stepper_Start(void); void Stepper_Stop(void); // 四相断电 void Stepper_SetDirection(stepper_dir_t dir); void Stepper_Task(void); // 周期调度
半步周期默认为 2 ms:
4096 半步/圈 ÷ (1 / 0.002 s) = 约 8.2 秒/圈
5. PC13 按键模块
按键使用 PC13 板载 B1,配置为:
输入,内部下拉
EXTI13 上升沿触发(按下时引脚被拉高)
NVIC 使能 EXTI13 中断
如果是按下接 GND 的板型(很多 Nucleo 默认如此),需要改成 上拉 + 下降沿, 并让回调接受 HAL_EXTI_TRIGGER_FALLING。
软件去抖 150 ms,在中断回调里只置一个事件标志,实际处理放在主循环:
static void key_exti_callback(hal_exti_handle_t *hexti, hal_exti_trigger_t trigger)
{
if (trigger != HAL_EXTI_TRIGGER_RISING) return;
uint32_t now = HAL_GetTick();
if ((now - s_key_tick) >= 150U) {
s_key_tick = now;
s_key_event = true;
}
}主循环收到事件后切换电机启停,并刷新 OLED。
6. OLED 模块(SSD1306)
6.1 驱动结构
128×64 显存,按 8 页组织,每页 8 像素高、128 列;
上电后写入初始化命令;
驱动维护 1024 字节的 RAM 显存,修改后统一发送;
内置 5×7 ASCII 字库,支持字符串和数字绘制。
6.2 接口
hal_status_t SSD1306_Init(hal_i2c_handle_t *hi2c); void SSD1306_Clear(void); void SSD1306_DrawString(uint8_t x, uint8_t page, const char *text); void SSD1306_DrawUInt(uint8_t x, uint8_t page, uint32_t value, uint8_t width); void SSD1306_Update(void); // 整屏刷新,1024 字节 void SSD1306_ClearPage(uint8_t page); void SSD1306_UpdatePage(uint8_t page); // 单页刷新,128 字节
6.3 页面布局
页像素行内容
| 0 | 0~7 | STEP MOTOR |
| 1 | 8~15 | 28BYJ-48 ULN2003 |
| 2 | 16~23 | 分隔线 |
| 3 | 24~31 | DIR : CW > |
| 4 | 32~39 | MODE: RUN / STOP |
| 5 | 40~47 | SPD : 02 ms |
| 6 | 48~55 | AI : RUN 99.985% |
| 7 | 56~63 | KEY : PC13 RUN/STOP |
6.4 刷新策略
100 kHz I2C 下,整屏 1024 字节约 90 ms;
单页 128 字节约 12 ms;
按键改变电机状态时才整屏刷新;
AI 结果每 2.56 秒更新一次,只刷新第 6 页,避免拖慢采样。
如果用的是 1.3 寸 SH1106 屏幕,SSD1306 的页寻址可能不兼容,需要修改初始化序列 和列偏移(可见控制器型号)。
7. LIS3DHTR 加速度计模块
7.1 接线与地址
VCC 3.3 V,GND 共地
SCL 接 PB6,SDA 接 PB7(与 OLED 共用 I2C1)
SDO 悬空或接高:地址 0x19;SDO 接 GND:地址 0x18
INT1/INT2 不接,本项目使用轮询
上电后先读 0x0F,值为 0x33 表示识别成功,驱动会依次尝试 0x19 和 0x18。
注意本次活动中的加速度计模块使用的HY2.0的接口,开发板排母使用2.54mm排针,无法直接连接到开发板上。建议使用转接线或者自行打样一个转接板。
7.2 关键寄存器配置
寄存器地址值含义
| CTRL_REG1 | 0x20 | 0x57 | ODR=100 Hz,XYZ 使能 |
| CTRL_REG2 | 0x21 | 0x00 | 不用高通滤波 |
| CTRL_REG3 | 0x22 | 0x00 | 不用中断输出 |
| CTRL_REG4 | 0x23 | 0x88 | BDU=1,±2 g,高分辨率 |
| CTRL_REG5 | 0x24 | 0x00 | FIFO 关闭 |
| STATUS_REG | 0x27 | — | bit3 = ZYXDA 新数据标志 |
| OUT_X_L~OUT_Z_H | 0x28~0x2D | — | 六字节加速度输出 |
±2 g 高分辨率模式下,1 LSB = 1 mg,1 g 约对应 1000 个计数值。由于输出是 12 位 左对齐放在 16 位寄存器里,低 4 位恒为 0,所以静止时 Z 轴原始值约为 16000。
7.3 读取流程
每 5 ms 轮询一次,一次读取 STATUS + 六字节数据:
/* 从 0x27 开始自动递增读 7 字节 */
lis3dh_read_regs(0x27 | 0x80, buf, 7);
if (buf[0] & 0x08) { /* ZYXDA:有新样本 */
x = (int16_t)((buf[2] << 8) | buf[1]);
y = (int16_t)((buf[4] << 8) | buf[3]);
z = (int16_t)((buf[6] << 8) | buf[5]);
}子地址最高位置 1 打开自动递增,避免 6 次独立事务。BDU=1 保证六字节来自同一次采样。
7.4 驱动接口
hal_status_t Lis3dh_Init(hal_i2c_handle_t *hi2c); hal_status_t Lis3dh_ReadRaw(int16_t *x, int16_t *y, int16_t *z); hal_status_t Lis3dh_ReadMg(int32_t *x, int32_t *y, int32_t *z); void Lis3dh_Task(void); // 采样 + 窗口输出 void Lis3dh_SetWindowCallback(lis3dh_window_cb_t cb);
7.5 量程与速率调整
需求CTRL_REG4说明
| ±2 g(当前) | 0x88 | 1 g ≈ 16000 原始值 |
| ±4 g | 0x98 | 1 g ≈ 8000 原始值 |
| ±8 g | 0xA8 | 1 g ≈ 4000 原始值 |
| ±16 g | 0xB8 | 1 g ≈ 1333 原始值 |
如果需要更高采样率,可把 CTRL_REG1 的 ODR 改成 200/400 Hz。但注意:模型是在 100 Hz 数据上训练的,改变采样率后频谱特征会变化,应当重新训练模型。
8. 加速度计如何采集步进电机数据
这一节是整个项目的核心,分几个方面说明。
8.1 物理安装
加速度计建议刚性固定在电机外壳或电机支架上,用双面胶+扎带固定也可以, 但不能让传感器悬空或只连着杜邦线,否则测到的主要是导线晃动。我这边因条件不足,使用的电气绝缘胶带缠绕连接。
传感器 Z 轴尽量与电机轴向一致或保持固定朝向,两种类别采集时保持同一朝向。
ULN2003 和 MCU 共地,电机电源单独 5 V 供电,避免电机启停时电源波动导致 MCU 复位或 I2C 异常。
I2C 线尽量短(10~20 cm),远离电机相线。
8.2 串口数据格式
每个窗口输出一行,格式严格固定:
x1 y1 z1 x2 y2 z2 ... x256 y256 z256\r\n
共 768 个整数,单个空格分隔;
数值是 LIS3DHTR 的原始 16 位寄存器值;
行尾 CRLF;
没有表头、时间戳、类别文字或启动信息,严格按照UTF-8,可以直接作为数据集文件,为后面使用Nanoedge AI studio进行数据训练做准备;
一行约 5.4 KB,921600 波特率下发送约 59 ms。
示例(截断):
160 352 16272 80 320 16080 144 320 16368 ... 208 304 16192
串口发送使用中断模式 HAL_UART_Transmit_IT(),不阻塞主循环。发送期间采样和电机 步进继续运行。缓冲区在下一个窗口到来前不会被修改(间隔 2.56 秒,远大于 59 ms)。
到此应该知晓了如何进行接线,如何驱动电机,将加速度计与电机进行刚性连接。学会将加速度计读取到的数据发送到串口。实现基本的任务,后将讲解如何在Nanoedge ai studio中进行模型训练并且部署到我们的现有的项目程序中,以实现边缘ai的检测。
我要赚赏金
