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, 3, write_buf);MyI2C_ReadMultiRegister(SPL06_ADDRESS, PRS_CFG, 3, 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
#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; //声明大气压强测量初始化配置结构体//*********************链表初始化*********************//
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);//**********************<对外API,重要!>*********************//
uint8_t SPL06_Init(void);
uint8_t GetCompensatedVal(float* baroValue, float* tempValue, COEF_ValueStruct* COEF);//计算出气压计的单位为hpa
float getAltitude(float P);
float AltitudeFilter(float newAltitude);#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);}
}
相关文章:
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 }; //存储校准系数…...
arcgisPro将面要素转成CAD多段线
1、说明:正常使用【导出为CAD】工具,则导出的是CAD三维多线段,无法进行编辑操作、读取面积等。这是因为要素面中包含Z值,导出则为三维多线段数据。需要利用【复制要素】工具禁用M值和Z值,再导出为CAD,则得到…...
Cocos Creator 试玩广告开发
之前主要是使用Unity,这次刚好项目是试玩游戏的开发,所以临时学了Cocos来开发。所以这篇文章,更加关注从Unity转到Cocos开发的经历以及试玩的基本开发。 首先,我是没有使用过Cocos的,也没有接触过Ts语言,对于Ts的开发开…...
【Linux】解锁文件描述符奥秘,高效缓存区的实战技巧
fd和缓冲区 1. 文件描述符fd1.1. 概念与本质1.2. 打开文件的管理1.3. 一切皆文件的理解1.4. 分配规则1.5. 重定向的本质1.5.1. dup2 2. FILE中的缓冲区2.1. 概念2.2. 存在的原因2.3. 类型(刷新方案)2.4. 存放的位置2.4.1. 代码证明、现象解释 2.5. 模拟C标准库中的方法 1. 文件…...
MySQL基础笔记(五)
在此特别感谢尚硅谷-康师傅的MySQL精品教程 获取更好的阅读体验请前往我的博客主站! 如果本文对你的学习有帮助,请多多点赞、评论、收藏,你们的反馈是我更新最大的动力! 约束 1. 约束(constraint)概述 1.1 为什么需要约束 数据完整性&…...
夯实数字技术,培育创新人才:数据科学与大数据技术专业人才培养实践
近年来,得益于全球各国家和地区对大数据产业的政策扶持以及数字经济的蓬勃发展,大数据市场在全球范围内展现出了迅猛的增长态势。国家层面相继出台了诸如《“数据要素 ” 三年行动计划(2024—2026 年)》《数字中国建设整体布局规划…...
Java爬虫大冒险:如何征服1688商品搜索之巅
在这个信息爆炸的时代,数据就是力量。对于电商平台而言,数据更是金矿。今天,我们要踏上一场Java爬虫的冒险之旅,目标是征服1688这个B2B电商巨头,获取按关键字搜索的商品信息。这不仅是技术的挑战,更是智慧的…...
IEC 101/104 中为什么我们需要单点和双点信号
REDISANT 提供互联网与物联网开发测试套件 # 互联网与中间件: Redis AssistantZooKeeper AssistantKafka AssistantRocketMQ AssistantRabbitMQ AssistantPulsar AssistantHBase AssistantNoSql AssistantEtcd AssistantGarnet Assistant 工业与物联网࿱…...
01、NodeJS学习笔记,第一节:Node.js初识与内置模块
一、初识Node.js与内置模块 ##网址 https://nodejs.org##npm包 https://www.npmjs.com/ (搜索)https://registry.npmjs.org/ (下载)1、初识Node.js ##思考:为什么JavaScript可以在浏览器中被执行因为浏览器…...
ElasticSearch 自动补全
1、前言 当用户在搜索框输入字符时,我们应该提示出与该字符有关的搜索项,根据用户输入的字母,提示完整词条的功能,就是自动补全。 2、安装拼音分词器 Github地址:https://github.com/infinilabs/analysis-pinyin 插件…...
整点(枚举)
Hello!大家好!我是学霸小羊,今天分享一道c枚举题: 题目描述 在二维坐标系, 有一个圆,圆心在(0,0),圆的半径是r。问圆内有多少个整点(所谓的整点就是横坐标和纵坐标都是整数的点)。若点P的横坐标是整数a&a…...
【WRF安装】WRF编译错误:problems building executables look for error in the build log
WRF编译错误 错误内容:problems building executables, look for error in the build log原因1:gcc版本过低安装高版本gcc 原因2:netcdf版本和配置有误原因3:库冲突原因4:export NETCDF_classic1终极手段:重…...
2024年12月陪玩系统-仿东郊到家约玩系统是一种新兴的线上预约线下社交、陪伴系统分享-优雅草央千澈-附带搭建教程
2024年12月陪玩系统-仿东郊到家约玩系统是一种新兴的线上预约线下社交、陪伴系统分享-优雅草央千澈-附带搭建教程 产品介绍 仿东郊到家约玩系统是一种新兴的线上预约,线下社交、陪伴、助娱、助攻、分享、解答、指导等服务模式,范围涉及电竞、运动、音乐…...
社区版 IDEA 开发webapp 配置tomcat
1.安装tomcat 参考Tomcat配置_tomcat怎么配置成功-CSDN博客 2.构建webapp项目结构 新建一个普通项目 然后添加webapp的目录结构: main目录下新建 webapp 文件夹 webapp文件夹下新建WEB_INF文件夹 *WEB_INF目录下新建web.xml wenapp文件夹下再新建index.html …...
IDEA中解决Edit Configurations中没有tomcat Server选项的问题
今天使用IDEA2024专业版的时候,发现Edit Configurations里面没有tomcat Server,最终找到解决方案。 一、解决办法 1、打开Settings 2、搜索tomcat插件 搜索tomcat插件之后,找到tomcat 发现tomcat插件处于未勾选状态,然后我们将其勾选保存即可。 二、结果展示 最后,再次编…...
【Python】主成分分析PCA - 算法、问题与Python实现
【Python】主成分分析PCA - 算法、问题与Python实现 一、PCA 算法简介(一)概念及作用(二)基本原理(三)算法步骤1.数据预处理2.计算协方差矩阵3.进行特征值分解4.选择主成分5.完成数据降维 二、PCA 常见问题…...
Go怎么做性能优化工具篇之pprof
工欲善其事、必先利其器。这次我们来看看Go的性能优化工具有哪些吧 Go性能优化的工具 一、pprof 工具 pprof 是 Go 语言自带的性能分析工具,可以帮助开发者分析程序的 CPU 使用情况、内存使用情况、goroutine 调度情况等,从而定位性能瓶颈。通过 pprof…...
DataOps驱动数据集成创新:Apache DolphinScheduler SeaTunnel on Amazon Web Services
引言 在数字化转型的浪潮中,数据已成为企业最宝贵的资产之一。DataOps作为一种文化、流程和实践的集合,旨在提高数据管道的质量和效率,从而加速数据从源头到消费的过程。白鲸开源科技,作为DataOps领域的领先开源原生公司…...
递归读取指定目录下的文件
序言 需要读取sftp服务器上符合指定的文件名正则的文件列表,目前想到的最好的办法就是递归。 我这里引入的依赖是: <!-- jsch-sftp连接 --><dependency><groupId>com.jcraft</groupId><artifactId>jsch</artif…...
代码随想录算法训练营day46|动态规划part12
今天就结束动态规划章节了,以后还要多加练习。 今天的两道题都很有难度,647回文子串的思路非常巧妙,因为用一维dp数组比较难表示子串的起点和终点,所以需要用二维dp数组表示,dp[i][j]表示以i为起点,j为终点…...
ubuntu 24.04.1安装FTP流程
1、安装vsftpd: sudo apt update sudo apt install vsftpd 2、安装后重启查看vsftpd状态 sudo systemctl status vsftpd 输出如下所示,表明vsftpd服务处于活动状态并正在运行: * vsftpd.service - vsftpd FTP server Loaded: loaded (/…...
【Linux】UDP通信
udp使用的是数据报传输。可以一对一,一对多进行传输,用于快速,实时性高的场景 服务器端: 使用步骤: 1.创建socket 2.bind绑定可接收的客户端 3.while{ recv接收数据 send发送数据 } #include <stdio.h> #inclu…...
日期格式、JSR303校验
日期格式 public class Monster() {DateTimeFormat(pattern "yyyy-MM-dd")private Date birthday; } 输入:2024-11-12, 输出:Monster{birthdaySun Nov 12 00:00:00 CST 2024} public class Monster {JsonFormat(pattern &…...
ELK系列-(六)Redis也能作为消息队列?(上)
一、前文回顾 🔍 在前面的ELK系列中,我们已经搭建了ELK的核心组件,包括: ELK系列-(一)Docker部署ELK核心组件ELK系列-(二)LogStash数据处理的瑞士军刀ELK系列-(三&…...
点击展示大图预览
原文链接在table表格里能够实现,点击里面的图片实现大图预览的效果; 一、先安装viewer — 使用npm安装 npm install v-viewer --save二、在main.js中引入 import Viewer from v-viewer //点击图片大图预览 import viewerjs/dist/viewer.css Vue.use(…...
游戏AI实现-寻路算法(BFS)
广度优先搜索算法(英语:Breadth-first search,缩写:BFS),又译作宽度优先搜索,或横向优先搜索,是一种图形搜索算法。 寻路地图搭建: 游戏AI实现-寻路地图搭建-CSDN博客 …...
tryhackme-Pre Security-HTTP in Detail(HTTP的详细内容)
任务一:What is HTTP(S)?(什么是http(s)) 1.What is HTTP? (HyperText Transfer Protocol)(什么是 HTTP?(超文本传输协议)) http是你查看网站的时候遵循的…...
CNN和Transfomer介绍
文章目录 CNN和Transfomer介绍CNN和Transfomer的区别1. **基本概念**2. **数据处理方式**3. **模型结构差异**4. **应用场景区别** 自注意力机制1. **自注意力机制的概念**2. **自注意力机制的实现步骤**3. **自注意力机制的优势** Transformer结构组成1. **多头注意力层&#…...
37. Three.js案例-绘制部分球体
37. Three.js案例-绘制部分球体 实现效果 知识点 WebGLRenderer WebGLRenderer 是Three.js中的一个渲染器类,用于将3D场景渲染到网页上。 构造器 WebGLRenderer( parameters : Object ) 参数类型描述parametersObject渲染器的配置参数,可选。 常用…...
Latex+VsCode+Win10搭建
最近在写论文,overleaf的免费使用次数受限,因此需要使用本地的形式进行编译。 安装TEXLive 下载地址:https://mirror-hk.koddos.net/CTAN/systems/texlive/Images/ 下载完成直接点击iso进行安装操作。 安装LATEX Workshop插件 设置VsCode文…...
【ETCD】【Linearizable Read OR Serializable Read】ETCD 数据读取:强一致性 vs 高性能,选择最适合的读取模式
ETCD 提供了两种不同类型的读取操作方式,分别是 Linearizable Read(线性化读取)和 Serializable Read(可串行化读取)。这两种方式主要区分在读取数据时对一致性的要求不同。 目录 1. Linearizable Read(线…...
windows下搭建本地sofa-registry
官方介绍: SOFARegistry 是蚂蚁金服开源的一个生产级、高时效、高可用的服务注册中心。SOFARegistry 最早源自于淘宝的 ConfigServer,十年来,随着蚂蚁金服的业务发展,注册中心架构已经演进至第五代。目前 SOFARegistry 不仅全面服…...
什么是MyBatis
MyBatis 简介 MyBatis 是一个流行的 Java 持久层框架(Persistence Framework),它主要用于简化数据库操作,提供了对数据库的映射支持,使得开发人员能够通过简单的配置和映射文件来执行数据库操作(如增、删、…...
Docker如何运行一个Java的jar包程序
Docker如何运行一个Java的jar包程序 1、jar包程序 2、start.sh运行jar包脚本 #!/bin/bash #进入目录 cd /app #1.下载SDK并安装 java -jar SDKDown1.4.jar #2.加载环境变量 export LD_LIBRARY_PATH/opt/casb/CipherSuiteSdk_linux/lib echo $LD_LIBRARY_PATH #3.执行SDK java …...
c语言----顺序结构
顺序结构的基本概念 定义:顺序结构是C语言程序中最基本的结构,它按照语句的先后顺序依次执行。就像我们日常做事一样,一步一步地按照顺序来完成任务。在C语言程序中,从程序的第一条语句开始,逐句向下执行,…...
BERT采用双向训练
BERT采用双向训练 定义 BERT(Bidirectional Encoder Representations from Transformers)是一种基于Transformer架构的预训练语言模型。它在自然语言处理(NLP)领域具有极其重要的地位,由谷歌在2018年提出,能够对文本进行深度的语义理解,从而广泛应用于各种语言相关的任务…...
流程引擎Activiti性能优化方案
流程引擎Activiti性能优化方案 Activiti工作流引擎架构概述 Activiti工作流引擎架构大致分为6层。从上到下依次为工作流引擎层、部署层、业务接口层、命令拦截层、命令层和行为层。 基于关系型数据库层面优化 MySQL建表语句优化 Activiti在MySQL中创建默认字符集为utf8&…...
安卓 文件管理相关功能记录
文件管理细分为图片、视频、音乐、文件四类 目录 权限 静态声明权限 动态检查和声明权限方法 如何开始上述动态申请的流程 提示 图片 获取图片文件的对象列表 展示 删除 视频 获取视频文件的对象列表 获取视频file列表 按日期装载视频文件列表 展示 播放 删除…...
监控视频汇聚融合云平台一站式解决视频资源管理痛点
随着5G技术的广泛应用,各领域都在通信技术加持下通过海量终端设备收集了大量视频、图像等物联网数据,并通过人工智能、大数据、视频监控等技术方式来让我们的世界更安全、更高效。然而,随着数字化建设和生产经营管理活动的长期开展࿰…...
【jvm】主要参数
Java 虚拟机(JVM)有许多参数用于控制其行为和性能,下面是一些 主要的 JVM 启动参数,这些参数通常分为以下几类: 内存管理相关参数 这些参数主要用来配置 JVM 的内存分配策略、堆内存、栈内存等。 -Xms 设置 JVM 启动…...
在Ubuntu中配置mysql,并允许外部访问数据库
在虚拟机中安装 MySQL 并允许外部访问,可以按照以下步骤操作: 1. 更新系统包 首先,确保你的系统是最新的,使用以下命令更新包列表: sudo apt update sudo apt upgrade2. 安装 MySQL Server 安装 MySQL 服务&#x…...
Golang的向前兼容性和toolchain规则,Go1.21.0
在 Go 1.21 中,在工具上新增了两个变化:增强了向前兼容性;工具链管理。 向前兼容性 在以前的版本中,Go 工具链尝试编译依赖于新版本的代码时,可能会遇到兼容性问题。例如,如果你的代码依赖于 Go 1.18 引入…...
如何有效修复ffmpeg.dll错误:一站式解决方案指南
当您遇到提示“ffmpeg.dll文件丢失”的错误时,这可能导致相关的应用程序无法启动或运行异常。本文将详细介绍如何有效地解决ffmpeg.dll文件丢失的问题,确保您的应用程序能够恢复正常运行。 ffmpeg.dll是什么?有哪些功能? ffmpeg.…...
更频繁的 Android SDK 发布:更快的创新、更高的质量和更完善
Android 一直致力于让创新更快地进入用户手中。除了每年的平台发布之外,我们还投资了Project Treble、Mainline、Google Play 服务、每月安全更新和季度发布,为 Pixel Drops 提供支持。 未来,Android 将更频繁地发布 SDK,计划于 …...
远程连接:构建智能家居舒适生活
远程连接技术让智能家居从梦想照进现实,为人们构建了舒适便捷的生活环境。通过家庭网络与各种智能设备的远程连接,用户可以在外出时,使用手机 APP 轻松控制家中的灯光、窗帘、空调、电视等设备。 例如,在炎热的夏天,下…...
Python 爬取网页文字并保存为 txt 文件教程
引言 在网络数据获取的过程中,我们常常需要从网页中提取有用的文字信息。Python 提供了强大的库来帮助我们实现这一目标。本教程将以https://theory.gmw.cn/2023 - 08/31/content_36801268.htm为例,介绍如何使用requests库和BeautifulSoup库爬取网页文字…...
多协议视频监控汇聚/视频安防系统Liveweb搭建智慧园区视频管理平台
智慧园区作为现代化城市发展的重要组成部分,不仅承载着产业升级的使命,更是智慧城市建设的重要体现。随着产业园区竞争的逐渐白热化,将项目打造成完善的智慧园区是越来越多用户关注的内容。 然而我们往往在规划前期就开始面临众多难题&#…...
InnoDB 查询成本
1. 单表查询成本 连接查询总成本 IO 成本 CPU 成本对于 InnoDB 存储引擎来说,页是磁盘和内存之间交互的基本单位,设计MySQL的大叔规定读取一个页面花费的成本默认是 1.0,读取以及检测一条记录是否符合搜索条件的成本默认是 0.2。1.0、0.2 …...
C++的高精度减法 分步详解
高精度减法计算原理 在读小学时,我们做减法都采用竖式方法,如图 1 所示。 这样,我们可以写出两个整数相减的算法。 我们就可以用 C 语言来模拟这个竖式减法的过程。我们可以考虑利用 C 的数组来存储对应数据,假设用数组 A 存储被…...
linux cpu 管理
视频教程:ubuntu cpu 管理_哔哩哔哩_bilibili 概述 平均负载,CPU 使用率,CPU上下文 1 平均负载 #查看命令: rootzyb:~# uptime 18:21:47 up 1:09, 2 users, load average: 0.00, 0.00, 0.00 依次则是过去 1 分钟、5 分钟、1…...