【STM32 LL库】基于STM32F103 LL库的BMP180驱动

BMP180

BMP180简介

BMP180是BMP085的功能兼容的继任者,这是一种用于消费者应用的新一代高精度数字压力传感器。BMP180的超低功率、低电压电子设备被优化用于移动电话、pda、GPS导航设备和户外设备。在快速转换时间下,BMP180的低空噪声仅为0.25米,因此BMP180提供了优越的性能。I2C接口允许与微控制器进行轻松的系统集成。BMP180基于压阻技术,具有EMC鲁棒性、高精度和线性度以及长期稳定性。罗伯特博世是世界汽车应用压力传感器的市场领导者。基于现场超过4亿个压力传感器的经验,BMP180继续使用新一代的微加工压力传感器。

BMP180测量流程

123
由上图可以看出,BMP180发送指令开始温度转换,等待4.5ms后读取未校准温度;然后发送指令开始压力转换,等待若干时间(由用户设定的采样速率决定)后读取未校准压力值;得到未校准温度和未校准压力后,再根据内部出厂设定的校准参数进行校准

BMP180内部寄存器

1、控制寄存器
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

参考资料

BMP180气压传感器
【InterFace】STM32 I2C 死锁问题
STM32 使用 LL库进行I2C读写

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值