我想为电子钟增加环境数据监测功能,主要是气温,湿度和气压这三项,BME280模块可以测量这三项数据,是一个不错的选择。
今天对照datasheet和之前坛友分享的资料,编写代码实现了气温,湿度和气压这三项数据的读取,并在LCD1602屏幕和UART打印显示,
效果如图所示:
在实践过程中,有以下心得:
1、BME280模块有三种工作模式,其中forced mode适合我的需要
2、我的需求,可以对照Weather Monitoring方式,文档上有详细说明
我对精度要求并不高,oversampleing选择x1即可,如此设置,功耗也最小。
3、读取的ADC数据,不能直接使用,必须进行补偿计算,64位整数运算精度最高,但对于单片机不太合适,可以使用double类型
计算过程,详见datasheet中的附件代码
main函数代码:
- void main()
- {
- uint8 chip_id = 0;
- uint8 pdata pbuf[31] = {0};
- ConfigUART(9600);
- printf(">ConfigUART done.\r\n\r\n");
- Delay500ms();
- BME280_Init();
- printf(">BME280_Init done.\r\n\r\n");
- Delay500ms();
- chip_id = BME280_Read_Chip_Id();
- printf(">BME280_Chip_Id = 0x%bx\r\n\r\n", (uint8)chip_id);
- LCD1602_Init(); //初始化液晶
- LCD1602_Show_Char(6, 0, 0); //5x7字符 ℃
- LCD1602_Show_Char(14, 0, '%');//5x7字符 %
- LCD1602_Show_Str(8, 1, "hPa"); // 液晶显示屏更新显示
-
- while(1)
- {
- Delay500ms();Delay500ms();
- BME280_Read_ADC(&BME280_adc_P, &BME280_adc_T, &BME280_adc_H);
- printf(">BME280_adc_T = 0x%08lx \r\n", BME280_adc_T);
- printf(">BME280_adc_H = 0x%08lx \r\n", BME280_adc_H);
- printf(">BME280_adc_P = 0x%08lx \r\n", BME280_adc_P);
- printf("\r\n");
- BME280_Temperature = BME280_compensate_T_double(BME280_adc_T);
- BME280_Humidity = BME280_compensate_H_double(BME280_adc_H);
- BME280_Pressure = BME280_compensate_P_double(BME280_adc_P);
-
- sprintf(pbuf, "%6.2f", BME280_Temperature);
- printf(">BME280_Temperature : %s c\r\n", pbuf);
- LCD1602_Show_Str(0, 0, pbuf); // 液晶显示屏更新显示
- sprintf(pbuf, "%6.2f", BME280_Humidity);
- printf(">BME280_Humidity : %s %%\r\n", pbuf);
- LCD1602_Show_Str(8, 0, pbuf); // 液晶显示屏更新显示
-
- sprintf(pbuf, "%7.2f", BME280_Pressure/100);
- printf(">BME280_Pressure : %s hPa\r\n", pbuf);
- LCD1602_Show_Str(0, 1, pbuf); // 液晶显示屏更新显示
- printf("--------------------------------\r\n\r\n");
- }
- }
复制代码
读取ADC数据代码:
- void BME280_Read_ADC(int32 *adc_P, int32 *adc_T, int32 *adc_H)
- {
- uint8 press_msb, press_lsb, press_xlsb;
- uint8 temp_msb, temp_lsb, temp_xlsb;
- uint8 hum_msb, hum_lsb;
- BME280_Set_Measure_Mode();
- BME280_Read_Compensation_Parameters();
- i2c_start();
- i2c_write_byte(BME280_SlaveAddr_Write);
- i2c_send_nack();
- i2c_write_byte(BME280_RegAddr_Pressure);
- i2c_send_nack();
- i2c_start();
- i2c_write_byte(BME280_SlaveAddr_Read); // burst read from 0xF7 to 0xFE
- i2c_send_nack();
- // read pressure
- press_msb = BME280_Burst_Read_Byte_Ack(); // 0xF7, burst read begin
- press_lsb = BME280_Burst_Read_Byte_Ack(); // 0xF8
- press_xlsb = BME280_Burst_Read_Byte_Ack(); // 0xF9
- // read temperature
- temp_msb = BME280_Burst_Read_Byte_Ack(); // 0xFA
- temp_lsb = BME280_Burst_Read_Byte_Ack(); // 0xFB
- temp_xlsb = BME280_Burst_Read_Byte_Ack(); // 0xFC
- // read humidity
- hum_msb = BME280_Burst_Read_Byte_Ack(); // 0xFD
- hum_lsb = BME280_Burst_Read_Byte_NAck(); // 0xFE, burst read end
- *adc_P = (int32)(((uint32)press_msb << 12)|((uint32)press_lsb << 4)|((uint32)press_xlsb >> 4));
- *adc_T = (int32)(((uint32)temp_msb << 12)|((uint32)temp_lsb << 4)|((uint32)temp_xlsb >> 4));
- *adc_H = (int32)(((uint32)hum_msb<<8)|((uint32)hum_lsb));
- }
复制代码
ADC数据的补偿计算代码(double类型):
- // Returns temperature in DegC, double precision. Output value of "51.23" equals 51.23 DegC.
- // t_fine carries fine temperature as global value
- double BME280_compensate_T_double(BME280_s32_t adc_T)
- {
- double var1, var2, T;
- var1 = (((double)adc_T) / 16384.0 - ((double)dig_T1) / 1024.0) * ((double)dig_T2);
- var2 = ((((double)adc_T) / 131072.0 - ((double)dig_T1) / 8192.0) * (((double)adc_T) / 131072.0 - ((double)dig_T1) / 8192.0)) * ((double)dig_T3);
- t_fine = (BME280_s32_t)(var1 + var2);
- T = (var1 + var2) / 5120.0;
- return T;
- }
- // Returns pressure in Pa as unsigned 32 bit integer. Output value of "96386.2" equals 96386 Pa = 963.86 hPa
- double BME280_compensate_P_double(BME280_s32_t adc_P)
- {
- double var1, var2, p;
- var1 = ((double)t_fine / 2.0) - 64000.0;
- var2 = var1 * var1 * ((double)dig_P6) / 32768.0;
- var2 = var2 + var1 * ((double)dig_P5) * 2.0;
- var2 = (var2 / 4.0) + (((double)dig_P4) * 65536.0);
- var1 = (((double)dig_P3) * var1 * var1 / 524288.0 + ((double)dig_P2) * var1) / 524288.0;
- var1 = (1.0 + var1 / 32768.0) * ((double)dig_P1);
- if(0.0 == var1)
- {
- return 0; // avoid exception caused by division by zero
- }
- p = 1048576.0 - (double)adc_P;
- p = (p - (var2 / 4096.0)) * 6250.0 / var1;
- var1 = ((double)dig_P9) * p * p / 2147483648.0;
- var2 = p * ((double)dig_P8) / 32768.0;
- p = p + (var1 + var2 + ((double)dig_P7)) / 16.0;
-
- return p;
- }
- // Returns humidity in %rH as as double. Output value of "46.332" represents 46.332 %rH
- double BME280_compensate_H_double(BME280_s32_t adc_H)
- {
- double var_H;
- var_H = (((double)t_fine) - 76800.00);
- 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)));
- var_H = var_H * (1.0 - ((double)dig_H1) * var_H / 524288.0);
-
- if(var_H > 100.0)
- {
- var_H = 100.0;
- }
- else if(var_H < 0.0)
- {
- var_H = 0.0;
- }
-
- return var_H;
- }
复制代码
详细代码请参见附件
以上代码使用C51开发板调试,接线简单,具体端口可参看config.h
初学单片机,难免有错漏之处,还请各位坛友不吝赐教。
BME280_UART_LCD1602_STC89C52RC.7z
(1.33 MB, 下载次数: 162)
|