cubeIDE开发,I2C协议采集传感器数据(SHTC1、LTR-553ALS、BMP280、LSM6DSL、MMC3680KJ)

news2024/7/6 18:24:48

一、I2C总线协议

       I2C(Inter Integrated Circuit)总线是 PHILIPS 公司开发的一种半双工、双向二线制同步串行总线。I2C 总线传输数据时只需两根信号线,一根是双向数据线 SDA(serial data),另一根是双向时钟线 SCL(serial clock)。SPI 总线有两根线分别用于主从设备之间接收数据和发送数据,而 I2C 总线只使用一根线进行数据收发。I2C 以主从的方式工作,并允许同时有多个主设备存在,每个连接到总线上的器件都有唯一的地址,主设备启动数据传输并产生时钟信号,从设备被主设备寻址,同一时刻只允许有一个主设备。

        I2C 总线主要的数据传输格式:

        当总线空闲时,SDA 和 SCL 都处于高电平状态,当主机要和某个从机通讯时,会先发送一个开始条件,然后发送从机地址和读写控制位,接下来传输数据(主机发送或者接收数据),数据传输结束时主机会发送停止条件。传输的每个字节为8位,高位在前,低位在后。

        开始标记:SCL 为高电平时,主机将 SDA 拉低,表示数据传输即将开始;

        从设备地址(或叫从机地址):主机发送的第一个字节为从机地址,高 7 位为地址,最低位为 R/W 读写控制位,1 表示读操作,0 表示写操作。一般从机地址有 7 位地址模式和 10 位地址模式两种,如果是 10 位地址模式,需要用两个字节(16位)来表述,第一个字节的头 7 位 是 11110XX 的组合,其中最后两位(XX)是 10 位地址的两个最高位,第二个字节为 10 位从机地址的剩下8位:       

         应答: 每传输完成一个字节的数据,接收方就需要回复一个 ACK(acknowledge)。写数据时由从机发送 ACK,读数据时由主机发送 ACK。当主机读到最后一个字节数据时,可发送 NACK(Not acknowledge)然后跟停止条件。

        数据: 从机地址发送完后可能会发送一些指令,依从机而定,然后开始传输数据,由主机或者从机发送,每个数据为 8 位,数据的字节数没有限制。

        重复开始: 在一次通信过程中,主机可能需要和不同的从机传输数据或者需要切换读写操作时,主机可以再发送一个开始条件。

        停止标记: 在 SDA 为低电平时,主机将 SCL 拉高并保持高电平,然后在将 SDA 拉高,表示传输结束。

二、I2C协议的两种从机应对方式

        从机对I2C协议通讯我本人认为提供了两种实现方式:

        寄存器直接访问方式:这种方式是从机直接将其参数、采集数据放置存储区域,并将存储地址暴露给主机,让主机直接按存储地址获取数据,或修改存储地址上的数据,从机感知数据变化做应对处理,从而实现对从机下行控制。我个人管这种方式较从机地址+寄存器地址。

         命令接口间接访问方式:这种方式从机对主机采用问答式服务,不会提供存储地址给主机,只是给出相关指令信息给主机,这些指令相当于从机对外提供的业务接口,例如主机需要读取某个数值,需要先向从机发送读取指令,从机将需要的数据做准备并等待主机下一次指令,主机再去读取数据。我个人管这种方式较从机地址+CMD指令。

         我们再看HLA标准库提供I2C接口API,也分为这两张方式:

//从机地址+CMD
HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData,
                                          uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData,

//从机地址+寄存器地址
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress,
                                    uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress,
                                   uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);

三、传感器信息

        本文采用STM32L496VGTX的ali开发板, 该开发板已经连接了一下传感器,下图蓝色部分标注的5个传感器就是本文需要实现的:

         这些传感器的硬件原理图如下:

        1)SHTC1温湿度传感器

        2)LTR-553ALS光感及接近传感器

         3)BMP280气压传感器

        4) LSM6DSL加速度及角速度传感器

        5) MMC3680KJ三轴磁传感器

         这些传感器都是通过I2C总线连接到STM32L496VGT3的MCU上,MCU的I2C引脚接口如下:

        另外 LTR-553ALS还需要一个GPIO引脚辅助

 四、工程创建及引脚配置

        本文新建了一个STM32L496VGTX_I2C工程,并移植了前面已经实现过的串口调试输出及OLED屏幕输出文字的源码,详细见:

 cubeIDE开发, stm32调试信息串口通信输出显示_py_free的博客-CSDN博客

cubeIDE开发, stm32的OLED点亮及字符显示设计(基于SPI通信)_py_free的博客-CSDN博客

        假设已经基于STM32L496VGTX的MCU上实现了lpusart调试信息输出,和SPI1的oled屏幕显示,接下来配置I2C2和I2C4接口及PA15引脚。

        1)开启I2C2配置,参数保持默认,注意从机地址7bit

         2)开启I2C2的DMA支持和中断支持(本文代码实现暂时没采用DMA,只是先开启)

         3)同样开启I2C4接口以及开启其DMA功能和中断功能

         I2C4的DMA及中断功能

        4) I2C2、I2C4引脚参数配置

         5)配置LTR-553ALS传感器需要的PA15引脚,并开启该PA15的中断功能支持

        配置完成后点击保存或生成代码按钮,完成图形配置到d代码生产的输出。

 五、STCH1传感器实现

        在ICore源码目录下添加STCH1文件夹,并在该文件夹下添加STCH1.h和STCH1.c文件作为STCH1传感器的驱动文件。

        本人去网上下载了一份STCH1传感器的数据手册,读取分析发现采用前面所述的从机地址+CMD指令方式,MCU通过I2C协议读取STCH1传感器的温湿度数据需要经历以下几个过程,先明确STCH1的设备地址是0X70,而开发板给出的地址是0XE0,STCH1集成到开发板是经过了微调(0XE0=(0X70<<1)),那我们采用0XE0就好:

        1)STCH1传感器的ID号确认,简单描述就是向STCH1写入两字节的0XEF 0XC8,再读取两个字节数据(16bit),取0~5bit的数据如果是0X07就表明OK。

         2)STCH1软重置要求,就是向STCH1写入两字节(16bit)的0X80 0X5D数据即可实现软重置。

         3)STCH1读取数据前需要支持数据读取组合格式,意思就是I2C开启Clock Stretching时,向STCH1写入16bit的0X7C 0XA2数据,再去读取数据时就是温度数据在前、湿度数据灾后,其他类似,如下图,是否开启Clock Stretching和是否温度在前组合共有四种组合方式。

         4)下图指出如何读取数据,在告知数据组合方式后,需要读取六字节(6*8 bit)的数据,其中第三和第六字节是CRC数据,剩余的是温湿度数据,第一、第二字节组成一个具体数据,最高有效位(MSB)在前、最低有效位(LSB)在后,第三、第四字节组成一个具体数据,第一、第二字节是温度还是湿度数据,由读取前写入指令确定,详见3)。

         5)数据换算到的原数据,需要经过换算公式换算后,才能表示实际的温湿度数值。

         6)伪代码设计:

init:
write 0xef 0xc8 to 0XE0
read  两字节Data     from 0XE0
取出 Data的0~5位数据与0X07比较完成ID识别
write 0X80, 0X5D to 0XE0 完成重置

read data
write 读取方式指令,例如0X7C 0XA2 to 0XE0
read 六字节Data from 0XE0
Data 1、2字节为温度原始数据,经换算公式获得实际温度值
Data 3、4字节为湿度原始数据,经换算公式获得实际湿度值

         7)源码STCH1.h和STCH1.c文件内容如下:

        STCH1.h

#ifndef SHTC1_SHTC1_H_
#define SHTC1_SHTC1_H_

#include "main.h"

void shtc1_init();
uint8_t read_ht(float *cur_humi,float *cur_temp);

#endif /* SHTC1_SHTC1_H_ */

         STCH1.c

#include <stdio.h>
#include "SHTC1.h"

extern I2C_HandleTypeDef hi2c2;

#define SHTC1_I2C_SLAVE_ADDR 0x70

#define SHTC1_ADDR_TRANS(n) ((n) << 1)
#define SHTC1_I2C_ADDR SHTC1_ADDR_TRANS(SHTC1_I2C_SLAVE_ADDR)

/* delays for non-blocking i2c commands, both in ms */
#define SHTC1_NONBLOCKING_WAIT_TIME_HPM 15
#define SHTC1_NONBLOCKING_WAIT_TIME_LPM 1

#define SHTC1_CHIP_ID_VAL 0x07
#define SHTC1_ID_REG_MASK 0x1f

#define SHTC1_CMD_LENGTH 2
#define SHTC1_RESPONSE_LENGTH 6

#define SHTC1_DATA_READ_MIN_INTERVAL 200 /* in millisecond */

typedef enum
{
    FLAG_INIT_TEMP = 0,
    FLAG_INIT_HUMI,
} FLAG_INIT_BIT;

typedef enum
{
    SHTC1_CMD_read_id_reg,
    SHTC1_CMD_measure_blocking_hpm,
    SHTC1_CMD_measure_nonblocking_hpm,
    SHTC1_CMD_measure_blocking_lpm,
    SHTC1_CMD_measure_nonblocking_lpm,
    SHTC1_CMD_END
} CMD_SHTC1_ENUM;

uint8_t SHTC1_id_check()
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	uint8_t data[SHTC1_CMD_LENGTH] = { 0xef, 0xc8 };
	hi2c2_status = HAL_I2C_Master_Transmit(&hi2c2,SHTC1_I2C_ADDR,data,SHTC1_CMD_LENGTH,1000);
	if(HAL_OK!=hi2c2_status){
		printf("set SHTC1_id error\r\n");
		return 1;
	}
	uint8_t value[2] = { 0 };
	hi2c2_status = HAL_I2C_Master_Receive(&hi2c2,SHTC1_I2C_ADDR,value,2,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get SHTC1_id error\r\n");
		return 1;
	}
	printf("SHTC1_id:0X%02X%02X\r\n",value[0],value[1]);
	//SHTC1_ID_REG_MASK=0X1F,SHTC1_CHIP_ID_VAL=0X07
	if ((value[1] & SHTC1_ID_REG_MASK) != SHTC1_CHIP_ID_VAL) {
        return 1;
    }
	printf("SHTC1_id check successfully\r\n");
	return 0;
}
//软重置
void reSet()
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
    uint8_t temp[2] = {0X80, 0X5D};
    hi2c2_status = HAL_I2C_Master_Transmit(&hi2c2,SHTC1_I2C_ADDR,temp,2,1000);
    if(HAL_OK!=hi2c2_status){
		printf("SHTC1 reset error\r\n");
		return;
	}
    printf("SHTC1 reSet successfully\r\n");
}

/*SHTC1提供了定义测量期间的传感器行为以及测量结果的传输序列的可能性。
 *每个测量命令都会同时触发温度测量和湿度测量。
 *bool enabled时钟是否启用,bool humi是否在前*/
void clock_set(uint8_t enabled,uint8_t humi)
{
    uint8_t temp[2] = {0, 0};
    if(enabled){
        /*时钟拉伸 已启用*/
        if(humi){
            /*湿度、温度*/
            temp[0] = 0x5C;
            temp[1] = 0x24;
        }else{
            /*温度、湿度*/
            temp[0] = 0x7C;
            temp[1] = 0xA2;
        }
    }else{
        /*时钟拉伸 丧失能力的*/
        if(humi){
            /*湿度、温度*/
            temp[0] = 0x58;
            temp[1] = 0xE0;
        }else{
            /*温度、湿度*/
            temp[0] = 0x78;
            temp[1] = 0x66;
        }
    }
    printf("out model:");
    for(uint8_t i=0; i<2; i++ )
    {
        printf("%02X ", temp[i]);
    }
    printf("\n");
    HAL_I2C_Master_Transmit(&hi2c2,SHTC1_I2C_ADDR,temp,2,1000);
}

void shtc1_init()
{
	SHTC1_id_check();
    reSet();
    HAL_Delay(1000);
    /*温度在前*/
    clock_set(1,0);
    HAL_Delay(1000);
}

uint8_t read_ht(float *cur_humi,float *cur_temp)
{
	/* 1、先发送要读取确认 */
	clock_set(1,0);/*时钟拉伸 已启用 && 温度、湿度->0X7C 0XA2*/
	/* 2、读取数据 */;
	HAL_StatusTypeDef hi2c2_status = 0x00;
	uint8_t retval[SHTC1_RESPONSE_LENGTH] = {0x00};
	hi2c2_status = HAL_I2C_Master_Receive(&hi2c2, SHTC1_I2C_ADDR, retval, 6, 1000);
	if(HAL_OK!=hi2c2_status)
		return 1;
	else{
	    uint32_t val01 = (retval[0] << 8 | retval[1]);
	    uint32_t val02 = (retval[3] << 8 | retval[4]);
	    printf("val01:%d,val02:%d\n",(int)val01,(int)val02);
	    /* 温度数据转换 */
	    *cur_temp =  val01 * 175.0 / (1 << 16) - 45;
	    //*cur_temp = (int32_t)((21875 * val01) >> 13) - 45000;//千位表示
	    /* 湿度数据转换 */
	    *cur_humi = val02 * 100.0 / (1 << 16);
	    //*cur_humi = (uint32_t)((12500 * val02) >> 13);
	    //lpusart
	    printf("\nread shtc1 sensor humidity   : %d.%d\n", (int)(*cur_humi), (int)((*cur_humi) * 100) % 100);
	    if( (*cur_temp) >= 0 )
		{
	    	printf("read shtc1 sensor temperature: %d.%d\n", (int)(*cur_temp), (int)((*cur_temp) * 100) % 100);
		}else{
			printf("read shtc1 sensor temperature: %d.%d\n", (int)(*cur_temp), (int)(-(*cur_temp) * 100) % 100);
	    }
		return 0;
	}
}

六、LTR_553ALS传感器(light sensor [ALS] and proximity sensor)

        在ICore目录下,创建LTR-553ALS-WA文件夹,并在该文件夹下创建LTR-553ALS-WA.h和LTR-553ALS-WA.c源码文件,作为LTR-553ALS传感器驱动。

        本人在网上下载了一份LTR-553ALS-WA的数据手册文档,进行分析其实是我们前面所述的从机地址+寄存器地址方式来实现de ,那么主要就是分析寄存器地址及相关含义即可,从机地址如下(0X46=0X23<<1),显然开发板做了调整:

        1)先看LTR-553ALS的I2C通信格式,下图是写入通信,典型从机地址(Slave address)+寄存器地址(Register Address)方式+写入数据(Register Command)。

         读通信方式,类似写入方式。

         2)下图是LTR-553ALS-WA的总寄存器地址描述表,可以看出0X80是ALS(光感应)的模式控制、重置的功能地址,OX81是PS(接近感应)的模式控制,0X82是PS_LED取值地址,0X84、0X85是ALS、PS的激活地址,0X86、0X87是设备的ID验证地址,0X88、0X89、0X8A、0X8B是ALS 数值存储地址,0X8D、0X8E是PS数值存储地址。

         3)设备ID验证,就是读取0X86的PART_ID数据,正确返回值是0X92,读取0X87的manufac_id数据,正确返回值是0X05.

         4)ALS的启用,主要:1.就是想0X85写入激活mode。设置检测time 和 rate,

                 2.向0X80写入contr mode,看起或关闭ACTIVE,如果想保留原来设置,可先读取,在&需要的设值,重新写入实现增加或删减支持模式,0X80还支持 software reset.

        5)PS的启用,类似于ALS设置,0X84开启Meas Rate激活PS,具体功能支持参考一下图。

         向0X81写入数据设置contr mode,开启或关闭ACTIVE

         6)ALS数据读取,最低有效位在前,0X88、0X89读取通道1(ch1)数据

         0X8A、0X8B读取通道0(ch0)数据

         7)读取PS数据,访问0X8D、0X8E地址,最低有效位在前。

         8)读取ALS(光感应)、PS(接近感应)数据伪代码实现:

从机地址是0x46
Init:
read data1 from 从机0x46 寄存地址 0X86
read data2 from 从机0x46 寄存地址 0X87
确保data1=0x92,data2=0x05

ALS init
write 设值 to 从机0x46 寄存地址 0X85 设置Measure Time and Rate
write 设值 to 从机0x46 寄存地址 0X80 设置 Active

PS init 
write 设值 to 从机0x46 寄存地址 0X84 设置Measure Rate
write 设值 to 从机0x46 寄存地址 0X81 设置 Active

读取数据

ALS read 前提确保0X80 设置 Active开启
read data1~4 from 从机0x46 寄存地址 0X88 0X89 0X8A 0X8B
对data1~4数据进行换算处理

PS read 前提确保0X81 设置 Active开启
read data1~2 from 从机0x46 寄存地址 0X8D 0X8E
对data1~2数据进行换算处理

        9)LTR-553ALS传感器驱动具体代码见LTR-553ALS-WA.h和LTR-553ALS-WA.c文件

        LTR-553ALS-WA.h

#ifndef _LTR_553ALS_WA_H_
#define _LTR_553ALS_WA_H_

#include "main.h"

void LTR_ALS_init();
void LTR_PS_init();

uint8_t ltr553_als_open();
uint8_t ltr553_als_close();

uint8_t ltr553_ps_open();
uint8_t ltr553_ps_close();

uint8_t read_als(uint32_t *als_data);
uint8_t read_ps(uint32_t *ps_data);

#endif /* LTR_553ALS_WA_LTR_553ALS_WA_H_ */

         LTR-553ALS-WA.c

#include <stdio.h>
#include "LTR-553ALS-WA.h"

#define WAIT_FOREVER 0xffffffffu

extern I2C_HandleTypeDef hi2c2;

#define LTR553_ALS_CONTR 0x80 /* ALS operation mode, SW reset */
#define LTR553_PS_CONTR 0x81  /* PS operation mode */
#define LTR553_PS_LED 0x82    /* LED pulse freq, current duty, peak current */
#define LTR553_PS_MEAS_RATE 0x84  /* measurement rate*/
#define LTR553_ALS_MEAS_RATE 0x85 /* ALS integ time, measurement rate*/
#define LTR553_PART_ID 0x86
#define LTR553_MANUFAC_ID 0x87
#define LTR553_ALS_DATA1_L 0x88
#define LTR553_ALS_DATA1_H 0x89
#define LTR553_ALS_DATA0_L 0x8a
#define LTR553_ALS_DATA0_H 0x8b
#define LTR553_ALS_PS_STATUS 0x8c
#define LTR553_PS_DATA_L 0x8d
#define LTR553_PS_DATA_H 0x8e
#define LTR553_INTR 0x8f           /* output mode, polarity, mode */
#define LTR553_PS_THRESH_UP 0x90   /* 11 bit, ps upper threshold */
#define LTR553_PS_THRESH_LOW 0x92  /* 11 bit, ps lower threshold */
#define LTR553_ALS_THRESH_UP 0x97  /* 16 bit, ALS upper threshold */
#define LTR553_ALS_THRESH_LOW 0x99 /* 16 bit, ALS lower threshold */
#define LTR553_INTR_PRST 0x9e      /* ps thresh, als thresh */
#define LTR553_MAX_REG 0x9f

#define LTR553_I2C_SLAVE_ADDR 0x23

#define LTR553_ADDR_TRANS(n) ((n) << 1)
#define LTR553_I2C_ADDR LTR553_ADDR_TRANS(LTR553_I2C_SLAVE_ADDR)
#define LTR553_PART_ID_VAL 0x92
#define LTR553_MANUFAC_ID_VAL 0x05

#define LTR553_ALS_CONTR_REG_ALS_GAIN__POS (2)
#define LTR553_ALS_CONTR_REG_ALS_GAIN__MSK (0x1c)
#define LTR553_ALS_CONTR_REG_ALS_GAIN__REG (LTR553_ALS_CONTR)

#define LTR553_ALS_CONTR_REG_ALS_MODE__POS (0)
#define LTR553_ALS_CONTR_REG_ALS_MODE__MSK (0x01)
#define LTR553_ALS_CONTR_REG_ALS_MODE__REG (LTR553_ALS_CONTR)

#define LTR553_ALS_MEAS_RATE_REG_INTEG_TIME__POS (3)
#define LTR553_ALS_MEAS_RATE_REG_INTEG_TIME__MSK (0x38)
#define LTR553_ALS_MEAS_RATE_REG_INTEG_TIME__REG (LTR553_ALS_MEAS_RATE)

#define LTR553_ALS_MEAS_RATE_REG_MEAS_RATE__POS (0)
#define LTR553_ALS_MEAS_RATE_REG_MEAS_RATE__MSK (0x07)
#define LTR553_ALS_MEAS_RATE_REG_MEAS_RATE__REG (LTR553_ALS_MEAS_RATE)

#define LTR553_ALS_PS_STATUS_REG_ALS_STATUS__POS (2)
#define LTR553_ALS_PS_STATUS_REG_ALS_STATUS__MSK (0x04)
#define LTR553_ALS_PS_STATUS_REG_ALS_STATUS__REG (LTR553_ALS_PS_STATUS)

#define LTR553_PS_CONTR_REG_PS_GAIN__POS (2)
#define LTR553_PS_CONTR_REG_PS_GAIN__MSK (0x0c)
#define LTR553_PS_CONTR_REG_PS_GAIN__REG (LTR553_PS_CONTR)

#define LTR553_PS_CONTR_REG_PS_MODE__POS (0)
#define LTR553_PS_CONTR_REG_PS_MODE__MSK (0x03)
#define LTR553_PS_CONTR_REG_PS_MODE__REG (LTR553_PS_CONTR)

#define LTR553_PS_LED_REG_PLUSE_FREQ__POS (5)
#define LTR553_PS_LED_REG_PLUSE_FREQ__MSK (0xe0)
#define LTR553_PS_LED_REG_PLUSE_FREQ__REG (LTR553_PS_LED)

#define LTR553_PS_LED_REG_CURRENT_DUTY__POS (3)
#define LTR553_PS_LED_REG_CURRENT_DUTY__MSK (0x18)
#define LTR553_PS_LED_REG_CURRENT_DUTY__REG (LTR553_PS_LED)

#define LTR553_PS_LED_REG_CURRENT__POS (0)
#define LTR553_PS_LED_REG_CURRENT__MSK (0x07)
#define LTR553_PS_LED_REG_CURRENT__REG (LTR553_PS_LED)

#define LTR553_PS_MEAS_RATE_REG_MEAS_RATE__POS (0)
#define LTR553_PS_MEAS_RATE_REG_MEAS_RATE__MSK (0x0F)
#define LTR553_PS_MEAS_RATE_REG_MEAS_RATE__REG (LTR553_PS_MEAS_RATE)

#define LTR553_ALS_PS_STATUS_REG_PS_STATUS__POS (0)
#define LTR553_ALS_PS_STATUS_REG_PS_STATUS__MSK (0x01)
#define LTR553_ALS_PS_STATUS_REG_PS_STATUS__REG (LTR553_ALS_PS_STATUS)

#define LTR553_GET_BITSLICE(regvar, bitname) \
    ((regvar & bitname##__MSK) >> bitname##__POS)
#define LTR553_SET_BITSLICE(regvar, bitname, val) \
    ((regvar & ~bitname##__MSK) | ((val << bitname##__POS) & bitname##__MSK))

#define LTR553_WAIT_TIME_PER_CHECK (10)
#define LTR553_WAIT_TIME_TOTAL (1000)

typedef enum
{
    AG_GAIN_1X  = 0x0, /* 1 lux to 64k lux (default) */
    AG_GAIN_2X  = 0x1, /* 0.5 lux to 32k lux */
    AG_GAIN_4X  = 0x2, /* 0.25 lux to 16k lux */
    AG_GAIN_8X  = 0x3, /* 0.125 lux to 8k lux */
    AG_GAIN_48X = 0x6, /* 0.02 lux to 1.3k lux */
    AG_GAIN_96X = 0x7, /* 0.01 lux to 600 lux */
} CFG_ALS_Gain;

typedef enum
{
    PG_GAIN_X16 = 0x0, /* X16 (default) */
    PG_GAIN_X32 = 0x2, /* X32 */
    PG_GAIN_X64 = 0x3, /* X64 */
} CFG_PS_Gain;

typedef enum
{
    LPMF_PERIOD_30K  = 0x0, /* LED pulse period = 30kHz */
    LPMF_PERIOD_40K  = 0x1, /* LED pulse period = 40kHz */
    LPMF_PERIOD_50K  = 0x2, /* LED pulse period = 50kHz */
    LPMF_PERIOD_60K  = 0x3, /* LED pulse period = 60kHz(default) */
    LPMF_PERIOD_70K  = 0x4, /* LED pulse period = 70kHz */
    LPMF_PERIOD_80K  = 0x5, /* LED pulse period = 80kHz */
    LPMF_PERIOD_90K  = 0x6, /* LED pulse period = 90kHz */
    LPMF_PERIOD_100K = 0x7, /* LED pulse period = 100kHz */
} CFG_LED_pulse_Modulation_Frequency;

typedef enum
{
    LCD_PER_25  = 0x0, /* DUTY = 25% */
    LCD_PER_50  = 0x1, /* DUTY = 50% */
    LCD_PER_75  = 0x2, /* DUTY = 75% */
    LCD_PER_100 = 0x3, /* DUTY = 100%(default) */
} CFG_LED_Current_DUTY;

typedef enum
{
    LC_LEVEL_5   = 0x0, /* LED pulse current level = 5mA */
    LC_LEVEL_10  = 0x1, /* LED pulse current level = 10mA */
    LC_LEVEL_20  = 0x2, /* LED pulse current level = 20mA */
    LC_LEVEL_50  = 0x3, /* LED pulse current level = 50mA */
    LC_LEVEL_100 = 0x4, /* LED pulse current level = 100mA(default) */
} CFG_LED_Current;

typedef enum
{
    PMR_RATE_50   = 0x0, /* PS Measurement Repeat Rate = 50ms */
    PMR_RATE_70   = 0x1, /* PS Measurement Repeat Rate = 70ms */
    PMR_RATE_100  = 0x2, /* PS Measurement Repeat Rate = 100ms(default) */
    PMR_RATE_200  = 0x3, /* PS Measurement Repeat Rate = 200ms */
    PMR_RATE_500  = 0x4, /* PS Measurement Repeat Rate = 500ms */
    PMR_RATE_1000 = 0x5, /* PS Measurement Repeat Rate = 1000ms */
    PMR_RATE_2000 = 0x6, /* PS Measurement Repeat Rate = 2000ms */
    PMR_RATE_10   = 0x8, /* PS Measurement Repeat Rate = 10ms */
} CFG_PS_measurement_rate;

typedef enum
{
    AIT_TIME_100 = 0x0, /* ALS integration_time = 100ms(default) */
    AIT_TIME_50  = 0x1, /* ALS integration_time = 50ms */
    AIT_TIME_200 = 0x2, /* ALS integration_time = 200ms */
    AIT_TIME_400 = 0x3, /* ALS integration_time = 400ms */
    AIT_TIME_150 = 0x4, /* ALS integration_time = 150ms */
    AIT_TIME_250 = 0x5, /* ALS integration_time = 250ms */
    AIT_TIME_300 = 0x6, /* ALS integration_time = 300ms */
    AIT_TIME_350 = 0x7, /* ALS integration_time = 350ms */
} CFG_ALS_integration_time;

typedef enum
{
    AMR_RATE_50   = 0x0, /* ALS Measurement Repeat Rate = 50ms */
    AMR_RATE_100  = 0x1, /* ALS Measurement Repeat Rate = 100ms */
    AMR_RATE_200  = 0x2, /* ALS Measurement Repeat Rate = 200ms */
    AMR_RATE_500  = 0x3, /* ALS Measurement Repeat Rate = 500ms(default) */
    AMR_RATE_1000 = 0x4, /* ALS Measurement Repeat Rate = 1000ms */
    AMR_RATE_2000 = 0x5, /* ALS Measurement Repeat Rate = 2000ms */
} CFG_ALS_measurement_rate;

typedef enum
{
    PM_MODE_STANDBY = 0,
    PM_MODE_ACTIVE  = 3,
} CFG_PS_mode;

typedef enum
{
    AM_MODE_STANDBY = 0,
    AM_MODE_ACTIVE  = 1,
} CFG_ALS_mode;

typedef enum
{
    ADS_STATUS_OLD = 0,
    ADS_STATUS_NEW = 1,
} CFG_ALS_data_status;

typedef enum
{
    PDS_STATUS_OLD = 0,
    PDS_STATUS_NEW = 1,
} CFG_PS_data_status;

typedef enum
{
    FLAG_INIT_ALS = 0,
    FLAG_INIT_PS,
} FLAG_INIT_BIT;

typedef enum {
    DEV_POWER_OFF = 0,
    DEV_POWER_ON,
    DEV_SLEEP,
    DEV_SUSPEND,
    DEV_DEEP_SUSPEND,
} LTR_power_mode;

uint8_t LTR553_id_check()
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	/*ID check*/
	//LTR553_PART_ID=0X86,LTR553_MANUFAC_ID=0X87
	//LTR553_PART_ID_VAL=0X92,LTR553_MANUFAC_ID_VAL=0X05
	uint8_t id_addr_val[6] = {LTR553_PART_ID,LTR553_PART_ID_VAL,0x00,LTR553_MANUFAC_ID,LTR553_MANUFAC_ID_VAL,0x00};
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c2,LTR553_I2C_ADDR,id_addr_val[0],1,&id_addr_val[2],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get part_id error\r\n");
		return 1;
	}
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c2,LTR553_I2C_ADDR,id_addr_val[3],1,&id_addr_val[5],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get manufac_id error\r\n");
		return 1;
	}
	if(id_addr_val[1]!=id_addr_val[2]||id_addr_val[4]!=id_addr_val[5]){
		printf("drv_als_ps_liteon_ltr553_validate_id is error\r\n");
		return 1;
	}
	printf("part_id:%02X,manufac_id:%02X\r\n",id_addr_val[2],id_addr_val[5]);
	return 0;
}

uint8_t ltr553_als_set_power_mode(LTR_power_mode mode)
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	uint8_t dev_mode  = 0;
	uint8_t value     = 0;

	hi2c2_status = HAL_I2C_Mem_Read(&hi2c2,LTR553_I2C_ADDR,LTR553_ALS_CONTR,1,&value,1,WAIT_FOREVER);
	if(HAL_OK!=hi2c2_status){
		printf("get als_contr error\r\n");
		return 1;
	}
	printf("ALS_CONTR old:%02X\r\n",value);
    switch (mode) {
        case DEV_POWER_OFF:
        case DEV_SLEEP:
            dev_mode = LTR553_SET_BITSLICE(dev_mode, LTR553_ALS_CONTR_REG_ALS_MODE, AM_MODE_STANDBY);
            break;
        case DEV_POWER_ON:
            dev_mode = LTR553_SET_BITSLICE(dev_mode, LTR553_ALS_CONTR_REG_ALS_MODE, AM_MODE_ACTIVE);
            break;
        default:
            return 1;
    }
    printf("ALS_CONTR new:%02X\r\n",dev_mode);
	hi2c2_status = HAL_I2C_Mem_Write(&hi2c2,LTR553_I2C_ADDR,LTR553_ALS_CONTR,1,&dev_mode,1,WAIT_FOREVER);
	if(HAL_OK!=hi2c2_status){
		printf("set ALS_CONTR error\r\n");
		return 1;
	}
	printf("successfully LTR553_ALS set_power_mode!\r\n");
    return 0;
}

uint8_t ltr553_ps_set_power_mode(LTR_power_mode mode)
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	uint8_t dev_mode  = 0;
	uint8_t value     = 0;

	hi2c2_status = HAL_I2C_Mem_Read(&hi2c2,LTR553_I2C_ADDR,LTR553_PS_CONTR,1,&value,1,WAIT_FOREVER);
	if(HAL_OK!=hi2c2_status){
		printf("get ps_contr error\r\n");
		return 1;
	}
	printf("PS_CONTR old:%02X\r\n",value);
    switch (mode) {
        case DEV_POWER_OFF:
        case DEV_SLEEP:
            dev_mode = LTR553_SET_BITSLICE(value, LTR553_PS_CONTR_REG_PS_MODE,PM_MODE_STANDBY);
            break;
        case DEV_POWER_ON:
            dev_mode = LTR553_SET_BITSLICE(value, LTR553_PS_CONTR_REG_PS_MODE,PM_MODE_ACTIVE);
            break;
        default:
            return 1;
    }
    printf("ALS_CONTR new:%02X\r\n",dev_mode);
	hi2c2_status = HAL_I2C_Mem_Write(&hi2c2,LTR553_I2C_ADDR,LTR553_PS_CONTR,1,&dev_mode,1,WAIT_FOREVER);
	if(HAL_OK!=hi2c2_status){
		printf("set PS_CONTR error\r\n");
		return 1;
	}
	printf("successfully LTR553_PS set_power_mode!\r\n");
    return 0;
}

uint8_t ltr553_als_is_ready()
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	uint8_t value = 0;
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c2,LTR553_I2C_ADDR,LTR553_ALS_PS_STATUS,1,&value,1,WAIT_FOREVER);
	if(HAL_OK!=hi2c2_status){
		printf("get ps_contr error\r\n");
		return 0;
	}
//	printf("PS_CONTR old:%02X\r\n",value);
	uint8_t ret = (LTR553_GET_BITSLICE(value, LTR553_ALS_PS_STATUS_REG_ALS_STATUS) == ADS_STATUS_NEW)? 1 : 0;
	return ret;
}

uint8_t ltr553_ps_is_ready()
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	uint8_t value = 0;
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c2,LTR553_I2C_ADDR,LTR553_ALS_PS_STATUS,1,&value,1,WAIT_FOREVER);
	if(HAL_OK!=hi2c2_status){
		printf("get ps_contr error\r\n");
		return 0;
	}
//	printf("PS_CONTR old:%02X\r\n",value);
	uint8_t ret = (LTR553_GET_BITSLICE(value, LTR553_ALS_PS_STATUS_REG_PS_STATUS) == PDS_STATUS_NEW)? 1 : 0;
	return ret;
}

uint8_t ltr553_als_set_default_config()
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	uint8_t value = 0;
	value = LTR553_SET_BITSLICE(value, LTR553_ALS_MEAS_RATE_REG_INTEG_TIME,AIT_TIME_100);
	value = LTR553_SET_BITSLICE(value, LTR553_ALS_MEAS_RATE_REG_MEAS_RATE,AMR_RATE_100);
	printf("ALS_MEAS_RATE:%02X\r\n",value);
	hi2c2_status = HAL_I2C_Mem_Write(&hi2c2,LTR553_I2C_ADDR,LTR553_ALS_MEAS_RATE,1,&value,1,WAIT_FOREVER);
	if(HAL_OK!=hi2c2_status){
		printf("set ALS_MEAS_RATE error\r\n");
		return 1;
	}
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c2,LTR553_I2C_ADDR,LTR553_ALS_CONTR,1,&value,1,WAIT_FOREVER);
	if(HAL_OK!=hi2c2_status){
		printf("get als_contr error\r\n");
		return 1;
	}
	printf("ALS_CONTR old:%02X\r\n",value);
	value =	LTR553_SET_BITSLICE(value, LTR553_ALS_CONTR_REG_ALS_GAIN, AG_GAIN_1X);
	printf("ALS_CONTR new:%02X\r\n",value);
	hi2c2_status = HAL_I2C_Mem_Write(&hi2c2,LTR553_I2C_ADDR,LTR553_ALS_CONTR,1,&value,1,WAIT_FOREVER);
	if(HAL_OK!=hi2c2_status){
		printf("get ALS_CONTR error\r\n");
		return 1;
	}
	printf("successfully LTR553_ALS_default_config!\r\n");
	return 0;
}

uint8_t ltr553_ps_set_default_config()
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	//LTR553_PS_MEAS_RATE=0X84,LTR553_PS_LED=0X82,LTR553_PS_CONTR=0X81
	uint8_t value = 0;
	value = LTR553_SET_BITSLICE(value, LTR553_PS_MEAS_RATE_REG_MEAS_RATE,PMR_RATE_100);
	printf("PS_MEAS_RATE:%02X\r\n",value);
	hi2c2_status = HAL_I2C_Mem_Write(&hi2c2,LTR553_I2C_ADDR,LTR553_PS_MEAS_RATE,1,&value,1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("set PS_MEAS_RATE error\r\n");
		return 1;
	}
	//value default 0X7F
	value = LTR553_SET_BITSLICE(value, LTR553_PS_LED_REG_PLUSE_FREQ, LPMF_PERIOD_60K);
	value = LTR553_SET_BITSLICE(value, LTR553_PS_LED_REG_CURRENT_DUTY, LCD_PER_100);
	value = LTR553_SET_BITSLICE(value, LTR553_PS_LED_REG_CURRENT, LC_LEVEL_100);
	printf("PS_LED:%02X\r\n",value);
	hi2c2_status = HAL_I2C_Mem_Write(&hi2c2,LTR553_I2C_ADDR,LTR553_PS_MEAS_RATE,1,&value,1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get PS_LED error\r\n");
		return 1;
	}
	//check
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c2,LTR553_I2C_ADDR,LTR553_PS_CONTR,1,&value,1,WAIT_FOREVER);
	if(HAL_OK!=hi2c2_status){
		printf("get ps_contr error\r\n");
		return 1;
	}
	printf("PS_CONTR old:%02X\r\n",value);
	value = LTR553_SET_BITSLICE(value, LTR553_PS_CONTR_REG_PS_GAIN, PG_GAIN_X16);
	printf("PS_CONTR new:%02X\r\n",value);
	//
	hi2c2_status = HAL_I2C_Mem_Write(&hi2c2,LTR553_I2C_ADDR,LTR553_PS_CONTR,1,&value,1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get PS_CONTR error\r\n");
		return 1;
	}
	printf("successfully LTR553_PS default_config!\r\n");
	return 0;
}

uint8_t ltr553_als_open()
{
	uint8_t ret = 0;

	ret = ltr553_als_set_power_mode(DEV_POWER_ON);
    if (ret>0) {
        return 1;
    }
    printf("successfully LTR553_ALS Open!\r\n");
    return 0;
}

uint8_t ltr553_als_close()
{
	uint8_t ret = 0;

	ret = ltr553_als_set_power_mode(DEV_POWER_OFF);
    if (ret>0) {
        return 1;
    }
    printf("successfully LTR553_ALS Close!\r\n");
    return 0;
}

uint8_t ltr553_ps_open()
{
	uint8_t ret = 0;

	ret = ltr553_ps_set_power_mode(DEV_POWER_ON);
    if (ret>0) {
        return 1;
    }
    printf("successfully LTR553_ALS Open!\r\n");
    return 0;
}

uint8_t ltr553_ps_close()
{
	uint8_t ret = 0;

	ret = ltr553_ps_set_power_mode(DEV_POWER_OFF);
    if (ret>0) {
        return 1;
    }
    printf("successfully LTR553_ALS Close!\r\n");
    return 0;
}

void LTR_ALS_init()
{
	/*ID check*/
	if(LTR553_id_check()>0){
		return;
	}
	if(ltr553_als_set_default_config()>0)
		return;
	printf("successfully LTR553_ALS_init!\r\n");
}

void LTR_PS_init()
{
	/*ID check*/
	if(LTR553_id_check()){
		return;
	}
	/*PS check*/
	if(ltr553_ps_set_default_config()>0)
		return;
	printf("successfully LTR553_PS_init!\r\n");
}

uint8_t read_als(uint32_t *als_data)
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	/*
	 * LTR553_ALS_DATA1_L=0X88,LTR553_ALS_DATA1_H=0X89
	 * LTR553_ALS_DATA0_L=0X8A,LTR553_ALS_DATA0_H=0X8B
	 */
	uint8_t ALS_addr[4] = {LTR553_ALS_DATA1_L,LTR553_ALS_DATA1_H
			,LTR553_ALS_DATA0_L,LTR553_ALS_DATA0_H};
	uint8_t ALS_data[4] = {0x00};
	for(uint8_t i=0; i<4; i++){
		hi2c2_status = HAL_I2C_Mem_Read(&hi2c2,LTR553_I2C_ADDR,ALS_addr[i],1,&ALS_data[i],1,1000);
		if(HAL_OK!=hi2c2_status){
				return 1;
		}
	}
	uint32_t val01 = ALS_data[0]|(ALS_data[1]<<8);
    uint32_t val02 = ALS_data[2]|(ALS_data[3]<<8);
    printf("val01:%lu,val02:%lu\n",val01,val01);
    *als_data =  (uint32_t)((val01 + val02) >> 1);
    printf("als_data: %lu\r\n",*als_data);
    return 0;
}

uint8_t read_ps(uint32_t *ps_data)
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	/*
	 * LTR553_PS_DATA_L=0X8D,LTR553_PS_DATA_H=0X8E
	 */
    uint8_t PS_addr[2] = {LTR553_PS_DATA_L,LTR553_PS_DATA_H};
    uint8_t PS_data[2] = {0x00};
    for(uint8_t i=0; i<2; i++){
		hi2c2_status = HAL_I2C_Mem_Read(&hi2c2,LTR553_I2C_ADDR,PS_addr[i],1,&PS_data[i],1,1000);
		if(HAL_OK!=hi2c2_status){
				return 1;
		}
	}
    uint32_t val03 = PS_data[0]|(PS_data[1]<<8);
    printf("val03:%lu\n",val03);
    *ps_data = val03;
    printf("ps_data: %lu\r\n",*ps_data);
    return 0;
}

七、BMP280传感器(气压传感器)

        在ICore源码目录下,创建bmp280文件夹,再在该目录下创建bmp280.h和bmp280.c源码文件,作为BMP280传感器驱动。
        同样在网上查找下载bmp280数据手册,逐步分析,bmp280的地址(0XEE=0X77<<1),开发板同样做了微调,采用从机地址+寄存器地址+数据等方式通信,支持SPI或I2C通信,我们只研究I2C通信,如下:

        1)I2C读写通信设计如下

         2)设备ID寄存器地址0XD0,正确返回值应该是0X58,及软重置寄存器地址XE0,写入数据是0XB6重置生效,其他值无效。

         3)power模式设置地址0XF4,bit0~1设置0X03(0000 0011)开启正常模式,可以读取数据。bit5~7设置温度相关,bit2~4设置气压相关.

         4)设备参数配置地址0XF5,可设置设备作业的rate, filter and interface。I2C通信需要设置5~7bit。

         5)数据读取时的微调参数配置,其中dig_T1、dig_T2、dig_T3是为温度数据调整使用,dig_P1~9是气压数据调整时使用。

         6)读取数据,0XF7~F9读取气压相关数据,共3字节(24bit),0XFA~FC读取温度相关数据,共3字节(24bit)

         7)至此可设计出BMP280的伪代码

bmp280从机地址0XEE
init:
read data1 from 从机地址0XEE 寄存器地址 0XD0
确保data1==0X58
write 0XB6 to 从机地址0XEE 寄存器地址 0XE0 完成软重置
write val1 to 从机地址0XEE 寄存器地址 0XF4 完成设备模式设置
write val2 to 从机地址0XEE 寄存器地址 0XF5 完成设备参数设置
read conf1~24 from 从机地址0XEE 寄存器地址 0X88~0XA1 获取数据换算微调参数

读取数据:
确保设备为正常模式,例如write 0X03 to 从机地址0XEE 寄存器地址 0XF4 完成设备模式设置
read P1~3 from 从机地址0XEE 寄存器地址 0XF7~F9
将P1~3与conf4~24进行换算处理得到实际数据
read t1~3 from 从机地址0XEE 寄存器地址 0XFA~FC
将t1~3与conf1~3进行换算处理得到实际数据

         8)依据上面伪代码描述,BMP280传感器驱动文件源码如下:

        bmp280.h

#ifndef _BMP280_H_
#define _BMP280_H_

#include "main.h"

void BMP280_init();
uint8_t bmp280_open(void);
uint8_t bmp280_close(void);
uint8_t read_bmp280_temp(uint32_t *comp_temp);
uint8_t read_bmp280_baro(uint32_t *comp_baro);
#endif /* BMP280_BMP280_H_ */

         bmp280.c

#include <stdio.h>
#include "bmp280.h"

extern I2C_HandleTypeDef hi2c2;

#define BMP280_TEMPERATURE_CALIB_DIG_T1_LSB_REG (0x88)
#define BMP280_TEMPERATURE_CALIB_DIG_T1_MSB_REG (0x89)
#define BMP280_TEMPERATURE_CALIB_DIG_T2_LSB_REG (0x8A)
#define BMP280_TEMPERATURE_CALIB_DIG_T2_MSB_REG (0x8B)
#define BMP280_TEMPERATURE_CALIB_DIG_T3_LSB_REG (0x8C)
#define BMP280_TEMPERATURE_CALIB_DIG_T3_MSB_REG (0x8D)
#define BMP280_PRESSURE_CALIB_DIG_P1_LSB_REG (0x8E)
#define BMP280_PRESSURE_CALIB_DIG_P1_MSB_REG (0x8F)
#define BMP280_PRESSURE_CALIB_DIG_P2_LSB_REG (0x90)
#define BMP280_PRESSURE_CALIB_DIG_P2_MSB_REG (0x91)
#define BMP280_PRESSURE_CALIB_DIG_P3_LSB_REG (0x92)
#define BMP280_PRESSURE_CALIB_DIG_P3_MSB_REG (0x93)
#define BMP280_PRESSURE_CALIB_DIG_P4_LSB_REG (0x94)
#define BMP280_PRESSURE_CALIB_DIG_P4_MSB_REG (0x95)
#define BMP280_PRESSURE_CALIB_DIG_P5_LSB_REG (0x96)
#define BMP280_PRESSURE_CALIB_DIG_P5_MSB_REG (0x97)
#define BMP280_PRESSURE_CALIB_DIG_P6_LSB_REG (0x98)
#define BMP280_PRESSURE_CALIB_DIG_P6_MSB_REG (0x99)
#define BMP280_PRESSURE_CALIB_DIG_P7_LSB_REG (0x9A)
#define BMP280_PRESSURE_CALIB_DIG_P7_MSB_REG (0x9B)
#define BMP280_PRESSURE_CALIB_DIG_P8_LSB_REG (0x9C)
#define BMP280_PRESSURE_CALIB_DIG_P8_MSB_REG (0x9D)
#define BMP280_PRESSURE_CALIB_DIG_P9_LSB_REG (0x9E)
#define BMP280_PRESSURE_CALIB_DIG_P9_MSB_REG (0x9F)


#define BMP280_CHIP_ID_REG (0xD0)
#define BMP280_RST_REG (0xE0)
#define BMP280_STAT_REG (0xF3)
#define BMP280_CTRL_MEAS_REG (0xF4)
#define BMP280_CONFIG_REG (0xF5)
#define BMP280_PRESSURE_MSB_REG (0xF7)
#define BMP280_PRESSURE_LSB_REG (0xF8)
#define BMP280_PRESSURE_XLSB_REG (0xF9)
#define BMP280_TEMPERATURE_MSB_REG (0xFA)
#define BMP280_TEMPERATURE_LSB_REG (0xFB)
#define BMP280_TEMPERATURE_XLSB_REG (0xFC)


#define BMP280_SHIFT_BY_01_BIT (1)
#define BMP280_SHIFT_BY_02_BITS (2)
#define BMP280_SHIFT_BY_03_BITS (3)
#define BMP280_SHIFT_BY_04_BITS (4)
#define BMP280_SHIFT_BY_05_BITS (5)
#define BMP280_SHIFT_BY_08_BITS (8)
#define BMP280_SHIFT_BY_11_BITS (11)
#define BMP280_SHIFT_BY_12_BITS (12)
#define BMP280_SHIFT_BY_13_BITS (13)
#define BMP280_SHIFT_BY_14_BITS (14)
#define BMP280_SHIFT_BY_15_BITS (15)
#define BMP280_SHIFT_BY_16_BITS (16)
#define BMP280_SHIFT_BY_17_BITS (17)
#define BMP280_SHIFT_BY_18_BITS (18)
#define BMP280_SHIFT_BY_19_BITS (19)
#define BMP280_SHIFT_BY_25_BITS (25)
#define BMP280_SHIFT_BY_31_BITS (31)
#define BMP280_SHIFT_BY_33_BITS (33)
#define BMP280_SHIFT_BY_35_BITS (35)
#define BMP280_SHIFT_BY_47_BITS (47)


#define BMP280_PRESSURE_TEMPERATURE_CALIB_DATA_LENGTH (24)
#define BMP280_GEN_READ_WRITE_DATA_LENGTH (1)
#define BMP280_REGISTER_READ_DELAY (1)
#define BMP280_TEMPERATURE_DATA_LENGTH (3)
#define BMP280_PRESSURE_DATA_LENGTH (3)
#define BMP280_ALL_DATA_FRAME_LENGTH (6)
#define BMP280_INIT_VALUE (0)
#define BMP280_CHIP_ID_READ_COUNT (5)
#define BMP280_CHIP_ID_READ_SUCCESS (0)
#define BMP280_CHIP_ID_READ_FAIL ((int8_t)-1)
#define BMP280_INVALID_DATA (0)


#define BMP280_TEMPERATURE_DATA_SIZE (3)
#define BMP280_PRESSURE_DATA_SIZE (3)
#define BMP280_DATA_FRAME_SIZE (6)
#define BMP280_CALIB_DATA_SIZE (24)

#define BMP280_TEMPERATURE_MSB_DATA (0)
#define BMP280_TEMPERATURE_LSB_DATA (1)
#define BMP280_TEMPERATURE_XLSB_DATA (2)


#define BMP280_I2C_ADDRESS1 (0x76)
#define BMP280_I2C_ADDRESS2 (0x77)


#define BMP280_SLEEP_MODE (0x00)
#define BMP280_FORCED_MODE (0x01)
#define BMP280_NORMAL_MODE (0x03)
#define BMP280_SOFT_RESET_CODE (0xB6)


#define BMP280_STANDBY_TIME_1_MS (0x00)
#define BMP280_STANDBY_TIME_63_MS (0x01)
#define BMP280_STANDBY_TIME_125_MS (0x02)
#define BMP280_STANDBY_TIME_250_MS (0x03)
#define BMP280_STANDBY_TIME_500_MS (0x04)
#define BMP280_STANDBY_TIME_1000_MS (0x05)
#define BMP280_STANDBY_TIME_2000_MS (0x06)
#define BMP280_STANDBY_TIME_4000_MS (0x07)


#define BMP280_OVERSAMP_SKIPPED (0x00)
#define BMP280_OVERSAMP_1X (0x01)
#define BMP280_OVERSAMP_2X (0x02)
#define BMP280_OVERSAMP_4X (0x03)
#define BMP280_OVERSAMP_8X (0x04)
#define BMP280_OVERSAMP_16X (0x05)

#define BMP280_FILTER_COEFF_OFF (0x00)
#define BMP280_FILTER_COEFF_2 (0x01)
#define BMP280_FILTER_COEFF_4 (0x02)
#define BMP280_FILTER_COEFF_8 (0x03)
#define BMP280_FILTER_COEFF_16 (0x04)


#define BMP280_ULTRA_LOW_POWER_MODE (0x00)
#define BMP280_LOW_POWER_MODE (0x01)
#define BMP280_STANDARD_RESOLUTION_MODE (0x02)
#define BMP280_HIGH_RESOLUTION_MODE (0x03)
#define BMP280_ULTRA_HIGH_RESOLUTION_MODE (0x04)

#define BMP280_ULTRALOWPOWER_OVERSAMP_PRESSURE BMP280_OVERSAMP_1X
#define BMP280_ULTRALOWPOWER_OVERSAMP_TEMPERATURE BMP280_OVERSAMP_1X

#define BMP280_LOWPOWER_OVERSAMP_PRESSURE BMP280_OVERSAMP_2X
#define BMP280_LOWPOWER_OVERSAMP_TEMPERATURE BMP280_OVERSAMP_1X

#define BMP280_STANDARDRESOLUTION_OVERSAMP_PRESSURE BMP280_OVERSAMP_4X
#define BMP280_STANDARDRESOLUTION_OVERSAMP_TEMPERATURE BMP280_OVERSAMP_1X

#define BMP280_HIGHRESOLUTION_OVERSAMP_PRESSURE BMP280_OVERSAMP_8X
#define BMP280_HIGHRESOLUTION_OVERSAMP_TEMPERATURE BMP280_OVERSAMP_1X

#define BMP280_ULTRAHIGHRESOLUTION_OVERSAMP_PRESSURE BMP280_OVERSAMP_16X
#define BMP280_ULTRAHIGHRESOLUTION_OVERSAMP_TEMPERATURE BMP280_OVERSAMP_2X


#define BMP280_STATUS_REG_MEASURING__POS (3)
#define BMP280_STATUS_REG_MEASURING__MSK (0x08)
#define BMP280_STATUS_REG_MEASURING__LEN (1)
#define BMP280_STATUS_REG_MEASURING__REG (BMP280_STAT_REG)

#define BMP280_STATUS_REG_IM_UPDATE__POS (0)
#define BMP280_STATUS_REG_IM_UPDATE__MSK (0x01)
#define BMP280_STATUS_REG_IM_UPDATE__LEN (1)
#define BMP280_STATUS_REG_IM_UPDATE__REG (BMP280_STAT_REG)


#define BMP280_CTRL_MEAS_REG_OVERSAMP_TEMPERATURE__POS (5)
#define BMP280_CTRL_MEAS_REG_OVERSAMP_TEMPERATURE__MSK (0xE0)
#define BMP280_CTRL_MEAS_REG_OVERSAMP_TEMPERATURE__LEN (3)
#define BMP280_CTRL_MEAS_REG_OVERSAMP_TEMPERATURE__REG (BMP280_CTRL_MEAS_REG)


#define BMP280_CTRL_MEAS_REG_OVERSAMP_PRESSURE__POS (2)
#define BMP280_CTRL_MEAS_REG_OVERSAMP_PRESSURE__MSK (0x1C)
#define BMP280_CTRL_MEAS_REG_OVERSAMP_PRESSURE__LEN (3)
#define BMP280_CTRL_MEAS_REG_OVERSAMP_PRESSURE__REG (BMP280_CTRL_MEAS_REG)

#define BMP280_CTRL_MEAS_REG_POWER_MODE__POS (0)
#define BMP280_CTRL_MEAS_REG_POWER_MODE__MSK (0x03)
#define BMP280_CTRL_MEAS_REG_POWER_MODE__LEN (2)
#define BMP280_CTRL_MEAS_REG_POWER_MODE__REG (BMP280_CTRL_MEAS_REG)


#define BMP280_CONFIG_REG_STANDBY_DURN__POS (5)
#define BMP280_CONFIG_REG_STANDBY_DURN__MSK (0xE0)
#define BMP280_CONFIG_REG_STANDBY_DURN__LEN (3)
#define BMP280_CONFIG_REG_STANDBY_DURN__REG (BMP280_CONFIG_REG)

#define BMP280_CONFIG_REG_FILTER__POS (2)
#define BMP280_CONFIG_REG_FILTER__MSK (0x1C)
#define BMP280_CONFIG_REG_FILTER__LEN (3)
#define BMP280_CONFIG_REG_FILTER__REG (BMP280_CONFIG_REG)


#define BMP280_CONFIG_REG_SPI3_ENABLE__POS (0)
#define BMP280_CONFIG_REG_SPI3_ENABLE__MSK (0x01)
#define BMP280_CONFIG_REG_SPI3_ENABLE__LEN (1)
#define BMP280_CONFIG_REG_SPI3_ENABLE__REG (BMP280_CONFIG_REG)


#define BMP280_PRESSURE_XLSB_REG_DATA__POS (4)
#define BMP280_PRESSURE_XLSB_REG_DATA__MSK (0xF0)
#define BMP280_PRESSURE_XLSB_REG_DATA__LEN (4)
#define BMP280_PRESSURE_XLSB_REG_DATA__REG (BMP280_PRESSURE_XLSB_REG)

#define BMP280_TEMPERATURE_XLSB_REG_DATA__POS (4)
#define BMP280_TEMPERATURE_XLSB_REG_DATA__MSK (0xF0)
#define BMP280_TEMPERATURE_XLSB_REG_DATA__LEN (4)
#define BMP280_TEMPERATURE_XLSB_REG_DATA__REG (BMP280_TEMPERATURE_XLSB_REG)

#define BMP280_TEMPERATURE_MSB_DATA (0)
#define BMP280_TEMPERATURE_LSB_DATA (1)
#define BMP280_TEMPERATURE_XLSB_DATA (2)

#define BMP280_PRESSURE_MSB_DATA (0)
#define BMP280_PRESSURE_LSB_DATA (1)
#define BMP280_PRESSURE_XLSB_DATA (2)

#define BMP280_DATA_FRAME_PRESSURE_MSB_BYTE (0)
#define BMP280_DATA_FRAME_PRESSURE_LSB_BYTE (1)
#define BMP280_DATA_FRAME_PRESSURE_XLSB_BYTE (2)
#define BMP280_DATA_FRAME_TEMPERATURE_MSB_BYTE (3)
#define BMP280_DATA_FRAME_TEMPERATURE_LSB_BYTE (4)
#define BMP280_DATA_FRAME_TEMPERATURE_XLSB_BYTE (5)

#define BMP280_TEMPERATURE_CALIB_DIG_T1_LSB (0)
#define BMP280_TEMPERATURE_CALIB_DIG_T1_MSB (1)
#define BMP280_TEMPERATURE_CALIB_DIG_T2_LSB (2)
#define BMP280_TEMPERATURE_CALIB_DIG_T2_MSB (3)
#define BMP280_TEMPERATURE_CALIB_DIG_T3_LSB (4)
#define BMP280_TEMPERATURE_CALIB_DIG_T3_MSB (5)
#define BMP280_PRESSURE_CALIB_DIG_P1_LSB (6)
#define BMP280_PRESSURE_CALIB_DIG_P1_MSB (7)
#define BMP280_PRESSURE_CALIB_DIG_P2_LSB (8)
#define BMP280_PRESSURE_CALIB_DIG_P2_MSB (9)
#define BMP280_PRESSURE_CALIB_DIG_P3_LSB (10)
#define BMP280_PRESSURE_CALIB_DIG_P3_MSB (11)
#define BMP280_PRESSURE_CALIB_DIG_P4_LSB (12)
#define BMP280_PRESSURE_CALIB_DIG_P4_MSB (13)
#define BMP280_PRESSURE_CALIB_DIG_P5_LSB (14)
#define BMP280_PRESSURE_CALIB_DIG_P5_MSB (15)
#define BMP280_PRESSURE_CALIB_DIG_P6_LSB (16)
#define BMP280_PRESSURE_CALIB_DIG_P6_MSB (17)
#define BMP280_PRESSURE_CALIB_DIG_P7_LSB (18)
#define BMP280_PRESSURE_CALIB_DIG_P7_MSB (19)
#define BMP280_PRESSURE_CALIB_DIG_P8_LSB (20)
#define BMP280_PRESSURE_CALIB_DIG_P8_MSB (21)
#define BMP280_PRESSURE_CALIB_DIG_P9_LSB (22)
#define BMP280_PRESSURE_CALIB_DIG_P9_MSB (23)

#define BMP280_SOFT_RESRT_VALUE (0XB6)

#define BMP280_I2C_SLAVE_ADDR_LOW (0X76)
#define BMP280_I2C_SLAVE_ADDR_HIGH (0X77)

#define BMP280_DEFAULT_ODR_1HZ (1)

#define BMP280_BIT(x) ((uint8_t)(x))
#define BMP280_CHIP_ID_VAL BMP280_BIT(0X58)
#define BMP280_I2C_ADDR_TRANS(n) ((n) << 1)
#define BMP280_I2C_ADDR BMP280_I2C_ADDR_TRANS(BMP280_I2C_SLAVE_ADDR_HIGH)


#define BMP280_GET_BITSLICE(regvar, bitname) \
    ((regvar & bitname##__MSK) >> bitname##__POS)
#define BMP280_SET_BITSLICE(regvar, bitname, val) \
    ((regvar & ~bitname##__MSK) | ((val << bitname##__POS) & bitname##__MSK))

typedef struct bmp280_calib_param_t
{
    uint16_t dig_T1;
    int16_t  dig_T2;
    int16_t  dig_T3;
    uint16_t dig_P1;
    int16_t  dig_P2;
    int16_t  dig_P3;
    int16_t  dig_P4;
    int16_t  dig_P5;
    int16_t  dig_P6;
    int16_t  dig_P7;
    int16_t  dig_P8;
    int16_t  dig_P9;
    int      t_fine;
} bmp280_calib_param_t;

typedef struct bmp280_device_cfg_t
{
    uint8_t odr;
    uint8_t mode_filter;
    uint8_t mode_baro;
    uint8_t mode_temp;
    uint8_t mode_power;
    uint8_t oversamp_temp;
    uint8_t oversamp_baro;
} bmp280_device_cfg_t;

typedef enum {
    DEV_POWER_OFF = 0,
    DEV_POWER_ON,
    DEV_SLEEP,
    DEV_SUSPEND,
    DEV_DEEP_SUSPEND,
} bmp280_power_mode;

typedef enum {
    SENSOR_IOCTL_ODR_SET = 1,
    SENSOR_IOCTL_RANGE_SET,
    SENSOR_IOCTL_SET_POWER,
    SENSOR_IOCTL_GET_INFO,
    SENSOR_IOCTL_MAX
} cmd_type;

static bmp280_calib_param_t g_bmp280_calib_table;


uint8_t bmp280_id_check()
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	/*ID check*/
	//BMP280_CHIP_ID_REG = 0XD0,BMP280_CHIP_ID_VAL = 0X58
	uint8_t id_addr_val[3] = {0xD0,0x58,0x00};
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c2,BMP280_I2C_ADDR,id_addr_val[0],1,&id_addr_val[2],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get part_id error\r\n");
		return 1;
	}
	if(id_addr_val[1]!=id_addr_val[2]){
		printf("bmp280_validate_id is error\r\n");
		return 1;
	}
	printf("bmp280_id:%02X\r\n",id_addr_val[2]);
	return 0;
}

uint8_t bmp280_reset()
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	/*reset*/
	//BMP280_RST_REG = 0XE0,BMP280_SOFT_RESRT_VALUE=0XB6
	uint8_t addr_val[2] = {BMP280_RST_REG,BMP280_SOFT_RESRT_VALUE};
	hi2c2_status = HAL_I2C_Mem_Write(&hi2c2,BMP280_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("bmp280_reset error\r\n");
		return 1;
	}
	return 0;
}

uint8_t bmp280_set_power_mode(bmp280_power_mode mode)
{
	uint8_t dev_mode = 0x00;
    switch (mode) {
        case DEV_POWER_OFF:
        case DEV_SLEEP: {
            dev_mode = (uint8_t)BMP280_SLEEP_MODE;
            break;
        }
        case DEV_POWER_ON: {
            dev_mode = (uint8_t)BMP280_NORMAL_MODE;
            break;
        }
        default:
            return 1;
    }
	HAL_StatusTypeDef hi2c2_status = 0x00;
	//BMP280_CTRL_MEAS_REG=0XF4
	uint8_t mode_addr_val[3] = {BMP280_CTRL_MEAS_REG,0x00,dev_mode};
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c2,BMP280_I2C_ADDR,mode_addr_val[0],1,&mode_addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get bmp280_power_mode error\r\n");
		return 1;
	}
	printf("bmp280 mode_val[1]:%02X\r\n",mode_addr_val[1]);
	mode_addr_val[1] = BMP280_SET_BITSLICE(mode_addr_val[1], BMP280_CTRL_MEAS_REG_POWER_MODE, mode_addr_val[2]);
	printf("bmp280 mode_val[1]:%02X\r\n",mode_addr_val[1]);
	/*reset*/
	hi2c2_status = HAL_I2C_Mem_Write(&hi2c2,BMP280_I2C_ADDR,mode_addr_val[0],1,&mode_addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("bmp280_set_power_mode error\r\n");
		return 1;
	}
	return 0;
}
uint8_t bmp280_set_odr(uint8_t odr)
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	//BMP280_CONFIG_REG_STANDBY_DURN__REG=0XF5
	uint8_t odr_addr_val[2] = {BMP280_CONFIG_REG_STANDBY_DURN__REG,0x00};
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c2,BMP280_I2C_ADDR,odr_addr_val[0],1,&odr_addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get bmp280_odr error\r\n");
		return 1;
	}
	printf("bmp280 odr_val[1]:%02X\r\n",odr_addr_val[1]);
	//BMP280_DEFAULT_ODR_1HZ = 0X01
	odr_addr_val[1] = BMP280_SET_BITSLICE(odr_addr_val[1], BMP280_CONFIG_REG_STANDBY_DURN, odr);
	printf("bmp280 odr_val[1]:%02X\r\n",odr_addr_val[1]);
	/*reset*/
	hi2c2_status = HAL_I2C_Mem_Write(&hi2c2,BMP280_I2C_ADDR,odr_addr_val[0],1,&odr_addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("bmp280_set_odr error\r\n");
		return 1;
	}
	return 0;
}

static uint8_t bmp280_hz2odr(int hz)
{
    if (hz > 80) {
        return BMP280_STANDBY_TIME_1_MS;
    } else if (hz > 13) {
        return BMP280_STANDBY_TIME_63_MS;
    } else if (hz > 7) {
        return BMP280_STANDBY_TIME_125_MS;
    } else if (hz > 3) {
        return BMP280_STANDBY_TIME_250_MS;
    } else {
        return BMP280_STANDBY_TIME_500_MS;
    }
}


uint8_t bmp280_ioctl(cmd_type cmd,uint32_t arg)
{
	uint8_t ret = 0;
    switch (cmd) {
        case SENSOR_IOCTL_ODR_SET: {
            uint8_t odr = bmp280_hz2odr(arg);
            ret         = bmp280_set_odr( odr);
            if (ret>0) {
                return 1;
            }
        } break;
        case SENSOR_IOCTL_SET_POWER: {
            ret = bmp280_set_power_mode(arg);
            if (ret>0) {
                return 1;
            }
        } break;
        case SENSOR_IOCTL_GET_INFO: {

        } break;

        default:
            break;
    }
    return 0;
}

uint8_t bmp280_set_default_config()
{
	uint8_t ret = bmp280_set_power_mode(DEV_SLEEP);
	if(ret>0)
		return 1;
	ret = bmp280_set_odr(BMP280_DEFAULT_ODR_1HZ);
	if(ret>0)
		return 1;
	return 0;
}

uint8_t bmp280_get_calib_param()
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	uint8_t data_u8[BMP280_CALIB_DATA_SIZE] = { 0x00 };
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c2,BMP280_I2C_ADDR,BMP280_TEMPERATURE_CALIB_DIG_T1_LSB_REG
			,1,data_u8,BMP280_PRESSURE_TEMPERATURE_CALIB_DATA_LENGTH,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get bmp280_calib_param error\r\n");
		return 1;
	}
	g_bmp280_calib_table.dig_T1 = (uint16_t)(
			(((uint16_t)((uint8_t)data_u8[BMP280_TEMPERATURE_CALIB_DIG_T1_MSB])) << BMP280_SHIFT_BY_08_BITS)
			| data_u8[BMP280_TEMPERATURE_CALIB_DIG_T1_LSB]);
	g_bmp280_calib_table.dig_T2 = (int16_t)(
	      (((int16_t)((int8_t)data_u8[BMP280_TEMPERATURE_CALIB_DIG_T2_MSB])) << BMP280_SHIFT_BY_08_BITS)
		   | data_u8[BMP280_TEMPERATURE_CALIB_DIG_T2_LSB]);
	g_bmp280_calib_table.dig_T3 = (int16_t)(
	      (((int16_t)((int8_t)data_u8[BMP280_TEMPERATURE_CALIB_DIG_T3_MSB])) << BMP280_SHIFT_BY_08_BITS)
		  | data_u8[BMP280_TEMPERATURE_CALIB_DIG_T3_LSB]);
	g_bmp280_calib_table.dig_P1 = (uint16_t)(
	      (((uint16_t)((uint8_t)data_u8[BMP280_PRESSURE_CALIB_DIG_P1_MSB])) << BMP280_SHIFT_BY_08_BITS)
		  | data_u8[BMP280_PRESSURE_CALIB_DIG_P1_LSB]);
	g_bmp280_calib_table.dig_P2 = (int16_t)(
	      (((int16_t)((int8_t)data_u8[BMP280_PRESSURE_CALIB_DIG_P2_MSB])) << BMP280_SHIFT_BY_08_BITS)
		  | data_u8[BMP280_PRESSURE_CALIB_DIG_P2_LSB]);
	g_bmp280_calib_table.dig_P3 = (int16_t)(
	      (((int16_t)((int8_t)data_u8[BMP280_PRESSURE_CALIB_DIG_P3_MSB])) << BMP280_SHIFT_BY_08_BITS)
		  | data_u8[BMP280_PRESSURE_CALIB_DIG_P3_LSB]);
	g_bmp280_calib_table.dig_P4 = (int16_t)(
	      (((int16_t)((int8_t)data_u8[BMP280_PRESSURE_CALIB_DIG_P4_MSB])) << BMP280_SHIFT_BY_08_BITS)
		  | data_u8[BMP280_PRESSURE_CALIB_DIG_P4_LSB]);
	g_bmp280_calib_table.dig_P5 = (int16_t)(
	      (((int16_t)((int8_t)data_u8[BMP280_PRESSURE_CALIB_DIG_P5_MSB])) << BMP280_SHIFT_BY_08_BITS)
		  | data_u8[BMP280_PRESSURE_CALIB_DIG_P5_LSB]);
	g_bmp280_calib_table.dig_P6 = (int16_t)(
	      (((int16_t)((int8_t)data_u8[BMP280_PRESSURE_CALIB_DIG_P6_MSB])) << BMP280_SHIFT_BY_08_BITS)
		  | data_u8[BMP280_PRESSURE_CALIB_DIG_P6_LSB]);
	g_bmp280_calib_table.dig_P7 = (int16_t)(
	      (((int16_t)((int8_t)data_u8[BMP280_PRESSURE_CALIB_DIG_P7_MSB])) << BMP280_SHIFT_BY_08_BITS)
		  | data_u8[BMP280_PRESSURE_CALIB_DIG_P7_LSB]);
	g_bmp280_calib_table.dig_P8 = (int16_t)(
	      (((int16_t)((int8_t)data_u8[BMP280_PRESSURE_CALIB_DIG_P8_MSB])) << BMP280_SHIFT_BY_08_BITS)
		  | data_u8[BMP280_PRESSURE_CALIB_DIG_P8_LSB]);
	g_bmp280_calib_table.dig_P9 = (int16_t)(
	      (((int16_t)((int8_t)data_u8[BMP280_PRESSURE_CALIB_DIG_P9_MSB])) << BMP280_SHIFT_BY_08_BITS)
		  | data_u8[BMP280_PRESSURE_CALIB_DIG_P9_LSB]);
	return 0;
}

uint8_t bmp280_set_baro_work_mode(uint8_t mode)
{
    uint8_t value = 0;
    uint8_t temp  = 0;
    uint8_t baro  = 0;

    switch (mode) {
    case BMP280_ULTRA_LOW_POWER_MODE:
        temp = BMP280_OVERSAMP_1X;
        baro = BMP280_OVERSAMP_1X;
        break;

    case BMP280_LOW_POWER_MODE:
        temp = BMP280_OVERSAMP_2X;
        baro = BMP280_OVERSAMP_2X;
        break;

    case BMP280_STANDARD_RESOLUTION_MODE:
        temp = BMP280_OVERSAMP_4X;
        baro = BMP280_OVERSAMP_4X;
        break;

    case BMP280_HIGH_RESOLUTION_MODE:
        temp = BMP280_OVERSAMP_8X;
        baro = BMP280_OVERSAMP_8X;
        break;

    case BMP280_ULTRA_HIGH_RESOLUTION_MODE:
        temp = BMP280_OVERSAMP_16X;
        baro = BMP280_OVERSAMP_16X;
        break;

    default:
        return 1;
    }
    HAL_StatusTypeDef hi2c2_status = 0x00;

	hi2c2_status = HAL_I2C_Mem_Read(&hi2c2,BMP280_I2C_ADDR,BMP280_CTRL_MEAS_REG
			,1,&value,1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get bmp280_calib_param error\r\n");
		return 1;
	}
	value =	BMP280_SET_BITSLICE(value, BMP280_CTRL_MEAS_REG_OVERSAMP_PRESSURE, baro);
	value = BMP280_SET_BITSLICE(value, BMP280_CTRL_MEAS_REG_OVERSAMP_TEMPERATURE, temp);
	hi2c2_status = HAL_I2C_Mem_Write(&hi2c2,BMP280_I2C_ADDR,BMP280_CTRL_MEAS_REG,1,&value,1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("bmp280_set_power_mode error\r\n");
		return 1;
	}
	printf("successfully BMP280 set  baro_work_mode \r\n");
	return 0;
}

uint8_t bmp280_open(void)
{
	uint8_t ret = bmp280_set_baro_work_mode(BMP280_ULTRA_LOW_POWER_MODE);
	if(ret>0)
		return 1;
	ret = bmp280_set_power_mode(DEV_POWER_ON);
	if(ret>0)
		return 1;
	return 0;
}

uint8_t bmp280_close(void)
{
	uint8_t ret = bmp280_set_power_mode(DEV_POWER_OFF);
	if(ret>0)
		return 1;
	return 0;
}

void BMP280_init()
{
	if(bmp280_id_check()>0)
		return;
	if(bmp280_reset()>0)
		return;
	if(bmp280_set_default_config()>0)
		return;
	if(bmp280_get_calib_param()>0)
		return;
	printf("successfully BMP280 init\r\n");
}

uint8_t read_bmp280_temp(uint32_t *comp_temp)
{
	*comp_temp = 0;
	uint8_t data_u8[BMP280_TEMPERATURE_DATA_SIZE] = { 0 };
	int32_t temp;
	HAL_StatusTypeDef hi2c2_status = 0x00;

	hi2c2_status = HAL_I2C_Mem_Read(&hi2c2,BMP280_I2C_ADDR,BMP280_TEMPERATURE_MSB_REG
			,1,data_u8,BMP280_TEMPERATURE_DATA_SIZE,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get bmp280_calib_param error\r\n");
		return 1;
	}
	temp = (int)((((uint32_t)(data_u8[BMP280_TEMPERATURE_MSB_DATA]))
			<< BMP280_SHIFT_BY_12_BITS) | (((uint32_t)(data_u8[BMP280_TEMPERATURE_LSB_DATA]))
			<< BMP280_SHIFT_BY_04_BITS) | ((uint32_t)data_u8[BMP280_TEMPERATURE_XLSB_DATA]
			>> BMP280_SHIFT_BY_04_BITS));
	//
    int v_x1_u32r = 0;
    int v_x2_u32r = 0;
    v_x1_u32r = ((((temp >> BMP280_SHIFT_BY_03_BITS) -
    		((int)g_bmp280_calib_table.dig_T1 << BMP280_SHIFT_BY_01_BIT))) *
    		((int)g_bmp280_calib_table.dig_T2)) >> BMP280_SHIFT_BY_11_BITS;

    v_x2_u32r = (((((temp >> BMP280_SHIFT_BY_04_BITS) -
                    ((int)g_bmp280_calib_table.dig_T1)) *
                   ((temp >> BMP280_SHIFT_BY_04_BITS) -
                    ((int)g_bmp280_calib_table.dig_T1))) >>
                  BMP280_SHIFT_BY_12_BITS) *
                 ((int)g_bmp280_calib_table.dig_T3)) >>
                BMP280_SHIFT_BY_14_BITS;

    g_bmp280_calib_table.t_fine = v_x1_u32r + v_x2_u32r;

    temp = (g_bmp280_calib_table.t_fine * 5 + 128) >> BMP280_SHIFT_BY_08_BITS;
    printf("comp_temp: %d.%d\n", (int)temp/100, (int)(temp % 100));
    *comp_temp = temp;
    return 0;
}

uint8_t read_bmp280_baro(uint32_t *comp_baro)
{
	*comp_baro = 0;
	uint8_t data_u8[BMP280_PRESSURE_DATA_SIZE] = { 0 };
	int32_t temp;
	HAL_StatusTypeDef hi2c2_status = 0x00;
	//BMP280_PRESSURE_MSB_REG=0XF7,BMP280_PRESSURE_DATA_SIZE=0X03
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c2,BMP280_I2C_ADDR,BMP280_PRESSURE_MSB_REG
				,1,data_u8,BMP280_PRESSURE_DATA_SIZE,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get bmp280_calib_param error\r\n");
		return 1;
	}
	temp = (int)(
			(((uint32_t)(data_u8[BMP280_PRESSURE_MSB_DATA])) << BMP280_SHIFT_BY_12_BITS)
			| (((uint32_t)(data_u8[BMP280_PRESSURE_LSB_DATA])) << BMP280_SHIFT_BY_04_BITS)
			| ((uint32_t)data_u8[BMP280_PRESSURE_XLSB_DATA]	>> BMP280_SHIFT_BY_04_BITS)
			);
	//
	int      v_x1_u32r = 0;
	int      v_x2_u32r = 0;

	v_x1_u32r = (((int)g_bmp280_calib_table.t_fine) >> BMP280_SHIFT_BY_01_BIT) - (int)64000;
	v_x2_u32r = (((v_x1_u32r >> BMP280_SHIFT_BY_02_BITS) * (v_x1_u32r >> BMP280_SHIFT_BY_02_BITS)) >>
	                 BMP280_SHIFT_BY_11_BITS) * ((int)g_bmp280_calib_table.dig_P6);
	v_x2_u32r = v_x2_u32r + ((v_x1_u32r * ((int)g_bmp280_calib_table.dig_P5)) << BMP280_SHIFT_BY_01_BIT);
	v_x2_u32r = (v_x2_u32r >> BMP280_SHIFT_BY_02_BITS) + (((int)g_bmp280_calib_table.dig_P4) << BMP280_SHIFT_BY_16_BITS);
	v_x1_u32r = (((g_bmp280_calib_table.dig_P3 *  (((v_x1_u32r >> BMP280_SHIFT_BY_02_BITS) *
			(v_x1_u32r >> BMP280_SHIFT_BY_02_BITS)) >> BMP280_SHIFT_BY_13_BITS)) >> BMP280_SHIFT_BY_03_BITS) +
	        ((((int)g_bmp280_calib_table.dig_P2) * v_x1_u32r) >> BMP280_SHIFT_BY_01_BIT)) >> BMP280_SHIFT_BY_18_BITS;
	v_x1_u32r = ((((32768 + v_x1_u32r)) * ((int)g_bmp280_calib_table.dig_P1)) >> BMP280_SHIFT_BY_15_BITS);
	if (v_x1_u32r == 0)
	{
		return 1; // avoid exception caused by division by zero
	}
	//
	uint32_t val_baro = 0;
	val_baro = (((uint32_t)(((int)1048576) - temp) - (v_x2_u32r >> BMP280_SHIFT_BY_12_BITS))) * 3125;

	if (val_baro < 0x80000000) {
		if (v_x1_u32r != 0) {
			val_baro =	(val_baro << BMP280_SHIFT_BY_01_BIT) / ((uint32_t)v_x1_u32r);
		} else {
			return 1;
		}
	} else if (v_x1_u32r != 0) {
		val_baro = (val_baro / (uint32_t)v_x1_u32r) * 2;
	} else {
	        return 1;
	}
	v_x1_u32r = (((int)g_bmp280_calib_table.dig_P9) * ((int)(((val_baro >> BMP280_SHIFT_BY_03_BITS) *
	    		(val_baro >> BMP280_SHIFT_BY_03_BITS)) >> BMP280_SHIFT_BY_13_BITS))) >> BMP280_SHIFT_BY_12_BITS;

	v_x2_u32r = (((int)(val_baro >> BMP280_SHIFT_BY_02_BITS)) * ((int)g_bmp280_calib_table.dig_P8)) >>	BMP280_SHIFT_BY_13_BITS;

	val_baro = (uint32_t)((int)val_baro +
	    		((v_x1_u32r + v_x2_u32r + g_bmp280_calib_table.dig_P7) >> BMP280_SHIFT_BY_04_BITS));

	printf("comp_baro:%d.%d\r\n",(int)val_baro/100, (int)(val_baro % 100));
	*comp_baro = val_baro;
	return 0;
}

  八、LSM6DSL传感器(加速度及角速度)

        在ICore源码目录下,创建LSM6DSL文件夹,再在该目录下创建LSM6DSL.h和LSM6DSL.c源文件。

        在网上查找下载LSM6DSL传感器数据手册,逐步分析,该传感器的I2C通信也是采用了从机地址+寄存器地址+数据的通信方式,传感器从设备地址0XD4(0X6A(01101010)<<1)如下:

        但中间这段文字描述翻译如下:LSM6DSL相关的从属AD地址(SAD)为110101xb。SDO/SA0引脚可用于修改设备地址的低位。如果SDO/SA0引脚连接到电源电压,LSb为“1”(地址1101011b);否则,如果SDO/SA0引脚接地,则LSb值为“0”(地址1101010b)。该解决方案允许将两个不同的惯性模块连接并寻址到同一I2C总线,即有两个地址0X6A(1101010)、0X6B(1101011)。开发板的结合硬件原理图,在R500和R502接线下,取值不同,经测试0XD6、0XD7才能正确读取设备ID,开发板应该是R502接线,从设备地址是0XD6/7。

        1)设备ID,地址是0X0F,正确返回值是0X6A

         2)软重置设置,寄存器地址是0X12,设置mydata|0x01可重置设备

         3)acc加速度模式设置,涉及odr(rate、power)、 刻度(scale)、频宽、是否启动。

         4)Gyro角速度模式设置,涉及odr(rate)、刻度(scale)、是否启动。

         5)读取数据 地址0X22~0X27为gyro数值,共6字节(16bit).地址0X28~0X2D为acc数值,共6字节(16bit)

        ACC和GYRO数值换算表如下,相关含义读者可以查找加速度及角速度相关知识了解:

         6)按以上分析,给出LSM6DSl传感器的伪代码

LSM6DSL从机地址是0XD6
init:
read id from 从机地址是0XD6 寄存器地址0X0F
确定id==0X6A 
write myconf|0X01 to 从机地址是0XD6 寄存器地址0X12 软重置设备
write mymode to 从机地址是0XD6 寄存器地址0X10 设置设备ACC模式
write mymode to 从机地址是0XD6 寄存器地址0X11 设置设备GYRO模式

读取数据
acc 读取数据前确保设置了相关参数,如power mode,range,频宽等,在寄存器地址0X10 设置
read acc1~6 from 从机地址是0XD6 寄存器地址0X28,0X29,0X2A,0X2B,0X2C,0X2D
acc1~6进行换算处理得到acc数值

acc 读取数据前确保设置了相关参数,如power mode,range,频宽等,寄存器地址0X11设置
read gyro1~6 from 从机地址是0XD6 寄存器地址0X22,0X23,0X24,0X25,0X26,0X27
gyro1~6进行换算处理得到gyro数值

         7)按以上分析及伪代码设计,LSM6DSL传感器的给出LSM6DSL.h和LSM6DSL.c源文件

        LSM6DSL.h

#ifndef _LSM6DSL_H_
#define _LSM6DSL_H_

#include "main.h"

void LSM6DSL_acc_init();
uint8_t LSM6DSL_acc_st_open(void);
uint8_t LSM6DSL_acc_st_close(void);

void LSM6DSL_gyro_init();
uint8_t LSM6DSL_gyro_st_open(void);
uint8_t LSM6DSL_gyro_st_close(void);

uint8_t LSM6DSL_acc_read(int32_t *x_data,int32_t *y_data,int32_t *z_data);
uint8_t LSM6DSL_gyro_read(int32_t *x_data,int32_t *y_data,int32_t *z_data);

#endif /* LSM6DSL_LSM6DSL_H_ */

         LSM6DSL.c

#include <stdio.h>
#include "LSM6DSL.h"

extern I2C_HandleTypeDef hi2c4;

#define LSM6DSL_I2C_ADDR1 (0x6A)
#define LSM6DSL_I2C_ADDR2 (0x6B)
#define LSM6DSL_I2C_ADDR_TRANS(n) ((n) << 1)
#define LSM6DSL_I2C_ADDR LSM6DSL_I2C_ADDR_TRANS(LSM6DSL_I2C_ADDR2)

#define LSM6DSL_ACC_GYRO_FUNC_CFG_ACCESS 0x01
#define LSM6DSL_ACC_GYRO_SENSOR_SYNC_TIME 0x04
#define LSM6DSL_ACC_GYRO_SENSOR_RES_RATIO 0x05
#define LSM6DSL_ACC_GYRO_FIFO_CTRL1 0x06
#define LSM6DSL_ACC_GYRO_FIFO_CTRL2 0x07
#define LSM6DSL_ACC_GYRO_FIFO_CTRL3 0x08
#define LSM6DSL_ACC_GYRO_FIFO_CTRL4 0x09
#define LSM6DSL_ACC_GYRO_FIFO_CTRL5 0x0A
#define LSM6DSL_ACC_GYRO_DRDY_PULSE_CFG_G 0x0B
#define LSM6DSL_ACC_GYRO_INT1_CTRL 0x0D
#define LSM6DSL_ACC_GYRO_INT2_CTRL 0x0E
#define LSM6DSL_ACC_GYRO_WHO_AM_I_REG 0x0F
#define LSM6DSL_ACC_GYRO_CTRL1_XL 0x10
#define LSM6DSL_ACC_GYRO_CTRL2_G 0x11
#define LSM6DSL_ACC_GYRO_CTRL3_C 0x12
#define LSM6DSL_ACC_GYRO_CTRL4_C 0x13
#define LSM6DSL_ACC_GYRO_CTRL5_C 0x14
#define LSM6DSL_ACC_GYRO_CTRL6_C 0x15
#define LSM6DSL_ACC_GYRO_CTRL7_G 0x16
#define LSM6DSL_ACC_GYRO_CTRL8_XL 0x17
#define LSM6DSL_ACC_GYRO_CTRL9_XL 0x18
#define LSM6DSL_ACC_GYRO_CTRL10_C 0x19


#define LSM6DSL_ACC_GYRO_MASTER_CONFIG 0x1A
#define LSM6DSL_ACC_GYRO_WAKE_UP_SRC 0x1B
#define LSM6DSL_ACC_GYRO_TAP_SRC 0x1C
#define LSM6DSL_ACC_GYRO_D6D_SRC 0x1D
#define LSM6DSL_ACC_GYRO_STATUS_REG 0x1E

#define LSM6DSL_ACC_GYRO_OUT_TEMP_L 0x20
#define LSM6DSL_ACC_GYRO_OUT_TEMP_H 0x21
#define LSM6DSL_ACC_GYRO_OUTX_L_G 0x22
#define LSM6DSL_ACC_GYRO_OUTX_H_G 0x23
#define LSM6DSL_ACC_GYRO_OUTY_L_G 0x24
#define LSM6DSL_ACC_GYRO_OUTY_H_G 0x25
#define LSM6DSL_ACC_GYRO_OUTZ_L_G 0x26
#define LSM6DSL_ACC_GYRO_OUTZ_H_G 0x27
#define LSM6DSL_ACC_GYRO_OUTX_L_XL 0x28
#define LSM6DSL_ACC_GYRO_OUTX_H_XL 0x29
#define LSM6DSL_ACC_GYRO_OUTY_L_XL 0x2A
#define LSM6DSL_ACC_GYRO_OUTY_H_XL 0x2B
#define LSM6DSL_ACC_GYRO_OUTZ_L_XL 0x2C
#define LSM6DSL_ACC_GYRO_OUTZ_H_XL 0x2D
#define LSM6DSL_ACC_GYRO_SENSORHUB1_REG 0x2E
#define LSM6DSL_ACC_GYRO_SENSORHUB2_REG 0x2F
#define LSM6DSL_ACC_GYRO_SENSORHUB3_REG 0x30
#define LSM6DSL_ACC_GYRO_SENSORHUB4_REG 0x31
#define LSM6DSL_ACC_GYRO_SENSORHUB5_REG 0x32
#define LSM6DSL_ACC_GYRO_SENSORHUB6_REG 0x33
#define LSM6DSL_ACC_GYRO_SENSORHUB7_REG 0x34
#define LSM6DSL_ACC_GYRO_SENSORHUB8_REG 0x35
#define LSM6DSL_ACC_GYRO_SENSORHUB9_REG 0x36
#define LSM6DSL_ACC_GYRO_SENSORHUB10_REG 0x37
#define LSM6DSL_ACC_GYRO_SENSORHUB11_REG 0x38
#define LSM6DSL_ACC_GYRO_SENSORHUB12_REG 0x39
#define LSM6DSL_ACC_GYRO_FIFO_STATUS1 0x3A
#define LSM6DSL_ACC_GYRO_FIFO_STATUS2 0x3B
#define LSM6DSL_ACC_GYRO_FIFO_STATUS3 0x3C
#define LSM6DSL_ACC_GYRO_FIFO_STATUS4 0x3D
#define LSM6DSL_ACC_GYRO_FIFO_DATA_OUT_L 0x3E
#define LSM6DSL_ACC_GYRO_FIFO_DATA_OUT_H 0x3F
#define LSM6DSL_ACC_GYRO_TIMESTAMP0_REG 0x40
#define LSM6DSL_ACC_GYRO_TIMESTAMP1_REG 0x41
#define LSM6DSL_ACC_GYRO_TIMESTAMP2_REG 0x42

#define LSM6DSL_ACC_GYRO_TIMESTAMP_L 0x49
#define LSM6DSL_ACC_GYRO_TIMESTAMP_H 0x4A

#define LSM6DSL_ACC_GYRO_STEP_COUNTER_L 0x4B
#define LSM6DSL_ACC_GYRO_STEP_COUNTER_H 0x4C

#define LSM6DSL_ACC_GYRO_SENSORHUB13_REG 0x4D
#define LSM6DSL_ACC_GYRO_SENSORHUB14_REG 0x4E
#define LSM6DSL_ACC_GYRO_SENSORHUB15_REG 0x4F
#define LSM6DSL_ACC_GYRO_SENSORHUB16_REG 0x50
#define LSM6DSL_ACC_GYRO_SENSORHUB17_REG 0x51
#define LSM6DSL_ACC_GYRO_SENSORHUB18_REG 0x52

#define LSM6DSL_ACC_GYRO_FUNC_SRC 0x53
#define LSM6DSL_ACC_GYRO_TAP_CFG1 0x58
#define LSM6DSL_ACC_GYRO_TAP_THS_6D 0x59
#define LSM6DSL_ACC_GYRO_INT_DUR2 0x5A
#define LSM6DSL_ACC_GYRO_WAKE_UP_THS 0x5B
#define LSM6DSL_ACC_GYRO_WAKE_UP_DUR 0x5C
#define LSM6DSL_ACC_GYRO_FREE_FALL 0x5D
#define LSM6DSL_ACC_GYRO_MD1_CFG 0x5E
#define LSM6DSL_ACC_GYRO_MD2_CFG 0x5F

#define LSM6DSL_ACC_GYRO_OUT_MAG_RAW_X_L 0x66
#define LSM6DSL_ACC_GYRO_OUT_MAG_RAW_X_H 0x67
#define LSM6DSL_ACC_GYRO_OUT_MAG_RAW_Y_L 0x68
#define LSM6DSL_ACC_GYRO_OUT_MAG_RAW_Y_H 0x69
#define LSM6DSL_ACC_GYRO_OUT_MAG_RAW_Z_L 0x6A
#define LSM6DSL_ACC_GYRO_OUT_MAG_RAW_Z_H 0x6B

#define LSM6DSL_ACC_GYRO_X_OFS_USR 0x73
#define LSM6DSL_ACC_GYRO_Y_OFS_USR 0x74
#define LSM6DSL_ACC_GYRO_Z_OFS_USR 0x75

#define LSM6DSL_CHIP_ID_VALUE (0x6A)

#define LSM6DSL_RESET_VALUE (0x1)
#define LSM6DSL_RESET_MSK (0X1)
#define LSM6DSL_RESET_POS (0)

#define LSM6DSL_ACC_ODR_POWER_DOWN (0X00)
#define LSM6DSL_ACC_ODR_1_6_HZ (0X0B)
#define LSM6DSL_ACC_ODR_12_5_HZ (0x01)
#define LSM6DSL_ACC_ODR_26_HZ (0x02)
#define LSM6DSL_ACC_ODR_52_HZ (0x03)
#define LSM6DSL_ACC_ODR_104_HZ (0x04)
#define LSM6DSL_ACC_ODR_208_HZ (0x05)
#define LSM6DSL_ACC_ODR_416_HZ (0x06)
#define LSM6DSL_ACC_ODR_833_HZ (0x07)
#define LSM6DSL_ACC_ODR_1_66_KHZ (0x08)
#define LSM6DSL_ACC_ODR_3_33_KHZ (0x09)
#define LSM6DSL_ACC_ODR_6_66_KHZ (0x0A)
#define LSM6DSL_ACC_ODR_MSK (0XF0)
#define LSM6DSL_ACC_ODR_POS (4)

#define LSM6DSL_GYRO_ODR_POWER_DOWN (0X00)
#define LSM6DSL_GYRO_ODR_12_5_HZ (0x01)
#define LSM6DSL_GYRO_ODR_26_HZ (0x02)
#define LSM6DSL_GYRO_ODR_52_HZ (0x03)
#define LSM6DSL_GYRO_ODR_104_HZ (0x04)
#define LSM6DSL_GYRO_ODR_208_HZ (0x05)
#define LSM6DSL_GYRO_ODR_416_HZ (0x06)
#define LSM6DSL_GYRO_ODR_833_HZ (0x07)
#define LSM6DSL_GYRO_ODR_1_66_KHZ (0x08)
#define LSM6DSL_GYRO_ODR_3_33_KHZ (0x09)
#define LSM6DSL_GYRO_ODR_6_66_KHZ (0x0A)
#define LSM6DSL_GYRO_ODR_MSK (0XF0)
#define LSM6DSL_GYRO_ODR_POS (4)

#define LSM6DSL_ACC_RANGE_2G (0x0)
#define LSM6DSL_ACC_RANGE_4G (0x2)
#define LSM6DSL_ACC_RANGE_8G (0x3)
#define LSM6DSL_ACC_RANGE_16G (0x1)
#define LSM6DSL_ACC_RANGE_MSK (0X0C)
#define LSM6DSL_ACC_RANGE_POS (2)

#define LSM6DSL_ACC_SENSITIVITY_2G (61)
#define LSM6DSL_ACC_SENSITIVITY_4G (122)
#define LSM6DSL_ACC_SENSITIVITY_8G (244)
#define LSM6DSL_ACC_SENSITIVITY_16G (488)

#define LSM6DSL_GYRO_RANGE_245 (0x0)
#define LSM6DSL_GYRO_RANGE_500 (0x1)
#define LSM6DSL_GYRO_RANGE_1000 (0x2)
#define LSM6DSL_GYRO_RANGE_2000 (0x3)
#define LSM6DSL_GYRO_RANGE_MSK (0X0C)
#define LSM6DSL_GYRO_RANGE_POS (2)

#define LSM6DSL_GYRO_SENSITIVITY_245DPS (8750)
#define LSM6DSL_GYRO_SENSITIVITY_500DPS (17500)
#define LSM6DSL_GYRO_SENSITIVITY_1000DPS (35000)
#define LSM6DSL_GYRO_SENSITIVITY_2000DPS (70000)

#define LSM6DSL_SHIFT_EIGHT_BITS (8)
#define LSM6DSL_16_BIT_SHIFT (0xFF)
#define LSM6DSL_ACC_MUL (1000)
#define LSM6DSL_GYRO_MUL (1)

#define LSM6DSL_ACC_DEFAULT_ODR_100HZ (100)
#define LSM6DSL_GYRO_DEFAULT_ODR_100HZ (100)

#define LSM6DSL_GET_BITSLICE(regvar, bitname) \
    ((regvar & bitname##_MSK) >> bitname##_POS)

#define LSM6DSL_SET_BITSLICE(regvar, bitname, val) \
    ((regvar & ~bitname##_MSK) | ((val << bitname##_POS) & bitname##_MSK))

typedef enum {
    ACC_RANGE_2G,
    ACC_RANGE_4G,
    ACC_RANGE_8G,
    ACC_RANGE_16G,
    ACC_RANGE_6G,
    ACC_RANGE_12G,
    ACC_RANGE_24G,
    ACC_RANGE_100G,
    ACC_RANGE_200G,
    ACC_RANGE_400G,
    ACC_RANGE_MAX
} acc_range_e;

typedef enum {
    GYRO_RANGE_125DPS,
    GYRO_RANGE_250DPS,
    GYRO_RANGE_500DPS,
    GYRO_RANGE_1000DPS,
    GYRO_RANGE_2000DPS,
    GYRO_RANGE_MAX
} gyro_range_e;

static int32_t lsm6dsl_acc_factor[ACC_RANGE_MAX] = {
    LSM6DSL_ACC_SENSITIVITY_2G, LSM6DSL_ACC_SENSITIVITY_4G,
    LSM6DSL_ACC_SENSITIVITY_8G, LSM6DSL_ACC_SENSITIVITY_16G
};
static int32_t lsm6dsl_gyro_factor[GYRO_RANGE_MAX] = {
    0, LSM6DSL_GYRO_SENSITIVITY_245DPS, LSM6DSL_GYRO_SENSITIVITY_500DPS,
    LSM6DSL_GYRO_SENSITIVITY_1000DPS, LSM6DSL_GYRO_SENSITIVITY_2000DPS
};

typedef enum {
    DEV_POWER_OFF = 0,
    DEV_POWER_ON,
    DEV_SLEEP,
    DEV_SUSPEND,
    DEV_DEEP_SUSPEND,
} LSM6DSL_power_mode;

static int32_t cur_acc_factor  = 0;
static int32_t cur_gyro_factor = 0;

uint8_t LSM6DSL_ID_check()
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	uint8_t addr_val[3] = {LSM6DSL_ACC_GYRO_WHO_AM_I_REG,0x00,LSM6DSL_CHIP_ID_VALUE};
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get LSM6DSL ID error\r\n");
		return 1;
	}
	if(addr_val[1]!=addr_val[2]){
		printf("LSM6DSL validate_id is error\r\n");
		return 1;
	}
	printf("LSM6DSL_id:%02X\r\n",addr_val[1]);
	return 0;
}

uint8_t LSM6DSL_soft_reset()
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	/*first read*/
	uint8_t addr_val[2] = {LSM6DSL_ACC_GYRO_CTRL3_C,0x00};
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get LSM6DSL ACC_GYRO_CTRL3_C error\r\n");
		return 1;
	}
	printf("LSM6DSL ACC_GYRO_CTRL3_C old:%02X\r\n",addr_val[1]);
	addr_val[1] |= LSM6DSL_RESET_VALUE;
	printf("LSM6DSL ACC_GYRO_CTRL3_C new:%02X\r\n",addr_val[1]);
	hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("set LSM6DSL ACC_GYRO_CTRL3_C error\r\n");
		return 1;
	}
	printf("successfully LSM6DSL soft reset\r\n");
	return 0;
}
/*
 * 以正数为例,最大可到32767,如果是Accelerometer数据,量程为2g的情况下,
 * 32768个刻度,一个刻度代表:2g/32768 = 2000mg/32767 = 0.061035mg
 * 例如:如果读出数据为16384,则加速度:16384x0.061035mg = 1000mg = 1g
 */
uint8_t LSM6DSL_acc_set_range(uint32_t range)
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	/*first read*/
	uint8_t addr_val[2] = {LSM6DSL_ACC_GYRO_CTRL1_XL,0x00};
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get LSM6DSL acc range error\r\n");
		return 1;
	}
	uint8_t tmp   = 0;
    switch (range) {
    	case ACC_RANGE_2G: {
            tmp = LSM6DSL_ACC_RANGE_2G;
        } break;

        case ACC_RANGE_4G: {
            tmp = LSM6DSL_ACC_RANGE_4G;
        } break;

        case ACC_RANGE_8G: {
            tmp = LSM6DSL_ACC_RANGE_8G;
        } break;

        case ACC_RANGE_16G: {
            tmp = LSM6DSL_ACC_RANGE_16G;
        } break;

        default:
            break;
    }
    addr_val[1] = LSM6DSL_SET_BITSLICE(addr_val[1], LSM6DSL_ACC_RANGE, tmp);
    hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("set LSM6DSL acc range error\r\n");
		return 1;
	}
	if (range <= ACC_RANGE_16G) {
        cur_acc_factor = lsm6dsl_acc_factor[range];
    }
	printf("successfully LSM6DSL set acc range\r\n");
	return 0;
}

static uint8_t acc_st_lsm6dsl_hz2odr(uint32_t hz)
{
    if (hz > 3330)
        return LSM6DSL_ACC_ODR_6_66_KHZ;
    else if (hz > 1660)
        return LSM6DSL_ACC_ODR_3_33_KHZ;
    else if (hz > 833)
        return LSM6DSL_ACC_ODR_1_66_KHZ;
    else if (hz > 416)
        return LSM6DSL_ACC_ODR_833_HZ;
    else if (hz > 208)
        return LSM6DSL_ACC_ODR_416_HZ;
    else if (hz > 104)
        return LSM6DSL_ACC_ODR_208_HZ;
    else if (hz > 52)
        return LSM6DSL_ACC_ODR_104_HZ;
    else if (hz > 26)
        return LSM6DSL_ACC_ODR_52_HZ;
    else if (hz > 13)
        return LSM6DSL_ACC_ODR_26_HZ;
    else if (hz >= 2)
        return LSM6DSL_ACC_ODR_12_5_HZ;
    else
        return LSM6DSL_ACC_ODR_1_6_HZ;
}

uint8_t LSM6DSL_acc_set_odr(uint32_t hz)
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	/*first read*/
	uint8_t addr_val[2] = {LSM6DSL_ACC_GYRO_CTRL1_XL,0x00};
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get LSM6DSL acc odr error\r\n");
		return 1;
	}
	uint8_t odr   = acc_st_lsm6dsl_hz2odr(hz);
	addr_val[1] = LSM6DSL_SET_BITSLICE(addr_val[1], LSM6DSL_ACC_ODR, odr);
	hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("set LSM6DSL acc odr error\r\n");
		return 1;
	}
	printf("successfully LSM6DSL set acc odr\r\n");
	return 0;
}

uint8_t LSM6DSL_acc_power_mode(LSM6DSL_power_mode mode)
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	/*first read*/
	uint8_t addr_val[2] = {LSM6DSL_ACC_GYRO_CTRL1_XL,0x00};
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get LSM6DSL acc power_mode error\r\n");
		return 1;
	}
	switch (mode) {
		case DEV_POWER_ON: {
			addr_val[1] = LSM6DSL_SET_BITSLICE(addr_val[1], LSM6DSL_ACC_ODR,LSM6DSL_ACC_ODR_12_5_HZ);
		}
		break;
		case DEV_POWER_OFF: {
			addr_val[1] = LSM6DSL_SET_BITSLICE(addr_val[1], LSM6DSL_ACC_ODR,LSM6DSL_ACC_ODR_POWER_DOWN);
		}
		break;
		case DEV_SLEEP: {
			addr_val[1] = LSM6DSL_SET_BITSLICE(addr_val[1], LSM6DSL_ACC_ODR,LSM6DSL_ACC_ODR_12_5_HZ);
		}
		break;
		default:
			break;
	}
	hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("set LSM6DSL acc power_mode error\r\n");
		return 1;
	}
	printf("successfully LSM6DSL acc power_mode\r\n");
	return 0;
}

uint8_t LSM6DSL_acc_st_open(void)
{
	uint8_t ret = 0;

    ret = LSM6DSL_acc_power_mode( DEV_POWER_ON);
    if (ret>0) {
        return ret;
    }

    ret = LSM6DSL_acc_set_range(ACC_RANGE_8G);
    if (ret>0) {
        return ret;
    }

    ret = LSM6DSL_acc_set_odr(LSM6DSL_ACC_DEFAULT_ODR_100HZ);
    if (ret>0) {
        return ret;
    }
    printf("successfully LSM6DSL acc open\r\n");
    return 0;
}

uint8_t LSM6DSL_acc_st_close(void)
{
	uint8_t ret = 0;
    ret = LSM6DSL_acc_power_mode(DEV_POWER_OFF);
    if (ret>0) {
        return ret;
    }
    printf("successfully LSM6DSL acc close\r\n");
    return 0;
}

uint8_t LSM6DSL_gyro_set_range(uint32_t range)
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	/*first read*/
	uint8_t addr_val[2] = {LSM6DSL_ACC_GYRO_CTRL2_G,0x00};
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get LSM6DSL gyro range error\r\n");
		return 1;
	}
	uint8_t tmp   = 0;
	switch (range) {
    	case GYRO_RANGE_250DPS: {
            tmp = LSM6DSL_GYRO_RANGE_245;
        } break;

        case GYRO_RANGE_500DPS: {
            tmp = LSM6DSL_GYRO_RANGE_500;
        } break;

        case GYRO_RANGE_1000DPS: {
            tmp = LSM6DSL_GYRO_RANGE_1000;
        } break;

        case GYRO_RANGE_2000DPS: {
            tmp = LSM6DSL_GYRO_RANGE_2000;
        } break;

        default:
            break;
	}
	addr_val[1] = LSM6DSL_SET_BITSLICE(addr_val[1], LSM6DSL_GYRO_RANGE, tmp);
    hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("set LSM6DSL gyro range error\r\n");
		return 1;
	}
	if ((range >= GYRO_RANGE_250DPS) && (range <= GYRO_RANGE_2000DPS)) {
        cur_gyro_factor = lsm6dsl_gyro_factor[range];
    }
	printf("successfully LSM6DSL set gyro range\r\n");
	return 0;
}

static uint8_t gyro_st_lsm6dsl_hz2odr(uint32_t hz)
{
    if (hz > 3330)
        return LSM6DSL_GYRO_ODR_6_66_KHZ;
    else if (hz > 1660)
        return LSM6DSL_GYRO_ODR_3_33_KHZ;
    else if (hz > 833)
        return LSM6DSL_GYRO_ODR_1_66_KHZ;
    else if (hz > 416)
        return LSM6DSL_GYRO_ODR_833_HZ;
    else if (hz > 208)
        return LSM6DSL_GYRO_ODR_416_HZ;
    else if (hz > 104)
        return LSM6DSL_GYRO_ODR_208_HZ;
    else if (hz > 52)
        return LSM6DSL_GYRO_ODR_104_HZ;
    else if (hz > 26)
        return LSM6DSL_GYRO_ODR_52_HZ;
    else if (hz > 13)
        return LSM6DSL_GYRO_ODR_26_HZ;
    else
        return LSM6DSL_GYRO_ODR_12_5_HZ;
}

uint8_t LSM6DSL_gyro_set_odr(uint32_t hz)
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	/*first read*/
	uint8_t addr_val[2] = {LSM6DSL_ACC_GYRO_CTRL2_G,0x00};
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get LSM6DSL gyro odr error\r\n");
		return 1;
	}
	uint8_t odr = gyro_st_lsm6dsl_hz2odr(hz);
	addr_val[1] = LSM6DSL_SET_BITSLICE(addr_val[1], LSM6DSL_GYRO_ODR, odr);
	hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("set LSM6DSL gyro odr error\r\n");
		return 1;
	}
	printf("successfully LSM6DSL set gyro odr\r\n");
	return 0;
}

uint8_t LSM6DSL_gyro_power_mode(LSM6DSL_power_mode mode)
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	/*first read*/
	uint8_t addr_val[2] = {LSM6DSL_ACC_GYRO_CTRL2_G,0x00};
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get LSM6DSL gyro power_mode error\r\n");
		return 1;
	}
	switch (mode) {
		case DEV_POWER_ON: {
			addr_val[1] = LSM6DSL_SET_BITSLICE(addr_val[1], LSM6DSL_GYRO_ODR,LSM6DSL_GYRO_ODR_12_5_HZ);
			break;
		}
		case DEV_POWER_OFF: {
			addr_val[1] = LSM6DSL_SET_BITSLICE(addr_val[1], LSM6DSL_GYRO_ODR,LSM6DSL_GYRO_ODR_POWER_DOWN);
			break;
		}
		case DEV_SLEEP: {
			addr_val[1] = LSM6DSL_SET_BITSLICE(addr_val[1], LSM6DSL_GYRO_ODR,LSM6DSL_GYRO_ODR_12_5_HZ);
			break;
		}
		default:
			break;
	}
	hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,LSM6DSL_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("set LSM6DSL gyro power_mode error\r\n");
		return 1;
	}
	printf("successfully LSM6DSL gyro power_mode\r\n");
	return 0;
}

uint8_t LSM6DSL_gyro_st_open(void)
{
	uint8_t ret = 0;
    ret	= LSM6DSL_gyro_power_mode(DEV_POWER_ON);
    if (ret>0) {
        return 1;
    }

    ret = LSM6DSL_gyro_set_range(GYRO_RANGE_1000DPS);
    if (ret>0) {
        return 1;
    }

    ret = LSM6DSL_gyro_set_odr(LSM6DSL_GYRO_DEFAULT_ODR_100HZ);
    if (ret>0) {
        return 1;
    }
    printf("successfully LSM6DSL gyro open\r\n");
    return 0;
}

uint8_t LSM6DSL_gyro_st_close(void)
{
	uint8_t ret = 0;
    ret	= LSM6DSL_gyro_power_mode(DEV_POWER_OFF);
    if (ret>0) {
        return 1;
    }
    printf("successfully LSM6DSL gyro close\r\n");
    return 0;
}

void LSM6DSL_acc_init()
{
	if(LSM6DSL_ID_check()>0)
		return;
	if(LSM6DSL_soft_reset()>0)
		return;
	if(LSM6DSL_acc_power_mode(DEV_POWER_OFF)>0)
		return;
	printf("successfully LSM6DSL acc init\r\n");
}

void LSM6DSL_gyro_init()
{
	if(LSM6DSL_ID_check()>0)
		return;
	if(LSM6DSL_soft_reset()>0)
		return;
	if(LSM6DSL_gyro_power_mode(DEV_POWER_OFF)>0)
		return;
	printf("successfully LSM6DSL gyro init\r\n");
}

#define DATA_AXIS_X 0
#define DATA_AXIS_Y 1
#define DATA_AXIS_Z 2

uint8_t LSM6DSL_acc_read(int32_t *x_data,int32_t *y_data,int32_t *z_data)
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	/*read 0X28,0X29,0X2A,0X2B,0X2C,0X2D*/
	uint8_t addr[6] = {LSM6DSL_ACC_GYRO_OUTX_L_XL,LSM6DSL_ACC_GYRO_OUTX_H_XL,
			LSM6DSL_ACC_GYRO_OUTY_L_XL,LSM6DSL_ACC_GYRO_OUTY_H_XL,
			LSM6DSL_ACC_GYRO_OUTZ_L_XL,LSM6DSL_ACC_GYRO_OUTZ_H_XL};
	uint8_t val[6] = {0};
	for(uint8_t i=0; i<6; i++){
		hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,LSM6DSL_I2C_ADDR,addr[i],1,&val[i],1,1000);
		if(HAL_OK!=hi2c2_status){
			printf("get LSM6DSL acc_read[0X%02X] error\r\n",addr[i]);
			return 1;
		}
	}
	printf("read acc reg_data 1:%02X, 2:%02X, 3:%02X, 4:%02X, 5:%02X ,6:%02X\r\n"
		    		,val[0],val[1],val[2],val[3],val[4],val[5]);
	int32_t data[3] = {0};
	data[DATA_AXIS_X] = (int16_t)((((int16_t)((int8_t)val[1])) << LSM6DSL_SHIFT_EIGHT_BITS) | (val[0]));
	data[DATA_AXIS_Y] = (int16_t)((((int16_t)((int8_t)val[3])) << LSM6DSL_SHIFT_EIGHT_BITS) | (val[2]));
	data[DATA_AXIS_Z] = (int16_t)((((int16_t)((int8_t)val[5])) << LSM6DSL_SHIFT_EIGHT_BITS) | (val[4]));
    if (cur_acc_factor != 0)
    {
        data[DATA_AXIS_X] = (data[DATA_AXIS_X] * cur_acc_factor) / LSM6DSL_ACC_MUL;
        data[DATA_AXIS_Y] = (data[DATA_AXIS_Y] * cur_acc_factor) / LSM6DSL_ACC_MUL;
        data[DATA_AXIS_Z] = (data[DATA_AXIS_Z] * cur_acc_factor) / LSM6DSL_ACC_MUL;
    }
    printf("read acc cur_acc_factor:%ld, X:%ld,Y:%ld,Z:%ld\r\n"
    		,cur_acc_factor,data[0],data[1],data[2]);
    *x_data = data[DATA_AXIS_X];
    *y_data = data[DATA_AXIS_Y];
    *z_data = data[DATA_AXIS_Z];
	return 0;
}

uint8_t LSM6DSL_gyro_read(int32_t *x_data,int32_t *y_data,int32_t *z_data)
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	/*read 0X22,0X23,0X24,0X25,0X26,0X27*/
	uint8_t addr[6] = {LSM6DSL_ACC_GYRO_OUTX_L_G,LSM6DSL_ACC_GYRO_OUTX_H_G,
			LSM6DSL_ACC_GYRO_OUTY_L_G,LSM6DSL_ACC_GYRO_OUTY_H_G,
			LSM6DSL_ACC_GYRO_OUTZ_L_G,LSM6DSL_ACC_GYRO_OUTZ_H_G};
	uint8_t val[6] = {0};
	for(uint8_t i=0; i<6; i++){
		hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,LSM6DSL_I2C_ADDR,addr[i],1,&val[i],1,1000);
		if(HAL_OK!=hi2c2_status){
			printf("get LSM6DSL gyro_read[0X%02X] error\r\n",addr[i]);
			return 1;
		}
	}
	printf("read gyro reg_data 1:%02X, 2:%02X, 3:%02X, 4:%02X, 5:%02X ,6:%02X\r\n"
	    		,val[0],val[1],val[2],val[3],val[4],val[5]);
	int32_t data[3] = {0};
	data[DATA_AXIS_X] = (int16_t)((((int32_t)((int8_t)val[1])) << LSM6DSL_SHIFT_EIGHT_BITS) | (val[0]));
	data[DATA_AXIS_Y] = (int16_t)((((int32_t)((int8_t)val[3])) << LSM6DSL_SHIFT_EIGHT_BITS) | (val[2]));
	data[DATA_AXIS_Z] = (int16_t)((((int32_t)((int8_t)val[5])) << LSM6DSL_SHIFT_EIGHT_BITS) | (val[4]));

    if (cur_gyro_factor != 0) {
        data[DATA_AXIS_X] = (data[DATA_AXIS_X] * cur_gyro_factor) / LSM6DSL_GYRO_MUL;
        data[DATA_AXIS_Y] = (data[DATA_AXIS_Y] * cur_gyro_factor) / LSM6DSL_GYRO_MUL;
        data[DATA_AXIS_Z] = (data[DATA_AXIS_Z] * cur_gyro_factor) / LSM6DSL_GYRO_MUL;
    }
    printf("read gyro cur_gyro_factor:%ld, X:%ld,Y:%ld,Z:%ld\r\n"
    		,cur_gyro_factor,data[0],data[1],data[2]);
    *x_data = data[DATA_AXIS_X];
    *y_data = data[DATA_AXIS_Y];
    *z_data = data[DATA_AXIS_Z];
	return 0;
}

九、MMC3680KJ传感器(三轴磁传感器)

        在ICore源目录下,创建MMC3680KJ文件夹,并在该目录下创建MMC3680KJ.h和MMC3680KJ.c源文件。

        同样在网上查找及下载了MMC3680KJ数据手册,逐项分析,MMC3680KJ设备的I2C通信同样采用从机设备地址+寄存器地址+数据的模式,该设备的从机地址0X60(0X30(00110000)<<1)如下:

         2)寄存器地址总表,设备产品ID地址是0X2F,设备状态地址是0X07,0X00~0X05共6字节,表示三个轴向数值,0X06是设备作业温度值。0X08~0X0A是三个CTRL标识。

         3)三轴向数据值每2个字节表示一个轴向,最低有效位在前。

         4)作业温度,一个字节数据,给出范围及换算方法

         5)设备状态获取,读取数据前需要明确设备状态

         6)control01地址0X08,主要设置设备set和reset,实现设备启用。

         7)control02地址0X09,主要设置设备ODR和OTP。

         8)control03地址0X09,主要设置设备连续测量模式下频率,脉冲宽度。

         9)设备产品ID验证,寄存器地址是0X2F,正确返回值是0X0A(00001010)

         10)按以上分析,伪代码设计如下:

MMC3680KJ从设备地址0x60
init:
read status from 从设备地址0x60 寄存器地址0X07
read p_id from 从设备地址0x60 寄存器地址0X2F
确保p_id==0X0A
分别write myconf to 从设备地址0x60 寄存器地址0X08 0X09 0X0A ,完成频率、脉冲、启用等设置

读取数据
读取数据确保设备已经设置及启用,寄存器地址0X08,myconf|0X08|(0X01或 0X02)
read data1~6 from 从设备地址0x60 寄存器地址0X00~0X05,共六字节数据
将data1~6 换算处理
read temp from 从设备地址0x60 寄存器地址0X06,一个字节数据
将temp换算处理

         11)按以上分析及伪代码设计,得出MMC3680KJ传感器的MMC3680KJ.h和MMC3680KJ.c源码文件。

        MMC3680KJ.h

#ifndef _MMC3680KJ_H_
#define _MMC3680KJ_H_

#include "main.h"

void mmc3680kj_temp_memsic_init();
void mmc3680kj_mag_memsic_init();

uint8_t mmc3680kj_read_temp_memsic(int32_t *temperature);
uint8_t mmc3680kj_read_mag_memsic(int32_t *xval, int32_t *yval, int32_t *zval);

#endif /* MMC3680KJ_MMC3680KJ_H_ */

        MMC3680KJ.c

#include <stdio.h>
#include "MMC3680KJ.h"

extern I2C_HandleTypeDef hi2c4;

#define MMC3680KJ_REG_DATA 0x00
#define MMC3680KJ_REG_XL 0x00
#define MMC3680KJ_REG_XH 0x01
#define MMC3680KJ_REG_YL 0x02
#define MMC3680KJ_REG_YH 0x03
#define MMC3680KJ_REG_ZL 0x04
#define MMC3680KJ_REG_ZH 0x05
#define MMC3680KJ_REG_TEMP 0x06
#define MMC3680KJ_REG_STATUS 0x07
#define MMC3680KJ_REG_CTRL0 0x08
#define MMC3680KJ_REG_CTRL1 0x09
#define MMC3680KJ_REG_CTRL2 0x0a
#define MMC3680KJ_REG_X_THD 0x0b
#define MMC3680KJ_REG_Y_THD 0x0c
#define MMC3680KJ_REG_Z_THD 0x0d
#define MMC3680KJ_REG_SELFTEST 0x0e
#define MMC3680KJ_REG_PASSWORD 0x0f
#define MMC3680KJ_REG_OTPMODE 0x12
#define MMC3680KJ_REG_TESTMODE 0x13
#define MMC3680KJ_REG_SR_PWIDTH 0x20
#define MMC3680KJ_REG_OTP 0x2a
#define MMC3680KJ_REG_PRODUCTID 0x2f

#define MMC3680KJ_CMD_REFILL 0x20
#define MMC3680KJ_CMD_RESET 0x10
#define MMC3680KJ_CMD_SET 0x08
#define MMC3680KJ_CMD_TM_M 0x01
#define MMC3680KJ_CMD_TM_T 0x02
#define MMC3680KJ_CMD_START_MDT 0x04
#define MMC3680KJ_CMD_100HZ 0x00
#define MMC3680KJ_CMD_200HZ 0x01
#define MMC3680KJ_CMD_400HZ 0x02
#define MMC3680KJ_CMD_600HZ 0x03
#define MMC3680KJ_CMD_CM_14HZ 0x01
#define MMC3680KJ_CMD_CM_5HZ 0x02
#define MMC3680KJ_CMD_CM_1HZ 0x04
#define MMC3680KJ_CMD_SW_RST 0x80
#define MMC3680KJ_CMD_PASSWORD 0xe1
#define MMC3680KJ_CMD_OTP_OPER 0x11
#define MMC3680KJ_CMD_OTP_MR 0x80
#define MMC3680KJ_CMD_OTP_ACT 0x80
#define MMC3680KJ_CMD_OTP_NACT 0x00
#define MMC3680KJ_CMD_STSET_OPEN 0x02
#define MMC3680KJ_CMD_STRST_OPEN 0x04
#define MMC3680KJ_CMD_ST_CLOSE 0x00
#define MMC3680KJ_CMD_INT_MD_EN 0x40
#define MMC3680KJ_CMD_INT_MDT_EN 0x20

#define MMC3680KJ_PRODUCT_ID 0x0a
#define MMC3680KJ_OTP_READ_DONE_BIT 0x10
#define MMC3680KJ_PUMP_ON_BIT 0x08
#define MMC3680KJ_MDT_BIT 0x04
#define MMC3680KJ_MEAS_T_DONE_BIT 0x02
#define MMC3680KJ_MEAS_M_DONE_BIT 0x01

#define MMC3680KJ_I2C_SLAVE_ADDR 0x30
#define MMC3680KJ_ADDR_TRANS(n) ((n) << 1)
#define MMC3680KJ_I2C_ADDR MMC3680KJ_ADDR_TRANS(MMC3680KJ_I2C_SLAVE_ADDR)

#define MMC3680KJ_OFFSET 32768
#define MMC3680KJ_SENSITIVITY 1024000
#define MMC3680KJ_T_ZERO -75
#define MMC3680KJ_T_SENSITIVITY 80

#define MMC3680KJ_MAG_DATA_SIZE 6
#define OTP_CONVERT(REG) (((REG) >= 32 ? (32 - (REG)) : (REG)) * 6)

typedef enum
{
    FLAG_INIT_MAG = 0,
    FLAG_INIT_TEMP,
} FLAG_INIT_BIT;

static int32_t g_otp_matrix[3] = { 1000000, 1000000, 1350000 };

uint8_t mmc3680kj_check_otp()
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	uint8_t addr_val[3] = {MMC3680KJ_REG_STATUS,0x00,MMC3680KJ_OTP_READ_DONE_BIT};
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,MMC3680KJ_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get mmc3680kj opt error\r\n");
		return 1;
	}
	if ((addr_val[1] & addr_val[2]) != addr_val[2]) {
		printf("mmc3680kj opt is error\r\n");
        return 1;
    }
	printf("mmc3680kj opt:%02X\r\n",addr_val[1]);
	return 0;
}

uint8_t mmc3680kj_id_check()
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	uint8_t addr_val[3] = {MMC3680KJ_REG_PRODUCTID,0x00,MMC3680KJ_PRODUCT_ID};
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,MMC3680KJ_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("get mmc3680kj ID error\r\n");
		return 1;
	}
	if(addr_val[1]!=addr_val[2]){
		printf("mmc3680kj validate_id is error\r\n");
		return 1;
	}
	printf("mmc3680kj_id:%02X\r\n",addr_val[1]);
	return 0;
}

uint8_t mmc3680kj_set_comp_matrix()
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	/*first*/
	uint8_t addr_val[6][2] = {
			{MMC3680KJ_REG_PASSWORD,MMC3680KJ_CMD_PASSWORD},
			{MMC3680KJ_REG_OTPMODE,MMC3680KJ_CMD_OTP_OPER},
			{MMC3680KJ_REG_TESTMODE,MMC3680KJ_CMD_OTP_MR},
			{MMC3680KJ_REG_CTRL2,MMC3680KJ_CMD_OTP_ACT},
			{MMC3680KJ_REG_OTP,0X00},
			{MMC3680KJ_REG_CTRL2,MMC3680KJ_CMD_OTP_NACT}
	};
	for(uint8_t i=0; i<4; i++)
	{
		hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,MMC3680KJ_I2C_ADDR,addr_val[i][0],1,&addr_val[i][1],1,1000);
		if(HAL_OK!=hi2c2_status){
			printf("mmc3680kj comp_matrix addr(0X%02X) error\r\n",addr_val[i][0]);
			return 1;
		}
	}
	uint8_t reg_data[2] = { 0 };
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,MMC3680KJ_I2C_ADDR,addr_val[4][0],1,reg_data,2,1000);
	if(HAL_OK!=hi2c2_status){
		printf("mmc3680kj comp_matrix addr(0X%02X) error\r\n",addr_val[4][0]);
		return 1;
	}
	hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,MMC3680KJ_I2C_ADDR,addr_val[5][0],1,&addr_val[5][1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("mmc3680kj comp_matrix addr(0X%02X) error\r\n",addr_val[5][0]);
		return 1;
	}
	g_otp_matrix[0] = 1000000;
	g_otp_matrix[1] = OTP_CONVERT(reg_data[0] & 0x3f) * 1000 + 1000000;
	g_otp_matrix[2] = (OTP_CONVERT((reg_data[1] & 0x0f) << 2 | (reg_data[0] & 0xc0) >> 6) +	1000) * 1350;
	return 0;
}

uint8_t mmc3680kj_set_pulse_width()
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	/*first*/
	uint8_t addr_val[3][2] = {
			{MMC3680KJ_REG_CTRL2,MMC3680KJ_CMD_OTP_NACT},
			{MMC3680KJ_REG_PASSWORD,MMC3680KJ_CMD_PASSWORD},
			{MMC3680KJ_REG_SR_PWIDTH,0X00}
		};
	for(uint8_t i=0; i<2; i++)
	{
		hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,MMC3680KJ_I2C_ADDR,addr_val[i][0],1,&addr_val[i][1],1,1000);
		if(HAL_OK!=hi2c2_status){
			printf("mmc3680kj set pulse_width addr(0X%02X) error\r\n",addr_val[i][0]);
			return 1;
		}
	}
	hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,MMC3680KJ_I2C_ADDR,addr_val[2][0],1,&addr_val[2][1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("mmc3680kj set pulse_width addr(0X%02X) error\r\n",addr_val[2][0]);
		return 1;
	}
	addr_val[2][1] &= 0xe7;
	hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,MMC3680KJ_I2C_ADDR,addr_val[2][0],1,&addr_val[2][1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("mmc3680kj set pulse_width addr(0X%02X) error\r\n",addr_val[2][0]);
		return 1;
	}
	printf("successfully mmc3680kj set pulse_width\r\n");
	return 0;
}

uint8_t mmc3680kj_set_output_resolution()
{
	//MMC3680KJ_CMD_100HZ
	HAL_StatusTypeDef hi2c2_status = 0x00;
	uint8_t addr_val[2] = {MMC3680KJ_REG_CTRL1,MMC3680KJ_CMD_100HZ};
	hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,MMC3680KJ_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("mmc3680kj set output_resolution addr(0X%02X) error\r\n",addr_val[0]);
		return 1;
	}
	printf("successfully mmc3680kj set pulse_width\r\n");
	return 0;
}

uint8_t mmc3680kj_set()
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	uint8_t addr_val[2] = {MMC3680KJ_REG_CTRL0,MMC3680KJ_CMD_SET};
	hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,MMC3680KJ_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("mmc3680kj set addr(0X%02X) error\r\n",addr_val[0]);
		return 1;
	}
	printf("successfully mmc3680kj set\r\n");
	return 0;
}

uint8_t mmc3680kj_enable(FLAG_INIT_BIT flag)
{
	HAL_StatusTypeDef hi2c2_status = 0x00;
	if (flag == FLAG_INIT_MAG) {
		uint8_t addr_val[2] = {MMC3680KJ_REG_CTRL0,MMC3680KJ_CMD_TM_M};
		hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,MMC3680KJ_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
		if(HAL_OK!=hi2c2_status){
			printf("mmc3680kj enable addr(0X%02X) error\r\n",addr_val[0]);
			return 1;
		}
		uint8_t value = 0;
		do{
			HAL_Delay(10);
			hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,MMC3680KJ_I2C_ADDR,MMC3680KJ_REG_STATUS,1,&value,1,1000);
			if(HAL_OK!=hi2c2_status){
				printf("mmc3680kj enable addr(0X%02X) error\r\n",MMC3680KJ_REG_STATUS);
				return 1;
			}
		}while ((value & 0x01) != 0x01);
	}else if(flag==FLAG_INIT_TEMP){
		uint8_t addr_val[2] = {MMC3680KJ_REG_CTRL0,MMC3680KJ_CMD_TM_T};
		hi2c2_status = HAL_I2C_Mem_Write(&hi2c4,MMC3680KJ_I2C_ADDR,addr_val[0],1,&addr_val[1],1,1000);
		if(HAL_OK!=hi2c2_status){
			printf("mmc3680kj enable addr(0X%02X) error\r\n",addr_val[0]);
			return 1;
		}
		uint8_t value = 0;
		do{
			HAL_Delay(10);
			hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,MMC3680KJ_I2C_ADDR,MMC3680KJ_REG_STATUS,1,&value,1,1000);
			if(HAL_OK!=hi2c2_status){
				printf("mmc3680kj enable addr(0X%02X) error\r\n",MMC3680KJ_REG_STATUS);
				return 1;
			}
		}while ((value & 0x02) != 0x02);
	}else{
		return 1;
	}
	printf("successfully mmc3680kj enable\r\n");
	return 0;
}

static int mmc3680kj_tick()
{
    static uint32_t last_time = 0;
    uint32_t        now_time  = 0;

    now_time = HAL_GetTick();
    if (now_time - last_time > 5000) {
        last_time = now_time;
        return 1;
    }

    return 0;
}

uint8_t mmc3680kj_read_temp_memsic(int32_t *temperature)
{
	uint8_t ret = mmc3680kj_enable(FLAG_INIT_TEMP);
	if (ret>0) {
        return ret;
    }
	uint8_t reg_raw = 0;
	HAL_StatusTypeDef hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,MMC3680KJ_I2C_ADDR
				,MMC3680KJ_REG_TEMP,1,&reg_raw,1,1000);
	if(HAL_OK!=hi2c2_status){
		printf("mmc3680kj read_mag_memsic addr(0X%02X) error\r\n",MMC3680KJ_REG_STATUS);
		return 1;
	}
	printf("mmc3680kj_read_temp org:%02X\r\n",reg_raw);
	*temperature = ((int32_t)reg_raw) * MMC3680KJ_T_SENSITIVITY / 100 + MMC3680KJ_T_ZERO;
	printf("mmc3680kj_read_temp:%ld\r\n",*temperature);
	return 0;
}

uint8_t mmc3680kj_read_mag_memsic(int32_t *xval, int32_t *yval, int32_t *zval)
{
	uint8_t ret = 0;
	if (mmc3680kj_tick()) {
        ret = mmc3680kj_set();
        if (ret>0) {
            return ret;
        }
    }
	ret = mmc3680kj_enable(FLAG_INIT_MAG);
	if (ret>0) {
        return ret;
    }
	uint8_t reg_raw[MMC3680KJ_MAG_DATA_SIZE] = { 0 };
	HAL_StatusTypeDef hi2c2_status = HAL_I2C_Mem_Read(&hi2c4,MMC3680KJ_I2C_ADDR
			,MMC3680KJ_REG_DATA,1,reg_raw,MMC3680KJ_MAG_DATA_SIZE,1000);
	if(HAL_OK!=hi2c2_status){
		printf("mmc3680kj read_mag_memsic addr(0X%02X) error\r\n",MMC3680KJ_REG_STATUS);
		return 1;
	}
    uint16_t    data_raw[3] = { 0 };
    uint32_t    mag_raw[3]  = { 0 };
    data_raw[0] = (uint16_t)(reg_raw[1] << 8 | reg_raw[0]);
    data_raw[1] = (uint16_t)(reg_raw[3] << 8 | reg_raw[2]);
    data_raw[2] = (uint16_t)(reg_raw[5] << 8 | reg_raw[4]);
    mag_raw[0]  = (uint32_t)(data_raw[0]);
    mag_raw[1]  = (uint32_t)(data_raw[1] - data_raw[2] + MMC3680KJ_OFFSET);
    mag_raw[2]  = (uint32_t)(data_raw[1] + data_raw[2] - MMC3680KJ_OFFSET);

    *xval = (int32_t)(mag_raw[0] - MMC3680KJ_OFFSET) * g_otp_matrix[0] / MMC3680KJ_SENSITIVITY;
    *yval = (int32_t)(mag_raw[1] - MMC3680KJ_OFFSET) * g_otp_matrix[1] / MMC3680KJ_SENSITIVITY;
    *zval = (int32_t)(mag_raw[2] - MMC3680KJ_OFFSET) * g_otp_matrix[2] / MMC3680KJ_SENSITIVITY;
    printf("mmc3680kj_read_mag:%ld,%ld,%ld\r\n",*xval,*yval,*zval);
	return 0;
}

void mmc3680kj_temp_memsic_init()
{
	if(mmc3680kj_check_otp()>0)
		return ;
	if(mmc3680kj_id_check()>0)
		return ;
	printf("successfully mmc3680kj temp_memsic_init\r\n");
}

void mmc3680kj_mag_memsic_init()
{
	if(mmc3680kj_check_otp()>0)
		return ;
	if(mmc3680kj_id_check()>0)
		return ;
	if(mmc3680kj_set_comp_matrix()>0)
		return ;
	if(mmc3680kj_set_pulse_width()>0)
		return ;
	if(mmc3680kj_set_output_resolution()>0)
		return ;
	printf("successfully mmc3680kj mag_memsic_init\r\n");
}

十、驱动代码调用及数据采集与展示

        在main.c函数中,调用各个传感器的驱动头文件及调试、oled显示输出头文件

/* USER CODE BEGIN Includes */
#include "../../ICore/key/key.h"
#include "../../ICore/led/led.h"
#include "../../ICore/print/print.h"
#include "../../ICore/usart/usart.h"
#include "../../ICore/oled/oled.h"
#include "../../ICore/SHTC1/SHTC1.h"
#include "../../ICore/LTR-553ALS-WA/LTR-553ALS-WA.h"
#include "../../ICore/bmp280/bmp280.h"
#include "../../ICore/LSM6DSL/LSM6DSL.h"
#include "../../ICore/MMC3680KJ/MMC3680KJ.h"
/* USER CODE END Includes */

        在主函数中,逐个初始化各个传感器及相关接口,并将OLED设置为蓝色背景显示。

  /* USER CODE BEGIN 1 */
    float humidity, temperature;
    uint32_t als_data,ps_data;
    uint32_t comp_temp,comp_baro;
    int32_t acc_x,acc_y,acc_z;
    int32_t gyro_x,gyro_y,gyro_z;
    int32_t mmc_temp,mmc_aval,mmc_bval,mmc_cval;
  /* USER CODE END 1 */
...........................................
  /* USER CODE BEGIN 2 */
  ResetPrintInit(&hlpuart1);
  HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断
  HLPUSART_RX_STA = 0;
  //oled
  OLED_init();
  //shtc1
  humidity = temperature = 0.0;
  als_data = ps_data = 0;
  shtc1_init();
  //ltr553
  LTR_ALS_init();
  ltr553_als_open();
  LTR_PS_init();
  ltr553_ps_open();
  //bmp280
  BMP280_init();
  bmp280_open();
  comp_temp = comp_baro = 0;
  //mmc3680
  mmc3680kj_temp_memsic_init();
  mmc3680kj_mag_memsic_init();
  //
  LSM6DSL_acc_init();
  LSM6DSL_acc_st_open();
  LSM6DSL_gyro_init();
  LSM6DSL_gyro_st_open();
  acc_x = acc_y = acc_z = 0;
  gyro_x = gyro_y = gyro_z = 0;
  mmc_temp = mmc_aval = mmc_bval = mmc_cval =0;
  uint8_t menu = 0;
  //设置OLED蓝色背景显示
  BSP_LCD_Clear_DMA(LCD_DISP_BLUE);
  printf("OLED_Clear_DMA\r\n");
  /* USER CODE END 2 */

        在主函数循环中,加入对各个传感器数据读取以及显示输出,设置了一个菜单标识,按键可以改变它:按键KEY0清屏,按键KEY1实现I2C2接口读取(stch1、ltr553、bmp280)数据及显示;按键KEY2实现I2C4接口读取(LSM6DSL、MMC3680KJ)数据及显示。

 /* USER CODE BEGIN WHILE */
  while (1)
  {
	  if(HLPUSART_RX_STA&0xC000){//溢出或换行,重新开始
  		  //printf("%.*s\r\n",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);
  		  OLED_printf(10,10,"%.*s",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);
  		  HLPUSART_RX_STA=0;//接收错误,重新开始
  		  HAL_Delay(100);//等待
  	  }
	  if(KEY_0())
	  {
		  BSP_LCD_Clear_DMA(LCD_DISP_BLUE);
		  printf("OLED_Clear_DMA\r\n");
	  }
	  if(KEY_1())
	  {
		  if(menu&0x02)
			  BSP_LCD_Clear_DMA(LCD_DISP_BLUE);
		  if(menu&0x01)
			  menu &= 0XFE;	//取消I2C2数据刷新
		  else
			  menu |= 0X01; //开启I2C2数据刷新
		  menu &= 0XFD; //取消I2C4数据刷新

	  }
	  if(KEY_2())
	  {
		  if(menu&0x01)
			  BSP_LCD_Clear_DMA(LCD_DISP_BLUE);

		  if(menu&0x02)
			  menu &= 0XFD; //取消I2C4数据刷新
		  else
			  menu |= 0X02; //开启I2C4数据刷新
		  menu &= 0XFE;	//取消I2C2数据刷新

	  }
	  if(menu&0x01)
  	  {
		  /* 读取温湿度数据 */
  		  read_ht(&humidity,&temperature);
  		  //oled
  		  OLED_printf(10,10,"humidity   : %d.%d",(int)humidity, (int)(humidity * 100) % 100);
  		  if( temperature >= 0 )
  			  OLED_printf(10,26,"temperature: %d.%d",(int)temperature, (int)(temperature * 100) % 100);
  		  else
  			  OLED_printf(10,26,"temperature: %d.%d",(int)temperature, (int)(-temperature * 100) % 100);
		  read_als(&als_data);
		  read_ps(&ps_data);
		  //
		  OLED_printf(10,42,"light_data : %d.%d",(int)als_data, (int)(als_data * 100) % 100);
		  OLED_printf(10,58,"proximity  : %d.%d",(int)ps_data, (int)(ps_data * 100) % 100);
		  //
		  read_bmp280_temp(&comp_temp);
		  read_bmp280_baro(&comp_baro);
		  OLED_printf(10,74,"comp_DegC  : %d.%d",(int)comp_temp/100,(int)comp_temp%100);
		  OLED_printf(10,90,"comp_baro  : %d.%d",(int)comp_baro/100,(int)comp_baro%100);
  	  }
  	  if(menu&0x02)
  	  {
  		LSM6DSL_acc_read(&acc_x,&acc_y,&acc_z);
  		LSM6DSL_gyro_read(&gyro_x,&gyro_y,&gyro_z);
  		if(acc_x>0)
  			OLED_printf(10,10,"st_acc_x   : %d.%d    ",(acc_x*98)/10000,((acc_x*98)%10000)/100);
  		else
  			OLED_printf(10,10,"st_acc_x   : %d.%d    ",(acc_x*98)/10000,((-acc_x*98)%10000)/100);
  		if(acc_y>0)
  			OLED_printf(10,26,"st_acc_y   : %d.%d    ",(acc_y*98)/10000,((acc_y*98)%10000)/100);
  		else
  			OLED_printf(10,26,"st_acc_y   : %d.%d    ",(acc_y*98)/10000,((-acc_y*98)%10000)/100);
  		if(acc_z>0)
  			OLED_printf(10,42,"st_acc_z   : %d.%d    ",(acc_z*98)/10000,((acc_z*98)%10000)/100);
  		else
  			OLED_printf(10,42,"st_acc_z   : %d.%d    ",(acc_z*98)/10000,((-acc_z*98)%10000)/100);
  		if(gyro_x>0)
  			OLED_printf(10,58,"st_gyro_x  : %d.%d    ",(gyro_x)/1000,((gyro_x)%1000)/10);
  		else
  			OLED_printf(10,58,"st_gyro_x  : %d.%d    ",(gyro_x)/1000,((-gyro_x)%1000)/10);
  		if(gyro_y>0)
  			OLED_printf(10,74,"st_gyro_y  : %d.%d    ",(gyro_y)/1000,((gyro_y)%1000)/10);
  		else
  			OLED_printf(10,74,"st_gyro_y  : %d.%d    ",(gyro_y)/1000,((-gyro_y)%1000)/10);
  		if(gyro_z>0)
  			OLED_printf(10,90,"st_gyro_z  : %d.%d    ",(gyro_z)/1000,((gyro_z)%1000)/10);
  		else
  			OLED_printf(10,90,"st_gyro_z  : %d.%d    ",(gyro_z)/1000,((-gyro_z)%1000)/10);
  		mmc3680kj_read_temp_memsic(&mmc_temp);
  		mmc3680kj_read_mag_memsic(&mmc_aval,&mmc_bval,&mmc_cval);
		OLED_printf(10,106,"mmc_temp   : %d.%d    ",mmc_temp,0);
		OLED_printf(10,122,"mmc_aval   : %d.%d    ",mmc_aval,0);
		OLED_printf(10,138,"mmc_bval   : %d.%d    ",mmc_bval,0);
		OLED_printf(10,154,"mmc_cval   : %d.%d    ",mmc_cval,0);
  	  }
  	Toggle_led0();
    /* USER CODE END WHILE */

        程序编译及下载

         初始化打印输出

         以及oled屏幕显示I2C2读取数据,按键KEY1,将不断刷新,再按一次KEY1将停止刷新

         以及OLED屏幕显示I2C4读取数据 ,按键KEY2,将不断刷新,再按一次KEY2将停止刷新

十一、附件

        本文已经提供了全部源码及传感器涉及的主要参数资料,读者如果想自行调整及更深层次应用开发,请参考附件资料:

传感器数据手册:https://download.csdn.net/download/py8105/87229821

传感器驱动源文件:https://download.csdn.net/download/py8105/87229808

本人以后博文只要含有源码的,只对粉丝开放,不再公开发布,请CSDN的读友谅解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/52699.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

EMQX Enterprise 4.4.11 发布:CRL/OCSP Stapling、Google Cloud Pub/Sub 集成、预定义 API 密钥

我们很高兴地告诉大家&#xff0c;EMQX Enterprise 4.4.11 版本正式发布&#xff01; 在此版本中&#xff0c;我们发布了 CRL 与 OCSP Stapling 为客户端提供更灵活的安全防护&#xff0c;新增了 Google Cloud Pub/Sub 集成帮助您通过 Google Cloud 各类服务发掘更多物联网数据…

[附源码]Python计算机毕业设计Django高校学生信息采集系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

2022爱分析· 信创厂商全景报告 | 爱分析报告

报告编委 张扬 爱分析联合创始人&首席分析师 孙文瑞 爱分析高级分析师 戴甜 爱分析分析师 王命航 爱分析分析师 目录 研究范围定义市场洞察厂商全景地图市场定义与厂商评估厂商入选列表 1.研究范围定义 1.1研究背景 近年来&#xff0c;受中美贸易战、科技战等内外部多重因…

java -数据结构,单向链表

顺序表的问题及思考&#xff1a; 顺序表中间/头部的插入删除&#xff0c;时间复杂度为O(N)增容需要申请新空间&#xff0c;拷贝数据&#xff0c;释放旧空间。会有不小的消耗。增容一般是呈2倍的增长&#xff0c;势必会有一定的空间浪费。例如当前容量为100&#xff0c;满了以后…

HTTP和HTTPS协议(必备知识)

文章目录1、什么是HTTP协议2、HTTP协议格式<1>HTTP请求方法<2>HTTP的状态码3、HTTP是不保存状态的协议<1>使用Cookie的状态管理3、HTTPS<1>加密方式<2>理解HTTPS加密过程1、什么是HTTP协议 HTTP协议常被称为超文本传输协议&#xff0c;HTTP协议…

【网安神器篇】——mimikatz系统取证工具

作者名&#xff1a;Demo不是emo 主页面链接&#xff1a;主页传送门 创作初心&#xff1a;舞台再大&#xff0c;你不上台&#xff0c;永远是观众&#xff0c;没人会关心你努不努力&#xff0c;摔的痛不痛&#xff0c;他们只会看你最后站在什么位置&#xff0c;然后羡慕或鄙夷座…

C语言第十二课(中):操作符详解【单目、关系、逻辑、条件操作符】

目录 前言&#xff1a; 一、单目操作符&#xff01;、-、、&、sizeof、~、--、、*、(类型)&#xff1a; 1.逻辑反操作&#xff01;&#xff1a; 2.正负值操作符-、&#xff1a; 3.取地址操作符 &与解引用操作符 *&#xff1a; ①.取地址操作符&&#xff1a; ②.解…

数据结构与算法基础(王卓)(3)

前置&#xff1a; //#include<iostream> #include<stdlib.h>//存放exit#define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define INFEASIBLE -1 #define OVERFLOW -2 #define MAXlength 100 //初始大小为100&…

小程序开发音视频问题汇总及解决方案

目录 问题一&#xff1a;开发音视频&#xff0c;必用的两个小程序组件live-player和live-pusher&#xff0c;他们做什么用的&#xff0c;怎么才能使用&#xff1f; 问题二&#xff1a;一个页面只能插入一个 问题三&#xff1a;真机调试图片预览及视频全屏无反应 问题四&am…

图库 | 图存储的基础概念

前言 图存储的全称叫图数据库存储引擎或图数据库存储层&#xff08;组件&#xff09;。在功能层面&#xff0c;它负责图数据库或图数仓的数据的持久化存储。因为存储距离用户层的应用较图计算更为遥远&#xff0c;过往很少有论著会专门讲述图存储环节&#xff0c;但笔者要说的…

Python搭建虚拟环境

一、简介 1.特点&#xff1a; python的虚拟环境类似于虚拟机&#xff0c;能够创建一个独立的python运行环境&#xff0c; 虚拟环境中的安装的第三方依赖包和全局环境中的包相互独立。 2.环境 1. python3.3以上版本(自带venv模块&#xff0c;若已安装则可直接改变环境变量来…

【软件安装】Linux中RabbitMQ的安装

① 本篇是基于Linux操作系统中的安装&#xff0c;故先准备一个干净的Linux操作系统。本文中所有的操作基于CentOS8进行安装演示&#xff1b; ② 接下来的演示文本中&#xff0c;红色字体为操作步骤&#xff0c;黑色字体为解释说明&#xff1b; ③ 确保Linux系统中已经安装好必…

LightGBM 实现基于内容的个性化推荐

大家好&#xff0c;本文中&#xff0c;我将和大家一起学习如何训练 LightGBM 模型来估计电子商务广告的点击率的推荐系统的例子。将在Criteo数据集上训练一个基于LightGBM的模型。 LightGBM是一个基于树的梯度提升学习算法框架。是基于分布式框架设计的&#xff0c;因而非常高…

汇川伺服电机位置控制模式参数配置

1. 基本控制参数设置 1&#xff09;设置位置控制模式 2&#xff09;绝对值位置线性模式 2.端子输入参数设置 1&#xff09;将输入端子使能失效 3. 位置控制参数设置 1&#xff09;将位置来源设置为2&#xff1a;多段位位置指令 4.通信参数设置 1&#xff09;波特率设置为960…

单元测试我们需要知道哪些?

前言趁着刚读完《认知天性》这书&#xff0c;书有一点这样说&#xff1a;「我们学习行为更多凭着直觉&#xff0c;即使我们已经看到了科学数据&#xff0c;但我们也不愿意去相信自己的直觉存在问题。」那和我们单元测试有什么关系呢&#xff1f;这时我突然有一个问题&#xff1…

19-28-hive-数据类型-DDL

19-hive-数据类型-DDL&#xff1a; 基本数据类型 Hive 数据类型Java 数据类型长度例子TINYINTbyte1byte 有符号整数20SMALINTshort2byte 有符号整数20INTint4byte 有符号整数20BIGINTlong8byte 有符号整数20BOOLEANboolean布尔类型&#xff0c;true 或者falseTRUE FALSEFLOAT…

【Python】Labelme/PIL读取图片朝向错误解决

文章目录一、问题背景二、产生原因三、解决方案一、问题背景 发现使用labelme直接读取含imageData&#xff08;将图片bytes数据使用base64编码后的str数据&#xff09;的json文件时&#xff0c;读上来的图片会发生自动旋转的问题。比如原先是横放的图&#xff0c;读进来后就成…

虚拟化基本知识及virtio-net初探

QEMU/KVM是在Linux中被广泛使用的虚拟化技术之一&#xff0c;而virtio作为一个半虚拟化I/O事实上的标准[1]&#xff0c;是QEMU/KVM在I/O虚拟化部分的默认实现。virtio-net是virtio标准中的网卡设备&#xff0c;被广泛应用。本文将会沿着虚拟化&#xff0c;virtio半虚拟化I/O&am…

非对称风险模型

推荐模型&#xff1a;非对称性风险&#xff0c;让自己置身于一个好结果比坏结果影响大得多的环境中 比如投资&#xff0c;将85%~90%投入到极低风险的资产中&#xff08;国债&#xff09;&#xff0c;来享受确定性收益&#xff1b;剩下的投入的10%~15%投入到极高风险资产中&…

使用FeatureTask多线程优化in,提高查询速度

场景是这样的&#xff1a;使用in查询数据的时候&#xff0c;in的数量越多&#xff0c;效率越低&#xff0c;所以一个优化的思路是&#xff0c;缩小in查询的数量&#xff0c;用多线程的方式查询缩小数量后in的sql&#xff0c;并行查询。 直接上代码&#xff1a; public List&l…