设置 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);
    }
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)