熱門(mén): 51單片機(jī) | 24小時(shí)必答區(qū) | 單片機(jī)教程 | 單片機(jī)DIY制作 | STM32 | Cortex M3 | 模數(shù)電子 | 電子DIY制作 | 音響/功放 | 拆機(jī)樂(lè)園 | Arduino | 嵌入式OS | 程序設(shè)計(jì)
![]() |
發(fā)布時(shí)間: 2022-2-23 09:29
正文摘要:最近玩BMP280,發(fā)現(xiàn)測(cè)得的氣溫?cái)?shù)值比正常的高,大約要高出2至3度,而氣壓為0。讀取BMP280內(nèi)部所有寄存器,發(fā)現(xiàn)氣壓寄存器0xF7-0xF9的值均為0,而氣溫寄存器0xFA-0xFC均有氣溫ADC結(jié)果。這是為什么?下面是復(fù)位后和設(shè) ... |
問(wèn)一下溫度偏高解決了沒(méi)有 |
新新科技 發(fā)表于 2022-2-25 12:57 BMP280從機(jī)地址就是0xec的呀,沒(méi)錯(cuò)呀 BMP280_Read函數(shù)呢?里面有沒(méi)有應(yīng)答?每次讀取完一個(gè)字節(jié)的數(shù)據(jù)之后,都要主機(jī)產(chǎn)生一個(gè)應(yīng)答信號(hào)的 0xf3的讀取呢?是不是先讀取這個(gè)寄存器之后再讀取壓力和溫度數(shù)據(jù)的? 給你一個(gè)我的代碼參考一下,這是我?guī)讉(gè)月剛剛開(kāi)始學(xué)C語(yǔ)言的時(shí)候?qū)懙?已經(jīng)驗(yàn)證通過(guò)的了 /*BMP280.c BMP280相關(guān)操作函數(shù) 選擇IIC操作方式,相關(guān)的選擇端口要硬件先選擇好 SDO=0,IIC從機(jī)地址為:0xec(寫(xiě)),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運(yùn)行狀態(tài)位 unsigned short dig_T1; //BMP280校正值保存的相關(guān)地址 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初始化函數(shù) { Delay_ms(100); IIC_start(); Write_byte(Write_BMP280_slave); //從機(jī)地址 Write_byte(0xf4); //寄存器設(shè)置設(shè)備的數(shù)據(jù)采集選項(xiàng)(0xf4) Write_byte(0xf0); //先進(jìn)入休眠模式,完成0xf5的設(shè)置之后再進(jìn)入正常模式 Write_byte(0xf5); //存器設(shè)置設(shè)備的速率、過(guò)濾器和接口選項(xiàng) Write_byte(0x00); // IIR濾波關(guān)閉,0.5mS測(cè)量一次 Write_byte(0xf4); //寄存器設(shè)置設(shè)備的數(shù)據(jù)采集選項(xiàng)(0xf4) Write_byte(0xff); //溫度和壓力都是20位模式,采樣模式為正常模式 IIC_stop(); dig_T1=Read_BMP280_2Byte(0x88); //讀取幾個(gè)校驗(yàn)值 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) //讀取校正值,所有校正值是用兩個(gè)地址存放的,所以就讀取兩個(gè)字節(jié) { short temp; unsigned char Data_LSB,Data_MSB; IIC_start(); Write_byte(Write_BMP280_slave); //從機(jī)地址 Write_byte(BMP280_addr); IIC_start(); Write_byte(Read_BMP280_slave); //從機(jī)地址 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) //讀取測(cè)量值,所有測(cè)量值是用三地址存放的,所以就讀取三個(gè)字節(jié) { long temp; unsigned char Data_XLSB,Data_LSB,Data_MSB; IIC_start(); Write_byte(Write_BMP280_slave); //從機(jī)地址 Write_byte(BMP280_addr); IIC_start(); Write_byte(Read_BMP280_slave); //從機(jī)地址 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數(shù)據(jù) { // double Data; //返回值就是加入校正計(jì)算好的溫度或者壓力值 long adc_data,adc_data_add; //轉(zhuǎn)換結(jié)果保存 unsigned char f,measuring; // // if(Reg_addr==Read_BMP280_temp_msb) //根據(jù)輸入選擇溫度或者氣壓ADC { // for(f=0;f<32;f++) // { // do{measuring=Read_status();} //讀取ADC狀態(tài)位 while(measuring==0x08); // adc_data=Read_BMP280_3Byte(Read_BMP280_temp_msb); //讀取溫度ADC結(jié)果 adc_data_add=adc_data_add+adc_data; //adc結(jié)果相加 } // adc_data_add=adc_data_add/32; //進(jìn)行多次ADC,然后取平均值 Data=bmp280_compensate_T_double(adc_data); //進(jìn)行校正處理 } // else // { // for(f=0;f<128;f++) // { // do{measuring=Read_status();} //讀取ADC狀態(tài)位 while(measuring==0x08); // adc_data=Read_BMP280_3Byte(Read_BMP280_press_msb); //讀取氣壓ADC結(jié)果 adc_data_add=adc_data_add+adc_data; //adc結(jié)果相加 } // adc_data_add=adc_data_add/128; //進(jìn)行多次ADC,然后取平均值 Data=bmp280_compensate_P_double(adc_data); //進(jìn)行校正處理 } return Data; } //================================================================================================= double bmp280_compensate_T_double(long adc_T) //數(shù)據(jù)手冊(cè)復(fù)制過(guò)來(lái)的,溫度和校正值的計(jì)算 { 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) //數(shù)據(jù)手冊(cè)復(fù)制過(guò)來(lái)的氣壓和校正值的計(jì)算 { 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() //讀取狀態(tài)位,檢測(cè)ADC是否完成 { unsigned char temp; IIC_start(); Write_byte(Write_BMP280_slave); //從機(jī)地址 Write_byte(Read_BMP280_Status); //讀取ADC運(yùn)行狀態(tài)位 IIC_start(); Write_byte(Read_BMP280_slave); //從機(jī)地址 temp=read_byte(); IIC_Nask(); IIC_stop(); return temp; } //================================================================================================= |
本帖最后由 新新科技 于 2022-2-25 13:29 編輯 手冊(cè)提供的BMP280器件地址是0x76,而手頭這模塊是0xec,莫非不是BMP280? |
//關(guān)鍵源碼如下: #define BMP280_Address 0xec //器件地址 #define BMP280_TEMP_ADDR 0xfa //溫度寄存器 #define BMP280_PRESS_ADDR 0xf7 //氣壓寄存器 //校正參數(shù) 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) //讀取三個(gè)字節(jié) { 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) //讀取兩個(gè)字節(jié) { 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; } |
新新科技 發(fā)表于 2022-2-24 10:52 在95%的情況下,是代碼的問(wèn)題,跟BMP280是不是正品是沒(méi)有關(guān)系的 在第一個(gè)表格中,復(fù)位后的值是和280數(shù)據(jù)手冊(cè)上是一樣的 0xf3的數(shù)據(jù)是0xC0,就說(shuō)明轉(zhuǎn)換沒(méi)有完成,這一點(diǎn)很重要,只要是轉(zhuǎn)換沒(méi)有完成的,讀取的數(shù)據(jù)就有可能是任何數(shù)據(jù),去分析太多是沒(méi)有意義的 一定要轉(zhuǎn)換完成之后,馬上讀取6個(gè)溫度的壓力數(shù)據(jù),期間不要有太長(zhǎng)時(shí)間的延時(shí),如果你連續(xù)轉(zhuǎn)換模式,ADC轉(zhuǎn)換和數(shù)據(jù)改變是同時(shí)進(jìn)行的,也就是說(shuō)ADC邊進(jìn)行,邊改變溫度和壓力寄存器的值,這個(gè)在數(shù)據(jù)手冊(cè)中是有說(shuō)明的 還有,最好不要用串口,先用數(shù)碼管或者OLED進(jìn)行驗(yàn)證 如果還不行,就把代碼上傳 |
知道是什么原因了,昨晚試了三個(gè)模塊,發(fā)現(xiàn)的確是芯片的問(wèn)題,其他兩個(gè)模塊雖然能測(cè)量氣壓和溫度,但溫度的誤差也不盡人意,估計(jì)這280不是正品的。 |
Y_G_G 發(fā)表于 2022-2-23 14:48 不可能一直都沒(méi)有氣壓的數(shù)據(jù)吧。我覺(jué)得這東西在正常模式下面,從隱藏寄存器復(fù)制氣壓ADC數(shù)據(jù)到映射寄存器之前(或許正在轉(zhuǎn)換),映射寄存器應(yīng)該存儲(chǔ)上一次的數(shù)據(jù),這個(gè)數(shù)據(jù)暫時(shí)是不會(huì)被清零的。 |
我讀取bmp280內(nèi)部寄存器從0xf3開(kāi)始的10個(gè)字節(jié),然后判斷當(dāng)狀態(tài)寄存器0xF3的bit3為0時(shí),將這10個(gè)字節(jié)用串口發(fā)送到電腦,依然是那樣的結(jié)果:氣壓寄存器的數(shù)值為0,溫度寄存器有數(shù)據(jù)。 |
新新科技 發(fā)表于 2022-2-23 13:38 我不知道你上面的表格是怎么得來(lái)的,是仿真還是串口? 如果能確認(rèn)你讀寫(xiě)的程序都是對(duì)的話,那么,你所讀取到的0xf3的值是:0x0c,對(duì)應(yīng)的bit3是1,就是"轉(zhuǎn)換正在運(yùn)行",只有數(shù)據(jù)已經(jīng)復(fù)制到映射寄存器之后,bit3才會(huì)清除 你可能是看錯(cuò)了,是0x0c 而不是你認(rèn)為的0xc0 |
最好不要用串口顯示 |
要說(shuō)是轉(zhuǎn)換未完成嘛,0xf3狀態(tài)寄存器讀出的數(shù)據(jù)是0xc0且溫度寄存器已經(jīng)有了轉(zhuǎn)換后的原始數(shù)值。 |
BMP280雖然在溫度測(cè)量方面并不是很精確,但誤差一般都是可以在1攝氏度以下的 你這超過(guò)2攝氏度了,就要看一下你程序的時(shí)序?qū)Σ粚?duì)了 讀取數(shù)據(jù)之前要先讀取ADC標(biāo)志位,讀取到完成標(biāo)志位之后,再讀取溫度和壓力,然后再用數(shù)據(jù)手冊(cè)中提供的代碼進(jìn)行校正,最后再顯示 最好不要用串口顯示,直接是OLED或者數(shù)碼管顯示就行 |
Powered by 單片機(jī)教程網(wǎng)