你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【STM32U3 评测】MNIST 数字识别

[复制链接]
无垠的广袤 发布时间:2026-5-23 21:30

【STM32U3 评测】MNIST 数字识别

本文介绍了 NUCLEO-U3C5ZI-Q 开发板结合 STM32Cube AI Studio 软件和 MNIST 数据集以及 ONNX 预训练模型,实现手写数字识别的项目设计,包括环境搭建、工程创建、关键代码、流程图、效果演示等。

项目介绍

Nucleo-U3C5ZI-Q 开发板实现手写数字识别。

  • 准备工作:环境搭建、STM32Cube AI Studio、硬件连接、模型获取等;
  • 工程创建:流程图、模型转换、工程代码等;
  • 工程测试:工程编译、固件上传、效果演示等。

环境搭建

  • 下载、安装并运行 STM32Cube AI Studio 软件;
  • 进入 Setting 设置标签页,自动安装所需工具,包括 STM32CubeMX、STM32CubeProgrammer、STM32CubeIDE、ST Edge AI Core;

cubeaistudio_setting.jpg

详见:【STM32U3 评测】介绍、环境搭建、工程测试 .

MNIST

Modified National Institute of Standards and Technology (MNIST) 是一个包含手写数字的数据集,里面有上万张数字图片,每张图片都标注了对应的数字标签(0到9)。该数据集可用来训练识别手写数字的神经网络。

mnist.jpg

详见:yann.lecun.com

ONNX

Open Neural Network Exchange (ONNX) 是一个开放的生态系统,为 AI 开发人员提供支持 随着项目的发展选择正确的工具。

onnx.jpg

ONNX 为 AI 模型(包括深度学习和传统 ML)提供开源格式。它定义了一个可扩展的计算图模型,以及内置运算符和标准的定义 数据类型。

详见:onnx/onnx: Open standard for machine learning interoperability .

硬件连接

使用 Type-C 数据线连接开发板和电脑;

hardware_connect.jpg

流程图

flowchart_mnist-print.jpg

工程创建

  • 打开 STM32Cube AI Studio 软件,创建工程,选择空白新工程;

    cubeaistudio_create.jpg

  • 配置工程路径、工作空间,输入目标开发板 NUCLEO-U3C5ZI-Q;

    cubeaistudio_board.jpg

  • 加载目标 mnist-12-int8.onnx 模型文件,验证模型选择 On target ;

    cubeaistudio_model.jpg

  • 点击 Generate 按钮,自动生成代码;

cube-ai-studio_generate.jpg

  • 执行完成后,给出模型参数;

cube-ai-studio_generate_code.jpg

  • 模型转换结果概览;

cube-ai-studio_generate_code_result.jpg

  • 资源占用情况;

cube-ai-studio_generate_code_resource.jpg

  • 内存占用表格

cube-ai-studio_generate_code_memory.jpg

  • 模型可视化

cube-ai-studio_model_visualization.jpg

  • 点击右上角 Generate code 按钮,弹窗勾选 Generate project 选项,生成完整工程;

cube-ai-studio_generate_project.jpg

  • 模型生成并打开文件路径,使用 STM32CubeIDE 加载目标工程;

cube-ai-studio_generate_project_end.jpg

工程代码

使用 STM32CubeIDE 加载生成的数字识别工程;

  • 在左侧工程文件目录,双击打开 AI/APP/app_x-cube-ai.c 文件;

cubeide_app_cubeai.jpg

  • 修改输入数据函数定义,添加 28x28 手写数字图片对应的灰度值数组;
int acquire_and_process_data()
{
  /* USER CODE BEGIN acquire_and_process_data */
  /* fill the inputs of the c-model 
  for (int idx=0; idx < STAI_NETWORK_IN_NUM; idx++ )
  {
      stai_input[idx] = ....
  }
  */
const uint8_t pixel_data[] = {
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,116,125,171,255,255,150, 93,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,169,253,253,253,253,253,253,218, 30,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,169,253,253,253,213,142,176,253,253,122,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0, 52,250,253,210, 32, 12,  0,  6,206,253,140,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0, 77,251,210, 25,  0,  0,  0,122,248,253, 65,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0, 31, 18,  0,  0,  0,  0,209,253,253, 65,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,117,247,253,198, 10,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 76,247,253,231, 63,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,128,253,253,144,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,176,246,253,159, 12,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 25,234,253,233, 35,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,198,253,253,141,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0, 78,248,253,189, 12,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0, 19,200,253,253,141,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,134,253,253,173, 12,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,248,253,253, 25,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,248,253,253, 43, 20, 20, 20, 20,  5,  0,  5, 20, 20, 37,150,150,150,147, 10,  0,
  0,  0,  0,  0,  0,  0,  0,  0,248,253,253,253,253,253,253,253,168,143,166,253,253,253,253,253,253,253,123,  0,
  0,  0,  0,  0,  0,  0,  0,  0,174,253,253,253,253,253,253,253,253,253,253,253,249,247,247,169,117,117, 57,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,118,123,123,123,166,253,253,253,155,123,123, 41,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
};

memcpy((void*)stai_input[0], pixel_data, sizeof(pixel_data));

  return 0;
  /* USER CODE END acquire_and_process_data */
}
  • 修改后处理函数定义,添加输出结果和置信度等相关代码;
int post_process()
{
  /* USER CODE BEGIN post_process */
  /* process the predictions
  for (int idx=0; idx < STAI_NETWORK_OUT_NUM; idx++ )
  {
      stai_output[idx] = ....
  }

  */
    // ===================== 量化模型输出 =====================
      // 部署的 MNIST 是 uint8_t 量化输出(10个值:0~255)
      uint8_t *output = (uint8_t*)stai_output[0];

      // 找最大值
      int max_index = 0;
      uint8_t max_value = output[0];
      for(int i=1; i<10; i++){
          if(output[i] > max_value){
              max_value = output[i];
              max_index = i;
          }
      }
      // 输出 0~9 每个数字的百分比置信度
      for(int i=0; i<10; i++){
          float percent = (output[i] * 100.0f) / 255.0f;  // 转为 0~100%
          if(i == max_index){
              LC_PRINT("  数字 %d:%6.2f %%  ◀ 最高\r\n", i, percent);
          }else{
              LC_PRINT("  数字 %d:%6.2f %%\r\n", i, percent);
          }
      }
      // 串口打印结果
      LC_PRINT("========================================\r\n");
      LC_PRINT("  识别结果: 数字 %d | 置信度: %6.2f %%\r\n", max_index, max_value*100.0f/255.0f);
      LC_PRINT("========================================\r\n\n");

  return 0;
  /* USER CODE END post_process */
}

保存代码。

编译上传

cubeide_build_mnist.jpg

  • 点击上方工具栏的运行按钮,上传固件至开发板并自动运行;

cubeide_mnist_download.jpg

效果演示

  • 运行串口调试助手软件,连接 STLINK-V3 对应的虚拟串口,配置波特率 115200 bps,打开串口;
  • 短按板载复位按键,串口输出数字识别结果、计算时间等信息;

mnist_uart_print_num2.jpg

  • 输出每个数字的置信度

mnist_print_num2.jpg

总结

本文介绍了 NUCLEO-U3C5ZI-Q 开发板结合 STM32Cube AI Studio 软件和 MNIST 数据集以及 ONNX 预训练模型,实现手写数字识别的项目设计,包括环境搭建、工程创建、关键代码、流程图、效果演示等,为相关产品在边缘 AI 领域的快速开发和应用设计提供了参考。

收藏 评论0 发布时间:2026-5-23 21:30

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版