| 问一下温度偏高解决了没有 |
新新科技 发表于 2022-2-25 12:57 BMP280从机地址就是0xec的呀,没错呀 BMP280_Read函数呢?里面有没有应答?每次读取完一个字节的数据之后,都要主机产生一个应答信号的 0xf3的读取呢?是不是先读取这个寄存器之后再读取压力和温度数据的? 给你一个我的代码参考一下,这是我几个月刚刚开始学C语言的时候写的,已经验证通过的了 /*BMP280.c BMP280相关操作函数 选择IIC操作方式,相关的选择端口要硬件先选择好 SDO=0,IIC从机地址为:0xec(写),0xed(读) */ #include "BMP280.h" #include "IIC.h" #define BMP280_S32_t long #define Write_BMP280_slave 0xec #define Read_BMP280_slave 0xed #define Read_BMP280_temp_msb 0xfa //读取温度最高位地址,读取是从最高位读到最低位的 #define Read_BMP280_press_msb 0xf7 //读取气压最高位地址,读取是从最高位读到最低位的 #define Read_BMP280_Status 0xf3 //读取ADC运行状态位 unsigned short dig_T1; //BMP280校正值保存的相关地址 short dig_T2; short dig_T3; unsigned short dig_P1; short dig_P2; short dig_P3; short dig_P4; short dig_P5; short dig_P6; short dig_P7; short dig_P8; short dig_P9; //================================================================================================= void BMP280_init() //BMP280初始化函数 { Delay_ms(100); IIC_start(); Write_byte(Write_BMP280_slave); //从机地址 Write_byte(0xf4); //寄存器设置设备的数据采集选项(0xf4) Write_byte(0xf0); //先进入休眠模式,完成0xf5的设置之后再进入正常模式 Write_byte(0xf5); //存器设置设备的速率、过滤器和接口选项 Write_byte(0x00); // IIR滤波关闭,0.5mS测量一次 Write_byte(0xf4); //寄存器设置设备的数据采集选项(0xf4) Write_byte(0xff); //温度和压力都是20位模式,采样模式为正常模式 IIC_stop(); dig_T1=Read_BMP280_2Byte(0x88); //读取几个校验值 dig_T2=Read_BMP280_2Byte(0x8a); dig_T3=Read_BMP280_2Byte(0x8c); dig_P1=Read_BMP280_2Byte(0x8e); dig_P2=Read_BMP280_2Byte(0x90); dig_P3=Read_BMP280_2Byte(0x92); dig_P4=Read_BMP280_2Byte(0x94); dig_P5=Read_BMP280_2Byte(0x96); dig_P6=Read_BMP280_2Byte(0x98); dig_P7=Read_BMP280_2Byte(0x9a); dig_P8=Read_BMP280_2Byte(0x9c); dig_P9=Read_BMP280_2Byte(0x9e); } //================================================================================================= short Read_BMP280_2Byte(unsigned char BMP280_addr) //读取校正值,所有校正值是用两个地址存放的,所以就读取两个字节 { short temp; unsigned char Data_LSB,Data_MSB; IIC_start(); Write_byte(Write_BMP280_slave); //从机地址 Write_byte(BMP280_addr); IIC_start(); Write_byte(Read_BMP280_slave); //从机地址 Data_LSB=read_byte(); IIC_Ask(); Data_MSB=read_byte(); IIC_Nask(); IIC_stop(); temp=(Data_MSB<<8)|Data_LSB; return temp; } //================================================================================================= long Read_BMP280_3Byte(unsigned char BMP280_addr) //读取测量值,所有测量值是用三地址存放的,所以就读取三个字节 { long temp; unsigned char Data_XLSB,Data_LSB,Data_MSB; IIC_start(); Write_byte(Write_BMP280_slave); //从机地址 Write_byte(BMP280_addr); IIC_start(); Write_byte(Read_BMP280_slave); //从机地址 Data_MSB=read_byte(); IIC_Ask(); Data_LSB=read_byte(); IIC_Ask(); Data_XLSB=read_byte(); IIC_Nask(); IIC_stop(); temp=(long)(((unsigned long)Data_MSB<<12)|((unsigned long)Data_LSB<<4)|((unsigned long)Data_XLSB>>4)); return temp; } //================================================================================================= double Read_BMP280_adc(unsigned char Reg_addr) //读取传感器adc数据 { // double Data; //返回值就是加入校正计算好的温度或者压力值 long adc_data,adc_data_add; //转换结果保存 unsigned char f,measuring; // // if(Reg_addr==Read_BMP280_temp_msb) //根据输入选择温度或者气压ADC { // for(f=0;f<32;f++) // { // do{measuring=Read_status();} //读取ADC状态位 while(measuring==0x08); // adc_data=Read_BMP280_3Byte(Read_BMP280_temp_msb); //读取温度ADC结果 adc_data_add=adc_data_add+adc_data; //adc结果相加 } // adc_data_add=adc_data_add/32; //进行多次ADC,然后取平均值 Data=bmp280_compensate_T_double(adc_data); //进行校正处理 } // else // { // for(f=0;f<128;f++) // { // do{measuring=Read_status();} //读取ADC状态位 while(measuring==0x08); // adc_data=Read_BMP280_3Byte(Read_BMP280_press_msb); //读取气压ADC结果 adc_data_add=adc_data_add+adc_data; //adc结果相加 } // adc_data_add=adc_data_add/128; //进行多次ADC,然后取平均值 Data=bmp280_compensate_P_double(adc_data); //进行校正处理 } return Data; } //================================================================================================= double bmp280_compensate_T_double(long adc_T) //数据手册复制过来的,温度和校正值的计算 { double var1, var2, T,t_fine; 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 = (long)(var1 + var2); T = (var1 + var2) / 5120.0; return T; } //================================================================================================= double bmp280_compensate_P_double(long adc_P) //数据手册复制过来的气压和校正值的计算 { double var1, var2, p,t_fine; 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 (var1 == 0.0) { 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; } //================================================================================================= unsigned char Read_status() //读取状态位,检测ADC是否完成 { unsigned char temp; IIC_start(); Write_byte(Write_BMP280_slave); //从机地址 Write_byte(Read_BMP280_Status); //读取ADC运行状态位 IIC_start(); Write_byte(Read_BMP280_slave); //从机地址 temp=read_byte(); IIC_Nask(); IIC_stop(); return temp; } //================================================================================================= |
|
本帖最后由 新新科技 于 2022-2-25 13:29 编辑 手册提供的BMP280器件地址是0x76,而手头这模块是0xec,莫非不是BMP280? |
|
//关键源码如下: #define BMP280_Address 0xec //器件地址 #define BMP280_TEMP_ADDR 0xfa //温度寄存器 #define BMP280_PRESS_ADDR 0xf7 //气压寄存器 //校正参数 unsigned short dig_T1; short dig_T2; short dig_T3; unsigned short dig_P1; short dig_P2; short dig_P3; short dig_P4; short dig_P5; short dig_P6; short dig_P7; short dig_P8; short dig_P9; long bmp280_MultipleReadThree(unsigned char addr) //读取三个字节 { unsigned char msb, lsb, xlsb; long temp = 0; msb = BMP280_Read(addr); lsb = BMP280_Read(addr + 1); xlsb = BMP280_Read(addr + 2); temp = (long)(((unsigned long)msb << 12)|((unsigned long)lsb << 4)|((unsigned long)xlsb >> 4)); return temp; } short bmp280_MultipleReadTwo(unsigned char addr) //读取两个字节 { unsigned char msb, lsb; short temp = 0; lsb = BMP280_Read(addr); msb = BMP280_Read(addr + 1); temp = (short)msb << 8; temp |= (short)lsb; return temp; } bit BMP280_Init()//BMP280初始化 { unsigned char temp = 0; BMP280_Write(0xe0, 0xb6); temp = BMP280_Read(0xd0); if(temp != 0x58)return 1;// BMP280_Write(0xf4, 0xff); BMP280_Write(0xf5, 0x00); dig_T1 = bmp280_MultipleReadTwo(0x88); dig_T2 = bmp280_MultipleReadTwo(0x8A); dig_T3 = bmp280_MultipleReadTwo(0x8C); dig_P1 = bmp280_MultipleReadTwo(0x8E); dig_P2 = bmp280_MultipleReadTwo(0x90); dig_P3 = bmp280_MultipleReadTwo(0x92); dig_P4 = bmp280_MultipleReadTwo(0x94); dig_P5 = bmp280_MultipleReadTwo(0x96); dig_P6 = bmp280_MultipleReadTwo(0x98); dig_P7 = bmp280_MultipleReadTwo(0x9A); dig_P8 = bmp280_MultipleReadTwo(0x9C); dig_P9 = bmp280_MultipleReadTwo(0x9E); delay_ms(200); return 0; } long BMP280_GetValue(uchar i)//获取气压和温度 { long adc_T; long adc_P; long var1, var2, T, p; unsigned long t_fine; adc_T = bmp280_MultipleReadThree(BMP280_TEMP_ADDR); adc_P = bmp280_MultipleReadThree(BMP280_PRESS_ADDR); if(adc_P == 0) { return 0; } //Temperature 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 = (unsigned long)(var1+var2); T = (var1+var2)/51.20; 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); 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; if(i)return p; else return T; } |
新新科技 发表于 2022-2-24 10:52 在95%的情况下,是代码的问题,跟BMP280是不是正品是没有关系的 在第一个表格中,复位后的值是和280数据手册上是一样的 0xf3的数据是0xC0,就说明转换没有完成,这一点很重要,只要是转换没有完成的,读取的数据就有可能是任何数据,去分析太多是没有意义的 一定要转换完成之后,马上读取6个温度的压力数据,期间不要有太长时间的延时,如果你连续转换模式,ADC转换和数据改变是同时进行的,也就是说ADC边进行,边改变温度和压力寄存器的值,这个在数据手册中是有说明的 还有,最好不要用串口,先用数码管或者OLED进行验证 如果还不行,就把代码上传 |
| 知道是什么原因了,昨晚试了三个模块,发现的确是芯片的问题,其他两个模块虽然能测量气压和温度,但温度的误差也不尽人意,估计这280不是正品的。 |
Y_G_G 发表于 2022-2-23 14:48 不可能一直都没有气压的数据吧。我觉得这东西在正常模式下面,从隐藏寄存器复制气压ADC数据到映射寄存器之前(或许正在转换),映射寄存器应该存储上一次的数据,这个数据暂时是不会被清零的。 |
| 我读取bmp280内部寄存器从0xf3开始的10个字节,然后判断当状态寄存器0xF3的bit3为0时,将这10个字节用串口发送到电脑,依然是那样的结果:气压寄存器的数值为0,温度寄存器有数据。 |
新新科技 发表于 2022-2-23 13:38 我不知道你上面的表格是怎么得来的,是仿真还是串口? 如果能确认你读写的程序都是对的话,那么,你所读取到的0xf3的值是:0x0c,对应的bit3是1,就是"转换正在运行",只有数据已经复制到映射寄存器之后,bit3才会清除 你可能是看错了,是0x0c 而不是你认为的0xc0 |
| 最好不要用串口显示 |
| 要说是转换未完成嘛,0xf3状态寄存器读出的数据是0xc0且温度寄存器已经有了转换后的原始数值。 |
|
BMP280虽然在温度测量方面并不是很精确,但误差一般都是可以在1摄氏度以下的 你这超过2摄氏度了,就要看一下你程序的时序对不对了 读取数据之前要先读取ADC标志位,读取到完成标志位之后,再读取温度和压力,然后再用数据手册中提供的代码进行校正,最后再显示 最好不要用串口显示,直接是OLED或者数码管显示就行 |