(PS:最近在帮人做一个电子罗盘,刚好STM32F429i_DISCO上有个MEMS,但是我自己没有看到底是个什么传感器,搞搞搞了半天,读出来三个数据,但我移动板子时发现数据不对劲,仔细看了看原理图,居然是L3GD20,这是个陀螺仪,顿时感到一阵无语,我记得不错的话,PX4的板子上是有过一个冗余的陀螺仪的,貌似就是这个。相应的PX4原理图上还有一个LSM303D的加速度计+磁传感器,发现这两个都是ST公司的产品,由于最近比较用CUBEMX用的比较爽,对ST公司影响很好,所以果断就是它了。)
首先,果断考虑ST官网的开发套件。
这个 STEVAL-MKI108V2
看起来就很不错,居然同时装备两个传感器。
但是往下一看就傻眼了,居然要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.youkuaiyun.com/detail/yt454287063/9835449
有总比没有好吧。随便编译一下,出现了连个错误,I2C_BufferRead
和I2C_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那样启动的过程。看起来很爽。效果也不错。
不得不说,这个磁传感器用起来很方便。暂时放一会也看不到它漂移的。很稳定。
时间 | 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
这个软件应该可以做个漂亮一点的界面,有兴趣的童鞋可以去看看这个软件。