文章目录
文章目录
详细资料见Q群:531905626
对该项目感兴趣的同志,想要一起深入开发拓展可以联系本人邮箱:2560198277@qq.com。限于本人精力,在PCB设计、3D建模、嵌入式开发方面都有较大的需求。
书籍总目录:http://t.csdnimg.cn/YDe8m
4.2 这个有就更好了——气压计
4.2.1 DPS310简介
英飞凌生产的DPS310与常见的BMP280功能类似,用于测量大气压强进而得到当前位置的海拔高度,但其精度要比BMP280强不少(可以达到 ±0.5 m),可以使用SPI、I2C进行通信,支持单字节的写与读,多字节读(不支持多字节写,好像ICM42688也不支持)
(1)DPS310参数
参数 | 参数值 |
---|---|
量程 | 气压:300 –1200 hPa(hPa,百帕),温度: -40 – 85 °C |
气压计精度 | ± 0.005 hPa (或 ±0.05 m) |
气压计相对精度 | ± 0.06 hPa (或 ±0.5 m) |
气压计绝对精度 | ± 1 hPa (或 ±8 m) |
测量需要时间 | 105ms(高精度模式),27.6 ms标准模式(16倍),最小:5.2 ms低精度模式。 |
供电 | VDDIO: 1.2 – 3.6 V, VDD: 1.7 – 3.6 V |
I2C时钟最大频率 | 3.4 MHz |
主要参考“4、硬件资料\芯片数据手册\C130156_压力传感器_DPS310_规格书_INFINEON(英飞凌)压力传感器规格书.PDF”的的“3.5 Pressure Transfer Function”与“3.6 Timing Characteristics”小节
关于气压的采样频率,程序中设置为了标准模式,并将DPS130气压测量的频率设置为32 Hz
注:标准模式测量数据需要的时间是一个固定值,但具体测量的频率由另外的寄存器位设置。
(2)DPS310使用
与ICM42688相似,也是通过操作其内部寄存器(读写)来实现设置与测量值的读取,只不过是使用I2C通信方式。 DPS310相关的原理图如下,这里没找到AT32飞控的原理图,只能用老版本了,不过经过试验DPS310与BMP280的接线相同:
图4.2.1.1
(2.1)DPS310引脚
SCL(SCK):I2C时钟引脚
SDA(SDI):I2C数据引脚
CSB:片选引脚,“4、硬件资料\芯片数据手册\C130156_压力传感器_DPS310_规格书_INFINEON(英飞凌)压力传感器规格书.PDF”的“6 Digital interfaces”小节有如下描述:“ If CSB is connected to VDDIO, the I2C interface is active. If CSB is low, the SPI interface is active.”,这句话翻译过来就是“当CSB与VDDIO连接到相同电压下时I2C通信使能,当CSB连接到低电平时,SPI通信使能”,原理图中将VDDIO、CSB引脚直接接到了3.3V电源上(DPS310测试过应该与BMP280接线相同),表示一直使用I2C通信。
(2.2)I2C通信时DPS310器件的地址
根据芯片手册“6.1 I2C Interface”小节描述,当DPS310的SDO引脚与VDDIO短接时,器件地址为0x77;当SDO接GND时,器件地址为0x76。根据图4.2.1.1可知,SDO接了GND,所以DPS310在I2C通信时器件地址为0x76
(2.3)DPS310字节级I2C通信
先不管I2C具体的通信时序,这里先来了解一下如何与DPS310进行字节级的I2C通信。
关于与DPS310进行字节级I2C通信,其实与上节ICM42688相比有许多相似之处,芯片手册“6.1 I2C Interface”给出了如下通信流程图:
图4.2.1.2
(2.3.1)先来了解下各部分代表的意义(对照右上角):
首先,图中白色部分都表示主机(即AT32飞控)发送的数据;灰色则是DPS310这个人机发送的数据,主要就是寄存器值、应答位。
其次,是关于字节部分的,主机会发送两种字节:
- SLAVE address
- 从机地址,为7位,与读写位组成一个字节,这里分开来看。这个7个位在这里表示DPS310的器件地址,即0x76
- Register Address
- 寄存器地址,为8位,表示要读写DPS310哪个地址的寄存器。
- Register Data<7:0>
- 寄存器数据,为8位。只用于写操作,为写入寄存器的值
而从机只会发送一种字节:
- Register Data<7:0>
- 寄存器数据,为8位。只用于读操作,为当前DPS310中该寄存器的值
最后就是几个二进制位长度的位数据了:
- S
开始位,与SPI中的开始位类似 - R/W
读/写位,由主机发送,表示之后要进行的操作类型 - P
停止位,表示通信结束 - A
应答位,实际是一个值为0的二进制位 - N
无应答位,位的值为1
(2.3.2)
接下来就讲到具体的通信流程了,如图4.2.1.2左侧所示,共有三各操作方式:
- 写入DPS310一个字节的数据
如第一行所示:主机发送开始位、DPS310器件地址、写位然后等待从机的一个应答位;之后主机发送要操作的DPS310寄存器地址,再等待一次应答;最后发送该寄存器的值,等待应答,并发送停止位。下图是使用逻辑分析仪抓取的使用I2C向寄存器写入一字节数据时的实际波形(限于条件,实际为与BMP280通信的)
图4.2.1.3
- 读取DPS310一个字节数据
如前图4.2.1.2的第二列,要读取一字节数据。- (1)开始位、从机地址、写位、等待应答
- (2)发送要读取的寄存器地址、等待应答
- (3)开始位、从机地址、定位、发送应答位
这一步在最后由主机发送应答位(值为1),而不再是等待应答,但实测的等待应答也可以用,结合下面的多字节读取数据怀疑手册上的有点问题。 - (4)接收从机发送的寄存器的值、发送非应答位、发送停止位。
实际通信过程如下图所示:
图4.2.1.4
- 一次性读取DPS310多个字节数据
如前图4.2.1.2的剩余部分,首先开头部分与读取一字节时相同,只是最后主机发送的是应答位,则DPS310的寄存器地址自增1,然后循环读取,直到读取完毕,发送非应答位与停止位。实际通信过程如下图:(BMP280的)
图4.2.1.5
(3)DPS310寄存器
DPS310的寄存器相比ICM42688的寄存器要简单许多,如下图:
图4.2.1.6
-
8.10 Product and Revision ID (ID)
产品与版本ID寄存器,复位值是0x10- REV_ID 7:4
版本ID - PROD_ID 3:0
产品ID
- REV_ID 7:4
-
8.9 Soft Reset and FIFO flush (RESET)
复位寄存器,复位后需要等待一段时间,手册未找到具体要求,这里延时了40ms- SOFT_RST 3:0
向这四位写入‘1001’,则会执行软件复位。软件复位用于这种情况:当与之通信的单片机复位而DPS310在此过程中一直有供电,此时由于硬件复位未产生,便需要软件复位来清空之前的设置。
- SOFT_RST 3:0
-
8.5 Sensor Operating Mode and Status (MEAS_CFG)
传感器模式与状态寄存器-
COEF_RDY 7
系数可用标志位,复位值为1。这里的系数指用于气压、温度测量值补偿校准的系数,也是一组DPS310寄存器的值- 0 - 系数不可用
- 1 - 系数可用
-
SENSOR_RDY 6
气压传感器就绪标志位,复位值为1- 0 - 传感器未初始化完成
- 1 - 传感器初始化完成
-
MEAS_CTRL 2:0
模式控制位,可以设置成许多模式,这里只用到下面两个- 000 - 待机模式
- 111 - 连续压力与温度测量模式(其是属于背景模式下的一个模式)
-
-
8.11 Calibration Coefficients (COEF)
校准系数寄存器,总共有18个字节,保存着共9个系数的值,校准系数在手册中常简称为“系数”,其具体分布如下图:
图4.2.1.7
-
8.3 Pressure Configuration (PRS_CFG)
气压设置寄存器-
PM_RATE[2:0] 6:4
气压测量速率设置位- 000 - 1 Hz
- 001 - 2 Hz
- 010 - 4 Hz
- 011 - 8 Hz
- 100 - 16 Hz
- 101 - 32 Hz
- 110 - 64 Hz
- 111 - 128 Hz
-
PM_PRC[3:0] 3:0
过采样率设置位,与测量精度有关- 0000 - 1 倍 (低精度,采样时间5.2ms,192Hz)
- 0001 - 2 倍
- 0010 - 4 倍
- 0011 - 8 倍
- 0100 - 16 倍 (标准,采样时间27.6ms,36Hz)
- 0101 - 32 倍
- 0110 - 64 倍 (高精度,采样时间105ms,9Hz)
- 0111 - 128 倍
- 1xxx - Reserved
-
-
8.4 Temperature Configuration(TMP_CFG)
温度设置寄存器- TMP_EXT 7
温度测量选择位,要与“Coefficient Source 温度系数源选择寄存器”的选择相同。- 0 外部传感器
- 1 内部传感器(在压力传感器上的MEMS元件)
- TMP_RATE[2:0]
温度测量速率设置位- 000 - 1 Hz
- 001 - 2 Hz
- 010 - 4 Hz
- 011 - 8 Hz
- 100 - 16 Hz
- 101 - 32 Hz
- 110 - 64 Hz
- 111 - 128 Hz
- TMP_PRC[2:0] 3:0
温度过采样率设置位- 0000 - 1 倍 (采样时间3.6ms,之后更高倍的设置可能不会带来更高的精度)
- 0001 - 2 倍
- 0010 - 4 倍
- 0011 - 8 倍
- 0100 - 16 倍
- 0101 - 32 倍
- 0110 - 64 倍
- 0111 - 128 倍
- 1xxx - Reserved
- TMP_EXT 7
-
8.12 Coefficient Source
温度系数源选择寄存器- TMP_COEF_SRCE 7
这里设置为1,选择位于压力传感器上的MESM(不太清楚是什么)元件温度传感器。
0 - 使用外部温度传感器
1 - 使用内部温度传感器(在压力传感器上的MEMS元件) - 6:0 保留
- TMP_COEF_SRCE 7
-
8.6 Interrupt and FIFO configuration (CFG_REG)
设置寄存器- T_SHIFT 3
温度结果转移设置位- 0 - 不转移
- 1 - 转移结果到数据寄存器(过采样率大于8倍时必须置1)
- P_SHIFT 2
气压结果转移设置位- 0 - 不转移
- 1 - 转移结果到数据寄存器(过采样率大于8倍时必须置1)
- T_SHIFT 3
-
8.1 Pressure Data (PRS_Bn)
气压数据寄存器,包含 PRS_B2~ PRS_B0(MSB、LSB、XLSB)三个字节的寄存器,存储着采集到的气压的原始数据。 -
8.2 Temperature Data (TMP_Tn)
温度数据寄存器,包含TMP_T2~TMP_T0(MSB、LSB、XLSB)三个字节的寄存器,存储着采集到的温度的原始数据。
4.2.2 I2C简介
与stm32一样,AT32的也有I2C相关的寄存器,虽然不确定是否也有通信不稳定的问题,但确定很复杂,本小节采用GPIO模拟的I2C进行通信。
I2C字节级的通信上面已经介绍,这里说一下I2C的难时序。
(1)I2C引脚
SCL引脚: 与SPI类似,为时钟引脚。
SDA引脚: 数据引脚,主机、从机的SDA引脚接在一起。
(2)I2C通信时序
与SPI类似分为起始位、数据位、停止位,同时还多了一个应答位,如下图4.2.2.1
图4.2.2.1
(1)起始位(start):
SCL高电平期间,SDA由高电平向低电平变化产生一个下降沿。
(2)数据位:
通信要求高位在前,低位在后。并且要求SCL在低电平时SDA可以变化;SCL在高电平时,采集SDA的信号。
(3)应答位(ACK):
实际就是一个值为0的数据位,为1时就是非应答(NACK)
(4)停止位(stop):
SCL为高电平时,SDA由低电平向高电平变化产生一个上升沿。
4.2.3 硬件设计
本小节例程功能:使用ANO匿名上位机显示DPS310气压、温度、距地面高度(cm)等数据
用到的硬件资源有:
(1)两个GPIO引脚
I3_SCL_PC0
I3_SDA_PC1
图4.2.3.1
(2)板载DPS310传感器
图4.2.3.2
4.2.4 下载验证
进入“2、飞控例程\4.2 DPS310”,打开工程并编译。
按住BOOT按键,给飞控上电,进入Bootloader(同时进入USB的DFU模式)。编译例程,双击“Download_tool_ISP”文件夹下的“1_Download_by_usb.bat”,开始下载程序。
连接好蓝牙模块,打开ANO软件及其中的波形显示界面,这里设置:
通道7: 地面海拔高度:单位:cm
通道8: 相对地面高度:单位:cm
通道9: 气压:单位:mPa
通道10:气压计温度: 单位:℃
静止不动时相对地面高度会在误差1m的范围内波动,上抬飞控波形也上升,放回原处波形也下降,如下图:
图4.2.4.1
4.2.5 I2C相关调用函数
本小节的有关I2C低层驱动的源码放在“qy_drivers\myiic.c”与“qy_drivers\myiic.h”中,主要是
(1)IIC_Init()函数,初始化I2C有关GPIO引脚
(2)IIC_Send_Byte()函数,发送一个I2C字节
(3)IIC_Read_Byte()函数,读取一个I2C字节,并发送ACK、nACK位,原型为:
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL=0;
delay_us(2);
IIC_SCL=1;
receive<<=1;
if(READ_SDA)receive++;
delay_us(1);
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}
与DPS310气压计有关的驱动源友放在“qy_drivers\dps310.c”与“qy_drivers\dps310.h”中。其中关于I2C操作寄存器的函数有:
(1)DPS310_Read_Byte()函数,DPS310读取一个寄存器的值
(2)DPS310_Read_Bytes()函数,DPS310读取多个寄存器的值
(3)DPS310_Write_Byte()函数,DPS310向一个寄存器写入值
(4)DPS310_Write_ByteBits()函数,按位向DPS310的一个寄存器写入值。原型位:
static void DPS310_Write_ByteBits(uint8_t reg, uint8_t mask, uint8_t bits) //按二进制位写入 mask为要写入的二进抽位的补码(1表写入,0表不改变)
{
uint8_t val = DPS310_Read_Byte(reg);
if ((val & mask) != bits) {
val = (val & (~mask)) | bits;
DPS310_Write_Byte(reg, val);
}
}
bits为要写入的值,mask为要写入值的二进抽位的补码(1表写入,0表不改变)
(5)registerSetBits()函数,只将二进制的1位写入寄存器,0位不变。调用了DPS310_Write_ByteBits()函数,原型为:
static void registerSetBits(uint8_t reg, uint8_t setbits) //只将setbits中二进制的1位写入寄存器,0位不变
{
DPS310_Write_ByteBits(reg, setbits, setbits);
}
4.2.6 软件设计
(1)DPS310初始化
“main.c”的开始任务中有:
void START_task_function(void *pvParameters) //开始任务
{
/****************************************** 进入临界区,原子操作 ***************************************/
taskENTER_CRITICAL();
/****************************************** 地面站串口初始化 *****************************************/
printfSerialInit();
ANO_init_usart(230400);
/****************************************** LED初始化 ************************************************/
My_LED_init();
/****************************************** 遥控器初始化 ************************************************/
Remoter_init();
/****************************************** 航模遥控器初始化 ************************************/
Motor_init();
#ifdef QY_BY_CORE_BOARD //AT32核心板
/****************************************** 气压计初始化 ********************************************/
IIC_Init();
Bmp_Init();
#else //AT32飞控
/****************************************** 六轴传感器初始化 ****************************************/
bsp_Icm42688Init();
/****************************************** 气压计初始化 ********************************************/
DPS310_init();
#endif
/* 创建其他任务 */
qy_tasks_creat();
vTaskDelete(START_handler); //删除开始任务
/* 退出临界区 */
taskEXIT_CRITICAL();
}
行32:
调用DPS310_init()函数初始化DPS310初始化DPS310气压计
DPS310_init()函数原型为:
bool DPS310_init(void)
{
IIC_Init();
if (!deviceDetect()) //读取DPS310的ID来检测其是否存在
{
return false;
}
if (!deviceConfigure()) //初始化DPS310
{
return false;
}
return true;
}
(2)FreeRToS任务完善
DPS310的调用主要在“qy_tasks\qy_Ati_pos_solve_task.c”文件的姿位解算任务中进行(Ati_pos_solve_task_function函数),原型为:
void Ati_pos_solve_task_function(void *pvParameters)
{
u32 tick = 0;
TickType_t lastWakeTime; //上一次唤醒时间
const TickType_t delayTime = pdMS_TO_TICKS(1); //绝对延时时间(静态值),将要延时的时间转化为系统时钟节拍
//周期1ms,频率1000 Hz
lastWakeTime = xTaskGetTickCount(); //获取当前系统时钟节拍
while(1)
{
#ifdef QY_BY_CORE_BOARD //AT32核心板
//30 Hz运行频率
if (RATE_DO_EXECUTE(RATE_30_HZ, tick))
{
baroPressure = BMP280_Get_Pressure();
baroTemperature = BMP280_Get_Temperature();
}
#else //AT32飞控
//500 Hz运行频率
if (RATE_DO_EXECUTE(RATE_500_HZ, tick))
{
/* ICM42688数据读取与处理 */
icm42688_get_gyro(); //读取ICM24688陀螺仪、加速度计、温度数据
icm42688_get_acc();
icm42688_get_temp();
//数据标准化,并调整传感器方向,和机体坐标一致
Ati_pos_post.gyro.x = icm42688_gyro_transition(icm42688_gyro_x); // 单位为°/s
Ati_pos_post.gyro.y = icm42688_gyro_transition(icm42688_gyro_y);
Ati_pos_post.gyro.z = icm42688_gyro_transition(icm42688_gyro_z);
Ati_pos_post.acce.x = icm42688_acc_transition(icm42688_acc_x); // 单位为 g(m/s^2)
Ati_pos_post.acce.y = icm42688_acc_transition(icm42688_acc_y);
Ati_pos_post.acce.z = icm42688_acc_transition(icm42688_acc_z);
}
//30 Hz运行频率
if (RATE_DO_EXECUTE(RATE_30_HZ, tick))
{
DPS310Update(); //气压计数据更新
Ati_pos_post.BaroHeight = BaroAltitude_cm; //气压计相对高度,单位cm
}
#endif
//绝对延时
vTaskDelayUntil(&lastWakeTime, delayTime);
tick++;
}
}
行45~46:
是对DPS310数据的更新与处理。
这里除了添加DPS310相关的调用外,还基于FreeRTOS做了如下完善:
(1)FreeRTOS下的delay函数
FreeRTOS提供的delay函数是以系统时钟节拍为单位的,对于I2C时序等需要us级延时的情况并不适用。而AT32提供的延时函数也基于Systick的调用,与FreeRTOS冲突。这里采用一定技巧,使延时不与FreeRTOS冲突,相关的源码定义在“qy_math\delay_in_freeRTOS.c”中。
包括delay_us()、delay_ms()、delay_sec()三个函数,其核是delay_us()函数。
(2)任务精确频率运行频
之前在任务函数中一直使用vTaskDelay()函数进行延时,以保证任务内容以一定频率执行。但使用该函数时,因为任务执行时间不确定,任务执行的频率也是不确定的。这里改用绝对延时函数vTaskDelayUntil()来进行改善。
如上述任务的4~8行以及52行(其中, "const"是C语言的一个关键字,表示该变量是一个静态值,初始化后其值不可以被改变)。
具体原理参考“3、参考资料\STM32F1 FreeRTOS开发手册_V1.1.pdf”r的“12.3 函数vTaskDelayUntil()”小节。
(3)任务中任务
有时候任务中的不同部分所需的执行频率也不相同,如姿位解算任务中六轴、加速度计的刷新频率可以达到500Hz,而气压计只有30Hz。为实现不同频率运行,采用一些频率决断的算法。
主要是使用RATE_DO_EXECUTE宏,其原型为:
#define RATE_DO_EXECUTE(RATE_HZ, TICK) ((TICK % (RATE_1000_HZ / RATE_HZ)) == 0)
(3)DPS310数据处理
气压计数据的读取与处理主要在DPS310Update()函数中进行,该函数定义在“qy_math\barometer.c”中,原型为:
void DPS310Update(void)
{
float baroPressure;
DPS310GetData(); //读取气压、温度数据并处理
baroPressure = baroState.pressure;
if (!baro_init_flag) //气压计未校准完成
{
DPS310_init_Height_0(baroPressure);
BaroAltitude_cm = 0.0f;
Ati_pos_post.BaroHeight_0 = baro_Height_0; //赋值地面海拔高度
}
else
{
//计算去除地面高度后相对高度
BaroAltitude_cm = Press_to_height(baroPressure) - baro_Height_0;
}
}
(3.1)原始值转换为气压值
这里只讲解气压数据方面的转换,温度数据的转换原理与之类似,工程中通过DPS310GetData()函数来实现气压原始数据的采集与标准值转换,如下:
bool DPS310GetData(void) //读取气压、温度数据并处理
{
bool pressure_ready;
uint8_t buf[6];
// 1. Check if pressure is ready
pressure_ready = DPS310_Read_Byte(DPS310_REG_MEAS_CFG) & DPS310_MEAS_CFG_PRS_RDY; //压力数据更新标志(读取时自动清除)
if (!pressure_ready) {
return false;
}
// 2. Choose scaling factors kT (for temperature) and kP (for pressure) based on the chosen precision rate.
// The scaling factors are listed in Table 9.
static float kT = 253952; // 16 times (Standard)
static float kP = 253952; // 16 times (Standard)
// 3. Read the pressure and temperature result from the registers
// Read PSR_B2, PSR_B1, PSR_B0, TMP_B2, TMP_B1, TMP_B0
if (!DPS310_Read_Bytes(DPS310_REG_PSR_B2, buf, 6)) { //读取24位的压力与温度原始数据
return false;
}
const int32_t Praw = getTwosComplement((buf[0] << 16) + (buf[1] << 8) + buf[2], 24);
const int32_t Traw = getTwosComplement((buf[3] << 16) + (buf[4] << 8) + buf[5], 24);
// 4. Calculate scaled measurement results.
const float Praw_sc = Praw / kP;
const float Traw_sc = Traw / kT;
// 5. Calculate compensated measurement results.
const float c00 = baroState.calib.c00;
const float c01 = baroState.calib.c01;
const float c10 = baroState.calib.c10;
const float c11 = baroState.calib.c11;
const float c20 = baroState.calib.c20;
const float c21 = baroState.calib.c21;
const float c30 = baroState.calib.c30;
// See section 4.9.1, How to Calculate Compensated Pressure Values, of datasheet
baroState.pressure = c00 + Praw_sc * (c10 + Praw_sc * (c20 + Praw_sc * c30)) + Traw_sc * c01 + Traw_sc * Praw_sc * (c11 + Praw_sc * c21);
const float c0 = baroState.calib.c0;
const float c1 = baroState.calib.c1;
// See section 4.9.2, How to Calculate Compensated Temperature Values, of datasheet
baroState.temperature = c0 * 0.5f + c1 * Traw_sc;
return true;
}
行6~10:
判断气压数据是否已经采集完毕。
行12~15:
赋值气压与温度缩放系数,kT、kP两个系数可在芯片手册“4.9.3 Compensation Scale Factors”小节的表9(Table 9)中查找,如下图:
图 4.2.6.5
其中kT=kP,且两个系数与过采样率有关。
行17~24:
读取6字节气压与温度的原始值,并合并为两个int32类型的变量
行26~28:
“4.9.1 How to Calculate Compensated Pressure Values”小节详细讲解了如何从DPS310原始的寄存器值计算出标准的气压值(单位Pa),主要有两个公式:
公式1,缩放数据:
公式1,缩放数据:
Traw_sc = Traw/kT
Praw_sc = Praw/kP
公式2,转换为标准值:
Pcomp(Pa) = c00 + Praw_sc*(c10 + Praw_sc *(c20+ Praw_sc *c30)) +
Traw_sc *c01 + Traw_sc *Praw_sc *(c11+Praw_sc*c21)
这里用到的是公式1,其中Traw、Praw是原始值,Traw_sc、Praw_sc是缩放后的值。
行30~43:
获得补偿校准系数并计算气压标准值。计算标准值用到了公式2,用到了之前缩放后的值Traw_sc、Praw_sc以及在之前初始化时已经得到补偿校准系数。代入公式就得到了气压的标准值,单位是Pa(帕)。可以看到,气压计标准值与温度的测量值也有关联。
(3.2)气压值转换为海拔高度
powf函数定义在<math.h>头文件中,原型为:
float powf(float x, float y);
用于计算 x 的 y 次幂,并返回结果(float)
气压值转化为海拔高度的公式参考:
https://blog.csdn.net/weixin_41869763/article/details/113487986
图4.2.6.7
因为飞控没有测量大气温度的传感器,所以使用了不考虑大气温度的这个公式。工程中将气压值转化为海拔高度的函数为Press_to_height()函数,原型为:
//气压值转换为海拔
float Press_to_height(const float pressure)
{
return (1.0f - powf(pressure / 101325.0f, 0.190295f)) * 44330.0f * 100; //返回海拔高度值,单位cm
}
(3.3)获取地面海拔高度
主要在DPS310_init_Height_0()获取地面海拔高度,运用该参数可以方便将气压计的绝对海拔值转化为飞行器距地面的相对高度。该函数的原型为:
static float Press_ground = 101325.0f; //1个标准大气压,单位:Pa
……
//初始化地面海拔高度
static void DPS310_init_Height_0(float Press_now)
{
//慢慢收敛校准
const float Press_e = Press_now - Press_ground;
Press_ground += Press_e * 0.15f;
if (ABS(Press_e) < (5.0f)) // 5 Pa 约10cm
{
if ((SysTick->VAL - Init_time_out) > 250)
{
baro_Height_0 = Press_to_height(Press_ground);
baro_init_flag = true;
}
}
else
{
Init_time_out = SysTick->VAL;
}
}
行1:
Press_ground 为地面气压值变量,为了加快收敛速度,设定初始值为1个标准大气压。
行9~11:
使Press_ground与当前气压值不断对比收敛
行13~25:
对误差进行判断,当误差小于5 Pa(约10cm)超过250个Systick计数值时,判断地面海拔高度初始化完成。
nd = 101325.0f; //1个标准大气压,单位:Pa
……
//初始化地面海拔高度
static void DPS310_init_Height_0(float Press_now)
{
//慢慢收敛校准
const float Press_e = Press_now - Press_ground;
Press_ground += Press_e * 0.15f;
if (ABS(Press_e) < (5.0f)) // 5 Pa 约10cm
{
if ((SysTick->VAL - Init_time_out) > 250)
{
baro_Height_0 = Press_to_height(Press_ground);
baro_init_flag = true;
}
}
else
{
Init_time_out = SysTick->VAL;
}
}
行1:
Press_ground 为地面气压值变量,为了加快收敛速度,设定初始值为1个标准大气压。
行9~11:
使Press_ground与当前气压值不断对比收敛
行13~25:
对误差进行判断,当误差小于5 Pa(约10cm)超过250个Systick计数值时,判断地面海拔高度初始化完成。