单片机论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 202|回复: 1
打印 上一主题 下一主题
收起左侧

51单片机初学实践:用BME280模块获取温度、湿度和气压数据

[复制链接]
跳转到指定楼层
楼主
我想为电子钟增加环境数据监测功能,主要是气温,湿度和气压这三项,BME280模块可以测量这三项数据,是一个不错的选择。









今天对照datasheet和之前坛友分享的资料,编写代码实现了气温,湿度和气压这三项数据的读取,并在LCD1602屏幕和UART打印显示,
效果如图所示:






在实践过程中,有以下心得:

1、BME280模块有三种工作模式,其中forced mode适合我的需要







2、我的需求,可以对照Weather Monitoring方式,文档上有详细说明
我对精度要求并不高,oversampleing选择x1即可,如此设置,功耗也最小。










3、读取的ADC数据,不能直接使用,必须进行补偿计算,64位整数运算精度最高,但对于单片机不太合适,可以使用double类型
计算过程,详见datasheet中的附件代码









main函数代码:

  1. void main()
  2. {
  3.         uint8 chip_id = 0;
  4.         uint8 pdata pbuf[31] = {0};

  5.         ConfigUART(9600);
  6.         printf(">ConfigUART done.\r\n\r\n");
  7.         Delay500ms();

  8.         BME280_Init();
  9.         printf(">BME280_Init done.\r\n\r\n");
  10.         Delay500ms();

  11.         chip_id        = BME280_Read_Chip_Id();
  12.         printf(">BME280_Chip_Id = 0x%bx\r\n\r\n", (uint8)chip_id);

  13.     LCD1602_Init();        //初始化液晶
  14.         LCD1602_Show_Char(6, 0, 0);        //5x7字符 ℃
  15.         LCD1602_Show_Char(14, 0, '%');//5x7字符 %
  16.         LCD1602_Show_Str(8, 1, "hPa"); // 液晶显示屏更新显示
  17.        
  18.         while(1)
  19.         {
  20.                 Delay500ms();Delay500ms();
  21.                 BME280_Read_ADC(&BME280_adc_P, &BME280_adc_T, &BME280_adc_H);
  22.                 printf(">BME280_adc_T = 0x%08lx \r\n", BME280_adc_T);
  23.                 printf(">BME280_adc_H = 0x%08lx \r\n", BME280_adc_H);
  24.                 printf(">BME280_adc_P = 0x%08lx \r\n", BME280_adc_P);
  25.                 printf("\r\n");

  26.                 BME280_Temperature        = BME280_compensate_T_double(BME280_adc_T);
  27.                 BME280_Humidity                = BME280_compensate_H_double(BME280_adc_H);
  28.                 BME280_Pressure                = BME280_compensate_P_double(BME280_adc_P);
  29.                
  30.                 sprintf(pbuf, "%6.2f", BME280_Temperature);
  31.                 printf(">BME280_Temperature : %s c\r\n", pbuf);
  32.                 LCD1602_Show_Str(0, 0, pbuf); // 液晶显示屏更新显示

  33.                 sprintf(pbuf, "%6.2f", BME280_Humidity);
  34.                 printf(">BME280_Humidity : %s %%\r\n", pbuf);
  35.                 LCD1602_Show_Str(8, 0, pbuf); // 液晶显示屏更新显示
  36.                
  37.                 sprintf(pbuf, "%7.2f", BME280_Pressure/100);
  38.                 printf(">BME280_Pressure : %s hPa\r\n", pbuf);
  39.                 LCD1602_Show_Str(0, 1, pbuf); // 液晶显示屏更新显示

  40.                 printf("--------------------------------\r\n\r\n");
  41.         }
  42. }
复制代码

读取ADC数据代码:

  1. void BME280_Read_ADC(int32 *adc_P, int32 *adc_T, int32 *adc_H)
  2. {
  3.         uint8 press_msb, press_lsb, press_xlsb;
  4.         uint8 temp_msb, temp_lsb, temp_xlsb;
  5.         uint8 hum_msb, hum_lsb;

  6.         BME280_Set_Measure_Mode();
  7.         BME280_Read_Compensation_Parameters();

  8.         i2c_start();
  9.         i2c_write_byte(BME280_SlaveAddr_Write);
  10.         i2c_send_nack();
  11.         i2c_write_byte(BME280_RegAddr_Pressure);
  12.         i2c_send_nack();
  13.         i2c_start();                        
  14.         i2c_write_byte(BME280_SlaveAddr_Read); // burst read from 0xF7 to 0xFE
  15.         i2c_send_nack();

  16.         // read pressure
  17.         press_msb  = BME280_Burst_Read_Byte_Ack(); // 0xF7, burst read begin
  18.         press_lsb  = BME280_Burst_Read_Byte_Ack(); // 0xF8
  19.         press_xlsb = BME280_Burst_Read_Byte_Ack(); // 0xF9

  20.         // read temperature
  21.         temp_msb  = BME280_Burst_Read_Byte_Ack(); // 0xFA
  22.         temp_lsb  = BME280_Burst_Read_Byte_Ack(); // 0xFB
  23.         temp_xlsb = BME280_Burst_Read_Byte_Ack(); // 0xFC

  24.         // read humidity
  25.         hum_msb  = BME280_Burst_Read_Byte_Ack(); // 0xFD
  26.         hum_lsb  = BME280_Burst_Read_Byte_NAck(); // 0xFE, burst read end

  27.         *adc_P        = (int32)(((uint32)press_msb << 12)|((uint32)press_lsb << 4)|((uint32)press_xlsb >> 4));
  28.         *adc_T        = (int32)(((uint32)temp_msb << 12)|((uint32)temp_lsb << 4)|((uint32)temp_xlsb >> 4));
  29.         *adc_H        = (int32)(((uint32)hum_msb<<8)|((uint32)hum_lsb));
  30. }
复制代码

ADC数据的补偿计算代码(double类型):

  1. // Returns temperature in DegC, double precision. Output value of "51.23" equals 51.23 DegC.
  2. // t_fine carries fine temperature as global value
  3. double BME280_compensate_T_double(BME280_s32_t adc_T)
  4. {
  5.         double var1, var2, T;
  6.         var1 = (((double)adc_T) / 16384.0 - ((double)dig_T1) / 1024.0) * ((double)dig_T2);
  7.         var2 = ((((double)adc_T) / 131072.0 - ((double)dig_T1) / 8192.0) * (((double)adc_T) / 131072.0 - ((double)dig_T1) / 8192.0)) * ((double)dig_T3);

  8.         t_fine = (BME280_s32_t)(var1 + var2);
  9.         T = (var1 + var2) / 5120.0;

  10.         return T;
  11. }

  12. // Returns pressure in Pa as unsigned 32 bit integer. Output value of "96386.2" equals 96386 Pa = 963.86 hPa
  13. double BME280_compensate_P_double(BME280_s32_t adc_P)
  14. {
  15.         double var1, var2, p;
  16.         var1 = ((double)t_fine / 2.0) - 64000.0;
  17.         var2 = var1 * var1 * ((double)dig_P6) / 32768.0;
  18.         var2 = var2 + var1 * ((double)dig_P5) * 2.0;
  19.         var2 = (var2 / 4.0) + (((double)dig_P4) * 65536.0);
  20.         var1 = (((double)dig_P3) * var1 * var1 / 524288.0 + ((double)dig_P2) * var1) / 524288.0;
  21.         var1 = (1.0 + var1 / 32768.0) * ((double)dig_P1);
  22.         if(0.0 == var1)
  23.         {
  24.                 return 0; // avoid exception caused by division by zero
  25.         }
  26.         p = 1048576.0 - (double)adc_P;
  27.         p = (p - (var2 / 4096.0)) * 6250.0 / var1;
  28.         var1 = ((double)dig_P9) * p * p / 2147483648.0;
  29.         var2 = p * ((double)dig_P8) / 32768.0;
  30.         p = p + (var1 + var2 + ((double)dig_P7)) / 16.0;
  31.        
  32.         return p;
  33. }

  34. // Returns humidity in %rH as as double. Output value of "46.332" represents 46.332 %rH
  35. double BME280_compensate_H_double(BME280_s32_t adc_H)
  36. {
  37.         double var_H;

  38.         var_H = (((double)t_fine) - 76800.00);
  39.         var_H = (adc_H - (((double)dig_H4) * 64.0 + ((double)dig_H5) / 16384.0 * var_H)) * (((double)dig_H2) / 65536.0 * (1.0 + ((double)dig_H6) / 67108864.0 * var_H * (1.0 + ((double)dig_H3) / 67108864.0 * var_H)));
  40.         var_H = var_H * (1.0 - ((double)dig_H1) * var_H / 524288.0);
  41.        
  42.         if(var_H > 100.0)
  43.         {
  44.                 var_H = 100.0;
  45.         }
  46.         else if(var_H < 0.0)
  47.         {
  48.                 var_H = 0.0;
  49.         }
  50.        
  51.         return var_H;
  52. }
复制代码

详细代码请参见附件





以上代码使用C51开发板调试,接线简单,具体端口可参看config.h

初学单片机,难免有错漏之处,还请各位坛友不吝赐教。


BME280_UART_LCD1602_STC89C52RC.7z (1.33 MB, 下载次数: 9)



评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 转播转播 分享分享 分享淘帖 顶 踩
回复

使用道具 举报

沙发
251354715 发表于 2020-8-1 20:14 | 只看该作者
学习一下,有AVR单片机驱动BME280的程序吗?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表