SPL06 基于stm32F103 HAL库驱动(软件模拟IIC)

news2024/12/24 10:18:48

talk is cheap, show you my code

SPL06.c

#include "SPL06.h"

//*************全局变量*************//
Factor_List* b_list;                          			//存储过采样率对应的系数KP,KT
COEF_ValueStruct Coefficient = { 0 };								//存储校准系数
TEMP_InitTypedef TEMP_InitStructure = { 0 };        //温度测量初始化配置结构体
PSR_InitTypedef PSR_InitStructure = { 0 };          //大气压强测量初始化配置结构体

//*************1.初始化相关函数*************//
//*************1.1 链表初始化相关函数*******//
/**
 * @name    Factor_List* initList(void)
 * @brief   初始化链表头节点,将头节点也利用起来,存储信息
 * @param   [NONE]
 * @return  [p] 返回创建的链表头节点地址
 */
Factor_List* initList(void)
{
    Factor_List *p = (Factor_List*)malloc(sizeof(Factor_List));
    p->OverSamplingRate = _SINGLE_OVERSAMPLING;
    p->FACTOR = _SINGLE_SCALE_FACTOR;
    p->next = NULL;

    if (p == NULL) {
            // 处理内存分配失败的情况
            return NULL;
        }

    return p;
}

/**
 * @name    Factor_List* insertTail(Factor_List *l, uint8_t val, uint32_t Factor)
 * @brief   向链表的末尾添加一个节点,即尾插法
 * @param   [Factor_List *list] 链表的起始节点
 *          [uint8_t val] 链表OverSamplingRate部分的值,对应过采样率的寄存器值
 *          [uint32_t Factor] 过采样率对应的比例因子
 * @return  尾节点指针,由于数据量只有八个,且链表添加数据之后固定,为了简化代码,没有利用尾节点指针
 */
Factor_List* insertTail(Factor_List *l, uint8_t val, uint32_t Factor)
{
    //先创建一个新节点
    Factor_List *p = (Factor_List*)malloc(sizeof(Factor_List));
    p->OverSamplingRate = val;
    p->FACTOR = Factor;
    p->next = NULL;

    while(l->next != NULL) l = l->next;
    l->next = p;

    return p;
}

/**
 * @name    void Init_FactorList(void)
 * @brief   初始化链表的所有数据,将过采样率及其对应的比例因子插入到链表中
 * @param   [NONE]
 * @return  [NONE]
 */
void Init_FactorList(void)
{
    b_list = initList(); //_SINGLE_OVERSAMPLING的数据已经放入

    insertTail(b_list, _2TIMES_OVERSAMPLING, _2TIMES_SCALE_FACTOR);
    insertTail(b_list, _4TIMES_OVERSAMPLING, _4TIMES_SCALE_FACTOR);
    insertTail(b_list, _8TIMES_OVERSAMPLING, _8TIMES_SCALE_FACTOR);
    insertTail(b_list, _16TIMES_OVERSAMPLING, _16TIMES_SCALE_FACTOR);
    insertTail(b_list, _32TIMES_OVERSAMPLING, _32TIMES_SCALE_FACTOR);
    insertTail(b_list, _64TIMES_OVERSAMPLING, _64TIMES_SCALE_FACTOR);
    insertTail(b_list, _128TIMES_OVERSAMPLING, _128TIMES_SCALE_FACTOR);
}

/**
 * @brief   根据对应的过采样率寻找对应的比例因子
 * @param   [Factor_List *list] 要查找的链表
 *          [val] 用于查询的过采样率
 * @return  返回的比例因子数值
 */
uint32_t FindFactor(Factor_List* l, uint8_t val)
{
    while(l->OverSamplingRate != val)
    {
        l = l->next;
    }
    return l->FACTOR;
}


//*************1.2 SPL06初始化相关函数******//
/**
 * @name    uint8_t SPL06_Init(void)
 * @brief   SPL06初始化,包含采样模式,温度采样配置,大气压强采样配置,可以通过修改对应结构体成员来修改配置
 * @return  0   配置成功
 *  		1	I2C通讯异常
 *          2   配置采样模式失败,总线无应答
 *          3   配置大气压强采样失败,总线无应答
 *          4   配置温度采样失败,总线无应答
 *          5		获取校正系数失败,可能是校正系数没有准备好,也可能是I2C通讯异常
 */
uint8_t SPL06_Init(void)
{
	//1. 拉高SCL、SDA确保起始条件能够被正确发送
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(1);
	
	//2. 进行读写校验,验证I2C通讯
	uint8_t write_buf[2] = {0x11, 0x13};
	uint8_t read_buf[2];
	MyI2C_WriteMultiRegister(SPL06_ADDRESS, PRS_CFG, 2, write_buf);
	MyI2C_ReadMultiRegister(SPL06_ADDRESS, PRS_CFG, 2, read_buf);
	for(uint8_t i = 0; i < 2; i++)
	{
		if(read_buf[i] != write_buf[i])
		{
			return 1;
		}
	}
	
	//3. 确认I2C通信正常后,软复位芯片
	MyI2C_WriteRegister(RESET, 0x89);
	for(uint16_t i=0; i<1000; i++)
	{
		for(uint16_t j=0; j<2000; j++);
	}

	//4. 配置采样模式:连续采样大气压强和温度
	if(SPL_OperatingModeInit(STRAT_CONTINUOUS_PSR_TEMP))
			return 2;
	
	//5. 配置大气压强采样频率,过采样率
	PSR_InitStructure.MEASURE_RATE = _4HZ_MEASUREMENT;							//采样频率
	PSR_InitStructure.OVER_SAMPLING_TIMES = _64TIMES_OVERSAMPLING;	//过采样率
	if(SPL06_PSRInitStruct(&PSR_InitStructure))
			return 3;
	
	//6. 配置温度采样频率,过采样率
	TEMP_InitStructure.MEASURE_RATE = _4HZ_MEASUREMENT;							//采样频率
	TEMP_InitStructure.OVER_SAMPLING_TIMES = _SINGLE_OVERSAMPLING;	//过采样率
	TEMP_InitStructure.SENSOR_SOURCE = _EXTERNAL_SENSOR;
	if(SPL06_TEMPInitStruct(&TEMP_InitStructure))
			return 2;

    //7. 当大气压强过采样率>8时,必须启用P Shift
	MyI2C_WriteRegister(CFG_REG, 0x04);		//	启动P位移,0x04,禁用FIFO  0x06,启用FIFO
	
    //8. 初始化KP、KT链表
	Init_FactorList();
	
    //9. 读取矫正系数,保存在Coefficient结构体中
	if(GetCoefVal(&Coefficient) != 0)
			return 5;
	
    //10. 正常返回0
	return 0;
}


/**
 * @name    uint8_t SPL06_PSRInitStruct(PSR_InitTypedef* PSR_InitStructure)
 * @brief   配置大气压强测量控制寄存器,可配置采样频率,过采样率
 * @param   [PSR_InitStructure] 传入的结构体指针,包含配置信息
 * @return  0   成功
 *          1   失败
 */
uint8_t SPL06_PSRInitStruct(PSR_InitTypedef* PSR_InitStructure)
{
    uint8_t config = 0x00;
    config = PSR_InitStructure->MEASURE_RATE + PSR_InitStructure->OVER_SAMPLING_TIMES;

		if(MyI2C_WriteRegister(PRS_CFG, (uint8_t)config))
		{
			return 1;
		}

    return 0;
}

/**
 * @name    uint8_t SPL06_TEMPInitStruct(TEMP_InitTypedef* TEMP_InitStructure)
 * @brief   配置温度测量控制寄存器,可配置采样频率,过采样率
 * @param   [TEMP_InitStructure] 传入的结构体指针,包含配置信息
 * @return  0   成功
 *          1   失败
 */
uint8_t SPL06_TEMPInitStruct(TEMP_InitTypedef* TEMP_InitStructure)
{
    uint8_t config = 0x00;
    config = TEMP_InitStructure->SENSOR_SOURCE + TEMP_InitStructure->MEASURE_RATE \
                                        + TEMP_InitStructure->OVER_SAMPLING_TIMES;
		
		if(MyI2C_WriteRegister(TMP_CFG, config))
		{
			return 1;
		}
	
    return 0;
}

/**
 * @name    uint8_t SPL_OperatingModeInit(MeasureModeConfig config)
 * @brief   设置SPL06的测量模式,可以在@<! MeasureModeConfig >中查看可配置的测量模式
 * @param   [config] 具体见@<! MeasureModeConfig >
 * @return  0   成功
 *          1   失败
 */
uint8_t SPL_OperatingModeInit(MeasureModeConfig config)
{
		if(MyI2C_WriteRegister(MEAS_CFG, config))
		{
			return 1;
		}

    return 0;
}

/**
 * @name    uint8_t COEF_CheckStatus(void)
 * @brief   查询SPL06的矫正系数是否可读
 * @return  0   可读
 *          1   不可读
 */
uint8_t COEF_CheckStatus(void)
{
    if((MyI2C_ReadRegister(MEAS_CFG) & 0x80) == 0x80)               //如果bit[7]COFE_RDY为高,说明矫正系数可读
    {
        return 0;
    }

    return 1;
}

/**
 * @brief 	读取SPL06的ID
 * @param 	[void]
 * @return 	[ID] ID默认值
 */
uint8_t SPL06_ReadID(void)
{
    return MyI2C_ReadRegister(ID);
}

/**
 * @brief 获得出厂校准系数
 * @param COEF_ValueStruct* COEF,系数结构体指针,用于存储系数
 * @return 0 获取成功
 *         1 获取失败,读取过程出错,但矫正系数本身可以被读
 *         2 获取失败,矫正系数没有准备就绪
 */
uint8_t GetCoefVal(COEF_ValueStruct* COEF)
{
    uint8_t buffer[18] = { 0 };
    if(COEF_CheckStatus() == 0)
    {
        //开始读取矫正系数
        if(MyI2C_ReadMultiRegister(SPL06_ADDRESS, COEF_C0, 18, buffer))
        {
            return 1;
        }
    }else{
        return 2;
    }

    //将校正系数正确存放到变量中
    COEF->C0 = COEF->raw_C0 = (uint16_t)((buffer[0] << 4) | ((buffer[1] & 0xF0) >> 4)); 											// 12-bit value
		COEF->C1 = COEF->raw_C1 = (uint16_t)(((buffer[1] & 0x0F) << 8) | buffer[2]); 															// 12-bit value
    COEF->C00 = COEF->raw_C00 = (uint32_t)((buffer[3] << 12) | (buffer[4] << 4) | ((buffer[5] & 0xF0) >> 4)); // 20-bit value
		COEF->C10 = COEF->raw_C10 = (uint32_t)((buffer[5] & 0x0F) << 16 | buffer[6] << 8 | buffer[7]); // 20-bit value
    COEF->C01 = COEF->raw_C01 = (uint16_t)(buffer[8] << 8 | buffer[9]);
		COEF->C11 = COEF->raw_C11 = (uint16_t)(buffer[10] << 8 | buffer[11]);
		COEF->C20 = COEF->raw_C20 = (uint16_t)(buffer[12] << 8 | buffer[13]);
		COEF->C21 = COEF->raw_C21 = (uint16_t)(buffer[14] << 8 | buffer[15]);
		COEF->C30 = COEF->raw_C30 = (uint16_t)(buffer[16] << 8 | buffer[17]);

    //这些数据都是以补码形式存放,如果为负数,应该将其转换
    if(COEF->raw_C0 & 0x800)    COEF->C0 = (COEF->raw_C0 - Total_Number_12);
    if(COEF->raw_C1 & 0x800)    COEF->C1 = (COEF->raw_C1 - Total_Number_12);

    if(COEF->raw_C00 & 0x80000) COEF->C00 = COEF->raw_C00 - Total_Number_20;
    if(COEF->raw_C10 & 0x80000) COEF->C10 = COEF->raw_C10 - Total_Number_20;

    if(COEF->raw_C01 & 0x8000)  COEF->C01 = COEF->raw_C01 - Total_Number_16;
    if(COEF->raw_C11 & 0x8000)  COEF->C11 = COEF->raw_C11 - Total_Number_16;
    if(COEF->raw_C20 & 0x8000)  COEF->C20 = COEF->raw_C20 - Total_Number_16;
    if(COEF->raw_C21 & 0x8000)  COEF->C21 = COEF->raw_C21 - Total_Number_16;
    if(COEF->raw_C30 & 0x8000)  COEF->C30 = COEF->raw_C30 - Total_Number_16;
    
    return 0;
}

/**
 * @brief 获取经过出厂校准系数补偿过的大气压强值,温度值
* @param 	[float* baroValue] 接收大气压强值的浮点数,单位: 百帕(hpa)
*        	[float* tempValue] 接收温度值的浮点数,单位: 摄氏度(℃)
 *        [COEF_ValueStruct* COEF] 校准系数结构体指针
 * @return 0 获取成功
 *         1 获取失败,I2C通讯异常
 */
uint8_t GetCompensatedVal(float* baroValue, float* tempValue, COEF_ValueStruct* COEF)
{
    //1. 获取raw数据
    uint8_t arr_temp[6] = { 0 };
    uint32_t rawBaroValue = 0, rawTempValue = 0;
		int32_t Baro, Temp;
		
    if(MyI2C_ReadMultiRegister(SPL06_ADDRESS, PSR_B2, 6, arr_temp))//一次性读取大气压强值、温度值的6个寄存器
    {
        return 1;
    }
		
    rawBaroValue = (arr_temp[0] << 16) + (arr_temp[1] << 8) + (arr_temp[2]);          //24bit有符号数
    rawTempValue = (arr_temp[3] << 16) + (arr_temp[4] << 8) + (arr_temp[5]);
	
		Baro = rawBaroValue & 0x00FFFFFF;
		Temp = rawTempValue & 0x00FFFFFF;
		
    if(rawBaroValue & 0x80000) Baro = rawBaroValue - Total_Number_24;  //如果最高位为1,转化为负数
    if(rawTempValue & 0x80000) Temp = rawTempValue - Total_Number_24;

    //2. 根据过采样率选择对应的KP,KT系数
    volatile uint32_t KP, KT;
    float Praw_Sc, Traw_Sc;
    KP = FindFactor(b_list, PSR_InitStructure.OVER_SAMPLING_TIMES);   //在初始化的链表中寻找对应的比例因子
    KT = FindFactor(b_list, TEMP_InitStructure.OVER_SAMPLING_TIMES);
		
    //3. 带入公式求得校准后的数据
    Praw_Sc = (float)Baro / KP;
    Traw_Sc = (float)Temp / KT;

    //4. 将数据传递到地址中
    *baroValue = COEF->C00 + Praw_Sc * (COEF->C10 + Praw_Sc * ( COEF->C20 + Praw_Sc * COEF->C30)) + Traw_Sc * COEF->C01 + Traw_Sc * Praw_Sc * (COEF->C11 + Praw_Sc * COEF->C21);
		
	*baroValue /= 100; //将压强值转化为hpa
                
    *tempValue = COEF->C0 * 0.5f + COEF->C1 * Traw_Sc;

    return 0;
}

/**
 * @brief 将大气压强值转化为高度值
 * @param [float P] 大气压强值,单位hpa
 * @return -1 输入大气压强值错误
 *         Altitude 单精度浮点数,返回海拔高度值,单位m
 */
float getAltitude(float P)
{
		P *= 100;
    float Altitude;
    if(P > 30000 && P < 200000)
    {
        Altitude = 44330.0f * (1.0f - (float)pow(P / P0, 1.0/5.255));
    }else{
        return 0;
    }
    
    return Altitude;
}

//*************快速排序算法*************//
void swap(float* a, float* b) {
    float t = *a;
    *a = *b;
    *b = t;
}

int partition(float arr[], int low, int high) {
    float pivot = arr[high];    // 选择最后一个元素作为基准
    int i = (low - 1);          // 小于基准的元素的索引

    for (int j = low; j < high; j++) {
        // 如果当前元素小于或等于基准
        if (arr[j] <= pivot) {
            i++;    // 增加小于基准的元素的索引
            swap(&arr[i], &arr[j]);
        }
    }
    swap(&arr[i + 1], &arr[high]);
    return (i + 1);
}

void quickSort(float arr[], int low, int high) {
    if (low < high) {
        // pi 是 partitioning index, arr[p] 现在位于正确位置
        int pi = partition(arr, low, high);

        // 分别对基准左右两边的子数组进行递归排序
        quickSort(arr, low, pi - 1);
        quickSort(arr, pi + 1, high);
    }
}


/**
 * @name    float AltitudeFilter(float newAltitude)
 * @brief   对计算得到校准后的高度值进一步滤波,采用快速排序+中值均值滤波
 * @param   [float newAltitude] 采集到的新数据
 * @return  [filterdAltitude]  滤波后的数据
 */
float AltitudeFilter(float newAltitude)
{
		static float AltitudeRawArray[FILTER_MAX_SIZE] = { 0 };							//原始数据
		static float AltitudeBuffer[FILTER_MAX_SIZE] = { 0 };  							//排序缓冲数组
    float filterdAltitude;                                      //滤波后数据
    
    //把原始数组里的数据前移
    for(uint8_t i = 0; i < FILTER_MAX_SIZE - 1; i++)
    {
        AltitudeRawArray[i] = AltitudeRawArray[i + 1];
    }
    //更新数据
    AltitudeRawArray[FILTER_MAX_SIZE - 1] = newAltitude;
    
    //将更新的数据拷贝给缓冲排序数组
    memcpy(&AltitudeBuffer, &AltitudeRawArray, sizeof(AltitudeRawArray));

    //快速排序
    quickSort(AltitudeBuffer, 0, FILTER_MAX_SIZE - 1);

    //掐头去尾取中间,去掉前三分之一和后三分之一,取中间平均值
    float bufferSum = 0;
    for(uint8_t i = FILTER_MAX_SIZE / 3; i < FILTER_MAX_SIZE * 2/3; i++)
    {
        bufferSum += AltitudeBuffer[i];
    }
    filterdAltitude = bufferSum / (FILTER_MAX_SIZE / 3);

    return filterdAltitude;
}

SPL06.h

#ifndef __SPL06_H
#define __SPL06_H

#include <stdlib.h>
#include <string.h>
#include <math.h>

#include "MyI2C.h"

//************自然值************//
#define P0 101325.0f        //标准大气压强值

//************用于负数二补数转换************//
#define Total_Number_24 16777216.0
#define Total_Number_20 1048576.0
#define Total_Number_16 65536.0
#define Total_Number_12 4096.0

//************REGISTER ADDRESS************//
//仅列出了部分寄存器组,通过读写多个寄存器实现对所有寄存器的操作,如果需要更多的寄存器请参考datasheet
#define     PSR_B2      0x00
#define     PSR_B1      0x01
#define     PSR_B0      0x02
#define     TMP_B2      0x03
#define     TMP_B1      0x04
#define     TMP_B0      0x05
#define     PRS_CFG     0x06
#define     TMP_CFG     0x07
#define     MEAS_CFG    0x08
#define     CFG_REG     0x09
#define     INT_STS     0x0A
#define     FIFO_STS    0x0B
#define     RESET       0x0C
#define     ID          0x0D
#define     COEF_C0     0x10
#define     COEF_C00    0x13
#define     COEF_C10    0x17
#define     COEF_C01    0x18
#define     COEF_C11    0x1A
#define     COEF_C20    0x1C
#define     COEF_C21    0x1E
#define     COEF_C30    0x20

//************SPL06 I2C ADDRESS INITIALIZE************//
#define SPL06_ADDRESS   0x77       //SDO High -> 0x77, SDO Low -> 0x76
#define SPL06_ADDRESS_W (SPL06_ADDRESS<<1)|0x00
#define SPL06_ADDRESS_R (SPL06_ADDRESS<<1)|0x01


//************PRESSSURE & TEMPERATURE CONFIG************//
//bit[7] only accessiable for temperature config
#define     _INTERNAL_SENSOR        0x00
#define     _EXTERNAL_SENSOR        0x80
//bit[6:4] MEASURE_RATE for all
#define     _1HZ_MEASUREMENT        0x00
#define     _2HZ_MEASUREMENT        0x10
#define     _4HZ_MEASUREMENT        0x20
#define     _8HZ_MEASUREMENT        0x30
#define     _16HZ_MEASUREMENT       0x40
#define     _32HZ_MEASUREMENT       0x50
#define     _64HZ_MEASUREMENT       0x60
#define     _128HZ_MEASUREMENT      0x70
//bit[3:0] OVER_SAMPLING_TIMES for all
#define     _SINGLE_OVERSAMPLING    0x00
#define     _2TIMES_OVERSAMPLING    0x01
#define     _4TIMES_OVERSAMPLING    0x02
#define     _8TIMES_OVERSAMPLING    0x03
#define     _16TIMES_OVERSAMPLING   0x04
#define     _32TIMES_OVERSAMPLING   0x05
#define     _64TIMES_OVERSAMPLING   0x06
#define     _128TIMES_OVERSAMPLING  0x07

//************SCALE FACTOR************//
//存放KP、KT的数据集合,该数值与过采样率(OVER_SAMPLING_TIMES)相关
#define _SINGLE_SCALE_FACTOR    524288					//单次过采样对应scaleFactor
#define _2TIMES_SCALE_FACTOR    1572864					//2次过采样对应scaleFactor
#define _4TIMES_SCALE_FACTOR    3670016 				//4次过采样对应scaleFactor
#define _8TIMES_SCALE_FACTOR    7864320 				//8次过采样对应scaleFactor
#define _16TIMES_SCALE_FACTOR   253952					//16次过采样对应scaleFactor
#define _32TIMES_SCALE_FACTOR   516096					//32次过采样对应scaleFactor
#define _64TIMES_SCALE_FACTOR   1040384					//64次过采样对应scaleFactor
#define _128TIMES_SCALE_FACTOR  2088960					//128次过采样对应scaleFactor

//************滤波最大缓冲数************//
#define FILTER_MAX_SIZE 32

typedef struct 
{
    uint8_t MEASURE_RATE;               //see @MEASURE_RATE
    uint8_t OVER_SAMPLING_TIMES;        //see @OVER_SAMPLING_TIMES
} PSR_InitTypedef;

typedef struct
{
    uint8_t MEASURE_RATE;
    uint8_t OVER_SAMPLING_TIMES;
    uint8_t SENSOR_SOURCE;
} TEMP_InitTypedef;

//校准系数: coefficient
typedef struct
{
		uint16_t raw_C0;
		uint16_t raw_C1;
    uint32_t raw_C00;
    uint32_t raw_C10;
    uint16_t raw_C01;
    uint16_t raw_C11;
    uint16_t raw_C20;
    uint16_t raw_C21;
    uint16_t raw_C30;
	
    int16_t C0;
    int16_t C1;
    int32_t C00;
    int32_t C10;
    int16_t C01;
    int16_t C11;
    int16_t C20;
    int16_t C21;
    int16_t C30;

} COEF_ValueStruct;

//传感器测量模式
typedef enum
{
    STANDBY = 0x00,                     //休眠
    START_SINGLE_PSR,                   //单次转换大气压强值
    START_SINGLE_TEMP,                  //单词转换温度值
    STRAT_CONTINUOUS_PSR = 0x05,        //连续转换大气压强值
    STRAT_CONTINUOUS_TEMP,              //连续转换温度值
    STRAT_CONTINUOUS_PSR_TEMP = 0x07,   //连续转换大气压强值和温度值
} MeasureModeConfig;


//定义过采样率对应的比例系数链表
typedef struct node
{
    /* data */
    uint8_t OverSamplingRate;
    uint32_t FACTOR;
    struct node* next;
} Factor_List;

extern Factor_List* b_list;													//声明比例系数链表存在
extern COEF_ValueStruct Coefficient;								//声明校准系数存在
extern TEMP_InitTypedef TEMP_InitStructure;        	//声明温度测量初始化配置结构体
extern PSR_InitTypedef PSR_InitStructure;          	//声明大气压强测量初始化配置结构体

//**********************<对外API,重要!>*********************//
//配置好GPIO引脚和IIC通讯地址后,依次调用下面四个函数即可得到高度值

uint8_t SPL06_Init(void);
uint8_t GetCompensatedVal(float* baroValue, float* tempValue, COEF_ValueStruct* COEF);//计算出气压计的单位为hpa
float getAltitude(float P);
float AltitudeFilter(float newAltitude);


//*********************链表初始化*********************//
Factor_List* initList(void);
Factor_List* insertTail(Factor_List *l, uint8_t val, uint32_t Factor);
void Init_FactorList(void);
uint32_t FindFactor(Factor_List* l, uint8_t val);


//*********************传感器初始化*********************//
uint8_t SPL06_PSRInitStruct(PSR_InitTypedef* PSR_InitStructure);
uint8_t SPL06_TEMPInitStruct(TEMP_InitTypedef* TEMP_InitStructure);
uint8_t SPL_OperatingModeInit(MeasureModeConfig config);


//*********************传感器状态获取*******************//
uint8_t COEF_CheckStatus(void);


//*********************传感器内部数据读取***************//
uint8_t GetCoefVal(COEF_ValueStruct* COEF);

uint8_t SPL06_ReadID(void);



#endif

MyI2C.c(基于江协科技)

#include "main.h"                  // Device header
#include "Delay.h"
#include "MyI2C.h"

void MyI2C_W_SCL(uint8_t BitValue)
{
    HAL_GPIO_WritePin(BARO_SCL_GPIO_Port, BARO_SCL_Pin, (GPIO_PinState)BitValue);

}

void MyI2C_W_SDA(uint8_t BitValue)
{
    HAL_GPIO_WritePin(BARO_SDA_GPIO_Port, BARO_SDA_Pin, (GPIO_PinState)BitValue);

}

uint8_t MyI2C_R_SDA(void)
{
	uint8_t BitValue;
	BitValue = HAL_GPIO_ReadPin(BARO_SDA_GPIO_Port, BARO_SDA_Pin);

	return BitValue;
}


void MyI2C_Start(void)
{
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(0);
}

void MyI2C_Stop(void)
{
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(1);
}

void MyI2C_SendByte(uint8_t Byte)
{
	uint8_t i;
	for (i = 0; i < 8; i ++)
	{
		MyI2C_W_SDA(!!(Byte & (0x80 >> i)));
		MyI2C_W_SCL(1);
		MyI2C_W_SCL(0);
	}
}

uint8_t MyI2C_ReceiveByte(void)
{
	uint8_t i, Byte = 0x00;
	MyI2C_W_SDA(1);
	for (i = 0; i < 8; i ++)
	{
		MyI2C_W_SCL(1);
		if (MyI2C_R_SDA()){Byte |= (0x80 >> i);}
		MyI2C_W_SCL(0);
	}
	return Byte;
}

void MyI2C_SendAck(uint8_t AckBit)
{
	MyI2C_W_SDA(AckBit);
	MyI2C_W_SCL(1);
	MyI2C_W_SCL(0);
}

uint8_t MyI2C_ReceiveAck(void)
{
	uint8_t AckBit;
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	AckBit = MyI2C_R_SDA();
	MyI2C_W_SCL(0);
	return AckBit;
}

uint8_t MyI2C_WriteRegister(uint8_t RegAddr, uint8_t byte)
{

    MyI2C_Start();                      //启动总线
    MyI2C_SendByte(SPL06_ADDRESS_W);    //发送写地址

    if(MyI2C_ReceiveAck() == 1)         //未应答
        return 1;

    MyI2C_SendByte(RegAddr);           //要写入的寄存器地址

    if(MyI2C_ReceiveAck() == 1)         //未应答
        return 1;

    MyI2C_SendByte(byte);
		
		if(MyI2C_ReceiveAck() == 1)         //未应答
        return 1;

    MyI2C_Stop();

    return 0;
}

uint8_t MyI2C_ReadRegister(uint8_t RegAddr)
{
    MyI2C_Start();                      //启动总线
    MyI2C_SendByte(SPL06_ADDRESS_W);              //发送写地址

    if(MyI2C_ReceiveAck() == 1)         //未应答
        return 1;

    MyI2C_SendByte(RegAddr);           //要写入的寄存器地址

    if(MyI2C_ReceiveAck() == 1)         //未应答
        return 1;

    MyI2C_Start();                      //启动总线
    MyI2C_SendByte(SPL06_ADDRESS_R);              //发送读地址

    if(MyI2C_ReceiveAck() == 1)         //未应答
        return 1;

    uint8_t byte =  MyI2C_ReceiveByte();
		
		MyI2C_SendAck(1);

    MyI2C_Stop();

    return byte;
}

uint8_t MyI2C_ReadMultiRegister(uint8_t I2CAddr, uint8_t RegAddr, uint8_t length, uint8_t* temp)
{
	uint8_t AddrW,AddrR;
	AddrW = I2CAddr<<1;
	AddrR = (I2CAddr<<1) + 1;

	MyI2C_Start();                      //启动总线
    MyI2C_SendByte(AddrW);    			//发送写地址

    if(MyI2C_ReceiveAck() == 1)         //未应答
        return 1;

    MyI2C_SendByte(RegAddr);           //要写入的寄存器地址

    if(MyI2C_ReceiveAck() == 1)         //未应答
        return 1;

    MyI2C_Start();                      //启动总线
    MyI2C_SendByte(AddrR);    			//发送读地址

    if(MyI2C_ReceiveAck() == 1)         //未应答
        return 1;

	for(uint8_t i = 0; i < length; i++)
	{
		*(temp + i) = MyI2C_ReceiveByte();

		if(i < length - 1)
		{
			MyI2C_SendAck(0);
		}else{
			MyI2C_SendAck(1);
		}
	}

	MyI2C_Stop();

	return 0;
}

uint8_t MyI2C_WriteMultiRegister(uint8_t I2CAddr, uint8_t RegAddr, uint8_t length, uint8_t* temp)
{
	uint8_t AddrW;
	AddrW = I2CAddr<<1;

	MyI2C_Start();                      //启动总线
    MyI2C_SendByte(AddrW);    			//发送写地址

    if(MyI2C_ReceiveAck() == 1)         //未应答
        return 1;

    MyI2C_SendByte(RegAddr);           //要写入的寄存器地址

    if(MyI2C_ReceiveAck() == 1)         //未应答
        return 1;

	for(uint8_t i = 0; i < length; i++)
	{
		MyI2C_SendByte(*(temp + i));

		if(i < length - 1)
		{
			MyI2C_SendAck(0);
		}else{
			MyI2C_SendAck(1);
		}
	}
	MyI2C_Stop();

	return 0;
}

MyI2C.h

#ifndef __MYI2C_H
#define __MYI2C_H

#include "main.h"
#include "Delay.h"
#include "SPL06.h"

void MyI2C_W_SCL(uint8_t BitValue);
void MyI2C_W_SDA(uint8_t BitValue);
uint8_t MyI2C_R_SDA(void);

void MyI2C_Start(void);
void MyI2C_Stop(void);
void MyI2C_SendByte(uint8_t Byte);
uint8_t MyI2C_ReceiveByte(void);
void MyI2C_SendAck(uint8_t AckBit);
uint8_t MyI2C_ReceiveAck(void);

uint8_t MyI2C_ReadRegister(uint8_t RegAddr);
uint8_t MyI2C_WriteRegister(uint8_t RegAddr, uint8_t byte);
uint8_t MyI2C_ReadMultiRegister(uint8_t I2CAddr, uint8_t RegAddr, uint8_t length, uint8_t* temp);
uint8_t MyI2C_WriteMultiRegister(uint8_t I2CAddr, uint8_t RegAddr, uint8_t length, uint8_t* temp);
#endif

main.c

#include "main.h"
#include "SPL06.h"

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();

    uint8_t ack = SPL06_Init();
    float height, filtredHeight;
    float baro, temp;
  
    while(1)
    {
        //获取补偿后的值
		GetCompensatedVal(&baro, &temp, &Coefficient);
        
        //转化为高度值
		height = getAltitude(baro);
        
        //排序,中值平均滤波,可以在SPL06.h中修改FILTER_MAX_SIZE来调整滤波
		filtredHeight = AltitudeFilter(height);
        
		rt_thread_delay(250);
    }
}

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

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

相关文章

【QT常用技术讲解】发送POST包(两种方式:阻塞方式及非阻塞方式)

前言 http/https(应用层)协议是广泛使用的网络通信协议。在很多与第三方API对接的场景中&#xff0c;通常是通过http/https协议完成&#xff0c;比如API对接时&#xff0c;通常要通过POST包获取access_token进行鉴权&#xff0c;然后再进行数据交互&#xff08;本篇也包含有对接…

【电商搜索】文档的信息论生成聚类

【电商搜索】文档的信息论生成聚类 目录 文章目录 【电商搜索】文档的信息论生成聚类目录文章信息概览研究背景技术挑战如何破局技术应用主要相关工作与参考文献后续优化方向 后记 文章信息 https://arxiv.org/pdf/2412.13534 概览 本文提出了一种基于信息论的生成聚类&#…

【数据结构与算法】排序算法(下)——计数排序与排序总结

写在前面 书接上文&#xff1a;【数据结构与算法】排序算法(中)——交换排序之快速排序 文章主要讲解计数排序的细节与分析源码。之后进行四大排序的总结。 文章目录 写在前面一、计数排序(非比较排序)代码的实现&#xff1a; 二、排序总结 2.1、稳定性 3.2、排序算法复杂度及…

Unity全局雾效

1、全局雾效是什么 全局雾效&#xff08;Global Fog&#xff09;是一种视觉效果&#xff0c;用于在3D场景中模拟大气中的雾气对远处物体的遮挡 它通过在场景中加入雾的效果&#xff0c;使得距离摄像机较远的物体看起来逐渐被雾气覆盖&#xff0c;从而创造出一种朦胧、模糊的视…

Kafka Streams 在监控场景的应用与实践

作者&#xff1a;来自 vivo 互联网服务器团队- Pang Haiyun 介绍 Kafka Streams 的原理架构&#xff0c;常见配置以及在监控场景的应用。 一、背景 在当今大数据时代&#xff0c;实时数据处理变得越来越重要&#xff0c;而监控数据的实时性和可靠性是监控能力建设最重要的一环…

数据分析思维(五):分析方法——假设检验分析方法

数据分析并非只是简单的数据分析工具三板斧——Excel、SQL、Python&#xff0c;更重要的是数据分析思维。没有数据分析思维和业务知识&#xff0c;就算拿到一堆数据&#xff0c;也不知道如何下手。 推荐书本《数据分析思维——分析方法和业务知识》&#xff0c;本文内容就是提取…

解读DiffusionNER: Boundary Diffusion for Named Entity Recognition

content 摘要1. 图1图21. 上方&#xff1a;扩散过程与实体边界2. 下方&#xff1a;网络结构&#xff08;Sentence Encoder Entity Decoder&#xff09;3. 关键思想小结 摘要 主要内容分为四个部分&#xff1a; 模型定位与基本原理&#xff1a; 提出了DiffusionNER模型将命名…

【QSS样式表 - ⑥】:QPushButton控件样式

文章目录 QPushBUtton控件样式QSS示例 QPushBUtton控件样式 常用子控件 常用伪状态 QSS示例 代码&#xff1a; QPushButton {background-color: #99B5D1;color: white;font-weigth: bold;border-radius: 20px; }QPushButton:hover {background-color: red; }QPushButton:p…

数字经济下的 AR 眼镜

目录 1. &#x1f4c2; AR 眼镜发展历史 1.1 AR 眼镜相关概念 1.2 市面主流 XR 眼镜 1.3 AR 眼镜大事记 1.4 国内外 XR 眼镜 1.5 国内 AR 眼镜四小龙 2. &#x1f531; 关键技术 2.1 AR 眼镜近眼显示原理 2.2 AR 眼镜关键技术 2.3 AR 眼镜技术难点 3. &#x1f4a…

smb和nfs双栈协议共享目录

1 简介 NFS和SAMBA协议都是文件共享&#xff0c;Linux客户端常用于NFS协议访问远程共享目录&#xff0c;Windows客户端常用于SAMBA协议访问远程共享目录。 2 环境 合计使用三台服务器&#xff0c;服务器都位于同一个子网&#xff08;10.0.0.0/19&#xff09;、同一个安全组…

Day13 用Excel表体验梯度下降法

Day13 用Excel表体验梯度下降法 用所学公式创建Excel表 用Excel表体验梯度下降法 详见本Day文章顶部附带资源里的Excel表《梯度下降法》&#xff0c;可以对照表里的单元格公式进行理解&#xff0c;还可以多尝试几次不同的学习率 η \eta η来感受&#xff0c;只需要更改学习率…

Python获取系统负载并打印折线图

#! /opt/py36/bin/python import psutil import matplotlib.pyplot as plt import time# 创建一个空列表&#xff0c;用于存储负载数据 load_data []# 循环收集负载数据 while True:# 获取当前系统负载load_avg psutil.getloadavg()# 将平均负载添加到load_data列表中load_da…

RCE 命令执行漏洞 过滤模式 基本的过滤问题 联合ctf题目进行实践

前言 知道RCE 命令执行分为 代码执行 和 命令执行 原理 &#xff1a; 就是用户的输入被当做命令或者代码执行了 从而造成了危害 代码执行 除了eval php代码执行漏洞的函数还有 eval()、a ssert()、 preg_replace()、 create_function()、 array_map()、 call_user_func(…

Leetcode打卡:考场就坐

执行结果&#xff1a;通过 题目&#xff1a; 855 考场就坐 在考场里&#xff0c;有 n 个座位排成一行&#xff0c;编号为 0 到 n - 1。 当学生进入考场后&#xff0c;他必须坐在离最近的人最远的座位上。如果有多个这样的座位&#xff0c;他会坐在编号最小的座位上。(另外&am…

数据结构(哈希表(上)纯概念版)

前言 在软件开发和计算机科学中&#xff0c;数据结构的选择直接影响到程序的性能和效率。不同的数据结构适用于不同的场景&#xff0c;合理地选择合适的数据结构是高效编程的关键之一。哈希表&#xff08;哈希表&#xff08;Hash Table&#xff09;作为一种高效的键值对存储结…

【机器学习与数据挖掘实战】案例06:基于Apriori算法的餐饮企业菜品关联分析

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈机器学习与数据挖掘实战 ⌋ ⌋ ⌋ 机器学习是人工智能的一个分支,专注于让计算机系统通过数据学习和改进。它利用统计和计算方法,使模型能够从数据中自动提取特征并做出预测或决策。数据挖掘则是从大型数据集中发现模式、关联…

深入解析 Spring WebFlux:原理与应用

优质博文&#xff1a;IT-BLOG-CN WebFlux 是 Spring Framework 5 引入的一种响应式编程框架&#xff0c;和Spring MVC同级&#xff0c;旨在处理高并发和低延迟的非阻塞应用。这是一个支持反应式编程模型的新Web框架体系。 顺便一提&#xff0c;Spring Cloud Gateway在实现上是…

C语言基础——指针(4)

一&#xff0e; 字符指针变量 字符指针变量的使用和整型指针变量的使用方法相似&#xff0c;以下是其基本使用方法的例子&#xff1a; &#xff08;1&#xff09;字符指针变量还有一种使用方法&#xff1a; const char* p "abcd" 需…

『 Linux 』高级IO (一)

文章目录 内容回顾及铺垫五种IO模型不同类型IO的区别非阻塞IOfcntl( ) 多路转接 - select( )select( ) 的基本使用 - SelectServer服务器 内容回顾及铺垫 在博客『 Linux 』基础IO/文件IO (万字)中介绍了对IO的认识; IO实际上为Input/Output,输入输出; 以网络协议栈的视角来看,…

Spark-Streaming集成Kafka

Spark Streaming集成Kafka是生产上最多的方式&#xff0c;其中集成Kafka 0.10是较为简单的&#xff0c;即&#xff1a;Kafka分区和Spark分区之间是1:1的对应关系&#xff0c;以及对偏移量和元数据的访问。与高版本的Kafka Consumer API 集成时做了一些调整&#xff0c;下面我们…