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

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 ShiftMyI2C_WriteRegister(CFG_REG, 0x04);		//	启动P位移,0x04,禁用FIFO  0x06,启用FIFO//8. 初始化KP、KT链表Init_FactorList();//9. 读取矫正系数,保存在Coefficient结构体中if(GetCoefVal(&Coefficient) != 0)return 5;//10. 正常返回0return 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 valueCOEF->C1 = COEF->raw_C1 = (uint16_t)(((buffer[1] & 0x0F) << 8) | buffer[2]); 															// 12-bit valueCOEF->C00 = COEF->raw_C00 = (uint32_t)((buffer[3] << 12) | (buffer[4] << 4) | ((buffer[5] & 0xF0) >> 4)); // 20-bit valueCOEF->C10 = COEF->raw_C10 = (uint32_t)((buffer[5] & 0x0F) << 16 | buffer[6] << 8 | buffer[7]); // 20-bit valueCOEF->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 32typedef struct 
{uint8_t MEASURE_RATE;               //see @MEASURE_RATEuint8_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.mzph.cn/bicheng/64843.shtml

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

相关文章

移动魔百盒中的 OpenWrt作为旁路由 安装Tailscale并配置子网路由实现在外面通过家里的局域网ip访问内网设备

移动魔百盒中的 OpenWrt作为旁路由 安装Tailscale并配置子网路由实现在外面通过家里的局域网ip访问内网设备 一、前提条件 确保路由器硬件支持&#xff1a; OpenWrt 路由器需要足够的存储空间和 CPU 性能来运行 Tailscale。确保设备架构支持 Tailscale 二进制文件&#xff0c;例…

每天40分玩转Django:Django部署

Django部署 一、今日学习内容概述 学习模块重要程度主要内容生产环境配置⭐⭐⭐⭐⭐settings配置、环境变量WSGI服务器⭐⭐⭐⭐⭐Gunicorn配置、性能优化Nginx配置⭐⭐⭐⭐反向代理、静态文件安全设置⭐⭐⭐⭐⭐SSL证书、安全选项 二、生产环境配置 2.1 项目结构调整 mypr…

CVPR2024 | 通过集成渐近正态分布学习实现强可迁移对抗攻击

Strong Transferable Adversarial Attacks via Ensembled Asymptotically Normal Distribution Learning 摘要-Abstract引言-Introduction相关工作及前期准备-Related Work and Preliminaries1. 黑盒对抗攻击2. SGD的渐近正态性 提出的方法-Proposed Method随机 BIM 的渐近正态…

华为IPD流程6大阶段370个流程活动详解_第一阶段:概念阶段 — 81个活动

华为IPD流程涵盖了产品从概念到上市的完整过程,各阶段活动明确且相互衔接。在概念启动阶段,产品经理和项目经理分析可行性,PAC评审后成立PDT。概念阶段则包括产品描述、市场定位、投资期望等内容的确定,同时组建PDT核心组并准备项目环境。团队培训涵盖团队建设、流程、业务…

《LangChain大模型应用开发》书籍分享

前言 ChatGPT和OpenAI开发的GPT模型不仅改变了我们的写作和研究方式&#xff0c;还改变了我们处理信息的方式。《LangChain大模型应用开发》讨论了聊天模式下的LLM的运作、能力和局限性&#xff0c;包括ChatGPT和Gemini。书中通过一系列实际例子演示了如何使用LangChain框架构…

Win10将WindowsTerminal设置默认终端并添加到右键(无法使用微软商店)

由于公司内网限制&#xff0c;无法通过微软商店安装 Windows Terminal&#xff0c;本指南提供手动安装和配置新版 Windows Terminal 的步骤&#xff0c;并添加右键菜单快捷方式。 1. 下载新版终端安装包: 访问 Windows Terminal 的 GitHub 发布页面&#xff1a;https://githu…

Oracle中间件 SOA之 OSB 12C服务器环境搭建

环境信息 服务器基本信息 如下表&#xff0c;本次安装总共使用1台服务器&#xff0c;具体信息如下&#xff1a; App1服务器 归类 APP服务器 Ip Address 172.xx.30.xx HostName appdev01. xxxxx.com Alias appdev01 OSB1服务器 归类 OSB服务器 Ip Address 172.xx3…

java小知识点:比较器

java中自主排序主要根据一个Comparator类来实现。 他内部实现用的是Timsort策略。大概思想是说将整个集合分成几个小段&#xff0c;每个小段分别排序&#xff0c;然后再拼在一起。 主要用法是传入两个数&#xff08;也可以不是Integer或int类型&#xff0c;这里只是把他们都统称…

红米Note 9 Pro5G刷小米官方系统

前言 刷机有2种方式&#xff1a;线刷 和 卡刷。 线刷 线刷&#xff1a;需要用电脑刷机工具&#xff0c;例如&#xff1a;XiaoMiFlash.exe&#xff0c;通过电脑和数据线对设备进行刷机。 适用场景&#xff1a; 系统损坏无法开机。恢复官方出厂固件。刷机失败导致软砖、硬砖的…

Centos7 部署ZLMediakit

1、拉取代码 #国内用户推荐从同步镜像网站gitee下载 git clone --depth 1 https://gitee.com/xia-chu/ZLMediaKit cd ZLMediaKit #千万不要忘记执行这句命令 git submodule update --init 2、安装编译器 sudo yum -y install gcc 3、安装cmake sudo yum -y install cmake 4…

HarmonyOS NEXT 技术实践-基于意图框架服务实现智能分发

在智能设备的交互中&#xff0c;如何准确理解并及时响应用户需求&#xff0c;成为提升用户体验的关键。HarmonyOS Next 的意图框架服务&#xff08;Intents Kit&#xff09;为这一目标提供了强大的技术支持。本文将通过一个项目实现的示例&#xff0c;展示如何使用意图框架服务…

观察者模式(sigslot in C++)

大家&#xff0c;我是东风&#xff0c;今天抽点时间整理一下我很久前关注的一个不错的库&#xff0c;可以支持我们在使用标准C的时候使用信号槽机制进行观察者模式设计&#xff0c;sigslot 官网&#xff1a; http://sigslot.sourceforge.net/ 本文较为详尽探讨了一种观察者模…

workman服务端开发模式-应用开发-gateway长链接端工作原理

一、长链接的工作原理 Register类其实也是基于基础的Worker开发的。Gateway进程和BusinessWorker进程启动后分别向Register进程注册自己的通讯地址&#xff0c;Gateway进程和BusinessWorker通过Register进程得到通讯地址后&#xff0c;就可以建立起连接并通讯了。而Gateway进程…

Ubuntu vi(vim)编辑器配置一键补全main函数

1.打开对应的配置文件 vi ~/.vim/snippets/c.snippets 2.按G将光标定位到文件末尾 3.按i进入插入模式 以tab键开头插入下的内容&#xff0c;空行也要加 tab键 4.:wq保存退出 5.再打开任意一个新的 .c文件后&#xff0c;插入模式输入 main 然后按tal键就能补全了

Windows脚本清理C盘缓存

方法一&#xff1a;使用power文件.ps1的文件 脚本功能 清理临时文件夹&#xff1a; 当前用户的临时文件夹&#xff08;%Temp%&#xff09;。系统临时文件夹&#xff08;C:\Windows\Temp&#xff09;。 清理 Windows 更新缓存&#xff1a; 删除 Windows 更新下载缓存&#xff0…

THM:Skynet[WriteUP]

目录 连接至THM服务器并启动靶机 信息收集 使用rustscan对靶机TCP端口进行开放扫描 使用nmap对靶机TCP开放端口进行脚本、服务扫描 使用nmap对靶机TCP开放端口进行漏洞、系统扫描 使用nmap对靶机常用UDP端口进行开放扫描 使用nmap对137端口进行针对性扫描 使用enum4lin…

Redis篇--常见问题篇7--缓存一致性2(分布式事务框架Seata)

1、概述 在传统的单体应用中&#xff0c;事务管理相对简单&#xff0c;通常使用数据库的本地事务&#xff08;如MySQL的BEGIN和COMMIT&#xff09;来保证数据的一致性。然而&#xff0c;在微服务架构中&#xff0c;由于每个服务都有自己的数据库&#xff0c;跨服务的事务管理变…

基于winform的五子棋机器人系统开发 (更新中ing)

一、实物硬件表拟定 笔记本电脑、正运动控制器、三个汇川伺服驱动器、三个滑动模组 二、软件开发 注意细节&#xff1a; ①主界面使用三个panel容器进行构建 pannel容器设置属性参数&#xff1a;(1) dock ② 添加自定义控件&#xff1a;首先创建类库&#xff0c;删除默认…

微服务分布式(二、注册中心Consul)

首先我们需要安装consul,到官网下载Consul Install | Consul | HashiCorp Developer 在解压的consul目录下 执行启动命令 consul agent -dev 启动服务 -dev表示开发模式 -server表示服务模式 启动后在浏览器访问8500端口http://localhost:8500/可以看到服务管理界面 项目…

示波器--UNI-T 优利德 UT4102C 使用介绍

示波器--UNI-T 优利德 UT4102C 使用介绍 1 介绍图示特点 2 UTP04示波器探头&#xff08;100M带宽&#xff09;3 功能介绍4 示例RS232 电平信号测试 参考 1 介绍 图示 特点 2GS/s的实时采样率&#xff1a;设备能够以每秒2吉萨&#xff08;Giga Samples per second&#xff09;…