采用 SPI通訊方式驅(qū)動MS5607睹簇,主控用的是STM32F777
程序是利用STM32CUBEMX生成的 驅(qū)動 根據(jù)芯片手冊和一些參考資料自己寫的扯夭,數(shù)據(jù)暫時看是沒問題的械媒。
沒有測試環(huán)境 沒有系統(tǒng)測試過劲妙。
1限府,上電初始化MS5607:主要是復位芯片 然后讀出prom校準數(shù)據(jù)(C1-C6)
向spi總線發(fā)送0x1e,復位芯片
void MX56XX_Ba_Reset(void)
{
uint8_t _cmd=0x1e;
MS5607_SPI_CS(0);
MS56XX_ReadWriteByte(_cmd);
MS5607_SPI_CS(1);
delay_xms(3);
}
然后讀取prom校準數(shù)據(jù),這個數(shù)據(jù)是廠商寫好的 供汛,只需要開機上電讀取一次就行枪汪。
prom read地址從0xA0到0xAE 。
void MX56XX_Read_Prom_Data(void)
{
uint8_t _cmd;
uint8_t _ctr;
uint8_t _buff[2];
_cmd = 0xa0; //prom首地址
for(_ctr = 0;_ctr<8;_ctr++)
{
MS5607_SPI_CS(0);
MS56XX_ReadWriteByte(_cmd);
_buff[0] = MS56XX_ReadWriteByte(0XFF);
_buff[1] = MS56XX_ReadWriteByte(0XFF);
Cal_C[_ctr]=(_buff[0]<<8)+_buff[1];
_cmd += 0x02;
MS5607_SPI_CS(1);
}
}
這里有個地方需要注意 怔昨,下圖是prom的內(nèi)存映射雀久。
之前讀取的數(shù)據(jù)一直不對,以為數(shù)據(jù)C1的地址是0xa0趁舀,后來看了手冊后才知道還有制造商的信息赖捌。
從prom的內(nèi)存映射可以看出,prom的首地址 存放的是制造商的數(shù)據(jù)和設備信息 矮烹,地址 1-6是校準數(shù)據(jù)c1-c6越庇,地址7是4bit的crc校驗信息。
所以 這就是循環(huán)讀取8次的原因擂送,然后Cal_C[1]~Cal_C[6] 就對應了的C1~C6的校準數(shù)據(jù)悦荒。Cal_C[7]是CRC校驗數(shù)據(jù),可以進行驗證通信使用嘹吨。
還有就是C1~C6的數(shù)據(jù)是16位的 搬味,我用的SPI讀取是讀一個字節(jié),所以 連續(xù)讀取兩次在組成16位的數(shù)據(jù)在用就可以了蟀拷。
2 以上初始化完成以后碰纬,接下來就是循環(huán)讀取D1,D2的值 然后用公式計算 數(shù)字溫度和壓強。
讀地址是ADC Rread 0x00问芬。
D1 的分辨率 OSR=4096 地址 0x48
D2的分辨率 OSR=4096 地址 0x58
計算公式和變量信息悦析。
讀D1
uint8_t _presbuf[3];
uint32_t MS56XX_Do_Conversion_Pres(void) //數(shù)據(jù)讀取
{
uint8_t _cmd=0X48;
uint32_t _D1;
// uint8_t _buf[4];
MS5607_SPI_CS(0);
MS56XX_ReadWriteByte(_cmd); //0x48 -->D1 OSR=4096
MS5607_SPI_CS(1);
MS56XX_Read_Buf(0x00,_presbuf,3);
_D1=(_presbuf[0]<<16)+ (_presbuf[1]<<8) +(_presbuf[2]);//讀取adc值
//_D1=_buf[0]<<24 | buf[1]<<16 |buf[2]<<8 | buf[3];//讀取adc值
return _D1;
}
讀D2
uint8_t _tempbuf[3];
uint32_t MS56XX_Do_Conversion_Temp(void) //數(shù)據(jù)讀取
{
uint8_t _cmd=0X58;
uint32_t _D2;
MS5607_SPI_CS(0);
MS56XX_ReadWriteByte(_cmd); //0x58 -->D2 OSR=4096
MS5607_SPI_CS(1);
MS56XX_Read_Buf(0x00,_tempbuf,3);
_D2=(_tempbuf[0]<<16)+ (_tempbuf[1]<<8) +(_tempbuf[2]);//讀取adc值
return _D2;
}
//讀取并計算數(shù)字溫度
char MS56XX_GetTemperature (void) //計算溫度
{
D2_Temp = MS56XX_Do_Conversion_Temp ( ); //循環(huán)讀取 D1 D2
if(D2_Temp == 0)
return 0;
delay_ms ( 10 );
if(D2_Temp > ( ( uint32_t ) Cal_C[5] * (0x00000001 << 8) ))
dT = D2_Temp - ( ( uint32_t ) Cal_C[5] * (0x00000001 << 8) ); //公式 dT = D2 - TREF = D2 - C5 * 2^8
else
{
dT = ( ( uint32_t ) Cal_C[5] * (0x00000001 << 8) ) - D2_Temp;
dT *= -1;
}
Temperature = 2000 + ( dT * Cal_C[6] ) / (0x00000001 << 23); //算出溫度值的100倍,2001表示20.01° 公式TEMP =20°C + dT * TEMPSENS =2000 + dT * C6 / 2^23
if(Temperature<-4000) Temperature=-4000;
if(Temperature>8500) Temperature=8500;
return 1;
}
讀取并計算數(shù)字氣壓
char MS56XX_GetPressure (void) //計算溫度補償壓力
{
D1_Pres = MS56XX_Do_Conversion_Pres ( ); //循環(huán)讀取 D1 D2
if(D1_Pres == 0)
return 0;
delay_xms ( 10 );
OFF = ( ( int64_t )Cal_C[2] * (0x00000001 << 17) ) + ( ( int64_t ) Cal_C[4] * dT ) / 64.0; //公式 OFF = OFFT1 + TCO *dT = C2 *2^17 +(C4 *dT )/ 2^6
SENS = ( ( int64_t ) Cal_C[1] * (0x00000001 << 16) ) + ( ( int64_t ) Cal_C[3] * dT ) / 128.0; //公式SENS = SENST1 + TCS* dT= C1 * 2^16 + (C3 * dT )/ 2^7
//溫度補償部分 邏輯看芯片手冊
if ( Temperature < 2000 ) // second order temperature compensation when under 20 degrees C
{
T2 = ( dT * dT ) / (( uint64_t )0x0000000001 << 31);
OFF2 = 61 * (( Temperature - 2000 ) * ( Temperature - 2000 )) / 16;
SENS2 = 2 * (( Temperature - 2000 ) * ( Temperature - 2000 )) ;
if ( Temperature < -1500 )
{
OFF2 = OFF2 + 15 * (( Temperature + 1500 ) * ( Temperature + 1500 )) ;
SENS2 = SENS2 + 8 * (( Temperature + 1500 ) * ( Temperature + 1500 )) ;
}
}
else //(Temperature > 2000)
{
T2 = 0;
OFF2 = 0;
SENS2 = 0;
}
Temperature = Temperature - T2;
OFF = OFF - OFF2;
SENS = SENS - SENS2;
Pressure = ( D1_Pres * SENS / (0x00000001 << 21) - OFF ) / (0x00000001 << 15); //公式 P = D1 * SENS - OFF = (D1 * SENS / 2^21 - OFF) / 2^15
Ms5607.Temperature=(float)Temperature/100; //單位 ℃
Ms5607.Pressure=(float)Pressure/100; //單位 mbar
if(Ms5607.Temperature<-40) Ms5607.Temperature=-40;
if(Ms5607.Temperature>85) Ms5607.Temperature=85;
if(Ms5607.Pressure<10) Ms5607.Pressure=10;
if(Ms5607.Pressure>1200) Ms5607.Pressure=1200;
printf("Pressure=%4f mbar\r\n",Ms5607.Pressure);
return 1;
}
溫度補償部分的邏輯
補充1
/********************************************************************************
** 1MPa=1000,000Pa=10bar=10000mbar hPa(百帕)=mbar(毫巴)此衅。
** 每提高12m强戴,大氣壓下降1mmHg(1毫升水銀柱)或者每上升9m,大氣壓降低100Pa挡鞍。
** 例如已知氣壓970hpa,如何求出海拔是多少骑歹? 標準大氣壓為1013.25百帕(hpa)
** 所以,海拔高度為h=(1013.25-970)*9=389.25(米)墨微。
********************************************************************************/
補充2
SPI時序:在分辨率=4096的是時候 adc的轉換時間是8.22ms 所以要留夠延時時序道媚。
D1和D2雖然變量定義是32的 但是實際讀取字節(jié)的時候是讀取24bit的數(shù)據(jù),也就是3個字節(jié)的數(shù)據(jù)。
//SPI 讀寫一個字節(jié)
//TxData:要寫入的字節(jié)
//返回值:讀取到的字節(jié)
uint8_t MS56XX_ReadWriteByte(uint8_t TxData)
{
uint8_t Rxdata;
HAL_SPI_TransmitReceive(&hspi2,&TxData,&Rxdata,1, 1000);
return Rxdata; //返回收到的數(shù)據(jù)
}
uint8_t MS56XX_Read_Buf(uint8_t reg ,uint8_t *pbuf,uint8_t len)//參數(shù)說明 發(fā)送寄存器位置 讀取指定長度的數(shù)據(jù) 放在pbuf里
{
u8 status,_ctr;
MS5607_SPI_CS(0);
delay_xms(9);//預留給ad轉換時間最域,因為osr=4096分辨率 時序上轉換時間約為8.2ms
status=MS56XX_ReadWriteByte(reg); //發(fā)送寄存器位置
for(_ctr=0;_ctr<len;_ctr++)
{
pbuf[_ctr] = MS56XX_ReadWriteByte(0XFF);
}
MS5607_SPI_CS(1);
return status;//返回收到的數(shù)據(jù)
}
uint8_t MS56XX_Write_Buf(u8 reg, u8 *pBuf, u8 len)//參數(shù)說明 發(fā)送寄存器位置 寫指定長度的數(shù)據(jù)
{
u8 status,_ctr;
MS5607_SPI_CS(0); //使能 SPI 傳輸
status = MS56XX_ReadWriteByte(reg); //發(fā)送寄存器值(位置),并讀取狀態(tài)值
for(_ctr=0; _ctr<len; _ctr++)
{
MS56XX_ReadWriteByte(*pBuf++); //寫入數(shù)據(jù)
}
MS5607_SPI_CS(1); //關閉 SPI 傳輸
return status; //返回讀到的狀態(tài)值
}
結果
筆者在調(diào)試時谴分,參考了以下博文,向這些博主及作者表示感謝镀脂!
MS56XX:
https://blog.csdn.net/zhxlx/article/details/93984496
https://bbs.21ic.com/icview-1722818-1-3.html