【附工程文件下载】基于STM32F103 LL库的BMP180驱动
BMP180
BMP180简介
BMP180是BMP085的功能兼容的继任者,这是一种用于消费者应用的新一代高精度数字压力传感器。BMP180的超低功率、低电压电子设备被优化用于移动电话、pda、GPS导航设备和户外设备。在快速转换时间下,BMP180的低空噪声仅为0.25米,因此BMP180提供了优越的性能。I2C接口允许与微控制器进行轻松的系统集成。BMP180基于压阻技术,具有EMC鲁棒性、高精度和线性度以及长期稳定性。罗伯特博世是世界汽车应用压力传感器的市场领导者。基于现场超过4亿个压力传感器的经验,BMP180继续使用新一代的微加工压力传感器。
BMP180测量流程
由上图可以看出,BMP180发送指令开始温度转换,等待4.5ms后读取未校准温度;然后发送指令开始压力转换,等待若干时间(由用户设定的采样速率决定)后读取未校准压力值;得到未校准温度和未校准压力后,再根据内部出厂设定的校准参数进行校准
BMP180内部寄存器
1、out_xlsb、out_lsb、out_msb 这三个为数据寄存器,当转换完成后,从这三个寄存器中读取数据
2、ctrl_meas为控制寄存器,地址为0xF4,向这个寄存器中写入指令可实现不同功能,如下图所示。
3、soft_reset 软复位寄存器,地址为0xE0,向这个寄存器中写入0xB6,执行与上电相同的软复位
4、ID寄存器,地址为0xD0,读取这个寄存器即可获得硬件ID 0x55
5、calib21 downto calib0 校准参数寄存器,存放有各种出厂的校准参数,详细地址如下图所示。
BMP180校准流程
BMP180校准过程如下图所示,感兴趣的可以仔细看看
海拔计算
p为测量值,p0为海平面压力
代码
LL库IIC驱动
参考自其他人的代码,只适用于F103系列
1、读驱动
uint8_t i2c_read_len(I2C_TypeDef *I2Cx, uint8_t Addr , uint8_t Reg, uint8_t len,uint8_t *buf)
{
/* 1.保证I2C外设不在使用中. */
while(LL_I2C_IsActiveFlag_BUSY(I2Cx));
/* Check if the I2C is already enabled */
if ((I2Cx->CR1 & I2C_CR1_PE) != I2C_CR1_PE)
{
/* Enable I2C peripheral */
LL_I2C_Enable(I2Cx);
}
/* Disable Pos */
CLEAR_BIT(I2Cx->CR1, I2C_CR1_POS);
/* Enable Acknowledge */
SET_BIT(I2Cx->CR1, I2C_CR1_ACK);
/* 2.发送START信号 */
LL_I2C_GenerateStartCondition(I2Cx);
while(!LL_I2C_IsActiveFlag_SB(I2Cx));
/* 2.写器件地址 */
LL_I2C_TransmitData8(I2Cx, Addr);
/* Wait until ADDR flag is set */
while(!LL_I2C_IsActiveFlag_ADDR(I2Cx)){};
/* Clear ADDR flag */
LL_I2C_ClearFlag_ADDR(I2Cx);
/* Wait until TXE flag is set */
while(!LL_I2C_IsActiveFlag_TXE(I2Cx));
/* 4.发送器件寄存器地址. */
LL_I2C_TransmitData8(I2Cx, Reg);
while(!LL_I2C_IsActiveFlag_TXE(I2Cx));
/* 5.提供RESTART信号. */
// LL_I2C_GenerateStopCondition(I2Cx);
LL_I2C_GenerateStartCondition(I2Cx);
while(!LL_I2C_IsActiveFlag_SB(I2Cx));
/* 6.重新发送地址,并附带读标记. */
LL_I2C_TransmitData8(I2Cx, Addr | 0x01);
/* Wait until ADDR flag is set */
while(!LL_I2C_IsActiveFlag_ADDR(I2Cx)){};
//
if (len == 0U)
{
/* Clear ADDR flag */
LL_I2C_ClearFlag_ADDR(I2Cx);
/* Generate Stop */
LL_I2C_GenerateStopCondition(I2Cx);
}
else if (len == 1U)
{
/* Disable Acknowledge */
CLEAR_BIT(I2Cx->CR1, I2C_CR1_ACK);
/* Disable all active IRQs around ADDR clearing and STOP programming because the EV6_3
software sequence must complete before the current byte end of transfer */
__disable_irq();
/* Clear ADDR flag */
LL_I2C_ClearFlag_ADDR(I2Cx);
/* Generate Stop */
LL_I2C_GenerateStopCondition(I2Cx);
/* Re-enable IRQs */
__enable_irq();
}
else if (len == 2U)
{
/* Enable Pos */
SET_BIT(I2Cx->CR1, I2C_CR1_POS);
/* Disable all active IRQs around ADDR clearing and STOP programming because the EV6_3
software sequence must complete before the current byte end of transfer */
__disable_irq();
/* Clear ADDR flag */
LL_I2C_ClearFlag_ADDR(I2Cx);
/* Disable Acknowledge */
CLEAR_BIT(I2Cx->CR1, I2C_CR1_ACK);
/* Re-enable IRQs */
__enable_irq();
}
else
{
/* Enable Acknowledge */
SET_BIT(I2Cx->CR1, I2C_CR1_ACK);
/* Clear ADDR flag */
LL_I2C_ClearFlag_ADDR(I2Cx);
}
while (len > 0U)
{
if (len <= 3U)
{
/* One byte */
if (len == 1U)
{
/* Wait until RXNE flag is set */
while(!LL_I2C_IsActiveFlag_RXNE(I2Cx)){};
/* Read data from DR */
*buf = (uint8_t)LL_I2C_ReceiveData8(I2Cx);
/* Increment Buffer pointer */
buf++;
/* Update counter */
len--;
}
/* Two bytes */
else if (len == 2U)
{
/* Wait until BTF flag is set */
while(!LL_I2C_IsActiveFlag_BTF(I2Cx)){}
/* Disable all active IRQs around ADDR clearing and STOP programming because the EV6_3
software sequence must complete before the current byte end of transfer */
__disable_irq();
/* Generate Stop */
LL_I2C_GenerateStopCondition(I2Cx);
/* Read data from DR */
*buf = (uint8_t)LL_I2C_ReceiveData8(I2Cx);
/* Increment Buffer pointer */
buf++;
/* Update counter */
len--;
/* Re-enable IRQs */
__enable_irq();
/* Read data from DR */
*buf = (uint8_t)LL_I2C_ReceiveData8(I2Cx);
/* Increment Buffer pointer */
buf++;
/* Update counter */
len--;
}
/* 3 Last bytes */
else
{
/* Wait until BTF flag is set */
while(!LL_I2C_IsActiveFlag_BTF(I2Cx)){}
/* Disable Acknowledge */
CLEAR_BIT(I2Cx->CR1, I2C_CR1_ACK);
/* Disable all active IRQs around ADDR clearing and STOP programming because the EV6_3
software sequence must complete before the current byte end of transfer */
__disable_irq();
/* Read data from DR */
*buf = (uint8_t)LL_I2C_ReceiveData8(I2Cx);
/* Increment Buffer pointer */
buf++;
/* Update counter */
len--;
/* Wait until BTF flag is set */
while(!LL_I2C_IsActiveFlag_BTF(I2Cx)){}
/* Generate Stop */
LL_I2C_GenerateStopCondition(I2Cx);
/* Read data from DR */
*buf = (uint8_t)LL_I2C_ReceiveData8(I2Cx);
/* Increment Buffer pointer */
buf++;
/* Update counter */
len--;
/* Re-enable IRQs */
__enable_irq();
/* Read data from DR */
*buf = (uint8_t)LL_I2C_ReceiveData8(I2Cx);
/* Increment Buffer pointer */
buf++;
/* Update counter */
len--;
}
}
else
{
/* Wait until RXNE flag is set */
while(!LL_I2C_IsActiveFlag_RXNE(I2Cx)){};
/* Read data from DR */
*buf = (uint8_t)LL_I2C_ReceiveData8(I2Cx);
/* Increment Buffer pointer */
buf++;
/* Update counter */
len--;
if (LL_I2C_IsActiveFlag_BTF(I2Cx))
{
/* Read data from DR */
*buf = (uint8_t)LL_I2C_ReceiveData8(I2Cx);
/* Increment Buffer pointer */
buf++;
/* Update counter */
len--;
}
}
}
return 0;
}
2、写驱动
uint8_t i2c_write_len(I2C_TypeDef *I2Cx, uint8_t addr , uint8_t reg, uint8_t len,uint8_t *buf)
{
int i=0;
/* 1.保证I2C外设不在使用中. */
while(LL_I2C_IsActiveFlag_BUSY(I2Cx));
/* Check if the I2C is already enabled */
if ((I2Cx->CR1 & I2C_CR1_PE) != I2C_CR1_PE)
{
/* Enable I2C peripheral */
LL_I2C_Enable(I2Cx);
}
/* Disable Pos */
CLEAR_BIT(I2Cx->CR1, I2C_CR1_POS);
/* 2.发送START信号 */
LL_I2C_GenerateStartCondition(I2Cx);
while(!LL_I2C_IsActiveFlag_SB(I2Cx));
/* 2.写器件地址 */
LL_I2C_TransmitData8(I2Cx, addr);
while(!LL_I2C_IsActiveFlag_ADDR(I2Cx));
LL_I2C_ClearFlag_ADDR(I2Cx);
/* 3.地址位已经置位,通常TXE也会完成,为了谨慎,再查一下. */
while(!LL_I2C_IsActiveFlag_TXE(I2Cx)){}
/* 4.发送器件寄存器地址. */
LL_I2C_TransmitData8(I2Cx, reg);
i = len;
while(i>0)
{
while(!LL_I2C_IsActiveFlag_TXE(I2Cx)){};
/* 5.写入寄存器内容 */
LL_I2C_TransmitData8(I2Cx, *buf);
buf++;
i--;
if(LL_I2C_IsActiveFlag_BTF(I2Cx)==SET && i!=0)
{
LL_I2C_TransmitData8(I2Cx, *buf);
buf++;
i--;
}
}
while(!LL_I2C_IsActiveFlag_BTF(I2Cx)){}
/* 6.传送结束条件. */
LL_I2C_GenerateStopCondition(I2Cx);
return 0;
}
BMP180数据读取代码
1、温度读取代码
void BMP_Read_Temp(uint16_t * temp)
{
uint8_t ReadBuf[2];
i2c_write_len(I2C1, BMP180_WriteAddr, BMP180_ControlREG,1,BMP180_ReadTemp);
HAL_Delay(5);
i2c_read_len(I2C1, BMP180_WriteAddr , 0xf6, 2,ReadBuf);
*temp = (uint16_t)ReadBuf[0]<<8 | (uint16_t)ReadBuf[1];
}
2、压力读取代码
void BMP_Read_Pressure(uint32_t * pressure)
{
uint8_t ReadBuf[3];
i2c_write_len(I2C1, BMP180_WriteAddr, BMP180_ControlREG,1,BMP180_ReadPressure_H);
HAL_Delay(30);
i2c_read_len(I2C1, BMP180_WriteAddr , 0xf6, 3,ReadBuf);
*pressure = ((uint32_t)ReadBuf[0] << 16 | (uint32_t)ReadBuf[1] <<8 | (uint32_t)ReadBuf[2]) >> (8 - OSS);
}
3、ID读取代码
uint8_t BMP_Read_ID(void)
{
uint8_t ReadBuf[1];
i2c_read_len(I2C1, BMP180_WriteAddr , 0xd0, 1,ReadBuf);
return ReadBuf[0];
}
4、校准参数读取代码
void BMP180_Multiple_Read(uint8_t REG_Address, uint16_t *ReadData)
{
uint8_t REG_Data[2];
i2c_read_len(I2C1, BMP180_WriteAddr , REG_Address, 2,REG_Data);
*ReadData = (uint16_t)REG_Data[0]<<8 | (uint16_t)REG_Data[1];
}
void BMP180_Init(void)
{
BMP180_Multiple_Read( BMP_AC1_ADDR, (uint16_t *)&ac1 );
BMP180_Multiple_Read( BMP_AC2_ADDR, (uint16_t *)&ac2 );
BMP180_Multiple_Read( BMP_AC3_ADDR, (uint16_t *)&ac3 );
BMP180_Multiple_Read( BMP_AC4_ADDR, (uint16_t *)&ac4 );
BMP180_Multiple_Read( BMP_AC5_ADDR, (uint16_t *)&ac5 );
BMP180_Multiple_Read( BMP_AC6_ADDR, (uint16_t *)&ac6 );
BMP180_Multiple_Read( BMP_B1_ADDR, (uint16_t *)&b1 );
BMP180_Multiple_Read( BMP_B2_ADDR, (uint16_t *)&b2 );
BMP180_Multiple_Read( BMP_MB_ADDR, (uint16_t *)&mb );
BMP180_Multiple_Read( BMP_MC_ADDR, (uint16_t *)&mc );
BMP180_Multiple_Read( BMP_MD_ADDR, (uint16_t *)&md );
}
5、温度与压力校准
void BMP180Convert(float *temperature, long *pressure)
{
uint16_t ut;
uint32_t up;
long x1, x2, b5, b6, x3, b3, p;
unsigned long b4, b7;
BMP_Read_Temp(&ut);
BMP_Read_Pressure(&up);
// 计算温度
x1 = ((long)ut - ac6) * ac5 >> 15;
x2 = ((long) mc << 11) / (x1 + md);
b5 = x1 + x2;
*temperature = ((b5 + 8) >> 4) * 0.1f;
// 计算气压
b6 = b5 - 4000;
x1 = (b2 * (b6 * b6 >> 12)) >> 11;
x2 = (ac2 * b6) >> 11;
x3 = x1 + x2;
b3 = ((((long)ac1 * 4 + x3) << OSS) + 2) >> 2;
x1 = (ac3 * b6) >> 13;
x2 = (b1 * (b6 * b6>> 12)) >> 16;
x3 = ((x1 + x2) + 2) >> 2;
b4 = (ac4 * (unsigned long) (x3 + 32768)) >> 15;
b7 = ((unsigned long) up - b3) * (50000 >> OSS);
if( b7 < 0x80000000)
p = (b7 * 2) / b4 ;
else
p = (b7 / b4) * 2;
x1 = (p >> 8) * (p >> 8);
x1 = (x1 * 3038) >> 16;
x2 = (-7357 * p) >> 16;
* pressure = p + ((x1 + x2 + 3791) >> 4);
}
6、海拔计算
void BMP180_Altitude(float *temperature, long *pressure, float *altitide)
{
BMP180Convert(temperature, pressure); // 计算出压强
*altitide = 44330*(1 - pow((*pressure)/ PRESSURE_OF_SEA, 1.0f / 5.255f));
}
7、主函数代码
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
BMP_Read_Temp(&TempBuf);
BMP_Read_Pressure(&PresBuf);
ID = BMP_Read_ID();
BMP180Convert(&temp,&pressure); // 测量温度和大气压
BMP180_Altitude(&temp, &pressure, &altitude); // 计算海拔
printf("Temperature is: %.1f Pressure is: %ld Altitude is:%f\r\n", temp, pressure, altitude);
printf("Temp: %.3f\r\n", (float)TempBuf/1000);
printf("Pressure: %d\r\n", PresBuf);
printf("ID: %d\r\n", ID);
HAL_Delay(300);
//printf("ok");
}
另外STM32F103有IIC硬件死锁问题,这里顺带附上解决方法
若硬件IIC不能正常工作,在while(1)主循环前执行下列代码即可。
ErrorStatus IIC_Unlock(void)
{
//1.reset GPIO
LL_I2C_Disable(I2C1);
HAL_GPIO_DeInit(GPIOB, LL_GPIO_PIN_6|LL_GPIO_PIN_7);
User_I2C2_GeneralPurposeOutput_Init();
//2.Set out High
LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_7);
HAL_Delay(1);
LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_6);
HAL_Delay(1);
/* 3. Check SCL and SDA High level in GPIOx_IDR */
if ((LL_GPIO_IsInputPinSet(GPIOB, LL_GPIO_PIN_6) != 1)||(LL_GPIO_IsInputPinSet(GPIOB, LL_GPIO_PIN_7) != 1))
{
printf("3.PB7=%d, PB6=%d\r\n", HAL_GPIO_ReadPin(GPIOB, LL_GPIO_PIN_7), HAL_GPIO_ReadPin(GPIOB, LL_GPIO_PIN_6));
return ERROR;
}
/* 4. Configure the SDA I/O as General Purpose Output Open-Drain, Low level (Write 0 to GPIOx_ODR).
* 5. Check SDA Low level in GPIOx_IDR.
* 6. Configure the SCL I/O as General Purpose Output Open-Drain, Low level (Write 0 to GPIOx_ODR)
* 7. Check SCL Low level in GPIOx_IDR.
* */
LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_6);
LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_7);
HAL_Delay(1);
if ((LL_GPIO_IsInputPinSet(GPIOB, LL_GPIO_PIN_6) != 0)||(LL_GPIO_IsInputPinSet(GPIOB, LL_GPIO_PIN_7) != 0))
{
printf("4-7.PB7=%d, PB6=%d\r\n", HAL_GPIO_ReadPin(GPIOB, LL_GPIO_PIN_7), HAL_GPIO_ReadPin(GPIOB, LL_GPIO_PIN_6));
return ERROR;
}
/*
* 8. Configure the SCL I/O as General Purpose Output Open-Drain, High level (Write 1 to GPIOx_ODR).
* 9. Check SCL High level in GPIOx_IDR.
* 10. Configure the SDA I/O as General Purpose Output Open-Drain , High level (Write 1 to GPIOx_ODR).
* 11. Check SDA High level in GPIOx_IDR.
*/
LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_6);
LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_7);
HAL_Delay(1);
if ((LL_GPIO_IsInputPinSet(GPIOB, LL_GPIO_PIN_6) != 1)||(LL_GPIO_IsInputPinSet(GPIOB, LL_GPIO_PIN_7) != 1))
{
printf("8-11.PB7=%d, PB6=%d\r\n", HAL_GPIO_ReadPin(GPIOB, LL_GPIO_PIN_7), HAL_GPIO_ReadPin(GPIOB, LL_GPIO_PIN_6));
return ERROR;
}
/* 12. Configure the SCL and SDA I/Os as Alternate function Open-Drain. */
HAL_GPIO_DeInit(GPIOB, LL_GPIO_PIN_6|LL_GPIO_PIN_7);
User_I2C2_AlternateFunction_Init();
/* 13. Set SWRST bit in I2Cx_CR1 register. */
LL_I2C_EnableReset(I2C1);
HAL_Delay(2);
/* 14. Clear SWRST bit in I2Cx_CR1 register. */
LL_I2C_DisableReset(I2C1);
HAL_Delay(2);
/* 15. Enable the I2C peripheral by setting the PE bit in I2Cx_CR1 register */
MX_I2C1_Init();
LL_I2C_Enable(I2C1);
HAL_Delay(2);
printf("I2CResetBus\r\n");
return SUCCESS;
}
运行效果图
工程下载
链接: https://pan.baidu.com/s/1LIvHhlmgpL0Cf4lvNhjg6Q?pwd=s9s7 提取码: s9s7