1. 环境搭建与基础验证
任务目标
本案例完成STM32CubeAI环境搭建与基础验证闭环:使用CubeMX生成带AI库的工程,将Keras正弦波预测模型转换为STM32可用的C代码,并在开发板上运行推理,通过串口输出预测结果。
环境与依赖
- STM32CubeMX 6.x(含X-CUBE-AI扩展包,建议v7.3+)
- STM32CubeIDE 1.13+(或任意支持所生成工程的IDE)
- Python 3.8+,安装
tensorflow==2.10、numpy、keras - 开发板:NUCLEO-F401RE(本文以该板为例,其他F4系列可类推)
- USB转串口线(板载ST-Link已集成虚拟串口)
实现步骤
1. 生成并训练正弦波预测模型
创建Python脚本train_sine.py,训练一个输入为过去10个采样点、输出为下一点的LSTM模型,并保存为Keras格式。
import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
# 生成正弦波数据
t = np.linspace(0, 20*np.pi, 2000)
data = np.sin(t)
# 构造序列样本:用前10点预测下一点
seq_len = 10
X, y = [], []
for i in range(len(data)-seq_len-1):
X.append(data[i:i+seq_len])
y.append(data[i+seq_len])
X = np.array(X).reshape(-1, seq_len, 1)
y = np.array(y)
# 划分训练/验证
split = int(len(X)*0.8)
X_train, X_val = X[:split], X[split:]
y_train, y_val = y[:split], y[split:]
# 构建模型
model = keras.Sequential([
layers.LSTM(16, input_shape=(seq_len, 1)),
layers.Dense(1)
])
model.compile(optimizer='adam', loss='mse')
model.fit(X_train, y_train, epochs=30, validation_data=(X_val, y_val), verbose=0)
# 保存模型
model.save('sine_model.h5')
print('模型已保存为 sine_model.h5')
运行python train_sine.py生成模型文件。
2. CubeMX工程配置
- 打开CubeMX,新建基于NUCLEO-F401RE的工程。
- 配置USART2(PA2/PA3)为异步模式,波特率115200,用于输出推理结果。
- 在Software Packs中选择
X-CUBE-AI,点击Add。 - 进入Middleware and Software Packs → X-CUBE-AI → Network,点击Add Network,选择
sine_model.h5。 - 将网络名称设为
sine_net,其余保持默认(分析模式为ONNX/TFLite自动转换)。 - 时钟配置:确保主频84MHz(HSE+锁相环),CubeMX默认即可。
- 生成代码(Toolchain选择STM32CubeIDE)。
3. 编写推理主程序
在生成的工程中,打开Core/Src/main.c,在main()函数的用户代码区添加推理逻辑。核心代码如下:
/* 在main.c中添加头文件 */
#include "ai_platform.h"
#include "sine_net.h"
#include "sine_net_data.h"
/* 用户代码区(USER CODE BEGIN PV) */
static float input_data[10] = {0};
static float output_data[1] = {0};
static ai_handle network = AI_HANDLE_NULL;
static ai_handle weights[AI_SINE_NET_NUM_OF_WEIGHTS_ARRAYS] = {0};
static ai_buffer input_buffers[1];
static ai_buffer output_buffers[1];
static ai_i8 activations[AI_SINE_NET_DATA_ACTIVATIONS_SIZE];
/* USER CODE END PV */
/* main()函数内,在while(1)之前添加初始化与推理代码 */
int main(void)
{
/* ... CubeMX生成的初始化代码 ... */
/* USER CODE BEGIN 2 */
// 构造输入序列:模拟最近10个采样点(示例数据)
for (int i = 0; i < 10; i++) {
input_data[i] = sinf((float)(i) * 0.5f);
}
// 初始化AI网络
ai_error err;
err = ai_sine_net_create(&network, weights);
if (err.type != AI_ERROR_NONE) {
printf("网络创建失败\n");
Error_Handler();
}
// 绑定激活缓冲区
ai_sine_net_data_params_get(&network, AI_SINE_NET_DATA_ACTIVATIONS,
&activations[0], AI_SINE_NET_DATA_ACTIVATIONS_SIZE);
// 设置输入输出缓冲区
input_buffers[0].data = input_data;
input_buffers[0].format = AI_BUFFER_FORMAT_FLOAT;
input_buffers[0].size = 10 * sizeof(float);
output_buffers[0].data = output_data;
output_buffers[0].format = AI_BUFFER_FORMAT_FLOAT;
output_buffers[0].size = 1 * sizeof(float);
// 执行推理
ai_i32 ret = ai_sine_net_run(&network, input_buffers, output_buffers);
if (ret != 1) {
printf("推理失败\n");
Error_Handler();
}
// 输出结果
printf("预测值: %f\n", output_data[0]);
/* USER CODE END 2 */
while (1)
{
}
}
注意:printf重定向到USART2需在fputc中实现,CubeMX生成的工程默认支持(若未启用,在main.c中添加以下代码):
/* USER CODE BEGIN 0 */
int fputc(int ch, FILE *f) {
HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 100);
return ch;
}
/* USER CODE END 0 */
4. 编译与烧录
- 在STM32CubeIDE中编译工程,确认无错误。
- 连接开发板,点击Run烧录并启动调试。
5. 验证方法
打开串口终端(115200-8-N-1),观察输出。若程序正常运行,应看到类似以下输出(数值取决于输入序列):
预测值: 0.479426
通过条件:串口输出一行以预测值:开头的浮点数,且程序不进入Error_Handler。该数值与Python端对相同输入序列的推理结果一致(误差<1e-3),说明模型转换与部署链路正确。
常见问题
- 网络创建失败:检查CubeMX中X-CUBE-AI的
Network是否已正确添加,且sine_net.h头文件路径已包含。 - 编译报错找不到ai_platform.h:确认CubeMX生成的
Middlewares/ST/AI目录已加入include路径。 - 输出乱码:检查USART2波特率是否与终端一致,以及
fputc重定向是否正确。