环境配置以及各个物料的使用在开箱帖中记录了,本次主要记录ai训练过程,同时完善了一下传感器的驱动。
训练我使用的是NanoEdge AI Studio。
数据采集
对于电机运行状态我分为停止,高速,低速,异常四个类别,按照NanoEdge AI Studio所要求的数据格式分别对以上几个类别的数据进行采集。
input_signal[signal_index * 3 + 0] = (float)fifo_acc[i * 3 + 0]; // X
input_signal[signal_index * 3 + 1] = (float)fifo_acc[i * 3 + 1]; // Y
input_signal[signal_index * 3 + 2] = (float)fifo_acc[i * 3 + 2]; // Z
printf("%d %d %d ", fifo_acc[i * 3 + 0], fifo_acc[i * 3 + 1], fifo_acc[i * 3 + 2]);
count++;
if(count >= 256)
{
printf("\r\n");
count = 0;
}训练过程
打开软件后,新建工程。本次任务是对电机运行状态进行检测,对电机不同的运行状态进行分类,所以我选择Classify,在下一个界面选择开发板和传感器。选择好以后进入下一个环节,上传先前采集的数据,分好类后就可以进入训练环节了。

等待中
训练好以后进入导出文件环节,这个界面右边有示例代码,可以参考。将导出的.h和.a文件导入工程,按照示例代码进行编写就完成了。
在运行过程中,我的电机驱动是直接写在主函数中,通过延时调速,电机运行时卡卡的,很不丝滑,我修改了一下电机驱动,通过定时器中断触发,这下电机运行起来顺畅很多。
改动后再采集一次数据,重新训练,准确率大幅提高。

主程序代码
/**
******************************************************************************
* file : main.c
* brief : Main program body
* Calls target system initialization then loop in main.
******************************************************************************
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32c5xx_hal_gpio.h"
#include <stdint.h>
#include <stdio.h>
#include "LIS3DHTR.h"
#include "MOTO.h"
#include "NanoEdgeAI.h"
#include <stdbool.h>
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
float input_signal[NEAI_INPUT_SIGNAL_LENGTH * NEAI_INPUT_AXIS_NUMBER]; // Buffer of input values
float probabilities[NEAI_NUMBER_OF_CLASSES]; // Buffer of class probabilities
uint16_t wait = 0;
uint16_t key_num = 0;
#define MAX_FIFO_SAMPLES 32
int16_t fifo_acc[MAX_FIFO_SAMPLES * 3];
uint16_t signal_index = 0; // 当前蓄水池的水位
/* Private functions prototype -----------------------------------------------*/
void HAL_TIM_UpdateCallback(hal_tim_handle_t *htim)
{
if (htim == mx_tim7_gethandle()) {
MOTO_RUN(wait);
}
}
int __io_putchar(int ch)
{
uint8_t byte = (uint8_t)ch;
HAL_UART_Transmit(mx_usart2_uart_gethandle(), &byte, 1, 1000);
return ch;
}
uint16_t KEY_GET(uint16_t key_num)
{
if(HAL_GPIO_ReadPin(HAL_GPIOC, HAL_GPIO_PIN_13) == HAL_GPIO_PIN_SET)
{
HAL_Delay(20);
while(HAL_GPIO_ReadPin(HAL_GPIOC, HAL_GPIO_PIN_13) == HAL_GPIO_PIN_SET);
HAL_Delay(20);
key_num ++;
}
if(key_num > 2)
{
key_num = 0;
}
return key_num;
}
/**
* brief: The application entry point.
* retval: none but we specify int to comply with C99 standard
*/
int main(void)
{
/** System Init: this code placed in targets folder initializes your system.
* It calls the initialization (and sets the initial configuration) of the peripherals.
* You can use STM32CubeMX to generate and call this code or not in this project.
* It also contains the HAL initialization and the initial clock configuration.
*/
if (mx_system_init() != SYSTEM_OK)
{
return (-1);
}
else
{
/*
* You can start your application code here
*/
HAL_TIM_Start_IT(mx_tim7_gethandle());
LIS3DHTR_Init();
enum neai_state error_code = neai_classification_init();
if (error_code != NEAI_OK) {
printf("AI MODEL INIT FAILED\r\n");
/* Check the returned error code (cf NanoEdgeAI.h). */
}
else {
printf("AI MODEL INIT SUCCESS\r\n");
}
int id_class = 0;
uint32_t last_time = HAL_GetTick();
uint16_t key_num = 0;
uint16_t key_num_last = 5;
uint16_t class_count[4] = {0};
uint16_t count = 0;
while (1) {
int16_t acc[3] = {0};
key_num = KEY_GET(key_num);
if ( key_num_last != key_num)
{
key_num_last = key_num;
HAL_TIM_Stop_IT(mx_tim7_gethandle());
HAL_TIM_SetCounter(mx_tim7_gethandle(), 0);
if (key_num == 1)
{
HAL_TIM_SetPeriod(mx_tim7_gethandle(), 0x7CF); // 1 kHz
HAL_TIM_Start_IT(mx_tim7_gethandle());
}
else if (key_num == 2)
{
HAL_TIM_SetPeriod(mx_tim7_gethandle(), 0x4E1F); // 100 Hz
HAL_TIM_Start_IT(mx_tim7_gethandle());
}
else if(key_num == 0)
{
HAL_TIM_Stop_IT(mx_tim7_gethandle());
}
}
int samples_read = LIS3DHTR_Read_FIFO_Data(fifo_acc);
if(samples_read > 0)
{
for (int i = 0; i < samples_read; i++)
{
input_signal[signal_index * 3 + 0] = (float)fifo_acc[i * 3 + 0]; // X
input_signal[signal_index * 3 + 1] = (float)fifo_acc[i * 3 + 1]; // Y
input_signal[signal_index * 3 + 2] = (float)fifo_acc[i * 3 + 2]; // Z
signal_index++;
if(signal_index >= NEAI_INPUT_SIGNAL_LENGTH)
{
signal_index = 0;
neai_classification(input_signal, probabilities, &id_class);
switch (id_class) {
case 0:
printf("STOP\r\n");
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_11, HAL_GPIO_PIN_RESET);
break;
case 1:
printf("LOW\r\n");
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_11, HAL_GPIO_PIN_RESET);
break;
case 2:
printf("FAST\r\n");
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_11, HAL_GPIO_PIN_RESET);
break;
case 3:
printf("ABNORMAL\r\n");
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_11, HAL_GPIO_PIN_SET);
break;
default:
printf("Unknown class\r\n");
break;
}
}
}
}
}
}
} /* end main */电机驱动代码
#include "MOTO.h"
void MOTO_RUN(uint16_t wait)
{
static uint8_t step = 0;
(void)wait;
switch (step)
{
case 0: /* A+ */
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_2, HAL_GPIO_PIN_SET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_3, HAL_GPIO_PIN_RESET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_10, HAL_GPIO_PIN_RESET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_12, HAL_GPIO_PIN_RESET);
break;
case 1: /* A+B+ */
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_2, HAL_GPIO_PIN_SET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_3, HAL_GPIO_PIN_SET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_10, HAL_GPIO_PIN_RESET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_12, HAL_GPIO_PIN_RESET);
break;
case 2: /* B+ */
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_2, HAL_GPIO_PIN_RESET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_3, HAL_GPIO_PIN_SET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_10, HAL_GPIO_PIN_RESET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_12, HAL_GPIO_PIN_RESET);
break;
case 3: /* A-B+ */
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_2, HAL_GPIO_PIN_RESET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_3, HAL_GPIO_PIN_SET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_10, HAL_GPIO_PIN_SET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_12, HAL_GPIO_PIN_RESET);
break;
case 4: /* A- */
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_2, HAL_GPIO_PIN_RESET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_3, HAL_GPIO_PIN_RESET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_10, HAL_GPIO_PIN_SET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_12, HAL_GPIO_PIN_RESET);
break;
case 5: /* A-B- */
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_2, HAL_GPIO_PIN_RESET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_3, HAL_GPIO_PIN_RESET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_10, HAL_GPIO_PIN_SET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_12, HAL_GPIO_PIN_SET);
break;
case 6: /* B- */
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_2, HAL_GPIO_PIN_RESET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_3, HAL_GPIO_PIN_RESET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_10, HAL_GPIO_PIN_RESET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_12, HAL_GPIO_PIN_SET);
break;
default: /* A+B- */
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_2, HAL_GPIO_PIN_SET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_3, HAL_GPIO_PIN_RESET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_10, HAL_GPIO_PIN_RESET);
HAL_GPIO_WritePin(HAL_GPIOC, HAL_GPIO_PIN_12, HAL_GPIO_PIN_SET);
break;
}
step = (uint8_t)((step + 1U) & 0x07U);
}加速度传感器驱动代码.c文件
#include "LIS3DHTR.h"
void LIS3DHTR_Read(uint8_t reg, uint8_t *value, uint8_t len)
{
HAL_I2C_MASTER_MemRead(mx_i2c1_i2c_gethandle(), LIS3DHTR_ADDRESS_UPDATED << 1,
reg, 1, value, len, 100);
}
void LIS3DHTR_Write(uint8_t reg, uint8_t value)
{
HAL_I2C_MASTER_MemWrite(mx_i2c1_i2c_gethandle(), LIS3DHTR_ADDRESS_UPDATED << 1,
reg, 1, &value, 1, 100);
}
void LIS3DHTR_Init(void)
{
uint8_t id = 0;
LIS3DHTR_Read(LIS3DHTR_REG_WHO_AM_I, &id, 1);
if(id != 0x33)
{
return;
}
else
{
LIS3DHTR_Write(LIS3DHTR_REG_CTRL_REG1, 0x97);
LIS3DHTR_Write(LIS3DHTR_REG_CTRL_REG4, 0x88);
LIS3DHTR_Write(LIS3DHTR_REG_CTRL_REG5, 0x40);
LIS3DHTR_Write(LIS3DHTR_REG_FIFO_CTRL_REG, 0x8F);
// LIS3DHTR_Write(LIS3DHTR_REG_FIFO_CTRL_REG, 0xDF);
}
}
// void LIS3DHTR_Read_XYZ(int16_t *acc)
// {
// uint8_t acc_buf[6] = {0};
// LIS3DHTR_Read(0x28 | 0x80, acc_buf, 6); // 自动递增读 6 字节
// acc[0] = (int16_t)(((uint16_t)acc_buf[1] << 8) | acc_buf[0]) >> 4;
// acc[1] = (int16_t)(((uint16_t)acc_buf[3] << 8) | acc_buf[2]) >> 4;
// acc[2] = (int16_t)(((uint16_t)acc_buf[5] << 8) | acc_buf[4]) >> 4;
// }
#define FIFO_SIZE 32
int LIS3DHTR_Read_FIFO_Data(int16_t *fifo_data)
{
uint8_t raw_buf[FIFO_SIZE * 6];
uint8_t fifo_src = 0;
LIS3DHTR_Read(LIS3DHTR_REG_FIFO_SRC_REG, &fifo_src, 1);
uint8_t sample_count = fifo_src & 0x1F;
if (sample_count == 0) {
return 0; // FIFO为空
}
uint8_t read_len = sample_count * 6;
LIS3DHTR_Read(LIS3DHTR_REG_OUT_X_L | 0x80, raw_buf, read_len);
for (int i = 0; i < sample_count; i++)
{
int offset = i * 6;
fifo_data[i*3 + 0] = (int16_t)(((uint16_t)raw_buf[offset+1] << 8) | raw_buf[offset+0]) >> 4; // X
fifo_data[i*3 + 1] = (int16_t)(((uint16_t)raw_buf[offset+3] << 8) | raw_buf[offset+2]) >> 4; // Y
fifo_data[i*3 + 2] = (int16_t)(((uint16_t)raw_buf[offset+5] << 8) | raw_buf[offset+4]) >> 4; // Z
}
return sample_count;
}.h文件
#ifndef LIS3DHTR_H #define LIS3DHTR_H #include "main.h" #define LIS3DHTR_ADDRESS_UPDATED (0x19) #define LIS3DHTR_REG_STATUS_REG (0x07) // Status Register #define LIS3DHTR_REG_WHO_AM_I (0X0F) #define LIS3DHTR_REG_TMEP_CFG_REG (0X1F)//温度使能 #define LIS3DHTR_REG_CTRL_REG0 (0X1E) #define LIS3DHTR_REG_CTRL_REG1 (0X20)//速率,低功耗,XYZ使能 #define LIS3DHTR_REG_CTRL_REG2 (0X21) #define LIS3DHTR_REG_CTRL_REG3 (0X22) #define LIS3DHTR_REG_CTRL_REG4 (0X23)//分辨率 #define LIS3DHTR_REG_CTRL_REG5 (0X24)//FIFO启动 #define LIS3DHTR_REG_CTRL_REG6 (0X25) #define LIS3DHTR_REG_OUT_X_L (0X28) #define LIS3DHTR_REG_OUT_X_H (0X29) #define LIS3DHTR_REG_OUT_Y_L (0X2A) #define LIS3DHTR_REG_OUT_Y_H (0X2B) #define LIS3DHTR_REG_OUT_Z_L (0X2C) #define LIS3DHTR_REG_OUT_Z_H (0X2D) #define LIS3DHTR_REG_FIFO_CTRL_REG (0X2E) #define LIS3DHTR_REG_FIFO_SRC_REG (0X2F) void LIS3DHTR_Read(uint8_t reg, uint8_t *value, uint8_t len); void LIS3DHTR_Write(uint8_t reg, uint8_t value); void LIS3DHTR_Init(void); void LIS3DHTR_Read_XYZ(int16_t *acc); int LIS3DHTR_Read_FIFO_Data(int16_t *fifo_data); #endif /* LIS3DHTR_H */
我要赚赏金
