LSM303DLHC

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yt454287063/article/details/71305879

(PS:最近在帮人做一个电子罗盘,刚好STM32F429i_DISCO上有个MEMS,但是我自己没有看到底是个什么传感器,搞搞搞了半天,读出来三个数据,但我移动板子时发现数据不对劲,仔细看了看原理图,居然是L3GD20,这是个陀螺仪,顿时感到一阵无语,我记得不错的话,PX4的板子上是有过一个冗余的陀螺仪的,貌似就是这个。相应的PX4原理图上还有一个LSM303D的加速度计+磁传感器,发现这两个都是ST公司的产品,由于最近比较用CUBEMX用的比较爽,对ST公司影响很好,所以果断就是它了。)

首先,果断考虑ST官网的开发套件。

ST官网的开发套件

这个 STEVAL-MKI108V2 看起来就很不错,居然同时装备两个传感器。

STEVAL-MKI108V2

但是往下一看就傻眼了,居然要30刀,我确定我没看错。

30刀

ST公司在和我开玩笑,上某宝搜一下,L3GD20和LSM303D怎么也凑不够30刀。。算了,我还是放弃官方套件吧。

在某报上随便买了一个LSM303D的板子。货到感觉还不错。

开始下载资料。

找到这个像是驱动文件的文件,居然有写驱动,ST公司还是很厚道的嘛。
http://www.st.com/content/st_com/en/products/embedded-software/mems-and-sensors-software/drivers-for-mems/stsw-mems009.html
但是,接下来的事情就很匪夷所思了,一个0kb的文档+一个不知道从什么地方随便拿出来的驱动文件。如下:
http://download.csdn.net/detail/yt454287063/9835449
有总比没有好吧。随便编译一下,出现了连个错误,I2C_BufferReadI2C_ByteWrite 丢失,这好办我就把原来的BSP代码封装一下就行了,但是这个命名规则怎么看都是两个人写的。而且没有一个标准约束。

uint8_t I2C_BufferRead(uint8_t* Data, uint8_t deviceAddress, uint8_t Reg,   uint16_t Length) {
    return I2Cx_ReadBuffer(deviceAddress, Reg, Data, Length);
}

void I2C_ByteWrite(uint8_t *Data, uint8_t deviceAddress, uint8_t WriteAddr) {
    I2Cx_WriteData((uint16_t) deviceAddress, WriteAddr, *Data);
}

总之这个驱动文件已经接入进来了。
参照main函数中的配置方法,照着现有的BSP文件随便写了个初始化函数:

uint8_t BSP_LSM303D_Init(void)
{
    uint8_t ret = LSM303D_OK;
    I2Cx_Init();
    BSP_LCD_SelectLayer(LTDC_LAYER_1);
    BSP_LCD_SetFont(&Font12);
    BSP_LCD_SetTextColor(LCD_COLOR_WHITE);
    BSP_LCD_SetBackColor(LCD_COLOR_BLACK);

    if (BSP_ACC_ReadID() == I_AM_LMS303DLHC) {
        uint8_t response;
        char LCD_Line_Text[34];
        char ACC_Str[3] = "ACC";
        char MAG_Str[3] = "MAG";
        char *Set_ACC_Object[4] = { "SetODR", "SetMode", "SetFullScale", "SetAxis" };
        char *Set_MAG_Object[4] = { "SetODR_M", "SetModeMag", "SetGainMag", "SetTemperature" };
        char *Get_MAG_Object[1] = { "GetTemperature" };
        char *Set_Ret_State[2] = { "NO", "OK" };

        uint8_t Line_Num = 4;
        uint8_t Obje_Num = 0;

        //Set ACC
        //set ODR_ACCELEROMETER (turn ON device)
        sprintf(LCD_Line_Text, "%s %-14s         ...[..]", ACC_Str, Set_ACC_Object[Obje_Num++]);
        BSP_LCD_SetTextColor(LCD_COLOR_WHITE);
        BSP_LCD_DisplayStringAtLine(Line_Num, (uint8_t *) LCD_Line_Text);
        response = SetODR(ODR_25Hz);
        if (response == MEMS_ERROR)
            ret = LSM303D_ERROR;
        BSP_LCD_SetTextColor(response ? LCD_COLOR_GREEN : LCD_COLOR_RED);
        BSP_LCD_DisplayStringAt(31 * 7, LINE(Line_Num++), (uint8_t *) (Set_Ret_State[response]), LEFT_MODE);

        //set PowerMode
        sprintf(LCD_Line_Text, "%s %-14s         ...[..]", ACC_Str, Set_ACC_Object[Obje_Num++]);
        BSP_LCD_SetTextColor(LCD_COLOR_WHITE);
        BSP_LCD_DisplayStringAtLine(Line_Num, (uint8_t *) LCD_Line_Text);
        response = SetMode(NORMAL);
        if (response == MEMS_ERROR)
            ret = LSM303D_ERROR;
        BSP_LCD_SetTextColor(response ? LCD_COLOR_GREEN : LCD_COLOR_RED);
        BSP_LCD_DisplayStringAt(31 * 7, LINE(Line_Num++), (uint8_t *) (Set_Ret_State[response]), LEFT_MODE);

        //set Fullscale
        sprintf(LCD_Line_Text, "%s %-14s         ...[..]", ACC_Str, Set_ACC_Object[Obje_Num++]);
        BSP_LCD_SetTextColor(LCD_COLOR_WHITE);
        BSP_LCD_DisplayStringAtLine(Line_Num, (uint8_t *) LCD_Line_Text);
        response = SetFullScale(FULLSCALE_2);
        if (response == MEMS_ERROR)
            ret = LSM303D_ERROR;
        BSP_LCD_SetTextColor(response ? LCD_COLOR_GREEN : LCD_COLOR_RED);
        BSP_LCD_DisplayStringAt(31 * 7, LINE(Line_Num++), (uint8_t *) (Set_Ret_State[response]), LEFT_MODE);

        //set axis Enable
        sprintf(LCD_Line_Text, "%s %-14s         ...[..]", ACC_Str, Set_ACC_Object[Obje_Num++]);
        BSP_LCD_SetTextColor(LCD_COLOR_WHITE);
        BSP_LCD_DisplayStringAtLine(Line_Num, (uint8_t *) LCD_Line_Text);
        response = SetAxis(X_ENABLE | Y_ENABLE | Z_ENABLE);
        if (response == MEMS_ERROR)
            ret = LSM303D_ERROR;
        BSP_LCD_SetTextColor(response ? LCD_COLOR_GREEN : LCD_COLOR_RED);
        BSP_LCD_DisplayStringAt(31 * 7, LINE(Line_Num++), (uint8_t *) (Set_Ret_State[response]), LEFT_MODE);

        //Set MAG
        Obje_Num = 0;
        //set ODR_MAGNETOMETER (turn ON device)
        sprintf(LCD_Line_Text, "%s %-14s         ...[..]", MAG_Str, Set_MAG_Object[Obje_Num++]);
        BSP_LCD_SetTextColor(LCD_COLOR_WHITE);
        BSP_LCD_DisplayStringAtLine(Line_Num, (uint8_t *) LCD_Line_Text);
        response = SetODR_M(ODR_220Hz_M);
        if (response == MEMS_ERROR)
            ret = LSM303D_ERROR;
        BSP_LCD_SetTextColor(response ? LCD_COLOR_GREEN : LCD_COLOR_RED);
        BSP_LCD_DisplayStringAt(31 * 7, LINE(Line_Num++), (uint8_t *) (Set_Ret_State[response]), LEFT_MODE);

        //set Magnetometer Mode
        sprintf(LCD_Line_Text, "%s %-14s         ...[..]", MAG_Str, Set_MAG_Object[Obje_Num++]);
        BSP_LCD_SetTextColor(LCD_COLOR_WHITE);
        BSP_LCD_DisplayStringAtLine(Line_Num, (uint8_t *) LCD_Line_Text);
        response = SetModeMag(CONTINUOUS_MODE);
        if (response == MEMS_ERROR)
            ret = LSM303D_ERROR;
        BSP_LCD_SetTextColor(response ? LCD_COLOR_GREEN : LCD_COLOR_RED);
        BSP_LCD_DisplayStringAt(31 * 7, LINE(Line_Num++), (uint8_t *) (Set_Ret_State[response]), LEFT_MODE);

        //set Magnetometer Gain     
        sprintf(LCD_Line_Text, "%s %-14s         ...[..]", MAG_Str, Set_MAG_Object[Obje_Num++]);
        BSP_LCD_SetTextColor(LCD_COLOR_WHITE);
        BSP_LCD_DisplayStringAtLine(Line_Num, (uint8_t *) LCD_Line_Text);
        response = SetGainMag(GAIN_450_M);
        if (response == MEMS_ERROR)
            ret = LSM303D_ERROR;
        BSP_LCD_SetTextColor(response ? LCD_COLOR_GREEN : LCD_COLOR_RED);
        BSP_LCD_DisplayStringAt(31 * 7, LINE(Line_Num++), (uint8_t *) (Set_Ret_State[response]), LEFT_MODE);

        //set temperature Enable
        sprintf(LCD_Line_Text, "%s %-14s         ...[..]", MAG_Str, Set_MAG_Object[Obje_Num++]);
        BSP_LCD_SetTextColor(LCD_COLOR_WHITE);
        BSP_LCD_DisplayStringAtLine(Line_Num, (uint8_t *) LCD_Line_Text);
        response = SetTemperature(MEMS_ENABLE);
        if (response == MEMS_ERROR)
            ret = LSM303D_ERROR;
        BSP_LCD_SetTextColor(response ? LCD_COLOR_GREEN : LCD_COLOR_RED);
        BSP_LCD_DisplayStringAt(31 * 7, LINE(Line_Num++), (uint8_t *) (Set_Ret_State[response]), LEFT_MODE);

        //get temperature data value (DegC)
        i16_t temperature = 0;
        sprintf(LCD_Line_Text, "%s %-14s         ...[..]", MAG_Str, Get_MAG_Object[0]);
        BSP_LCD_SetTextColor(LCD_COLOR_WHITE);
        BSP_LCD_DisplayStringAtLine(Line_Num, (uint8_t *) LCD_Line_Text);
        response = GetTempRaw(&temperature);
        if (response == MEMS_ERROR)
            ret = LSM303D_ERROR;
        BSP_LCD_SetTextColor(response ? LCD_COLOR_GREEN : LCD_COLOR_RED);
        BSP_LCD_DisplayStringAt(31 * 7, LINE(Line_Num++), (uint8_t *) (Set_Ret_State[response]), LEFT_MODE);

        sprintf(LCD_Line_Text, "    Temperature: %d *C", temperature);
        BSP_LCD_DisplayStringAtLine(13, (uint8_t *) LCD_Line_Text);

        //get Magnetometer data
        MagAxesRaw_t dataM;
        response = GetMagAxesRaw(&dataM);
        if (response == MEMS_ERROR) {
            BSP_LCD_DisplayStringAtLine(13, "MAG [NODATA]            ...[ERROR]");
            ret = LSM303D_ERROR;
        } else {
            char B[34];
            sprintf(B, "Mag: xM=%5d yM=%5d zM=%5d   ", dataM.AXIS_X, dataM.AXIS_Y, dataM.AXIS_Z);
            BSP_LCD_DisplayStringAtLine(13, (uint8_t *) B);
        }
    }
    return ret;
}

改的像Linux那样启动的过程。看起来很爽。效果也不错。
LSM303D

不得不说,这个磁传感器用起来很方便。暂时放一会也看不到它漂移的。很稳定。

时间 xM yM zM
17:37 8 -3 -4
17:40 8 -3 -4
17:43 8 -3 -4
17:47 8 -3 -4
17:57 8 -3 -4
18:15 8 -3 -4

.

按照它的XYZ大概一个坐标就能出来。
这里抛开Z轴,按照数值,可以大概列出一个XYZ转换为角度的关系,指向北方的时候,

方位 xM yM
8 +0
-6 0
西 0 -8
0 7

果断选用arctan

Angel = atan2(dataM.AXIS_Y, dataM.AXIS_X);

把它打印在屏幕上,通过旋转并观察屏幕上的角度值,要在屏幕上画一条线用来指示方向的话,就有:

      Point_XY.X = (uint16_t)((LCD_XSize / 2) - (LCD_XSize / 2 - 10) * arm_sin_f32(Angel));
      Point_XY.Y = (uint16_t)((LCD_YSize - LCD_XSize / 2) - (LCD_XSize / 2 - 10) * arm_cos_f32(Angel));

完成后看起来很不错:

这里写图片描述

这里写图片描述

这里写图片描述

指向的方向基本是在北面,加还是减去一个小角度就可以消除这个误差。
最后这个罗盘界面看起来比较简单(丑)。不过Embedded Wizard Studio 这个软件应该可以做个漂亮一点的界面,有兴趣的童鞋可以去看看这个软件。

猜你喜欢

转载自blog.csdn.net/yt454287063/article/details/71305879
LSM