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

基于STM32CubeIDE开发之人工智能开发经验分享(三)

[复制链接]
攻城狮Melo 发布时间:2023-4-3 20:46
一、cube.AI实际项目应用
        接篇二,前文都是采用FP-AI-SENSING1案例和配套的B-L475E-IOT01A开发板来阐述的,而实际项目中,我们都是基于自身项目硬件平台来训练模型及部署模型的,我们仅仅需要cube.AI软件包(作为可调用库)来支持我们项目,不会强行采用FP-AI-SENSING1案例去收集数据及配套的B-L475E-IOT01A等硬件平台部署。

        回顾篇一,ST公司支持到如下图芯片型号,

4d182ddd0de84071bde2da8485c6df8e.png

         在本文中,将采用STM32L496VGT6-ali开发板来部署cube.AI实现人工智能。STM32L496VGT6开发板已经集成了LSM6DSL传感器(三轴加速度计及三轴陀螺仪传感器),项目设想如下:

        1)通过LSM6DSL采集加速度数值(x/y/z三轴加速度)

        2)本文只采集三种姿态(开发板正面朝上,静止不动、左右移动、上下移动三种姿态)时的加速度数值,用来实现分类神经网络,三种姿态作为神经网络模型输出值(分类)

        3)每次输入读取三组加速度值(每组数据是读取x/y/z三轴的三个加速度值),共9个数值作为神经网络模型输入数据

        4)利用STM32L496VGT6开发板上的三个按钮,KEY0为静止不动姿态采集按键,KEY1为左右移动姿态采集按键,KEY2为上下移动姿态采集按键。

        5)通过串口打印输出采集数据信息,并通过串联助手连接获得采集日志并保存成TXT文件

        6)将记录数据文件转换为csv文件,通过keras框架,编写神经网络训练模型python项目,进行神经网络模型训练,并输出.h5训练模型文件

       7)通过cubeMX和cube.AI将h5神经网络模型转换为c语言神经网络模型

        8)将LSM6DSL实时采集数据推送给c语言神经网络模型API,进行神经网络计算,查看输出结果是否符合预期。


二、创建工程
        在CubeIDE上,基于STM32L496VGT6芯片,创建新工程STM32工程,并实现了串口lpuart1调试日志输出,三个按键KEY0~2和三个LED灯LED0~2的功能实现,并实现LSM6DSL传感器采集数据功能(I2C4)

        现给出简要的配置及源码信息:

2.1 工程配置
        1)内核功能配置及RCC开启外部时钟支持

d994c8a337554424af0d57eabf5044ca.png

26da26bb3e50480e9f28ab57a6fdaa51.png

         2)开启LPUART1,并开启其中断支持

b343e2b418f6422eaa8ded4d215b6152.png

787896505721411bbf6e6c7da41c6a4b.png

         3)开启I2C4,并开启其中断功能及DMA功能



1d2aeb0b33bb40228f87c29cf927862a.png

8914a29389b840c0a8f61255753d4753.png

        4)配置GPIO引脚(三个按键及三个LED灯)

f23eb057b9694975aa57d5828b01dca4.png

         5)配置时钟树

8278667ed0234aa99fbfb8084a695ee4.png

         6)引脚视图

f513caf26be4453880b49b01c2cf9012.png

         7)工程配置,选择为每个外设生成独立的.h/.c文件

c5c6284c91c346e29346d06473445297.png

         生成输出代码

2.2 外设代码设计
        禁用syscalls.c文件(右键进入文件属性设置页面)

2062a0cfad8d447c85d42e90adfd4c36.png

        在工程下,创建源目录ICore,在该目录下,如下图所示,创建子目录及外设驱动源文件

28c523d627b94bbf94b1898222a7853f.png

         源码文件内容如下:
        1)key.h
  1. #ifndef KEY_H_
  2. #define KEY_H_

  3. #include "main.h"
  4. #include "gpio.h"

  5. GPIO_PinState get_key0_val();
  6. GPIO_PinState get_key1_val();
  7. GPIO_PinState get_key2_val();

  8. uint8_t KEY_0(void);
  9. uint8_t KEY_1(void);
  10. uint8_t KEY_2(void);

  11. #endif /* KEY_H_ */
复制代码

         key.c
  1. #include "key.h"

  2. GPIO_PinState get_key0_val()
  3. {
  4.         return HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin);
  5. };

  6. GPIO_PinState get_key1_val()
  7. {
  8.         return HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin);
  9. };

  10. GPIO_PinState get_key2_val()
  11. {
  12.         return HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin);
  13. };

  14. uint8_t KEY_0(void)
  15. {
  16.         uint8_t a;
  17.         a=0;//如果未进入按键处理,则返回0
  18.         if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==GPIO_PIN_RESET){//读按键接口的电平
  19.                 HAL_Delay(20);//延时去抖动
  20.                 if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==GPIO_PIN_RESET){ //读按键接口的电平
  21.                         a=1;//进入按键处理,返回1
  22.                 }
  23.         }
  24.         while(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==GPIO_PIN_RESET); //等待按键松开
  25.         return a;
  26. }

  27. uint8_t KEY_1(void)
  28. {
  29.         uint8_t a;
  30.         a=0;//如果未进入按键处理,则返回0
  31.         if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET){//读按键接口的电平
  32.                 HAL_Delay(20);//延时去抖动
  33.                 if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET){ //读按键接口的电平
  34.                         a=1;//进入按键处理,返回1
  35.                 }
  36.         }
  37.         while(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET); //等待按键松开
  38.         return a;
  39. }

  40. uint8_t KEY_2(void)
  41. {
  42.         uint8_t a;
  43.         a=0;//如果未进入按键处理,则返回0
  44.         if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==GPIO_PIN_RESET){//读按键接口的电平
  45.                 HAL_Delay(20);//延时去抖动
  46.                 if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==GPIO_PIN_RESET){ //读按键接口的电平
  47.                         a=1;//进入按键处理,返回1
  48.                 }
  49.         }
  50.         while(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==GPIO_PIN_RESET); //等待按键松开
  51.         return a;
  52. }
复制代码

         2) led.h
  1. #ifndef LED_H_
  2. #define LED_H_
  3. #include "main.h"
  4. #include "gpio.h"

  5. void Toggle_led0();
  6. void Toggle_led1();
  7. void Toggle_led2();

  8. void set_led0_val(GPIO_PinState PinState);
  9. void set_led1_val(GPIO_PinState PinState);
  10. void set_led2_val(GPIO_PinState PinState);

  11. #endif /* LED_H_ */
复制代码

         led.c
  1. #include "led.h"

  2. void Toggle_led0()
  3. {
  4.         HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
  5. }

  6. void Toggle_led1()
  7. {
  8.         HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
  9. }

  10. void Toggle_led2()
  11. {
  12.         HAL_GPIO_TogglePin(LED2_GPIO_Port,LED2_Pin);
  13. }

  14. void set_led0_val(GPIO_PinState PinState)
  15. {
  16.         HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,PinState);
  17. };

  18. void set_led1_val(GPIO_PinState PinState)
  19. {
  20.         HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,PinState);
  21. };

  22. void set_led2_val(GPIO_PinState PinState)
  23. {
  24.         HAL_GPIO_WritePin(LED2_GPIO_Port,LED2_Pin,PinState);
  25. };
复制代码

         3)print.h
  1. #ifndef INC_RETARGET_H_
  2. #define INC_RETARGET_H_

  3. #include "stm32l4xx_hal.h"
  4. #include "stdio.h"//用于printf函数串口重映射
  5. #include <sys/stat.h>

  6. void ResetPrintInit(UART_HandleTypeDef  *huart);

  7. int _isatty(int fd);
  8. int _write(int fd, char* ptr, int len);
  9. int _close(int fd);
  10. int _lseek(int fd, int ptr, int dir);
  11. int _read(int fd, char* ptr, int len);
  12. int _fstat(int fd, struct stat* st);

  13. #endif /* INC_RETARGET_H_ */
复制代码

         print.c
  1. #include <_ansi.h>
  2. #include <_syslist.h>
  3. #include <errno.h>
  4. #include <sys/time.h>
  5. #include <sys/times.h>
  6. #include <limits.h>
  7. #include <signal.h>
  8. #include <stdint.h>
  9. #include <stdio.h>

  10. #include "print.h"

  11. #if !defined(OS_USE_SEMIHOSTING)
  12. #define STDIN_FILENO  0
  13. #define STDOUT_FILENO 1
  14. #define STDERR_FILENO 2

  15. UART_HandleTypeDef *gHuart;

  16. void ResetPrintInit(UART_HandleTypeDef *huart)  {
  17.   gHuart = huart;
  18.   /* Disable I/O buffering for STDOUT  stream, so that
  19.    * chars are sent out as soon as they are  printed. */
  20.   setvbuf(stdout, NULL, _IONBF, 0);
  21. }
  22. int _isatty(int fd) {
  23.   if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO)
  24.     return 1;
  25.   errno = EBADF;
  26.   return 0;
  27. }
  28. int _write(int fd, char* ptr, int len) {
  29.   HAL_StatusTypeDef hstatus;
  30.   if (fd == STDOUT_FILENO || fd ==  STDERR_FILENO) {
  31.     hstatus = HAL_UART_Transmit(gHuart,  (uint8_t *) ptr, len, HAL_MAX_DELAY);
  32.     if (hstatus == HAL_OK)
  33.       return len;
  34.     else
  35.       return EIO;
  36.   }
  37.   errno = EBADF;
  38.   return -1;
  39. }
  40. int _close(int fd) {
  41.   if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO)
  42.     return 0;
  43.   errno = EBADF;
  44.   return -1;
  45. }
  46. int _lseek(int fd, int ptr, int dir) {
  47.   (void) fd;
  48.   (void) ptr;
  49.   (void) dir;
  50.   errno = EBADF;
  51.   return -1;
  52. }
  53. int _read(int fd, char* ptr, int len) {
  54.   HAL_StatusTypeDef hstatus;
  55.   if (fd == STDIN_FILENO) {
  56.     hstatus = HAL_UART_Receive(gHuart,  (uint8_t *) ptr, 1, HAL_MAX_DELAY);
  57.     if (hstatus == HAL_OK)
  58.       return 1;
  59.     else
  60.       return EIO;
  61.   }
  62.   errno = EBADF;
  63.   return -1;
  64. }
  65. int _fstat(int fd, struct stat* st) {
  66.   if (fd >= STDIN_FILENO && fd <=  STDERR_FILENO) {
  67.     st->st_mode = S_IFCHR;
  68.     return 0;
  69.   }
  70.   errno = EBADF;
  71.   return 0;
  72. }

  73. #endif //#if !defined(OS_USE_SEMIHOSTING)
复制代码

        4) usart.h
  1. #ifndef INC_USART_H_
  2. #define INC_USART_H_

  3. #include "stm32l4xx_hal.h" //HAL库文件声明
  4. #include <string.h>//用于字符串处理的库
  5. #include "../print/print.h"//用于printf函数串口重映射

  6. extern UART_HandleTypeDef hlpuart1;//声明LPUSART的HAL库结构体

  7. #define HLPUSART_REC_LEN  256//定义LPUSART最大接收字节数

  8. extern uint8_t  HLPUSART_RX_BUF[HLPUSART_REC_LEN];//接收缓冲,最大HLPUSART_REC_LEN个字节.末字节为换行符
  9. extern uint16_t HLPUSART_RX_STA;//接收状态标记
  10. extern uint8_t HLPUSART_NewData;//当前串口中断接收的1个字节数据的缓存


  11. void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart);//串口中断回调函数声明

  12. #endif /* INC_USART_H_ */
复制代码

        usart.c
  1. #include "usart.h"

  2. uint8_t  HLPUSART_RX_BUF[HLPUSART_REC_LEN];//接收缓冲,最大HLPUSART_REC_LEN个字节.末字节为换行符
  3. /*
  4. * bit15:接收到回车(0x0d)时设置HLPUSART_RX_STA|=0x8000;
  5. * bit14:接收溢出标志,数据超出缓存长度时,设置HLPUSART_RX_STA|=0x4000;
  6. * bit13:预留
  7. * bit12:预留
  8. * bit11~0:接收到的有效字节数目(0~4095)
  9. */
  10. uint16_t HLPUSART_RX_STA=0;接收状态标记//bit15:接收完成标志,bit14:接收到回车(0x0d),bit13~0:接收到的有效字节数目
  11. uint8_t HLPUSART_NewData;//当前串口中断接收的1个字节数据的缓存

  12. void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart)//串口中断回调函数
  13. {
  14.         if(huart ==&hlpuart1)//判断中断来源(串口1:USB转串口)
  15.     {
  16.                 if(HLPUSART_NewData==0x0d){//回车标记
  17.                HLPUSART_RX_STA|=0x8000;//标记接到回车
  18.                 }else{
  19.                         if((HLPUSART_RX_STA&0X0FFF)<HLPUSART_REC_LEN){
  20.                                 HLPUSART_RX_BUF[HLPUSART_RX_STA&0X0FFF]=HLPUSART_NewData; //将收到的数据放入数组
  21.                                 HLPUSART_RX_STA++;  //数据长度计数加1
  22.                         }else{
  23.                                 HLPUSART_RX_STA|=0x4000;//数据超出缓存长度,标记溢出
  24.                         }
  25.         }
  26.        HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData,1); //再开启接收中断
  27.     }
  28. }
复制代码

        5) LSM6DSL.h
  1. #ifndef _LSM6DSL_H_
  2. #define _LSM6DSL_H_

  3. #include "main.h"

  4. void LSM6DSL_init();
  5. //
  6. uint8_t LSM6DSL_acc_st_open(void);
  7. uint8_t LSM6DSL_acc_st_close(void);

  8. uint8_t LSM6DSL_gyro_st_open(void);
  9. uint8_t LSM6DSL_gyro_st_close(void);

  10. uint8_t LSM6DSL_acc_read(int32_t *x_data,int32_t *y_data,int32_t *z_data);
  11. uint8_t LSM6DSL_gyro_read(int32_t *x_data,int32_t *y_data,int32_t *z_data);

  12. #endif /* LSM6DSL_LSM6DSL_H_ */
复制代码

        LSM6DSL.c,实现传感器的ID检验、软重置、模式设置、数据读取及转换功能。
  1. #include <stdio.h>
  2. #include "LSM6DSL.h"

  3. extern I2C_HandleTypeDef hi2c4;

  4. #define LSM6DSL_I2C_ADDR1 (0x6A)
  5. #define LSM6DSL_I2C_ADDR2 (0x6B)
  6. #define LSM6DSL_I2C_ADDR_TRANS(n) ((n) << 1)
  7. #define LSM6DSL_I2C_ADDR LSM6DSL_I2C_ADDR_TRANS(LSM6DSL_I2C_ADDR2)

  8. #define LSM6DSL_ACC_GYRO_FUNC_CFG_ACCESS 0x01
  9. #define LSM6DSL_ACC_GYRO_SENSOR_SYNC_TIME 0x04
  10. #define LSM6DSL_ACC_GYRO_SENSOR_RES_RATIO 0x05
  11. #define LSM6DSL_ACC_GYRO_FIFO_CTRL1 0x06
  12. #define LSM6DSL_ACC_GYRO_FIFO_CTRL2 0x07
  13. #define LSM6DSL_ACC_GYRO_FIFO_CTRL3 0x08
  14. #define LSM6DSL_ACC_GYRO_FIFO_CTRL4 0x09
  15. #define LSM6DSL_ACC_GYRO_FIFO_CTRL5 0x0A
  16. #define LSM6DSL_ACC_GYRO_DRDY_PULSE_CFG_G 0x0B
  17. #define LSM6DSL_ACC_GYRO_INT1_CTRL 0x0D
  18. #define LSM6DSL_ACC_GYRO_INT2_CTRL 0x0E
  19. #define LSM6DSL_ACC_GYRO_WHO_AM_I_REG 0x0F
  20. #define LSM6DSL_ACC_GYRO_CTRL1_XL 0x10
  21. #define LSM6DSL_ACC_GYRO_CTRL2_G 0x11
  22. #define LSM6DSL_ACC_GYRO_CTRL3_C 0x12
  23. #define LSM6DSL_ACC_GYRO_CTRL4_C 0x13
  24. #define LSM6DSL_ACC_GYRO_CTRL5_C 0x14
  25. #define LSM6DSL_ACC_GYRO_CTRL6_C 0x15
  26. #define LSM6DSL_ACC_GYRO_CTRL7_G 0x16
  27. #define LSM6DSL_ACC_GYRO_CTRL8_XL 0x17
  28. #define LSM6DSL_ACC_GYRO_CTRL9_XL 0x18
  29. #define LSM6DSL_ACC_GYRO_CTRL10_C 0x19


  30. #define LSM6DSL_ACC_GYRO_MASTER_CONFIG 0x1A
  31. #define LSM6DSL_ACC_GYRO_WAKE_UP_SRC 0x1B
  32. #define LSM6DSL_ACC_GYRO_TAP_SRC 0x1C
  33. #define LSM6DSL_ACC_GYRO_D6D_SRC 0x1D
  34. #define LSM6DSL_ACC_GYRO_STATUS_REG 0x1E

  35. #define LSM6DSL_ACC_GYRO_OUT_TEMP_L 0x20
  36. #define LSM6DSL_ACC_GYRO_OUT_TEMP_H 0x21
  37. #define LSM6DSL_ACC_GYRO_OUTX_L_G 0x22
  38. #define LSM6DSL_ACC_GYRO_OUTX_H_G 0x23
  39. #define LSM6DSL_ACC_GYRO_OUTY_L_G 0x24
  40. #define LSM6DSL_ACC_GYRO_OUTY_H_G 0x25
  41. #define LSM6DSL_ACC_GYRO_OUTZ_L_G 0x26
  42. #define LSM6DSL_ACC_GYRO_OUTZ_H_G 0x27
  43. #define LSM6DSL_ACC_GYRO_OUTX_L_XL 0x28
  44. #define LSM6DSL_ACC_GYRO_OUTX_H_XL 0x29
  45. #define LSM6DSL_ACC_GYRO_OUTY_L_XL 0x2A
  46. #define LSM6DSL_ACC_GYRO_OUTY_H_XL 0x2B
  47. #define LSM6DSL_ACC_GYRO_OUTZ_L_XL 0x2C
  48. #define LSM6DSL_ACC_GYRO_OUTZ_H_XL 0x2D
  49. #define LSM6DSL_ACC_GYRO_SENSORHUB1_REG 0x2E
  50. #define LSM6DSL_ACC_GYRO_SENSORHUB2_REG 0x2F
  51. #define LSM6DSL_ACC_GYRO_SENSORHUB3_REG 0x30
  52. #define LSM6DSL_ACC_GYRO_SENSORHUB4_REG 0x31
  53. #define LSM6DSL_ACC_GYRO_SENSORHUB5_REG 0x32
  54. #define LSM6DSL_ACC_GYRO_SENSORHUB6_REG 0x33
  55. #define LSM6DSL_ACC_GYRO_SENSORHUB7_REG 0x34
  56. #define LSM6DSL_ACC_GYRO_SENSORHUB8_REG 0x35
  57. #define LSM6DSL_ACC_GYRO_SENSORHUB9_REG 0x36
  58. #define LSM6DSL_ACC_GYRO_SENSORHUB10_REG 0x37
  59. #define LSM6DSL_ACC_GYRO_SENSORHUB11_REG 0x38
  60. #define LSM6DSL_ACC_GYRO_SENSORHUB12_REG 0x39
  61. #define LSM6DSL_ACC_GYRO_FIFO_STATUS1 0x3A
  62. #define LSM6DSL_ACC_GYRO_FIFO_STATUS2 0x3B
  63. #define LSM6DSL_ACC_GYRO_FIFO_STATUS3 0x3C
  64. #define LSM6DSL_ACC_GYRO_FIFO_STATUS4 0x3D
  65. #define LSM6DSL_ACC_GYRO_FIFO_DATA_OUT_L 0x3E
  66. #define LSM6DSL_ACC_GYRO_FIFO_DATA_OUT_H 0x3F
  67. #define LSM6DSL_ACC_GYRO_TIMESTAMP0_REG 0x40
  68. #define LSM6DSL_ACC_GYRO_TIMESTAMP1_REG 0x41
  69. #define LSM6DSL_ACC_GYRO_TIMESTAMP2_REG 0x42

  70. #define LSM6DSL_ACC_GYRO_TIMESTAMP_L 0x49
  71. #define LSM6DSL_ACC_GYRO_TIMESTAMP_H 0x4A

  72. #define LSM6DSL_ACC_GYRO_STEP_COUNTER_L 0x4B
  73. #define LSM6DSL_ACC_GYRO_STEP_COUNTER_H 0x4C

  74. #define LSM6DSL_ACC_GYRO_SENSORHUB13_REG 0x4D
  75. #define LSM6DSL_ACC_GYRO_SENSORHUB14_REG 0x4E
  76. #define LSM6DSL_ACC_GYRO_SENSORHUB15_REG 0x4F
  77. #define LSM6DSL_ACC_GYRO_SENSORHUB16_REG 0x50
  78. #define LSM6DSL_ACC_GYRO_SENSORHUB17_REG 0x51
  79. #define LSM6DSL_ACC_GYRO_SENSORHUB18_REG 0x52

  80. #define LSM6DSL_ACC_GYRO_FUNC_SRC 0x53
  81. #define LSM6DSL_ACC_GYRO_TAP_CFG1 0x58
  82. #define LSM6DSL_ACC_GYRO_TAP_THS_6D 0x59
  83. #define LSM6DSL_ACC_GYRO_INT_DUR2 0x5A
  84. #define LSM6DSL_ACC_GYRO_WAKE_UP_THS 0x5B
  85. #define LSM6DSL_ACC_GYRO_WAKE_UP_DUR 0x5C
  86. #define LSM6DSL_ACC_GYRO_FREE_FALL 0x5D
  87. #define LSM6DSL_ACC_GYRO_MD1_CFG 0x5E
  88. #define LSM6DSL_ACC_GYRO_MD2_CFG 0x5F

  89. #define LSM6DSL_ACC_GYRO_OUT_MAG_RAW_X_L 0x66
  90. #define LSM6DSL_ACC_GYRO_OUT_MAG_RAW_X_H 0x67
  91. #define LSM6DSL_ACC_GYRO_OUT_MAG_RAW_Y_L 0x68
  92. #define LSM6DSL_ACC_GYRO_OUT_MAG_RAW_Y_H 0x69
  93. #define LSM6DSL_ACC_GYRO_OUT_MAG_RAW_Z_L 0x6A
  94. #define LSM6DSL_ACC_GYRO_OUT_MAG_RAW_Z_H 0x6B

  95. #define LSM6DSL_ACC_GYRO_X_OFS_USR 0x73
  96. #define LSM6DSL_ACC_GYRO_Y_OFS_USR 0x74
  97. #define LSM6DSL_ACC_GYRO_Z_OFS_USR 0x75

  98. #define LSM6DSL_CHIP_ID_VALUE (0x6A)

  99. #define LSM6DSL_RESET_VALUE (0x1)
  100. #define LSM6DSL_RESET_MSK (0X1)
  101. #define LSM6DSL_RESET_POS (0)

  102. #define LSM6DSL_ACC_ODR_POWER_DOWN (0X00)
  103. #define LSM6DSL_ACC_ODR_1_6_HZ (0X0B)
  104. #define LSM6DSL_ACC_ODR_12_5_HZ (0x01)
  105. #define LSM6DSL_ACC_ODR_26_HZ (0x02)
  106. #define LSM6DSL_ACC_ODR_52_HZ (0x03)
  107. #define LSM6DSL_ACC_ODR_104_HZ (0x04)
  108. #define LSM6DSL_ACC_ODR_208_HZ (0x05)
  109. #define LSM6DSL_ACC_ODR_416_HZ (0x06)
  110. #define LSM6DSL_ACC_ODR_833_HZ (0x07)
  111. #define LSM6DSL_ACC_ODR_1_66_KHZ (0x08)
  112. #define LSM6DSL_ACC_ODR_3_33_KHZ (0x09)
  113. #define LSM6DSL_ACC_ODR_6_66_KHZ (0x0A)
  114. #define LSM6DSL_ACC_ODR_MSK (0XF0)
  115. #define LSM6DSL_ACC_ODR_POS (4)

  116. #define LSM6DSL_GYRO_ODR_POWER_DOWN (0X00)
  117. #define LSM6DSL_GYRO_ODR_12_5_HZ (0x01)
  118. #define LSM6DSL_GYRO_ODR_26_HZ (0x02)
  119. #define LSM6DSL_GYRO_ODR_52_HZ (0x03)
  120. #define LSM6DSL_GYRO_ODR_104_HZ (0x04)
  121. #define LSM6DSL_GYRO_ODR_208_HZ (0x05)
  122. #define LSM6DSL_GYRO_ODR_416_HZ (0x06)
  123. #define LSM6DSL_GYRO_ODR_833_HZ (0x07)
  124. #define LSM6DSL_GYRO_ODR_1_66_KHZ (0x08)
  125. #define LSM6DSL_GYRO_ODR_3_33_KHZ (0x09)
  126. #define LSM6DSL_GYRO_ODR_6_66_KHZ (0x0A)
  127. #define LSM6DSL_GYRO_ODR_MSK (0XF0)
  128. #define LSM6DSL_GYRO_ODR_POS (4)

  129. #define LSM6DSL_ACC_RANGE_2G (0x0)
  130. #define LSM6DSL_ACC_RANGE_4G (0x2)
  131. #define LSM6DSL_ACC_RANGE_8G (0x3)
  132. #define LSM6DSL_ACC_RANGE_16G (0x1)
  133. #define LSM6DSL_ACC_RANGE_MSK (0X0C)
  134. #define LSM6DSL_ACC_RANGE_POS (2)

  135. #define LSM6DSL_ACC_SENSITIVITY_2G (61)
  136. #define LSM6DSL_ACC_SENSITIVITY_4G (122)
  137. #define LSM6DSL_ACC_SENSITIVITY_8G (244)
  138. #define LSM6DSL_ACC_SENSITIVITY_16G (488)

  139. #define LSM6DSL_GYRO_RANGE_245 (0x0)
  140. #define LSM6DSL_GYRO_RANGE_500 (0x1)
  141. #define LSM6DSL_GYRO_RANGE_1000 (0x2)
  142. #define LSM6DSL_GYRO_RANGE_2000 (0x3)
  143. #define LSM6DSL_GYRO_RANGE_MSK (0X0C)
  144. #define LSM6DSL_GYRO_RANGE_POS (2)

  145. #define LSM6DSL_GYRO_SENSITIVITY_245DPS (8750)
  146. #define LSM6DSL_GYRO_SENSITIVITY_500DPS (17500)
  147. #define LSM6DSL_GYRO_SENSITIVITY_1000DPS (35000)
  148. #define LSM6DSL_GYRO_SENSITIVITY_2000DPS (70000)

  149. #define LSM6DSL_SHIFT_EIGHT_BITS (8)
  150. #define LSM6DSL_16_BIT_SHIFT (0xFF)
  151. #define LSM6DSL_ACC_MUL (1000)
  152. #define LSM6DSL_GYRO_MUL (1)

  153. #define LSM6DSL_ACC_DEFAULT_ODR_100HZ (100)
  154. #define LSM6DSL_GYRO_DEFAULT_ODR_100HZ (100)

  155. #define LSM6DSL_GET_BITSLICE(regvar, bitname) \
  156.     ((regvar & bitname##_MSK) >> bitname##_POS)

  157. #define LSM6DSL_SET_BITSLICE(regvar, bitname, val) \
  158.     ((regvar & ~bitname##_MSK) | ((val << bitname##_POS) & bitname##_MSK))

  159. typedef enum {
  160.     ACC_RANGE_2G,
  161.     ACC_RANGE_4G,
  162.     ACC_RANGE_8G,
  163.     ACC_RANGE_16G,
  164.     ACC_RANGE_6G,
  165.     ACC_RANGE_12G,
  166.     ACC_RANGE_24G,
  167.     ACC_RANGE_100G,
  168.     ACC_RANGE_200G,
  169.     ACC_RANGE_400G,
  170.     ACC_RANGE_MAX
  171. } acc_range_e;

  172. typedef enum {
  173.     GYRO_RANGE_125DPS,
  174.     GYRO_RANGE_250DPS,
  175.     GYRO_RANGE_500DPS,
  176.     GYRO_RANGE_1000DPS,
  177.     GYRO_RANGE_2000DPS,
  178.     GYRO_RANGE_MAX
  179. } gyro_range_e;

  180. static int32_t lsm6dsl_acc_factor[ACC_RANGE_MAX] = {
  181.     LSM6DSL_ACC_SENSITIVITY_2G, LSM6DSL_ACC_SENSITIVITY_4G,
  182.     LSM6DSL_ACC_SENSITIVITY_8G, LSM6DSL_ACC_SENSITIVITY_16G
  183. };
  184. static int32_t lsm6dsl_gyro_factor[GYRO_RANGE_MAX] = {
  185.     0, LSM6DSL_GYRO_SENSITIVITY_245DPS, LSM6DSL_GYRO_SENSITIVITY_500DPS,
  186.     LSM6DSL_GYRO_SENSITIVITY_1000DPS, LSM6DSL_GYRO_SENSITIVITY_2000DPS
  187. };

  188. typedef enum {
  189.     DEV_POWER_OFF = 0,
  190.     DEV_POWER_ON,
  191.     DEV_SLEEP,
  192.     DEV_SUSPEND,
  193.     DEV_DEEP_SUSPEND,
  194. } LSM6DSL_power_mode;

  195. static int32_t cur_acc_factor  = 0;
  196. static int32_t cur_gyro_factor = 0;

  197. uint8_t LSM6DSL_ID_check()
  198. {
  199.         HAL_StatusTypeDef hi2c2_status = 0x00;
  200.         uint8_t addr_val[3] = {LSM6DSL_ACC_GYRO_WHO_AM_I_REG,0x00,LSM6DSL_CHIP_ID_VALUE};
  201.         hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
  202.         if(HAL_OK!=hi2c2_status){
  203.                 printf("get LSM6DSL ID error\r\n");
  204.                 return 1;
  205.         }
  206.         if(addr_val[1]!=addr_val[2]){
  207.                 printf("LSM6DSL validate_id is error\r\n");
  208.                 return 1;
  209.         }
  210.         printf("LSM6DSL_id:%02X\r\n",addr_val[1]);
  211.         return 0;
  212. }

  213. uint8_t LSM6DSL_soft_reset()
  214. {
  215.         HAL_StatusTypeDef hi2c2_status = 0x00;
  216.         /*first read*/
  217.         uint8_t addr_val[2] = {LSM6DSL_ACC_GYRO_CTRL3_C,0x00};
  218.         hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
  219.         if(HAL_OK!=hi2c2_status){
  220.                 printf("get LSM6DSL ACC_GYRO_CTRL3_C error\r\n");
  221.                 return 1;
  222.         }
  223.         printf("LSM6DSL ACC_GYRO_CTRL3_C old:%02X\r\n",addr_val[1]);
  224.         addr_val[1] |= LSM6DSL_RESET_VALUE;
  225.         printf("LSM6DSL ACC_GYRO_CTRL3_C new:%02X\r\n",addr_val[1]);
  226.         hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
  227.         if(HAL_OK!=hi2c2_status){
  228.                 printf("set LSM6DSL ACC_GYRO_CTRL3_C error\r\n");
  229.                 return 1;
  230.         }
  231.         printf("successfully LSM6DSL soft reset\r\n");
  232.         return 0;
  233. }
  234. /*
  235. * 以正数为例,最大可到32767,如果是Accelerometer数据,量程为2g的情况下,
  236. * 32768个刻度,一个刻度代表:2g/32768 = 2000mg/32767 = 0.061035mg
  237. * 例如:如果读出数据为16384,则加速度:16384x0.061035mg = 1000mg = 1g
  238. */
  239. uint8_t LSM6DSL_acc_set_range(uint32_t range)
  240. {
  241.         HAL_StatusTypeDef hi2c2_status = 0x00;
  242.         /*first read*/
  243.         uint8_t addr_val[2] = {LSM6DSL_ACC_GYRO_CTRL1_XL,0x00};
  244.         hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
  245.         if(HAL_OK!=hi2c2_status){
  246.                 printf("get LSM6DSL acc range error\r\n");
  247.                 return 1;
  248.         }
  249.         uint8_t tmp   = 0;
  250.     switch (range) {
  251.             case ACC_RANGE_2G: {
  252.             tmp = LSM6DSL_ACC_RANGE_2G;
  253.         } break;

  254.         case ACC_RANGE_4G: {
  255.             tmp = LSM6DSL_ACC_RANGE_4G;
  256.         } break;

  257.         case ACC_RANGE_8G: {
  258.             tmp = LSM6DSL_ACC_RANGE_8G;
  259.         } break;

  260.         case ACC_RANGE_16G: {
  261.             tmp = LSM6DSL_ACC_RANGE_16G;
  262.         } break;

  263.         default:
  264.             break;
  265.     }
  266.     addr_val[1] = LSM6DSL_SET_BITSLICE(addr_val[1], LSM6DSL_ACC_RANGE, tmp);
  267.     hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
  268.         if(HAL_OK!=hi2c2_status){
  269.                 printf("set LSM6DSL acc range error\r\n");
  270.                 return 1;
  271.         }
  272.         if (range <= ACC_RANGE_16G) {
  273.         cur_acc_factor = lsm6dsl_acc_factor[range];
  274.     }
  275.         printf("successfully LSM6DSL set acc range\r\n");
  276.         return 0;
  277. }

  278. static uint8_t acc_st_lsm6dsl_hz2odr(uint32_t hz)
  279. {
  280.     if (hz > 3330)
  281.         return LSM6DSL_ACC_ODR_6_66_KHZ;
  282.     else if (hz > 1660)
  283.         return LSM6DSL_ACC_ODR_3_33_KHZ;
  284.     else if (hz > 833)
  285.         return LSM6DSL_ACC_ODR_1_66_KHZ;
  286.     else if (hz > 416)
  287.         return LSM6DSL_ACC_ODR_833_HZ;
  288.     else if (hz > 208)
  289.         return LSM6DSL_ACC_ODR_416_HZ;
  290.     else if (hz > 104)
  291.         return LSM6DSL_ACC_ODR_208_HZ;
  292.     else if (hz > 52)
  293.         return LSM6DSL_ACC_ODR_104_HZ;
  294.     else if (hz > 26)
  295.         return LSM6DSL_ACC_ODR_52_HZ;
  296.     else if (hz > 13)
  297.         return LSM6DSL_ACC_ODR_26_HZ;
  298.     else if (hz >= 2)
  299.         return LSM6DSL_ACC_ODR_12_5_HZ;
  300.     else
  301.         return LSM6DSL_ACC_ODR_1_6_HZ;
  302. }

  303. uint8_t LSM6DSL_acc_set_odr(uint32_t hz)
  304. {
  305.         HAL_StatusTypeDef hi2c2_status = 0x00;
  306.         /*first read*/
  307.         uint8_t addr_val[2] = {LSM6DSL_ACC_GYRO_CTRL1_XL,0x00};
  308.         hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
  309.         if(HAL_OK!=hi2c2_status){
  310.                 printf("get LSM6DSL acc odr error\r\n");
  311.                 return 1;
  312.         }
  313.         uint8_t odr   = acc_st_lsm6dsl_hz2odr(hz);
  314.         addr_val[1] = LSM6DSL_SET_BITSLICE(addr_val[1], LSM6DSL_ACC_ODR, odr);
  315.         hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
  316.         if(HAL_OK!=hi2c2_status){
  317.                 printf("set LSM6DSL acc odr error\r\n");
  318.                 return 1;
  319.         }
  320.         printf("successfully LSM6DSL set acc odr\r\n");
  321.         return 0;
  322. }

  323. uint8_t LSM6DSL_acc_power_mode(LSM6DSL_power_mode mode)
  324. {
  325.         HAL_StatusTypeDef hi2c2_status = 0x00;
  326.         /*first read*/
  327.         uint8_t addr_val[2] = {LSM6DSL_ACC_GYRO_CTRL1_XL,0x00};
  328.         hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
  329.         if(HAL_OK!=hi2c2_status){
  330.                 printf("get LSM6DSL acc power_mode error\r\n");
  331.                 return 1;
  332.         }
  333.         switch (mode) {
  334.                 case DEV_POWER_ON: {
  335.                         addr_val[1] = LSM6DSL_SET_BITSLICE(addr_val[1], LSM6DSL_ACC_ODR,LSM6DSL_ACC_ODR_12_5_HZ);
  336.                 }
  337.                 break;
  338.                 case DEV_POWER_OFF: {
  339.                         addr_val[1] = LSM6DSL_SET_BITSLICE(addr_val[1], LSM6DSL_ACC_ODR,LSM6DSL_ACC_ODR_POWER_DOWN);
  340.                 }
  341.                 break;
  342.                 case DEV_SLEEP: {
  343.                         addr_val[1] = LSM6DSL_SET_BITSLICE(addr_val[1], LSM6DSL_ACC_ODR,LSM6DSL_ACC_ODR_12_5_HZ);
  344.                 }
  345.                 break;
  346.                 default:
  347.                         break;
  348.         }
  349.         hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
  350.         if(HAL_OK!=hi2c2_status){
  351.                 printf("set LSM6DSL acc power_mode error\r\n");
  352.                 return 1;
  353.         }
  354.         printf("successfully LSM6DSL acc power_mode\r\n");
  355.         return 0;
  356. }

  357. uint8_t LSM6DSL_acc_st_open(void)
  358. {
  359.         uint8_t ret = 0;

  360.     ret = LSM6DSL_acc_power_mode( DEV_POWER_ON);
  361.     if (ret>0) {
  362.         return ret;
  363.     }

  364.     ret = LSM6DSL_acc_set_range(ACC_RANGE_8G);
  365.     if (ret>0) {
  366.         return ret;
  367.     }

  368.     ret = LSM6DSL_acc_set_odr(LSM6DSL_ACC_DEFAULT_ODR_100HZ);
  369.     if (ret>0) {
  370.         return ret;
  371.     }
  372.     printf("successfully LSM6DSL acc open\r\n");
  373.     return 0;
  374. }

  375. uint8_t LSM6DSL_acc_st_close(void)
  376. {
  377.         uint8_t ret = 0;
  378.     ret = LSM6DSL_acc_power_mode(DEV_POWER_OFF);
  379.     if (ret>0) {
  380.         return ret;
  381.     }
  382.     printf("successfully LSM6DSL acc close\r\n");
  383.     return 0;
  384. }

  385. //LSM6DSL的满刻度加速度范围为±2/±4/±8/±16 g,角速度范围为±125/±250/±500/±1000/±2000 dps。
  386. uint8_t LSM6DSL_gyro_set_range(uint32_t range)
  387. {
  388.         HAL_StatusTypeDef hi2c2_status = 0x00;
  389.         /*first read*/
  390.         uint8_t addr_val[2] = {LSM6DSL_ACC_GYRO_CTRL2_G,0x00};
  391.         hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
  392.         if(HAL_OK!=hi2c2_status){
  393.                 printf("get LSM6DSL gyro range error\r\n");
  394.                 return 1;
  395.         }
  396.         uint8_t tmp   = 0;
  397.         switch (range) {
  398.             case GYRO_RANGE_250DPS: {
  399.             tmp = LSM6DSL_GYRO_RANGE_245;
  400.         } break;

  401.         case GYRO_RANGE_500DPS: {
  402.             tmp = LSM6DSL_GYRO_RANGE_500;
  403.         } break;

  404.         case GYRO_RANGE_1000DPS: {
  405.             tmp = LSM6DSL_GYRO_RANGE_1000;
  406.         } break;

  407.         case GYRO_RANGE_2000DPS: {
  408.             tmp = LSM6DSL_GYRO_RANGE_2000;
  409.         } break;

  410.         default:
  411.             break;
  412.         }
  413.         addr_val[1] = LSM6DSL_SET_BITSLICE(addr_val[1], LSM6DSL_GYRO_RANGE, tmp);
  414.     hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
  415.         if(HAL_OK!=hi2c2_status){
  416.                 printf("set LSM6DSL gyro range error\r\n");
  417.                 return 1;
  418.         }
  419.         if ((range >= GYRO_RANGE_250DPS) && (range <= GYRO_RANGE_2000DPS)) {
  420.         cur_gyro_factor = lsm6dsl_gyro_factor[range];
  421.     }
  422.         printf("successfully LSM6DSL set gyro range\r\n");
  423.         return 0;
  424. }

  425. static uint8_t gyro_st_lsm6dsl_hz2odr(uint32_t hz)
  426. {
  427.     if (hz > 3330)
  428.         return LSM6DSL_GYRO_ODR_6_66_KHZ;
  429.     else if (hz > 1660)
  430.         return LSM6DSL_GYRO_ODR_3_33_KHZ;
  431.     else if (hz > 833)
  432.         return LSM6DSL_GYRO_ODR_1_66_KHZ;
  433.     else if (hz > 416)
  434.         return LSM6DSL_GYRO_ODR_833_HZ;
  435.     else if (hz > 208)
  436.         return LSM6DSL_GYRO_ODR_416_HZ;
  437.     else if (hz > 104)
  438.         return LSM6DSL_GYRO_ODR_208_HZ;
  439.     else if (hz > 52)
  440.         return LSM6DSL_GYRO_ODR_104_HZ;
  441.     else if (hz > 26)
  442.         return LSM6DSL_GYRO_ODR_52_HZ;
  443.     else if (hz > 13)
  444.         return LSM6DSL_GYRO_ODR_26_HZ;
  445.     else
  446.         return LSM6DSL_GYRO_ODR_12_5_HZ;
  447. }

  448. uint8_t LSM6DSL_gyro_set_odr(uint32_t hz)
  449. {
  450.         HAL_StatusTypeDef hi2c2_status = 0x00;
  451.         /*first read*/
  452.         uint8_t addr_val[2] = {LSM6DSL_ACC_GYRO_CTRL2_G,0x00};
  453.         hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
  454.         if(HAL_OK!=hi2c2_status){
  455.                 printf("get LSM6DSL gyro odr error\r\n");
  456.                 return 1;
  457.         }
  458.         uint8_t odr = gyro_st_lsm6dsl_hz2odr(hz);
  459.         addr_val[1] = LSM6DSL_SET_BITSLICE(addr_val[1], LSM6DSL_GYRO_ODR, odr);
  460.         hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
  461.         if(HAL_OK!=hi2c2_status){
  462.                 printf("set LSM6DSL gyro odr error\r\n");
  463.                 return 1;
  464.         }
  465.         printf("successfully LSM6DSL set gyro odr\r\n");
  466.         return 0;
  467. }

  468. uint8_t LSM6DSL_gyro_power_mode(LSM6DSL_power_mode mode)
  469. {
  470.         HAL_StatusTypeDef hi2c2_status = 0x00;
  471.         /*first read*/
  472.         uint8_t addr_val[2] = {LSM6DSL_ACC_GYRO_CTRL2_G,0x00};
  473.         hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
  474.         if(HAL_OK!=hi2c2_status){
  475.                 printf("get LSM6DSL gyro power_mode error\r\n");
  476.                 return 1;
  477.         }
  478.         switch (mode) {
  479.                 case DEV_POWER_ON: {
  480.                         addr_val[1] = LSM6DSL_SET_BITSLICE(addr_val[1], LSM6DSL_GYRO_ODR,LSM6DSL_GYRO_ODR_12_5_HZ);
  481.                         break;
  482.                 }
  483.                 case DEV_POWER_OFF: {
  484.                         addr_val[1] = LSM6DSL_SET_BITSLICE(addr_val[1], LSM6DSL_GYRO_ODR,LSM6DSL_GYRO_ODR_POWER_DOWN);
  485.                         break;
  486.                 }
  487.                 case DEV_SLEEP: {
  488.                         addr_val[1] = LSM6DSL_SET_BITSLICE(addr_val[1], LSM6DSL_GYRO_ODR,LSM6DSL_GYRO_ODR_12_5_HZ);
  489.                         break;
  490.                 }
  491.                 default:
  492.                         break;
  493.         }
  494.         hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
  495.         if(HAL_OK!=hi2c2_status){
  496.                 printf("set LSM6DSL gyro power_mode error\r\n");
  497.                 return 1;
  498.         }
  499.         printf("successfully LSM6DSL gyro power_mode\r\n");
  500.         return 0;
  501. }

  502. uint8_t LSM6DSL_gyro_st_open(void)
  503. {
  504.         uint8_t ret = 0;
  505.     ret        = LSM6DSL_gyro_power_mode(DEV_POWER_ON);
  506.     if (ret>0) {
  507.         return 1;
  508.     }

  509.     ret = LSM6DSL_gyro_set_range(GYRO_RANGE_1000DPS);
  510.     if (ret>0) {
  511.         return 1;
  512.     }

  513.     ret = LSM6DSL_gyro_set_odr(LSM6DSL_GYRO_DEFAULT_ODR_100HZ);
  514.     if (ret>0) {
  515.         return 1;
  516.     }
  517.     printf("successfully LSM6DSL gyro open\r\n");
  518.     return 0;
  519. }

  520. uint8_t LSM6DSL_gyro_st_close(void)
  521. {
  522.         uint8_t ret = 0;
  523.     ret        = LSM6DSL_gyro_power_mode(DEV_POWER_OFF);
  524.     if (ret>0) {
  525.         return 1;
  526.     }
  527.     printf("successfully LSM6DSL gyro close\r\n");
  528.     return 0;
  529. }

  530. void LSM6DSL_init()
  531. {
  532.         if(LSM6DSL_ID_check()>0)
  533.                 return;
  534.         if(LSM6DSL_soft_reset()>0)
  535.                 return;
  536.         if(LSM6DSL_acc_power_mode(DEV_POWER_OFF)>0)
  537.                 return;
  538.         if(LSM6DSL_gyro_power_mode(DEV_POWER_OFF)>0)
  539.                         return;
  540.         printf("successfully LSM6DSL init\r\n");
  541. }

  542. #define DATA_AXIS_X 0
  543. #define DATA_AXIS_Y 1
  544. #define DATA_AXIS_Z 2

  545. uint8_t LSM6DSL_acc_read(int32_t *x_data,int32_t *y_data,int32_t *z_data)
  546. {
  547.         HAL_StatusTypeDef hi2c2_status = 0x00;
  548.         /*read 0X28,0X29,0X2A,0X2B,0X2C,0X2D*/
  549.         uint8_t addr[6] = {LSM6DSL_ACC_GYRO_OUTX_L_XL,LSM6DSL_ACC_GYRO_OUTX_H_XL,
  550.                         LSM6DSL_ACC_GYRO_OUTY_L_XL,LSM6DSL_ACC_GYRO_OUTY_H_XL,
  551.                         LSM6DSL_ACC_GYRO_OUTZ_L_XL,LSM6DSL_ACC_GYRO_OUTZ_H_XL};
  552.         uint8_t val[6] = {0};
  553.         for(uint8_t i=0; i<6; i++){
  554.                 hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,LSM6DSL_I2C_ADDR,addr[i],1,&val[i],1,1000);
  555.                 if(HAL_OK!=hi2c2_status){
  556.                         printf("get LSM6DSL acc_read[0X%02X] error\r\n",addr[i]);
  557.                         return 1;
  558.                 }
  559.         }
  560. //        printf("read acc reg_data 1:%02X, 2:%02X, 3:%02X, 4:%02X, 5:%02X ,6:%02X\r\n"
  561. //                                    ,val[0],val[1],val[2],val[3],val[4],val[5]);
  562.         int32_t data[3] = {0};
  563.         data[DATA_AXIS_X] = (int16_t)((((int16_t)((int8_t)val[1])) << LSM6DSL_SHIFT_EIGHT_BITS) | (val[0]));
  564.         data[DATA_AXIS_Y] = (int16_t)((((int16_t)((int8_t)val[3])) << LSM6DSL_SHIFT_EIGHT_BITS) | (val[2]));
  565.         data[DATA_AXIS_Z] = (int16_t)((((int16_t)((int8_t)val[5])) << LSM6DSL_SHIFT_EIGHT_BITS) | (val[4]));
  566.     if (cur_acc_factor != 0)
  567.     {
  568.         data[DATA_AXIS_X] = (data[DATA_AXIS_X] * cur_acc_factor) / LSM6DSL_ACC_MUL;
  569.         data[DATA_AXIS_Y] = (data[DATA_AXIS_Y] * cur_acc_factor) / LSM6DSL_ACC_MUL;
  570.         data[DATA_AXIS_Z] = (data[DATA_AXIS_Z] * cur_acc_factor) / LSM6DSL_ACC_MUL;
  571.     }
  572. //    printf("read acc cur_acc_factor:%ld, X:%ld,Y:%ld,Z:%ld\r\n"
  573. //                    ,cur_acc_factor,data[0],data[1],data[2]);
  574.     *x_data = data[DATA_AXIS_X];
  575.     *y_data = data[DATA_AXIS_Y];
  576.     *z_data = data[DATA_AXIS_Z];
  577.         return 0;
  578. }

  579. uint8_t LSM6DSL_gyro_read(int32_t *x_data,int32_t *y_data,int32_t *z_data)
  580. {
  581.         HAL_StatusTypeDef hi2c2_status = 0x00;
  582.         /*read 0X22,0X23,0X24,0X25,0X26,0X27*/
  583.         uint8_t addr[6] = {LSM6DSL_ACC_GYRO_OUTX_L_G,LSM6DSL_ACC_GYRO_OUTX_H_G,
  584.                         LSM6DSL_ACC_GYRO_OUTY_L_G,LSM6DSL_ACC_GYRO_OUTY_H_G,
  585.                         LSM6DSL_ACC_GYRO_OUTZ_L_G,LSM6DSL_ACC_GYRO_OUTZ_H_G};
  586.         uint8_t val[6] = {0};
  587.         for(uint8_t i=0; i<6; i++){
  588.                 hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,LSM6DSL_I2C_ADDR,addr[i],1,&val[i],1,1000);
  589.                 if(HAL_OK!=hi2c2_status){
  590.                         printf("get LSM6DSL gyro_read[0X%02X] error\r\n",addr[i]);
  591.                         return 1;
  592.                 }
  593.         }
  594. //        printf("read gyro reg_data 1:%02X, 2:%02X, 3:%02X, 4:%02X, 5:%02X ,6:%02X\r\n"
  595. //                            ,val[0],val[1],val[2],val[3],val[4],val[5]);
  596.         int32_t data[3] = {0};
  597.         data[DATA_AXIS_X] = (int16_t)((((int32_t)((int8_t)val[1])) << LSM6DSL_SHIFT_EIGHT_BITS) | (val[0]));
  598.         data[DATA_AXIS_Y] = (int16_t)((((int32_t)((int8_t)val[3])) << LSM6DSL_SHIFT_EIGHT_BITS) | (val[2]));
  599.         data[DATA_AXIS_Z] = (int16_t)((((int32_t)((int8_t)val[5])) << LSM6DSL_SHIFT_EIGHT_BITS) | (val[4]));

  600.     if (cur_gyro_factor != 0) {
  601.         data[DATA_AXIS_X] = (data[DATA_AXIS_X] * cur_gyro_factor) / LSM6DSL_GYRO_MUL;
  602.         data[DATA_AXIS_Y] = (data[DATA_AXIS_Y] * cur_gyro_factor) / LSM6DSL_GYRO_MUL;
  603.         data[DATA_AXIS_Z] = (data[DATA_AXIS_Z] * cur_gyro_factor) / LSM6DSL_GYRO_MUL;
  604.     }
  605. //    printf("read gyro cur_gyro_factor:%ld, X:%ld,Y:%ld,Z:%ld\r\n"
  606. //                    ,cur_gyro_factor,data[0],data[1],data[2]);
  607.     *x_data = data[DATA_AXIS_X];
  608.     *y_data = data[DATA_AXIS_Y];
  609.     *z_data = data[DATA_AXIS_Z];
  610.         return 0;
  611. }
复制代码

2.3 传感器数据采集与输出源码设计
        在main.c文件中,添加各个外设驱动头文件支持
  1. /* Private includes ----------------------------------------------------------*/
  2. /* USER CODE BEGIN Includes */
  3. #include "../../ICore/key/key.h"
  4. #include "../../ICore/led/led.h"
  5. #include "../../ICore/print/print.h"
  6. #include "../../ICore/usart/usart.h"
  7. #include "../../ICore/LSM6DSL/LSM6DSL.h"
  8. /* USER CODE END Includes */
复制代码

        打印实时采集的三轴加速度信息
  1. /* Private user code ---------------------------------------------------------*/
  2. /* USER CODE BEGIN 0 */
  3. void out_print(int32_t acc_x, int32_t acc_y, int32_t acc_z)
  4. {
  5.         if(acc_x>0)
  6.                 printf("%d.%d, ",(acc_x*98)/10000,((acc_x*98)%10000)/100);
  7.         else
  8.                 printf("%d.%d, ",(acc_x*98)/10000,((-acc_x*98)%10000)/100);
  9.         if(acc_y>0)
  10.                 printf("%d.%d, ",(acc_y*98)/10000,((acc_y*98)%10000)/100);
  11.         else
  12.                 printf("%d.%d, ",(acc_y*98)/10000,((-acc_y*98)%10000)/100);
  13.         if(acc_z>0)
  14.                 printf("%d.%d, ",(acc_z*98)/10000,((acc_z*98)%10000)/100);
  15.         else
  16.                 printf("%d.%d, ",(acc_z*98)/10000,((-acc_z*98)%10000)/100);
  17. }
  18. /* USER CODE END 0 */
复制代码

        在main函数中,初始化各个外设
  1. int main(void)
  2. {
  3.   /* USER CODE BEGIN 1 */
  4.     int32_t acc_x,acc_y,acc_z;
  5.   /* USER CODE END 1 */

  6.   /* MCU Configuration--------------------------------------------------------*/

  7.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  8.   HAL_Init();

  9.   /* USER CODE BEGIN Init */

  10.   /* USER CODE END Init */

  11.   /* Configure the system clock */
  12.   SystemClock_Config();

  13.   /* USER CODE BEGIN SysInit */

  14.   /* USER CODE END SysInit */

  15.   /* Initialize all configured peripherals */
  16.   MX_GPIO_Init();
  17.   MX_DMA_Init();
  18.   MX_I2C4_Init();
  19.   MX_LPUART1_UART_Init();
  20.   /* USER CODE BEGIN 2 */
  21.   ResetPrintInit(&hlpuart1);
  22.   HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断
  23.   HLPUSART_RX_STA = 0;
  24.   //LSM6DSL
  25.   LSM6DSL_init();
  26.   LSM6DSL_acc_st_open();
  27.   acc_x = acc_y = acc_z = 0;
  28.   uint8_t menu = 0;
  29.   uint8_t step_size = 3;
  30.   /* USER CODE END 2 */
复制代码

        在main函数循环体内,实现根据按键采集传感器数据(开发板正面朝上):
        1)保持开发板在桌面不动,按键KEY0按下时,采集静止不动姿态时的三轴加速度,并每采集三次,输出一次姿态结果[1,0,0],再次按下KEY0时停止采集
        2)保持开发板在桌面左右移动,按键KEY1按下时,采集左右移动姿态时的三轴加速度,并每采集三次,输出一次姿态结果[0,1,0],再次按下KEY1时停止采集
        3)保持开发板在桌面上上下移动(垂直方向),按键KEY2按下时,采集左右移动姿态时的三轴加速度,并每采集三次,输出一次姿态结果[0,0,1],再次按下KEY2时停止采集

  1. /* USER CODE BEGIN WHILE */
  2.   while (1)
  3.   {
  4.           if(HLPUSART_RX_STA&0xC000){//溢出或换行,重新开始
  5.                     printf("%.*s\r\n",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);
  6.                     HLPUSART_RX_STA=0;//接收错误,重新开始
  7.                     HAL_Delay(100);//等待
  8.             }
  9.           if(KEY_0())
  10.           {
  11.                   if(menu&0x01)
  12.                           menu &= 0XFE;        //取消静止不动数据刷新
  13.                   else{
  14.                           menu |= 0X01; //开启静止不动数据刷新
  15.                   }
  16.                   menu &= 0XF9; //取消其他数据刷新
  17.           }
  18.           if(KEY_1())
  19.           {
  20.                   if(menu&0x02)
  21.                           menu &= 0XFD;        //取消左右移动数据刷新
  22.                   else{
  23.                           menu |= 0X02; //开启左右移动数据刷新
  24.                   }
  25.                   menu &= 0XFA; //取消其他数据刷新

  26.           }
  27.           if(KEY_2())
  28.           {
  29.                   if(menu&0x04)
  30.                           menu &= 0XFB; //取消上下移动数据刷新
  31.                   else{
  32.                           menu |= 0X04; //开启上下移动数据刷新
  33.                   }
  34.                   menu &= 0XFC;        //取消其他数据刷新

  35.           }
  36.           if(menu&0x01)//静止不动
  37.             {
  38.                   for(uint8_t i =0; i<step_size;i++){
  39.                           LSM6DSL_acc_read(&acc_x,&acc_y,&acc_z);
  40.                           out_print(acc_x,acc_y,acc_z);
  41.                           HAL_Delay(100);//等待
  42.                   }
  43.                           printf("1, 0, 0\r\n");
  44.                           Toggle_led0();
  45.             }
  46.             if(menu&0x02)//左右移动
  47.             {
  48.                   for(uint8_t i =0; i<step_size;i++){
  49.                           LSM6DSL_acc_read(&acc_x,&acc_y,&acc_z);
  50.                           out_print(acc_x,acc_y,acc_z);
  51.                           HAL_Delay(100);//等待
  52.                   }
  53.                     printf("0, 1, 0\r\n");
  54.                     Toggle_led1();
  55.             }
  56.             if(menu&0x04)//上下移动
  57.             {
  58.                   for(uint8_t i =0; i<step_size;i++){
  59.                           LSM6DSL_acc_read(&acc_x,&acc_y,&acc_z);
  60.                           out_print(acc_x,acc_y,acc_z);
  61.                           HAL_Delay(100);//等待
  62.                   }
  63.                     printf("0, 0, 1\r\n");
  64.                     Toggle_led2();
  65.             }
  66.     /* USER CODE END WHILE */
复制代码

2.4 编辑下载程序,采集数据
        编译程序及加载到开发板

53e8d134e31e4867a23b630a29abad1b.png

         打开串口助手,连接开发板,先清空屏幕,然后按上述功能操作进行数据采集,每种姿态采集大概一分钟的数据,完成后保存数据。

8f96c2eb5a0545e8811cb313d9a0c556.png

         创建目录My_HAR_Study,将保存的txt文件拷贝到该目录,并将该文件修改为.csv后缀

c30ad29736a943f1a0fb513bdb31dbb7.png

三、模型训练
        在该目录下,创建myrun.py文件,内容如下:
  1. #模型训练文件 myrun.py 训练 epochs 1000次
  2. # myrun.py
  3. '''
  4. 开发板(正面朝上)姿态检测
  5. 静止不动、左右移动、上下移动

  6. 输入层 -> 隐藏层 -> 输出层
  7. '''

  8. # 导入工具包
  9. import pandas as pd
  10. import numpy as np
  11. from keras.models import Sequential
  12. from keras.layers import Dense, Dropout
  13. from keras.optimizers import SGD

  14. # %% 读取数据
  15. data = pd.read_csv('SaveWindows2023_1_28_16-31-14.csv', sep=',', header=None)
  16. data_x = data.loc[:, 0:8]  # 取1~9列所有数据
  17. data_y = data.loc[:, 9:11]
  18. data_y.astype(int)
  19. #
  20. print("-x-")
  21. print(data_x[0:2])
  22. print("-y-")
  23. print(data_y[0:2])

  24. # %% 建立模型
  25. model = Sequential()
  26. # Dense(64) 是一个具有 64 个隐藏神经元的全连接层。
  27. # 在第一层必须指定所期望的输入数据尺寸:
  28. # 在这里,是一个 9 维的向量。
  29. model.add(Dense(64, activation='relu', input_dim=9))
  30. model.add(Dense(32, activation='relu'))
  31. model.add(Dense(3, activation='softmax'))

  32. sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
  33. model.compile(loss='categorical_crossentropy',
  34.               optimizer=sgd,
  35.               metrics=['accuracy'])

  36. model.fit(data_x, data_y,
  37.           epochs=1000,
  38.           batch_size=72)
  39. score = model.evaluate(data_x, data_y, batch_size=72)

  40. # 保存模型
  41. model.save('myhar.h5')
复制代码

         当前目录启动命令行工具,运行python3 .\myrun.py命令,

1cc36b81279e4591ada532fbccd66940.png

62679aa62de8410f89ac4554db353a67.png

四、cube.AI配置及c模型生成

        回到数据采集工程(stm32L496VGT6_AI),双击.ioc打开cubeMX配置页面。

b63e43167a1241b1984baef9edc3145a.png

         添加my_har模型,选择刚刚生成的keras模型文件(.h5),注意值生成模型,不需要应用程序。

80a0bc25ef004636b99a176c0b701c5b.png

         分析结果显示,模型精度很差,意料之中,毕竟神经网络层只进行了简单设计,实现不了那么复杂姿态识别,但验证模型没有错误,支持转换,可以用来演示完开发流程就OK。

059add4f247d49ad827b603b138402d2.png

         根据分析稍微调整一下heap和stack大小

1a2aaa5163bb46b9b671c91f210a99fe.png

         生成输出代码如下图所示。

3c2b6411cf37402baf22ddef38e2c433.png


五、模型调用及测试
        在项目属性设置页面,开启float支持

bdf96382612c40549ee075820da972b1.png

          在main.c源文件中,添加AI模型库的头文件
  1. /* Private includes ----------------------------------------------------------*/
  2. /* USER CODE BEGIN Includes */
  3. #include <stdlib.h>
  4. #include "../../ICore/key/key.h"
  5. #include "../../ICore/led/led.h"
  6. #include "../../ICore/print/print.h"
  7. #include "../../ICore/usart/usart.h"
  8. #include "../../ICore/LSM6DSL/LSM6DSL.h"
  9. #include "../../X-CUBE-AI/app/my_har.h"
  10. #include "../../X-CUBE-AI/app/my_har_data.h"
  11. /* USER CODE END Includes */
复制代码

        在main.c源文件中,添加AI模型库支持函数
  1. /* Private user code ---------------------------------------------------------*/
  2. /* USER CODE BEGIN 0 */
  3. void out_print(int32_t acc_x, int32_t acc_y, int32_t acc_z)
  4. {
  5.         if(acc_x>0)
  6.                 printf("%d.%d, ",(acc_x*98)/10000,((acc_x*98)%10000)/100);
  7.         else
  8.                 printf("%d.%d, ",(acc_x*98)/10000,((-acc_x*98)%10000)/100);
  9.         if(acc_y>0)
  10.                 printf("%d.%d, ",(acc_y*98)/10000,((acc_y*98)%10000)/100);
  11.         else
  12.                 printf("%d.%d, ",(acc_y*98)/10000,((-acc_y*98)%10000)/100);
  13.         if(acc_z>0)
  14.                 printf("%d.%d, ",(acc_z*98)/10000,((acc_z*98)%10000)/100);
  15.         else
  16.                 printf("%d.%d, ",(acc_z*98)/10000,((-acc_z*98)%10000)/100);
  17. }

  18. /* Global handle to reference the instantiated C-model */
  19. static ai_handle network = AI_HANDLE_NULL;

  20. /* Global c-array to handle the activations buffer */
  21. AI_ALIGNED(32)
  22. static ai_u8 activations[AI_MY_HAR_DATA_ACTIVATIONS_SIZE];

  23. AI_ALIGNED(32)
  24. static ai_float in_data[AI_MY_HAR_IN_1_SIZE];

  25. AI_ALIGNED(32)
  26. static ai_float out_data[AI_MY_HAR_OUT_1_SIZE];

  27. /* Array of pointer to manage the model's input/output tensors */
  28. static ai_buffer *ai_input;
  29. static ai_buffer *ai_output;
  30. static ai_buffer_format fmt_input;
  31. static ai_buffer_format fmt_output;

  32. #define NSIZE 3

  33. void buf_print(void)
  34. {
  35.         printf("in_data:");
  36.         for (int i=0; i<AI_MY_HAR_IN_1_SIZE; i++)
  37.         {
  38.                 printf("%.2f ",((ai_float*)in_data)[i]);
  39.         }
  40.         printf("\n");
  41.         printf("out_data:");
  42.         for (int i=0; i<AI_MY_HAR_OUT_1_SIZE; i++)
  43.         {
  44.                 printf("%.2f ",((ai_float*)out_data)[i]);
  45.         }
  46.         printf("\n");
  47. }

  48. void aiPrintBufInfo(const ai_buffer *buffer)
  49. {
  50.         printf("(%lu, %lu, %lu, %lu)", AI_BUFFER_SHAPE_ELEM(buffer, AI_SHAPE_BATCH),
  51.                                                                                      AI_BUFFER_SHAPE_ELEM(buffer, AI_SHAPE_HEIGHT),
  52.                                          AI_BUFFER_SHAPE_ELEM(buffer, AI_SHAPE_WIDTH),
  53.                                          AI_BUFFER_SHAPE_ELEM(buffer, AI_SHAPE_CHANNEL));
  54.         printf(" buffer_size:%d ", (int)AI_BUFFER_SIZE(buffer));
  55. }

  56. void aiPrintDataType(const ai_buffer_format fmt)
  57. {
  58.     if (AI_BUFFER_FMT_GET_TYPE(fmt) == AI_BUFFER_FMT_TYPE_FLOAT)
  59.             printf("float%d ", (int)AI_BUFFER_FMT_GET_BITS(fmt));
  60.     else if (AI_BUFFER_FMT_GET_TYPE(fmt) == AI_BUFFER_FMT_TYPE_BOOL) {
  61.             printf("bool%d ", (int)AI_BUFFER_FMT_GET_BITS(fmt));
  62.     } else { /* integer type */
  63.             printf("%s%d ", AI_BUFFER_FMT_GET_SIGN(fmt)?"i":"u",
  64.             (int)AI_BUFFER_FMT_GET_BITS(fmt));
  65.     }
  66. }

  67. void aiPrintDataInfo(const ai_buffer *buffer,const ai_buffer_format fmt)
  68. {
  69.           if (buffer->data)
  70.                   printf(" @0x%X/%d \n",
  71.                 (int)buffer->data,
  72.                 (int)AI_BUFFER_BYTE_SIZE(AI_BUFFER_SIZE(buffer), fmt)
  73.             );
  74.           else
  75.                   printf(" (User Domain)/%d \n",
  76.                 (int)AI_BUFFER_BYTE_SIZE(AI_BUFFER_SIZE(buffer), fmt)
  77.             );
  78. }

  79. void aiPrintNetworkInfo(const ai_network_report report)
  80. {
  81.         printf("Model name      : %s\n", report.model_name);
  82.         printf(" model signature : %s\n", report.model_signature);
  83.         printf(" model datetime     : %s\r\n", report.model_datetime);
  84.         printf(" compile datetime   : %s\r\n", report.compile_datetime);
  85.         printf(" runtime version    : %d.%d.%d\r\n",
  86.               report.runtime_version.major,
  87.               report.runtime_version.minor,
  88.               report.runtime_version.micro);
  89.         if (report.tool_revision[0])
  90.                 printf(" Tool revision      : %s\r\n", (report.tool_revision[0])?report.tool_revision:"");
  91.         printf(" tools version      : %d.%d.%d\r\n",
  92.               report.tool_version.major,
  93.               report.tool_version.minor,
  94.               report.tool_version.micro);
  95.         printf(" complexity         : %lu MACC\r\n", (unsigned long)report.n_macc);
  96.         printf(" c-nodes            : %d\r\n", (int)report.n_nodes);

  97.         printf(" map_activations    : %d\r\n", report.map_activations.size);
  98.           for (int idx=0; idx<report.map_activations.size;idx++) {
  99.               const ai_buffer *buffer = &report.map_activations.buffer[idx];
  100.               printf("  [%d] ", idx);
  101.               aiPrintBufInfo(buffer);
  102.               printf("\r\n");
  103.           }

  104.         printf(" map_weights        : %d\r\n", report.map_weights.size);
  105.           for (int idx=0; idx<report.map_weights.size;idx++) {
  106.               const ai_buffer *buffer = &report.map_weights.buffer[idx];
  107.               printf("  [%d] ", idx);
  108.               aiPrintBufInfo(buffer);
  109.               printf("\r\n");
  110.           }
  111. }

  112. /*
  113. * Bootstrap
  114. */
  115. int aiInit(void) {
  116.   ai_error err;

  117.   /* Create and initialize the c-model */
  118.   const ai_handle acts[] = { activations };
  119.   err = ai_my_har_create_and_init(&network, acts, NULL);
  120.   if (err.type != AI_ERROR_NONE) {
  121.           printf("ai_error_type:%d,ai_error_code:%d\r\n",err.type,err.code);
  122.   };

  123.   ai_network_report report;
  124.   if (ai_my_har_get_report(network, &report) != true) {
  125.       printf("ai get report error\n");
  126.       return -1;
  127.   }

  128.   aiPrintNetworkInfo(report);

  129.   /* Reteive pointers to the model's input/output tensors */
  130.   ai_input = ai_my_har_inputs_get(network, NULL);
  131.   ai_output = ai_my_har_outputs_get(network, NULL);
  132.   //
  133.   fmt_input = AI_BUFFER_FORMAT(ai_input);
  134.   fmt_output = AI_BUFFER_FORMAT(ai_output);

  135.   printf(" n_inputs/n_outputs : %u/%u\r\n", report.n_inputs,
  136.             report.n_outputs);
  137.   printf("input :");
  138.   aiPrintBufInfo(ai_input);
  139.   aiPrintDataType(fmt_input);
  140.   aiPrintDataInfo(ai_input, fmt_input);
  141.   //
  142.   printf("output :");
  143.   aiPrintBufInfo(ai_output);
  144.   aiPrintDataType(fmt_output);
  145.   aiPrintDataInfo(ai_output, fmt_output);
  146.   return 0;
  147. }

  148. int acquire_and_process_data(void *in_data,uint8_t index, int32_t acc_x, int32_t acc_y, int32_t acc_z)
  149. {
  150.         char buf_srt[64]={0};
  151.         if(acc_x>0){
  152.                 sprintf(buf_srt,"%d.%d, ",(acc_x*98)/10000,((acc_x*98)%10000)/100);
  153.                 ((ai_float*)in_data)[NSIZE*index] =(float)atof(buf_srt);
  154.         }else{
  155.                 sprintf(buf_srt,"%d.%d, ",(acc_x*98)/10000,((-acc_x*98)%10000)/100);
  156.                 ((ai_float*)in_data)[NSIZE*index] =(float)atof(buf_srt);
  157.         }
  158.         if(acc_y>0){
  159.                 sprintf(buf_srt,"%d.%d, ",(acc_y*98)/10000,((acc_y*98)%10000)/100);
  160.                 ((ai_float*)in_data)[NSIZE*index+1] =(float)atof(buf_srt);
  161.         }else{
  162.                 sprintf(buf_srt,"%d.%d, ",(acc_y*98)/10000,((-acc_y*98)%10000)/100);
  163.                 ((ai_float*)in_data)[NSIZE*index+1] =(float)atof(buf_srt);
  164.         }
  165.         if(acc_z>0){
  166.                 sprintf(buf_srt,"%d.%d, ",(acc_z*98)/10000,((acc_z*98)%10000)/100);
  167.                 ((ai_float*)in_data)[NSIZE*index+2] =(float)atof(buf_srt);
  168.         }else{
  169.                 sprintf(buf_srt,"%d.%d, ",(acc_z*98)/10000,((-acc_z*98)%10000)/100);
  170.                 ((ai_float*)in_data)[NSIZE*index+2] =(float)atof(buf_srt);
  171.         }
  172.         return 0;
  173. }
  174. /*
  175. * Run inference
  176. */
  177. int aiRun(const void *in_data, void *out_data) {
  178.   ai_i32 n_batch;
  179.   ai_error err;

  180.   /* 1 - Update IO handlers with the data payload */
  181.   ai_input[0].data = AI_HANDLE_PTR(in_data);
  182.   ai_output[0].data = AI_HANDLE_PTR(out_data);

  183.   /* 2 - Perform the inference */
  184.   n_batch = ai_my_har_run(network, &ai_input[0], &ai_output[0]);
  185.   if (n_batch != 1) {
  186.           err = ai_my_har_get_error(network);
  187.           printf("ai_error_type:%d,ai_error_code:%d\r\n",err.type,err.code);
  188.   };

  189.   return 0;
  190. }

  191. /* USER CODE END 0 */
复制代码

        在main函数中初始化ai模型
  1. /* USER CODE BEGIN 2 */
  2.   ResetPrintInit(&hlpuart1);
  3.   HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断
  4.   HLPUSART_RX_STA = 0;
  5.   //LSM6DSL
  6.   LSM6DSL_init();
  7.   LSM6DSL_acc_st_open();
  8.   acc_x = acc_y = acc_z = 0;
  9.   uint8_t menu = 0;
  10.   uint8_t step_size = NSIZE;
  11.   //
  12.   aiInit();
  13.   buf_print();
  14.   /* USER CODE END 2 */
复制代码

        在main函数循环体中,通过串口lpuart1调试发送test,开启将实时数据推送给ai模型
  1.   /* Infinite loop */
  2.   /* USER CODE BEGIN WHILE */
  3.   while (1)
  4.   {
  5.           if(HLPUSART_RX_STA&0xC000){//溢出或换行,重新开始
  6.                     printf("%.*s\r\n",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);
  7.                   if(strstr((const char*)HLPUSART_RX_BUF,(const char*)"test"))
  8.                   {
  9.                         menu = 0x08;
  10.                   }
  11.                     HLPUSART_RX_STA=0;//接收错误,重新开始
  12.                     HAL_Delay(100);//等待
  13.             }
  14.           if(KEY_0())
  15.           {
  16.                   if(menu&0x01)
  17.                           menu &= 0XFE;        //取消静止不动数据刷新
  18.                   else{
  19.                           menu |= 0X01; //开启静止不动数据刷新
  20.                   }
  21.                   menu &= 0XF9; //取消其他数据刷新
  22.           }
  23.           if(KEY_1())
  24.           {
  25.                   if(menu&0x02)
  26.                           menu &= 0XFD;        //取消左右移动数据刷新
  27.                   else{
  28.                           menu |= 0X02; //开启左右移动数据刷新
  29.                   }
  30.                   menu &= 0XFA; //取消其他数据刷新

  31.           }
  32.           if(KEY_2())
  33.           {
  34.                   if(menu&0x04)
  35.                           menu &= 0XFB; //取消上下移动数据刷新
  36.                   else{
  37.                           menu |= 0X04; //开启上下移动数据刷新
  38.                   }
  39.                   menu &= 0XFC;        //取消其他数据刷新

  40.           }
  41.           if(menu&0x01)//静止不动
  42.             {
  43.                   for(uint8_t i =0; i<step_size;i++){
  44.                           LSM6DSL_acc_read(&acc_x,&acc_y,&acc_z);
  45.                           out_print(acc_x,acc_y,acc_z);
  46.                           HAL_Delay(100);//等待
  47.                   }
  48.                           printf("1, 0, 0\r\n");
  49.                           Toggle_led0();
  50.             }
  51.             if(menu&0x02)//左右移动
  52.             {
  53.                   for(uint8_t i =0; i<step_size;i++){
  54.                           LSM6DSL_acc_read(&acc_x,&acc_y,&acc_z);
  55.                           out_print(acc_x,acc_y,acc_z);
  56.                           HAL_Delay(100);//等待
  57.                   }
  58.                     printf("0, 1, 0\r\n");
  59.                     Toggle_led1();
  60.             }
  61.             if(menu&0x04)//上下移动
  62.             {
  63.                   for(uint8_t i =0; i<step_size;i++){
  64.                           LSM6DSL_acc_read(&acc_x,&acc_y,&acc_z);
  65.                           out_print(acc_x,acc_y,acc_z);
  66.                           HAL_Delay(100);//等待
  67.                   }
  68.                     printf("0, 0, 1\r\n");
  69.                     Toggle_led2();
  70.             }
  71.             if(menu&0x08)//测试
  72.             {
  73.                   for(uint8_t i =0; i<step_size;i++){
  74.                           LSM6DSL_acc_read(&acc_x,&acc_y,&acc_z);
  75.                           acquire_and_process_data(in_data,i,acc_x,acc_y,acc_z);
  76.                           HAL_Delay(100);//等待
  77.                   }
  78.                   aiRun(in_data, out_data);
  79.                   buf_print();
  80.             }
  81.     /* USER CODE END WHILE */
复制代码

        编译及下载程序

8dd3fe13cad84691bb3147a1fa74e7e2.png

         串口助手通过lpuart1连接开发板,发送“test”,开启AI计算,静止不动开发板情况如下:

7b89aa3c842a423f96797a33a5675007.png

         左右移动开发板测试输出:

3485cd2c17dc40c39b3e9fe04aa8a9f0.png

         上下移动(垂直方向)开发板测试输出:

d643661039ca4585a52ae0b426e5793c.png

        通过测试可以看出,基本能识别开发板的行为,若需要更准确的识别,更好数据采集方法,也可以更多姿态行为模式计算(开发板不同朝向、倾斜度等)
————————————————
版权声明:py_free-物联智能
如有侵权请联系删除

a9c9b6b9b7064dad91153cac8262d575.png
收藏 1 评论0 发布时间:2023-4-3 20:46

举报

0个回答

所属标签

相似分享

官网相关资源

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