微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

设置 LIS3DH 以获取 Nucleo L432KC 上的加速度计数据

如何解决设置 LIS3DH 以获取 Nucleo L432KC 上的加速度计数据

我按照这个嵌入式 AI 教程对加速度计数据进行分类https://cartesiam-neai-docs.readthedocs-hosted.com/tutorials/class_multispeed_fan/class_multispeed_fan.html#class-multispeed-fan

它使用 Mbed OS 进行编译,但现在我需要将它移植到 Cube MX 以更进一步(而且我有点不喜欢像 Mbed 这样的黑魔法)。

尽管如此,我必须承认,在本教程中使用 Mbed 非常方便的一件事是加速度计的初始化方式和加速度计数据的读取方式。这正是我不知道如何处理的部分。

硬件: STM32 Nucleo L432KC + LIS3DH(3 轴 MEMS 加速度计)

用于设置和从加速度计获取数据的 Mbed 代码

知道如何将其移植到 Cube MX 以独立于 Mbed 吗?

main.cpp

#include "mbed.h"
#include "LIS3DH.h"

/* Defines -------------------------------------------------------------------*/
#define BUFFER_SIZE     512
#define NB_AXES         3

/* Objects -------------------------------------------------------------------*/
UnbufferedSerial pc (USBTX,USBRX,115200);
I2C lis3dh_i2c (D0,D1); // (I2C_SDA,I2C_SCL)

/* Sampling: 1600 Hz,Sensitivity: 4G */
LIS3DH lis3dh (lis3dh_i2c,LIS3DH_G_CHIP_ADDR,LIS3DH_DR_LP_1R6KHZ,LIS3DH_FS_4G);

/********************** Prototypes **********************/

void init (void);
void fill_acc_array (void);

/* Variables -----------------------------------------------------------------*/
float acc_x,acc_y,acc_z,last_acc_x,last_acc_y,last_acc_z = 0;
float acc_buffer[BUFFER_SIZE * NB_AXES] = {0},lis3dh_xyz[NB_AXES] = {0};


/* BEGIN CODE-----------------------------------------------------------------*/
int main()
{
    /* Initialization */
    init();

    while(1) {
        fill_acc_array();
    }

}

/* Functions deFinition ------------------------------------------------------*/

void init ()
{
    if (lis3dh.read_id() != 0x33) {
        printf("ERROR: Accelerometer not found");
    }
}


/* Code for buiding accelerometer buffers using raw accelerometer data */
void fill_acc_array () // We get 256 samples of acc 3 axes
{
    for (uint16_t i = 0; i < BUFFER_SIZE; i++) {
        if (lis3dh.data_ready()) { // New data is available
            lis3dh.read_data(&lis3dh_xyz[0]);
            acc_buffer[NB_AXES * i] = lis3dh_xyz[0];
            acc_buffer[(NB_AXES * i) + 1] = lis3dh_xyz[1];
            acc_buffer[(NB_AXES * i) + 2] = lis3dh_xyz[2];
        } else {
            i--; // New data not ready
        }
    }
    
    /* Print accelerometer buffer,only for data logging */
    for (uint16_t isample = 0; isample < (NB_AXES * BUFFER_SIZE) - 1; isample++) {
        printf("%.4f ",acc_buffer[isample]);
    }
    printf("%.4f\n",acc_buffer[(NB_AXES * BUFFER_SIZE) - 1]);
}

LIS3DH.h

/*
 * mbed library program
 *  LIS3DH MEMS motion sensor: 3-axis "nano" accelerometer,made by STMicroelectronics
 *      http://www.st-japan.co.jp/web/jp/catalog/sense_power/FM89/SC444/PF250725
 *
 * copyright (c) 2014,'15,'17 Kenji arai / JH1PJL
 *  http://www.page.sannet.ne.jp/kenjia/index.html
 *  http://mbed.org/users/kenjiarai/
 *      Created: July       14th,2014
 *      Revised: August     23rd,2017
 */

#ifndef LIS3DH_H
#define LIS3DH_H

#include "mbed.h"

//  revision 6 have two bugs,(1) read_mg_data,(2) divided by 15 (16 is coorect value)
#define OLD_REV             0       // KEEP 0!! (If you set 1,work as old revision)

//  LIS3DH Address
//  7bit address = 0b001100x(0x18 or 0x19 depends on SA0/SDO)
#define LIS3DH_G_CHIP_ADDR  (0x18 << 1)    // SA0(=SDO pin) = Ground
#define LIS3DH_V_CHIP_ADDR  (0x19 << 1)    // SA0(=SDO pin) = Vdd


//   LIS3DH ID
#define I_AM_LIS3DH            0x33

//  Register's deFinition
#define LIS3DH_STATUS_REG_AUX  0x07
#define LIS3DH_OUT_ADC1_L      0x08
#define LIS3DH_OUT_ADC1_H      0x09
#define LIS3DH_OUT_ADC2_L      0x0a
#define LIS3DH_OUT_ADC2_H      0x0b
#define LIS3DH_OUT_ADC3_L      0x0c
#define LIS3DH_OUT_ADC3_H      0x0d
#define LIS3DH_INT_COUNTER_REG 0x0e
#define LIS3DH_WHO_AM_I        0x0f
#define LIS3DH_TEMP_CFG_REG    0x1f
#define LIS3DH_CTRL_REG1       0x20
#define LIS3DH_CTRL_REG2       0x21
#define LIS3DH_CTRL_REG3       0x22
#define LIS3DH_CTRL_REG4       0x23
#define LIS3DH_CTRL_REG5       0x24
#define LIS3DH_CTRL_REG6       0x25
#define LIS3DH_REFERENCE       0x26
#define LIS3DH_STATUS_REG      0x27
#define LIS3DH_OUT_X_L         0x28
#define LIS3DH_OUT_X_H         0x29
#define LIS3DH_OUT_Y_L         0x2a
#define LIS3DH_OUT_Y_H         0x2b
#define LIS3DH_OUT_Z_L         0x2c
#define LIS3DH_OUT_Z_H         0x2d
#define LIS3DH_FIFO_CTRL_REG   0x2e
#define LIS3DH_FIFO_SRC_REG    0x2f
#define LIS3DH_INT1_CFG        0x30
#define LIS3DH_INT1_SOURCE     0x31
#define LIS3DH_INT1_THS        0x32
#define LIS3DH_INT1_DURATION   0x33
#define LIS3DH_CLICK_CFG       0x38
#define LIS3DH_CLICK_SRC       0x39
#define LIS3DH_CLICK_THS       0x3a
#define LIS3DH_TIME_LIMIT      0x3b
#define LIS3DH_TIME_LATENCY    0x3c
#define LIS3DH_TIME_WINDOW     0x3d

// Output Data Rate (ODR)
#define LIS3DH_DR_PWRDWN       0
#define LIS3DH_DR_NR_LP_1HZ    1
#define LIS3DH_DR_NR_LP_10HZ   2
#define LIS3DH_DR_NR_LP_25HZ   3
#define LIS3DH_DR_NR_LP_50HZ   4
#define LIS3DH_DR_NR_LP_100HZ  5
#define LIS3DH_DR_NR_LP_200HZ  6
#define LIS3DH_DR_NR_LP_400HZ  7
#define LIS3DH_DR_LP_1R6KHZ    8
#define LIS3DH_DR_NR_1R25KHZ   9

// Bandwidth (Low pass)
#define LIS3DH_BW_LOW          0
#define LIS3DH_BW_M_LOW        1
#define LIS3DH_BW_M_HI         2
#define LIS3DH_BW_HI           3

// Low power mode enable/disable
#define LIS3DH_LP_EN           0
#define LIS3DH_LP_dis          1

// Axis control
#define LIS3DH_X_EN            1
#define LIS3DH_X_dis           0
#define LIS3DH_Y_EN            1
#define LIS3DH_Y_dis           0
#define LIS3DH_Z_EN            1
#define LIS3DH_Z_dis           0

// Full Scale
#define LIS3DH_FS_2G           0
#define LIS3DH_FS_4G           1
#define LIS3DH_FS_8G           2
#define LIS3DH_FS_16G          3

// deFinition for Nomalization
#if OLD_REV
#define LIS3DH_SENSITIVITY_2G  (0.001F)
#define LIS3DH_SENSITIVITY_4G  (0.002F)
#define LIS3DH_SENSITIVITY_8G  (0.004F)
#define LIS3DH_SENSITIVITY_16G (0.012F)
#else
#define LIS3DH_SENSITIVITY_2G  1
#define LIS3DH_SENSITIVITY_4G  2
#define LIS3DH_SENSITIVITY_8G  4
#define LIS3DH_SENSITIVITY_16G 12
#endif

//Gravity at Earth's surface in m/s/s
#if OLD_REV
#define GraviTY                (9.80665F)
#else
#define GraviTY                (9.80665F / 1000)
#endif

/** Interface for STMicronics MEMS motion sensor: 3-axis "nano" accelerometer
 *      Chip: LIS3DH
 *
 * @code
 * #include "mbed.h"
 *
 * // I2C Communication
 * LIS3DH acc(p_sda,p_scl,chip_addr,datarate,bandwidth,fullscale);
 * // If you connected I2C line not only this device but also other devices,* //     you need to declare following method.
 * I2C i2c(dp5,dp27);              // SDA,SCL
 * LIS3DH acc(i2c,fullscale);
 *
 * int main() {
 * float f[3];
 *
 *   if (acc.read_id() == I_AM_LIS3DH){
 *      acc.read_data(f);
 *   }
 * }
 * @endcode
 */

class LIS3DH
{
public:
    /** Configure data pin
      * @param data SDA and SCL pins
      * @param device address LIS3DH(SA0=0 or 1),LIS3DH_G_CHIP_ADDR or LIS3DH_V_CHIP_ADDR
      * @param output data rate selection,power down mode,1Hz to 5KHz
      * @param full scale selection,+/-2g to +/-16g
      */
    LIS3DH(PinName p_sda,PinName p_scl,uint8_t addr,uint8_t data_rate,uint8_t fullscale);

    /** Configure data pin
      * @param data SDA and SCL pins
      * @param device address LIS3DH(SA0=0 or 1),LIS3DH_G_CHIP_ADDR or LIS3DH_V_CHIP_ADDR
      * @default output data rate selection = 50Hz
      * @default full scale selection = +/-8g
      */
    LIS3DH(PinName p_sda,uint8_t addr);

    /** Configure data pin (with other devices on I2C line)
      * @param I2C prevIoUs deFinition
      * @param other parameters -> please see LIS3DH(PinName p_sda,...)
      */
    LIS3DH(I2C& p_i2c,uint8_t fullscale);

    /** Configure data pin (with other devices on I2C line)
      * @param I2C prevIoUs deFinition
      * @param other parameters -> please see LIS3DH(PinName p_sda,...)
      * @default output data rate selection = 50Hz
      * @default full scale selection = +/-8g
      */
    LIS3DH(I2C& p_i2c,uint8_t addr);

    /** Read a float type data from acc
      * @param float type of three arry's address,e.g. float dt_usr[3];
      * @return acc motion data unit: m/s/s(m/s2)
      * @return dt_usr[0]->x,dt_usr[1]->y,dt_usr[2]->z
      */
    void read_data(float *dt_usr);

    /** Read a float type data from acc
      * @param float type of three arry's address,e.g. float dt_usr[3];
      * @return acc motion data unit: mg
      * @return dt_usr[0]->x,dt_usr[2]->z
      */
    void read_mg_data(float *dt_usr);

    /** Read a acc ID number
      * @param none
      * @return if STM MEMS acc,it should be I_AM_ LIS3DH(0x33)
      */
    uint8_t read_id();

    /** Read Data Ready flag
      * @param none
      * @return 1 = Ready
      */
    uint8_t data_ready();

    /** Set I2C clock frequency
      * @param freq.
      * @return none
      */
    void frequency(int hz);

    /** Read register (general purpose)
      * @param register's address
      * @return register data
      */
    uint8_t read_reg(uint8_t addr);

    /** Write register (general purpose)
      * @param register's address
      * @param data
      * @return none
      */
    void write_reg(uint8_t addr,uint8_t data);

protected:
    void initialize(uint8_t,uint8_t,uint8_t);
    void read_reg_data(char *data);

    I2C *_i2c_p;
    I2C &_i2c;

private:
#if OLD_REV
    float   fs_factor;  // full scale factor
#else
    uint8_t fs_factor;  // full scale factor
#endif
    char    dt[2];      // working buffer
    uint8_t acc_addr;   // acc sensor address
    uint8_t acc_id;     // acc ID
    uint8_t acc_ready;  // acc is on I2C line = 1,not = 0
};

#endif      // LIS3DH_H

LIS3DH.cpp

/*
 * mbed library program
 *  LIS3DH MEMS motion sensor: 3-axis "nano" accelerometer,2017
 */

#include "LIS3DH.h"

LIS3DH::LIS3DH (PinName p_sda,uint8_t fullscale)
 : _i2c_p(new I2C(p_sda,p_scl)),_i2c(*_i2c_p)
{
    _i2c.frequency(400000);
    initialize (addr,data_rate,fullscale);
}

LIS3DH::LIS3DH (PinName p_sda,uint8_t addr)
 : _i2c_p(new I2C(p_sda,LIS3DH_DR_NR_LP_50HZ,LIS3DH_FS_8G);
}

LIS3DH::LIS3DH (I2C& p_i2c,uint8_t fullscale)
 : _i2c(p_i2c)
{
    _i2c.frequency(400000);
    initialize (addr,fullscale);
}

LIS3DH::LIS3DH (I2C& p_i2c,uint8_t addr)
 : _i2c(p_i2c)
{
    _i2c.frequency(400000);
    initialize (addr,LIS3DH_FS_8G);
}

void LIS3DH::initialize (uint8_t addr,uint8_t fullscale)
{
    // Check acc is available of not
    acc_addr = addr;
    dt[0] = LIS3DH_WHO_AM_I;
    _i2c.write(acc_addr,dt,1,true);
    _i2c.read(acc_addr,false);
    if (dt[0] == I_AM_LIS3DH) {
        acc_ready = 1;
    } else {
        acc_ready = 0;
        return;     // acc chip is NOT on I2C line then terminate
    }
    //  Reg.1
    dt[0] = LIS3DH_CTRL_REG1;
    dt[1] = 0x07;
    dt[1] |= data_rate << 4;
    _i2c.write(acc_addr,2,false);
    //  Reg.4
    dt[0] = LIS3DH_CTRL_REG4;
    dt[1] = 0x08;  // High resolution
    dt[1] |= fullscale << 4;
    _i2c.write(acc_addr,false);
    switch (fullscale) {
        case LIS3DH_FS_2G:
            fs_factor = LIS3DH_SENSITIVITY_2G;
            break;
        case LIS3DH_FS_4G:
            fs_factor = LIS3DH_SENSITIVITY_4G;
            break;
        case LIS3DH_FS_8G:
            fs_factor = LIS3DH_SENSITIVITY_8G;
            break;
        case LIS3DH_FS_16G:
            fs_factor = LIS3DH_SENSITIVITY_16G;
            break;
        default:
            ;
    }
}

void LIS3DH::read_reg_data(char *data)
{
    // X,Y & Z
    // manual said that
    // In order to read multiple bytes,it is necessary to assert the most significant bit
    // of the subaddress field.
    // In other words,SUB(7) must be equal to ‘1’ while SUB(6-0) represents the address
    // of the first register to be read.
    dt[0] = LIS3DH_OUT_X_L | 0x80;
    _i2c.write(acc_addr,data,6,false);
}

void LIS3DH::read_mg_data(float *dt_usr)
{
    char data[6];

    if (acc_ready == 0) {
        dt_usr[0] = 0;
        dt_usr[1] = 0;
        dt_usr[2] = 0;
        return;
    }
    read_reg_data(data);
    // change data type
#if OLD_REV // Fixed bugs -> (1) unit is not mg but g (2) shift right 4bit = /16
    dt_usr[0] = float(short((data[1] << 8) | data[0])) * fs_factor / 15;
    dt_usr[1] = float(short((data[3] << 8) | data[2])) * fs_factor / 15;
    dt_usr[2] = float(short((data[5] << 8) | data[4])) * fs_factor / 15;
#else
    dt_usr[0] = float(short((data[1] << 8) | data[0]) >> 4) * fs_factor;
    dt_usr[1] = float(short((data[3] << 8) | data[2]) >> 4) * fs_factor;
    dt_usr[2] = float(short((data[5] << 8) | data[4]) >> 4) * fs_factor;
#endif
}

void LIS3DH::read_data(float *dt_usr)
{
    char data[6];

    if (acc_ready == 0) {
        dt_usr[0] = 0;
        dt_usr[1] = 0;
        dt_usr[2] = 0;
        return;
    }
    read_reg_data(data);
    // change data type
#if OLD_REV // Fixed bugs -> shift right 4bit = /16 (not /15)
    dt_usr[0] = float(short((data[1] << 8) | data[0])) * fs_factor / 15 * GraviTY;
    dt_usr[1] = float(short((data[3] << 8) | data[2])) * fs_factor / 15 * GraviTY;
    dt_usr[2] = float(short((data[5] << 8) | data[4])) * fs_factor / 15 * GraviTY;
#else
    dt_usr[0] = float(short((data[1] << 8) | data[0]) >> 4) * fs_factor * GraviTY;
    dt_usr[1] = float(short((data[3] << 8) | data[2]) >> 4) * fs_factor * GraviTY;
    dt_usr[2] = float(short((data[5] << 8) | data[4]) >> 4) * fs_factor * GraviTY;
#endif
}

uint8_t LIS3DH::read_id()
{
    dt[0] = LIS3DH_WHO_AM_I;
    _i2c.write(acc_addr,false);
    return (uint8_t)dt[0];
}

uint8_t LIS3DH::data_ready()
{
    if (acc_ready == 1) {
        dt[0] = LIS3DH_STATUS_REG_AUX;
        _i2c.write(acc_addr,true);
        _i2c.read(acc_addr,false);
        if (!(dt[0] & 0x01)) {
            return 0;
        }
    }
    return 1;
}

void LIS3DH::frequency(int hz)
{
    _i2c.frequency(hz);
}

uint8_t LIS3DH::read_reg(uint8_t addr)
{
    if (acc_ready == 1) {
        dt[0] = addr;
        _i2c.write(acc_addr,false);
    } else {
        dt[0] = 0xff;
    }
    return (uint8_t)dt[0];
}

void LIS3DH::write_reg(uint8_t addr,uint8_t data)
{
    if (acc_ready == 1) {
        dt[0] = addr;
        dt[1] = data;
        _i2c.write(acc_addr,false);
    }
}

解决方法

移植到 Cube MX 是什么意思?我的困惑是 Mbed OS 是一个带有构建系统的 RTOS。 Cube MX 只是 STM32 芯片的项目配置器。使用 Cube MX 创建的项目通常使用 STM32CubeIDE 构建。

如果您只想在 IDE 中打开 Mbed OS 项目,您可以export it

假设您想停止使用 Mbed OS,就像您提到的那样,您将失去面向 UART 和 I2C 的简单 API。

切换时,我建议使用 ST Micro 的 IDE:STM32CubeIDE。顾名思义,它集成了 Cube MX 作为项目配置器。

File 下拉菜单中启动 New 项目允许您选择一个 STM32 项目。这将打开 Cube MX 配置器。在那里您选择Board Selector 选项卡并搜索您的 L432KC 板。选择它并按下一步enter image description here 接下来将打开一个窗口,您可以在其中命名您的项目。这是你完成的地方。每次在 Cube MX 中使用电路板而不仅仅是芯片时,您都会看到一个弹出窗口。此弹出窗口将询问您是否要初始化此板上的默认外围设备。我建议你这样做,因为我怀疑你的例子使用了默认的 UART 端口,你必须检查一下。但更重要的是时钟将被正确配置。

下载板级支持包后,您的新项目将打开,Pinout & Configuration 打开。在连接下,您可以选择您想要的外围设备。对于演示,我使用 I2C1 制作了图像,但必须查看您实际使用的代码。接下来,您在 Mode 下拉菜单中激活此 I2C。完成此操作后,配置 部分将显示您可以设置的所有参数。您应该能够在 Mbed 代码中找到它们。 enter image description here

当您保存配置时,CubeMX 会提示您是否要生成“the”代码。这意味着在启动时配置外围设备的代码。实际使用 I2C 的代码您必须自己调用。您可以在以下位置找到 I2C 的函数:Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_i2c.h。在这里,您将找到 HAL_I2C_Master_TransmitHAL_I2C_Slave_Transmit_ITHAL_I2C_Master_Receive_DMA 等函数。您必须自己选择应该使用哪个,具体取决于您是主站(很有可能)还是从站,以及您是否想使用阻塞调用、回调或什至使用 DMA 传输。您应该能够从 MbedOS 代码中找出加速度计的逻辑并将其编写为使用这些 I2C 命令。

提示:检查软件包 X-CUBE-MEMS1 是否支持您的芯片。

main 可以在 Core/Src/main.c

中找到

您可以在新文件夹中添加 AI 源代码并开始移植。我对您在此处使用的库没有具体了解。我希望这对您有所帮助。

附言到目前为止,这个例子是裸机编程(没有操作系统)。如果您有兴趣,可以在 CubeMX 中轻松添加 FreeRTOS。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。