2025 Make Blocks第三期阶段2 - IMU设计
该项目使用了Kicad软件和stm32f103cb微控制器,实现了IMU的设计,它的主要功能为:3轴加速度,三轴陀螺仪,温湿度气压的测量,可通过MCU采集后通过CAN总线输出或者通过LCD显示或者直接通过IIC接口输出。。
标签
KiCad
MakeBlocks
wswsr
更新2025-10-24
66
KiCad文件
全屏

任务介绍

这里实现了3轴加速度,三轴陀螺仪,温湿度气压的测量,可通过MCU采集后通过CAN总线输出或者通过LCD显示或者直接通过IIC接口输出。

模块介绍

根据任务要求本次我选用的是STM32F103CBT6芯片设计了一款USB转换器,此板卡主要用于USB转换成IIC/SPI/UART/485/CAN/SWD信号,并可生成3路时钟信号,常用于电路模块的采集和调试。

STM32f103CBT6芯片DigiKey链接:STM32F103CBT6 STMicroelectronics | 集成电路(IC) | DigiKey

XC6206P332MR芯片DigiKey链接:XC6206P332MR-G Torex Semiconductor Ltd | 集成电路(IC) | DigiKey

BMI088芯片DigiKey链接:BMI088 Bosch Sensortec | 传感器,变送器 | DigiKey

BME280芯片DigiKey链接:BME280 Bosch Sensortec | 传感器,变送器 | DigiKey

原理图/PCB和3D图

这块板卡想实现常用IMU功能和温湿度气压的采集,能当作可以独立使用显示的模块,也可以通过Can总线接口输出,还可以当作IIC接口模块,一版多用,方便使用。电源采用USB供电,或者锂电池供电,可自由切换。每个接口做了ESD防护,主要是防止用手接触时静电损伤芯片。采用了BME280芯片实现温湿度气压测量,使用BMI088实现三轴陀螺仪和加速度测量,使用HMC5883L用作磁测量。

image.png

顶层原理图

image.png

电源模块

image.png

IMU模块

image.png

MCU模块

image.png

PCB

image.png

3D效果图

实物图

这个板子尺寸只有5*4cm,只做了一板。上面的器件是自己焊接的,有一处选型失误,磁力计封装太小了,手工根本没办法焊接,只能放弃这个功能了。

模块主要性能指标和管脚定义

主要性能指标

核心芯片:STM32F103CBT6,BMI088,BME280,HMC5883L

内核:CM-3

主频:72M

板卡尺寸:40mm*38mm

供电方式:USB

输出接口:IIC/CAN

主控芯片管脚定义

IIC接口:

IIC_SCL--PB10

IIC_SDA--PB11

CAN接口:

CAN_TX--PB9

CAN_RX--PB8

USB接口:

USB_DP--PA12

USB_DM--PA11

单片机调试接口SWD

SWDIO--PA13

SWCLK--PA14

SWO--PB3

调试软件和代码

主要代码有4大块,1是实现USB虚拟串口,能进行串口调试。这部分网上很多内容,不在描述。

第二部分,是U8G2驱动库的移植,这部分网上很多内容,不在描述。

第三部分是传感器驱动。通过模拟IIC实现了对BME280 温湿度气压传感器的数据采集和BMI088加速度计传感器的采集。

第四部分就是传感器数据的解析。

主要代码如下:


#include "delay.h"
#include "sys.h"
#include "stm32_u8g2.h"
#include "test.h"
#include "usart.h"
#include "usb_lib.h"
#include "hw_config.h"
#include "usb_pwr.h"
#include "imu.h"
#include "bmi08_defs.h"
#include "stm32f10x.h"
#include "math.h"
int8_t rslt;
struct bmi08_sensor_data bmi08_accel = {0,0,0};
uint8_t data = 0;
int count2=0;
int init_flag=0;

/*! Earth's gravity in m/s^2 */
#define GRAVITY_EARTH (9.80665f)
/*!
* @brief This function converts lsb to meter per second squared for 16 bit accelerometer at
* range 2G, 4G, 8G or 16G.
*/
static float lsb_to_mps2(int16_t val, int8_t g_range, uint8_t bit_width)
{
double power = 2;

float half_scale = (float)((pow((double)power, (double)bit_width) / 2.0f));

return (GRAVITY_EARTH * val * g_range) / half_scale;
}

/*!
* @brief This function converts lsb to degree per second for 16 bit gyro at
* range 125, 250, 500, 1000 or 2000dps.
*/
static float lsb_to_dps(int16_t val, float dps, uint8_t bit_width)
{
double power = 2;

float half_scale = (float)((pow((double)power, (double)bit_width) / 2.0f));

return (dps / (half_scale)) * (val);
}

void PC13_14_15_Gpio(void){
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO,ENABLE );
PWR_BackupAccessCmd( ENABLE );/* 允许修改RTC和后备寄存器*/
RCC_LSEConfig( RCC_LSE_OFF ); /* 关闭外部低速时钟,PC14+PC15可以用作普通IO*/

GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);

PWR_BackupAccessCmd(DISABLE);/* 禁止修改RTC和后备寄存器*/
}

int main(void)
{
u16 t;
u16 len;
u16 times=0;
u8 usbstatus=0;

float bme280_temp;
uint32_t bme280_press;
float bme280_humi;
u8g2_t u8g2;
struct bme280_calib_data calib_data;
struct bme280_data comp_data;
float x = 0.0, y = 0.0, z = 0.0;
delay_init();
delay_ms(100);

PC13_14_15_Gpio();
GPIO_SetBits(GPIOC,GPIO_Pin_15);
delay_ms(1000);
GPIO_ResetBits(GPIOC,GPIO_Pin_15);
delay_ms(1000);

IIC_GPIO_Init();
u8g2Init(&u8g2);

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200

Set_USBClock();
USB_Port_Set(0); //USB先断开
delay_ms(700);
USB_Port_Set(1); //USB再次连接
USB_Interrupts_Config();
USB_Init();
BME280_GPIO_Init();
if(BME280_CHIP_ID == BEM280_ReadID())
{
u8g2_ClearBuffer(&u8g2);
u8g2_DrawStr(&u8g2,0, 14, "BME280 Found!");
u8g2_SendBuffer(&u8g2);
}

BEM280_Reset();
BEM280_Init();
BME280_GetCali(&calib_data);
if(0X1E == BMI088a_ReadID())
{
u8g2_ClearBuffer(&u8g2);
u8g2_DrawStr(&u8g2,0, 14, "BMI088a Found!");
u8g2_SendBuffer(&u8g2);
usb_printf("BMI088a found\r\n\r\n");//插入换行
}
BMI088a_Reset();
BMI088a_Init();
BMI088a_GetData(&bmi08_accel);
/* Converting lsb to meter per second squared for 16 bit accelerometer at 24G range. */

x = lsb_to_mps2(bmi08_accel.x, 6, 16);
y = lsb_to_mps2(bmi08_accel.y, 6, 16);
z = lsb_to_mps2(bmi08_accel.z, 6, 16);
//usb_printf("%5d,%5d,%5d, %4.2f, %4.2f, %4.2f\n",bmi08_accel.x,bmi08_accel.y,bmi08_accel.z,x,y,z);
usb_printf("X轴:%4.2f,Y轴:%4.2f,Z轴:%4.2f\n",x,y,z);
usb_printf("\r\n\r\n");//插入换行


if(BMI08_GYRO_CHIP_ID == BMI088g_ReadID())
{
u8g2_ClearBuffer(&u8g2);
u8g2_DrawStr(&u8g2,0, 14, "BMI088g Found!");
u8g2_SendBuffer(&u8g2);
usb_printf("BMI088g found\r\n\r\n");//插入换行
}
while(1)
{
u8g2_FirstPage(&u8g2);

if(usbstatus!=bDeviceState)//USB连接状态发生了改变.
{
usbstatus=bDeviceState;//记录新的状态
if(usbstatus==CONFIGURED)
{
u8g2_ClearBuffer(&u8g2);
u8g2_DrawStr(&u8g2,0, 14, "USB Connected ");
u8g2_SendBuffer(&u8g2);
delay_ms(500);
}else
{
u8g2_ClearBuffer(&u8g2);
u8g2_DrawStr(&u8g2,0, 14, "USB Disconnected ");//提示USB断开
u8g2_SendBuffer(&u8g2);
delay_ms(500);
}
}
if(USB_USART_RX_STA&0x8000)
{
len=USB_USART_RX_STA&0x3FFF;//得到此次接收到的数据长度
usb_printf("\r\n您发送的消息为:%d\r\n\r\n",len);
for(t=0;t<len;t++)
{
USB_USART_SendData(USB_USART_RX_BUF[t]);//以字节方式,发送给USB
}
usb_printf("\r\n\r\n");//插入换行
USB_USART_RX_STA=0;
}else
{
times++;
if(times%2==0)
{
BEM280_GetData(&comp_data,&calib_data);
bme280_temp = comp_data.temperature/100.0;
bme280_press = comp_data.pressure;
bme280_humi = comp_data.humidity/1000.0;
usb_printf("温度:%.2f,压力:%d,湿度:%.3f",bme280_temp,bme280_press,bme280_humi);
usb_printf("\r\n\r\n");//插入换行

BMI088a_GetData(&bmi08_accel);
/* Converting lsb to meter per second squared for 16 bit accelerometer at 24G range. */
x = lsb_to_mps2(bmi08_accel.x, 6, 16);
y = lsb_to_mps2(bmi08_accel.y, 6, 16);
z = lsb_to_mps2(bmi08_accel.z, 6, 16);
usb_printf("X轴:%4.2f,Y轴:%4.2f,Z轴:%4.2f\n",x,y,z);
usb_printf("\r\n\r\n");//插入换行

}
if(times > 1000) times = 0;
delay_ms(300);
}
}
}

//IMU.C
#include "delay.h"
#include "imu.h"
#include "bmi08_defs.h"
/************************************************
读取BME280的角度(模拟I2C)
PB10--SCL
PB11--SDA
************************************************/


static void IIC_Start(void);
static void IIC_Stop(void);
static u8 IIC_Wait_Ack(void);
static void IIC_Ack(void);
static void IIC_NAck(void);
static void IIC_Send_Byte(u8 txd);
static u8 IIC_Read_Byte(u8 ack);
static u8 BME280_ReadOneByte(u8 addr);
static void BME280_WriteOneByte(u8 addr,u8 data);
static u8 BMI088a_ReadOneByte(u8 addr);
static u8 BMI088g_ReadOneByte(u8 addr);
static void BMI088a_WriteOneByte(u8 addr,u8 data);
static void BMI088g_WriteOneByte(u8 addr,u8 data);
static void parse_temp_press_calib_data(const uint8_t *reg_data, struct bme280_calib_data *calib_data);
static void parse_humidity_calib_data(const uint8_t *reg_data, struct bme280_calib_data *calib_data);
static void parse_sensor_data(const uint8_t *reg_data, struct bme280_uncomp_data *uncomp_data);
static int32_t compensate_temperature(const struct bme280_uncomp_data *uncomp_data,
struct bme280_calib_data *calib_data);
static uint32_t compensate_pressure(const struct bme280_uncomp_data *uncomp_data,
const struct bme280_calib_data *calib_data);
static uint32_t compensate_humidity(const struct bme280_uncomp_data *uncomp_data,
const struct bme280_calib_data *calib_data);
static int8_t bme280_compensate_data(const struct bme280_uncomp_data *uncomp_data,
struct bme280_data *comp_data,
struct bme280_calib_data *calib_data);
void BME280_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
GPIO_InitStructure.GPIO_Pin = BME280_SDA_Pin|BME280_SCL_Pin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(IIC_GPIO_Port, &GPIO_InitStructure);
}
/***************************************************************************/
static void IIC_Start(void)
{
IIC_SDA_1;
IIC_SCL_1;
delay_us(20);
IIC_SDA_0;
delay_us(20);
IIC_SCL_0;
delay_us(10);
}
/***************************************************************************/
static void IIC_Stop(void)
{
IIC_SCL_0;
IIC_SDA_0;
delay_us(20);
IIC_SCL_1;
delay_us(20);
IIC_SDA_1;
delay_us(10);
}
/***************************************************************************/
//1-fail,0-success
static u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;

SDA_IN();
IIC_SDA_1;
IIC_SCL_1;
delay_us(10);
while(READ_SDA!=0)
{
if(++ucErrTime>250)
{
SDA_OUT();
IIC_Stop();
return 1;
}
}
SDA_OUT();
IIC_SCL_0;
return 0;
}
/***************************************************************************/
static void IIC_Ack(void)
{
IIC_SCL_0;
IIC_SDA_0;
delay_us(20);
IIC_SCL_1;
delay_us(20);
IIC_SCL_0;
}
/***************************************************************************/
static void IIC_NAck(void)
{
IIC_SCL_0;
IIC_SDA_1;
delay_us(20);
IIC_SCL_1;
delay_us(20);
IIC_SCL_0;
}
/***************************************************************************/
static void IIC_Send_Byte(u8 txd)
{
u32 i;

IIC_SCL_0;
for(i=0;i<8;i++)
{
if((txd&0x80)!=0)IIC_SDA_1;
else
IIC_SDA_0;
txd<<=1;
delay_us(20);
IIC_SCL_1;
delay_us(20);
IIC_SCL_0;
delay_us(20);
}
}
/***************************************************************************/
static u8 IIC_Read_Byte(u8 ack)
{
u8 i,rcv=0;

SDA_IN();
for(i=0;i<8;i++)
{
IIC_SCL_0;
delay_us(20);
IIC_SCL_1;
rcv<<=1;
if(READ_SDA!=0)rcv++;
delay_us(10);
}
SDA_OUT();
if(!ack)IIC_NAck();
else
IIC_Ack();
return rcv;
}
/***************************************************************************/
static u8 BME280_ReadOneByte(u8 addr)
{
u8 temp;

IIC_Start();
IIC_Send_Byte(BME280_Address<<1);
IIC_Wait_Ack();
IIC_Send_Byte(addr);
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte((BME280_Address<<1)+1);
IIC_Wait_Ack();
temp=IIC_Read_Byte(0);
IIC_NAck();
IIC_Stop();

return temp;
}
static void BME280_WriteOneByte(u8 addr,u8 data)
{
IIC_Start();
IIC_Send_Byte(BME280_Address<<1);
IIC_Wait_Ack();
IIC_Send_Byte(addr);
IIC_Wait_Ack();
IIC_Send_Byte(data);
IIC_Wait_Ack();
IIC_Stop();
}

static u8 BMI088a_ReadOneByte(u8 addr)
{
u8 temp;

IIC_Start();
IIC_Send_Byte(BMI08_ACCEL_I2C_ADDR_PRIMARY<<1);
IIC_Wait_Ack();
IIC_Send_Byte(addr);
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte((BMI08_ACCEL_I2C_ADDR_PRIMARY<<1)+1);
IIC_Wait_Ack();
temp=IIC_Read_Byte(0);
IIC_NAck();
IIC_Stop();

return temp;
}
static u8 BMI088g_ReadOneByte(u8 addr)
{
u8 temp;

IIC_Start();
IIC_Send_Byte(BMI08_GYRO_I2C_ADDR_PRIMARY<<1);
IIC_Wait_Ack();
IIC_Send_Byte(addr);
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte((BMI08_GYRO_I2C_ADDR_PRIMARY<<1)+1);
IIC_Wait_Ack();
temp=IIC_Read_Byte(0);
IIC_NAck();
IIC_Stop();

return temp;
}
static void BMI088a_WriteOneByte(u8 addr,u8 data)
{
IIC_Start();
IIC_Send_Byte(BMI08_ACCEL_I2C_ADDR_PRIMARY<<1);
IIC_Wait_Ack();
IIC_Send_Byte(addr);
IIC_Wait_Ack();
IIC_Send_Byte(data);
IIC_Wait_Ack();
IIC_Stop();
}
static void BMI088g_WriteOneByte(u8 addr,u8 data)
{
IIC_Start();
IIC_Send_Byte(BMI08_GYRO_I2C_ADDR_PRIMARY<<1);
IIC_Wait_Ack();
IIC_Send_Byte(addr);
IIC_Wait_Ack();
IIC_Send_Byte(data);
IIC_Wait_Ack();
IIC_Stop();
}
/******************************BME280**************************************/
static void parse_temp_press_calib_data(const uint8_t *reg_data, struct bme280_calib_data *calib_data)
{
calib_data->dig_t1 = BME280_CONCAT_BYTES(reg_data[1], reg_data[0]);
calib_data->dig_t2 = (int16_t)BME280_CONCAT_BYTES(reg_data[3], reg_data[2]);
calib_data->dig_t3 = (int16_t)BME280_CONCAT_BYTES(reg_data[5], reg_data[4]);
calib_data->dig_p1 = BME280_CONCAT_BYTES(reg_data[7], reg_data[6]);
calib_data->dig_p2 = (int16_t)BME280_CONCAT_BYTES(reg_data[9], reg_data[8]);
calib_data->dig_p3 = (int16_t)BME280_CONCAT_BYTES(reg_data[11], reg_data[10]);
calib_data->dig_p4 = (int16_t)BME280_CONCAT_BYTES(reg_data[13], reg_data[12]);
calib_data->dig_p5 = (int16_t)BME280_CONCAT_BYTES(reg_data[15], reg_data[14]);
calib_data->dig_p6 = (int16_t)BME280_CONCAT_BYTES(reg_data[17], reg_data[16]);
calib_data->dig_p7 = (int16_t)BME280_CONCAT_BYTES(reg_data[19], reg_data[18]);
calib_data->dig_p8 = (int16_t)BME280_CONCAT_BYTES(reg_data[21], reg_data[20]);
calib_data->dig_p9 = (int16_t)BME280_CONCAT_BYTES(reg_data[23], reg_data[22]);
calib_data->dig_h1 = reg_data[25];
}
/*!
* @brief This internal API is used to parse the humidity calibration data
* and store it in device structure.
*/
static void parse_humidity_calib_data(const uint8_t *reg_data, struct bme280_calib_data *calib_data)
{
int16_t dig_h4_lsb;
int16_t dig_h4_msb;
int16_t dig_h5_lsb;
int16_t dig_h5_msb;

calib_data->dig_h2 = (int16_t)BME280_CONCAT_BYTES(reg_data[1], reg_data[0]);
calib_data->dig_h3 = reg_data[2];
dig_h4_msb = (int16_t)(int8_t)reg_data[3] * 16;
dig_h4_lsb = (int16_t)(reg_data[4] & 0x0F);
calib_data->dig_h4 = dig_h4_msb | dig_h4_lsb;
dig_h5_msb = (int16_t)(int8_t)reg_data[5] * 16;
dig_h5_lsb = (int16_t)(reg_data[4] >> 4);
calib_data->dig_h5 = dig_h5_msb | dig_h5_lsb;
calib_data->dig_h6 = (int8_t)reg_data[6];
}

/*!
* @brief This API is used to parse the pressure, temperature and
* humidity data and store it in the bme280_uncomp_data structure instance.
*/
static void parse_sensor_data(const uint8_t *reg_data, struct bme280_uncomp_data *uncomp_data)
{
/* Variables to store the sensor data */
uint32_t data_xlsb;
uint32_t data_lsb;
uint32_t data_msb;

/* Store the parsed register values for pressure data */
data_msb = (uint32_t)reg_data[0] << BME280_12_BIT_SHIFT;
data_lsb = (uint32_t)reg_data[1] << BME280_4_BIT_SHIFT;
data_xlsb = (uint32_t)reg_data[2] >> BME280_4_BIT_SHIFT;
uncomp_data->pressure = data_msb | data_lsb | data_xlsb;

/* Store the parsed register values for temperature data */
data_msb = (uint32_t)reg_data[3] << BME280_12_BIT_SHIFT;
data_lsb = (uint32_t)reg_data[4] << BME280_4_BIT_SHIFT;
data_xlsb = (uint32_t)reg_data[5] >> BME280_4_BIT_SHIFT;
uncomp_data->temperature = data_msb | data_lsb | data_xlsb;

/* Store the parsed register values for humidity data */
data_msb = (uint32_t)reg_data[6] << BME280_8_BIT_SHIFT;
data_lsb = (uint32_t)reg_data[7];
uncomp_data->humidity = data_msb | data_lsb;
}

/*!
* @brief This internal API is used to compensate the raw temperature data and
* return the compensated temperature data in integer data type.
*/
static int32_t compensate_temperature(const struct bme280_uncomp_data *uncomp_data,
struct bme280_calib_data *calib_data)
{
int32_t var1;
int32_t var2;
int32_t temperature;
int32_t temperature_min = -4000;
int32_t temperature_max = 8500;

var1 = (int32_t)((uncomp_data->temperature / 8) - ((int32_t)calib_data->dig_t1 * 2));
var1 = (var1 * ((int32_t)calib_data->dig_t2)) / 2048;
var2 = (int32_t)((uncomp_data->temperature / 16) - ((int32_t)calib_data->dig_t1));
var2 = (((var2 * var2) / 4096) * ((int32_t)calib_data->dig_t3)) / 16384;
calib_data->t_fine = var1 + var2;
temperature = (calib_data->t_fine * 5 + 128) / 256;

if (temperature < temperature_min)
{
temperature = temperature_min;
}
else if (temperature > temperature_max)
{
temperature = temperature_max;
}

return temperature;
}
/*!
* @brief This internal API is used to compensate the raw humidity data and
* return the compensated humidity data in integer data type.
*/
static uint32_t compensate_humidity(const struct bme280_uncomp_data *uncomp_data,
const struct bme280_calib_data *calib_data)
{
int32_t var1;
int32_t var2;
int32_t var3;
int32_t var4;
int32_t var5;
uint32_t humidity;
uint32_t humidity_max = 102400;

var1 = calib_data->t_fine - ((int32_t)76800);
var2 = (int32_t)(uncomp_data->humidity * 16384);
var3 = (int32_t)(((int32_t)calib_data->dig_h4) * 1048576);
var4 = ((int32_t)calib_data->dig_h5) * var1;
var5 = (((var2 - var3) - var4) + (int32_t)16384) / 32768;
var2 = (var1 * ((int32_t)calib_data->dig_h6)) / 1024;
var3 = (var1 * ((int32_t)calib_data->dig_h3)) / 2048;
var4 = ((var2 * (var3 + (int32_t)32768)) / 1024) + (int32_t)2097152;
var2 = ((var4 * ((int32_t)calib_data->dig_h2)) + 8192) / 16384;
var3 = var5 * var2;
var4 = ((var3 / 32768) * (var3 / 32768)) / 128;
var5 = var3 - ((var4 * ((int32_t)calib_data->dig_h1)) / 16);
var5 = (var5 < 0 ? 0 : var5);
var5 = (var5 > 419430400 ? 419430400 : var5);
humidity = (uint32_t)(var5 / 4096);

if (humidity > humidity_max)
{
humidity = humidity_max;
}

return humidity;
}
/*!
* @brief This internal API is used to compensate the raw pressure data and
* return the compensated pressure data in integer data type.
*/
static uint32_t compensate_pressure(const struct bme280_uncomp_data *uncomp_data,
const struct bme280_calib_data *calib_data)
{
int32_t var1;
int32_t var2;
int32_t var3;
int32_t var4;
uint32_t var5;
uint32_t pressure;
uint32_t pressure_min = 30000;
uint32_t pressure_max = 110000;

var1 = (((int32_t)calib_data->t_fine) / 2) - (int32_t)64000;
var2 = (((var1 / 4) * (var1 / 4)) / 2048) * ((int32_t)calib_data->dig_p6);
var2 = var2 + ((var1 * ((int32_t)calib_data->dig_p5)) * 2);
var2 = (var2 / 4) + (((int32_t)calib_data->dig_p4) * 65536);
var3 = (calib_data->dig_p3 * (((var1 / 4) * (var1 / 4)) / 8192)) / 8;
var4 = (((int32_t)calib_data->dig_p2) * var1) / 2;
var1 = (var3 + var4) / 262144;
var1 = (((32768 + var1)) * ((int32_t)calib_data->dig_p1)) / 32768;

/* Avoid exception caused by division by zero */
if (var1)
{
var5 = (uint32_t)((uint32_t)1048576) - uncomp_data->pressure;
pressure = ((uint32_t)(var5 - (uint32_t)(var2 / 4096))) * 3125;

if (pressure < 0x80000000)
{
pressure = (pressure << 1) / ((uint32_t)var1);
}
else
{
pressure = (pressure / (uint32_t)var1) * 2;
}

var1 = (((int32_t)calib_data->dig_p9) * ((int32_t)(((pressure / 8) * (pressure / 8)) / 8192))) / 4096;
var2 = (((int32_t)(pressure / 4)) * ((int32_t)calib_data->dig_p8)) / 8192;
pressure = (uint32_t)((int32_t)pressure + ((var1 + var2 + calib_data->dig_p7) / 16));

if (pressure < pressure_min)
{
pressure = pressure_min;
}
else if (pressure > pressure_max)
{
pressure = pressure_max;
}
}
else
{
pressure = pressure_min;
}

return pressure;
}
/*!
* @brief This API is used to compensate the pressure and/or
* temperature and/or humidity data according to the component selected
* by the user.
*/
static int8_t bme280_compensate_data(const struct bme280_uncomp_data *uncomp_data,
struct bme280_data *comp_data,
struct bme280_calib_data *calib_data)
{
/* Initialize to zero */
comp_data->temperature = 0;
comp_data->pressure = 0;
comp_data->humidity = 0;

/* Compensate the temperature data */
comp_data->temperature = compensate_temperature(uncomp_data, calib_data);

/* Compensate the pressure data */
comp_data->pressure = compensate_pressure(uncomp_data, calib_data);

/* Compensate the humidity data */
comp_data->humidity = compensate_humidity(uncomp_data, calib_data);
}
/***************************************************************************/
u8 BEM280_ReadID(void)
{
return BME280_ReadOneByte(BME280_REG_CHIP_ID);
}
/***************************************************************************/
u8 BEM280_Reset(void)
{
uint8_t try_times = 5;
uint8_t status;
BME280_WriteOneByte(BME280_REG_RESET,BME280_SOFT_RESET_COMMAND);
do{
delay_ms(2);
status = BME280_ReadOneByte(BME280_REG_STATUS);
}
while((BME280_STATUS_IM_UPDATE == status)&&(try_times--));

if(status == BME280_STATUS_IM_UPDATE)
return 0;
else
return 1;

}
void BME280_GetCali(struct bme280_calib_data* bme280_calib_data)
{
/* Array to store calibration data */
uint8_t calib_data[BME280_LEN_TEMP_PRESS_CALIB_DATA] = { 0 };
uint8_t i;
for(i=0;i<BME280_LEN_TEMP_PRESS_CALIB_DATA;i++)
{
calib_data[i] = BME280_ReadOneByte(BME280_REG_TEMP_PRESS_CALIB_DATA+i);
}
parse_temp_press_calib_data(calib_data, bme280_calib_data);

for(i=0;i<BME280_LEN_HUMIDITY_CALIB_DATA;i++)
{
calib_data[i] = BME280_ReadOneByte(BME280_REG_HUMIDITY_CALIB_DATA+i);
}
parse_humidity_calib_data(calib_data, bme280_calib_data);
}
//一定要配置采样率,否则不更新
void BEM280_Init(void)
{
uint8_t regAddress;
uint8_t command=0x00;
/* 配置配置寄存器 : 间隔周期 0.5ms、IIR 滤波系数 16、不使⽤ SPI3 线通讯 */
regAddress=BME280_REG_CONFIG;
command=BME280_STANDBY_TIME_0_5_MS<<5|BME280_FILTER_COEFF_OFF<<2|0x00;
BME280_WriteOneByte(regAddress,command);

/* 配置湿度测量控制寄存器,一定要先配置湿度后,在配置温度压力,测量控制寄存器对湿度也起作用,不能乱序*/
command=0x00;
regAddress=BME280_REG_CTRL_HUM;
command=BME280_OVERSAMPLING_1X;
BME280_WriteOneByte(regAddress,command);

/* 配置测量控制寄存器 : 温度 20 位,压⼒ 20 位,电源正常模式 */
command=0x00;
regAddress=BME280_REG_CTRL_MEAS;
command=BME280_OVERSAMPLING_1X<<5|BME280_OVERSAMPLING_1X<<2|BME280_POWERMODE_NORMAL;
BME280_WriteOneByte(regAddress,command);



delay_ms(10);

}

void BEM280_GetData(struct bme280_data *comp_data,struct bme280_calib_data* bme280_calib_data)
{
/* Array to store the pressure, temperature and humidity data read from
* the sensor
*/
uint8_t reg_data[BME280_LEN_P_T_H_DATA] = { 0 };
uint8_t i;
struct bme280_uncomp_data uncomp_data = { 0 };

for(i=0;i<BME280_LEN_P_T_H_DATA;i++)
{
reg_data[i] = BME280_ReadOneByte(BME280_REG_DATA+i);
}
/* Parse the read data from the sensor */
parse_sensor_data(reg_data, &uncomp_data);

/* Compensate the pressure and/or temperature and/or
* humidity data from the sensor
*/
bme280_compensate_data(&uncomp_data, comp_data, bme280_calib_data);
}

/*********************************BMI088*******************************************/
int8_t BMI088_Write(GPIO_TypeDef* GPIOx, uint16_t dev_addr, uint8_t reg_addr, uint8_t *data, uint16_t len)
{
uint8_t i;
if(BMI08_ACCEL_I2C_ADDR_PRIMARY == dev_addr)
{
for(i=0;i<len;i++)
{
BMI088a_WriteOneByte(reg_addr++,*data++);
}
}else if(BMI08_GYRO_I2C_ADDR_PRIMARY == dev_addr)
{
for(i=0;i<len;i++)
{
BMI088g_WriteOneByte(reg_addr++,*data++);
}
}
return 0;
}

int8_t BMI088_Read(GPIO_TypeDef* GPIOx,uint16_t dev_addr, uint8_t reg_addr, uint8_t *data, uint16_t len)
{
uint8_t i;
if(BMI08_ACCEL_I2C_ADDR_PRIMARY == dev_addr)
{
for(i=0;i<len;i++)
{
data[i] = BMI088a_ReadOneByte(reg_addr++);
}
}else if(BMI08_GYRO_I2C_ADDR_PRIMARY == dev_addr)
{
for(i=0;i<len;i++)
{
data[i] = BMI088g_ReadOneByte(reg_addr++);
}
}
return 0;
}

/***************************************************************************/
u8 BMI088a_ReadID(void)
{
return BMI088a_ReadOneByte(BMI08_REG_ACCEL_CHIP_ID);
}
/***************************************************************************/
void BMI088a_Reset(void)
{
uint8_t try_times = 5;
BMI088a_WriteOneByte(BMI08_REG_ACCEL_SOFTRESET,BMI08_SOFT_RESET_CMD);
delay_ms(80);
}
void BMI088a_Init(void)
{
uint8_t regAddress;
uint8_t command=0x00;

regAddress=BMI08_REG_ACCEL_RANGE;
command=BMI08_ACCEL_RANGE_6G;
BMI088a_WriteOneByte(regAddress,command);
delay_ms(50);


/* 配置配置寄存器 */
regAddress=BMI08_REG_ACCEL_PWR_CONF;
command=BMI08_ACCEL_PM_ACTIVE;
BMI088a_WriteOneByte(regAddress,command);
delay_ms(50);
regAddress=BMI08_REG_ACCEL_PWR_CTRL;
command=BMI08_ACCEL_POWER_ENABLE;
BMI088a_WriteOneByte(regAddress,command);
delay_ms(80);

}


void BMI088a_GetData(struct bmi08_sensor_data *accel)
{
uint8_t data[6],i;
uint8_t lsb, msb;
uint16_t msblsb;
int8_t rslt;

for(i=0;i<BMI08_REG_ACCEL_X_LSB_LENGHT;i++)
{
data[i] = BMI088a_ReadOneByte(BMI08_REG_ACCEL_X_LSB+i);
}

lsb = data[0];
msb = data[1];
msblsb = (msb << 8) | lsb;
accel->x = ((int16_t) msblsb); /* Data in X axis */

lsb = data[2];
msb = data[3];
msblsb = (msb << 8) | lsb;
accel->y = ((int16_t) msblsb); /* Data in Y axis */

lsb = data[4];
msb = data[5];
msblsb = (msb << 8) | lsb;
accel->z = ((int16_t) msblsb); /* Data in Z axis */
//if(BMI08_ACCEL_DATA_READY_INT == BMI088a_ReadOneByte(BMI08_REG_ACCEL_INT_STAT_1))
//{}
}
/***************************************************************************/
u8 BMI088g_ReadID(void)
{
return BMI088g_ReadOneByte(BMI08_REG_GYRO_CHIP_ID);
}
/***************************************************************************/
void BMI088g_Reset(void)
{
uint8_t try_times = 5;
BMI088g_WriteOneByte(BMI08_REG_GYRO_SOFTRESET,BMI08_SOFT_RESET_CMD);
delay_ms(50);//至少30ms
}
void BMI088g_Init(void)
{
uint8_t regAddress;
uint8_t command=0x00;

regAddress=BMI08_REG_GYRO_BANDWIDTH;
command=BMI08_GYRO_BW_230_ODR_2000_HZ;
BMI088g_WriteOneByte(regAddress,command);
delay_ms(50);

regAddress=BMI08_REG_GYRO_RANGE;
command=BMI08_GYRO_RANGE_250_DPS;
BMI088g_WriteOneByte(regAddress,command);
delay_ms(50);

regAddress=BMI08_REG_GYRO_LPM1;
command=BMI08_GYRO_PM_NORMAL;
BMI088g_WriteOneByte(regAddress,command);
delay_ms(80);//至少50ms

}


void BMI088g_GetData(struct bmi08_sensor_data *gyro)
{
uint8_t data[6],i;
uint8_t lsb, msb;
uint16_t msblsb;
int8_t rslt;

for(i=0;i<BMI08_REG_GYRO_X_LSB_LENGTH;i++)
{
data[i] = BMI088g_ReadOneByte(BMI08_REG_GYRO_X_LSB+i);
}

lsb = data[0];
msb = data[1];
msblsb = (msb << 8) | lsb;
gyro->x = (int16_t)msblsb; /* Data in X axis */

lsb = data[2];
msb = data[3];
msblsb = (msb << 8) | lsb;
gyro->y = (int16_t)msblsb; /* Data in Y axis */

lsb = data[4];
msb = data[5];
msblsb = (msb << 8) | lsb;
gyro->z = (int16_t)msblsb; /* Data in Z axis */

}
/***************************************************************************/



功能演示

这是最后的数据采集结果。

image.png

心得体会

通过本次活动学习了Kicad/VSCODE的使用,加深了的理解,收获颇丰,感谢电子森林和digikey的赞助。

附件下载
0.96OLED_U8g2_STDLIB_SWIIC_USB_HDRV.zip
Project.zip
团队介绍
王世瑞
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号