MS5837是一个是超紧凑型 SMT 安装数字压力传感器。
可用于测高计和气压计应用,且采用凝胶填充设计,可提供 13 cm 海拔刻度。 典型应用包括:健身跟踪仪、移动测高计/气压计系统、自行车码表、个人导航设备、多运动手表和轮胎压力计,水深压力传感。
但是网上找不到合适的源代码,只有C++代码。花了半天时间把C++改写成了C & lua,适合STM32使用,keil开发,HAL库。废话不说直接上源码。
未经同意,禁止转载。
/**
******************************************************************************
* @file MS5837.c
* @brief This file provides code for the configuration
* of the MS5837.
******************************************************************************
* @attention
*
* Copyright LEO.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#include "MS5837.h"
uint16_t MS5837_C[8];
uint32_t MS5837_D1, MS5837_D2;
struct MS5837RES MS5837;//temperature in 0.001 degree
//pressure in mbar
void MS5837_calculate(void);
uint8_t MS5837_crc4(uint16_t n_prom[]);
void delay_ms(int32_t nms);
/* USER CODE BEGIN MS5837 */
//return 0-ok, 1-crcFail, 2-i2cError
int MS5837_init(void) //i2c init first
{
uint8_t msg[] = {MS5837_RESET};
uint8_t data[2] = {0};
uint16_t val = 0;
// Reset the MS5837, per datasheet
if(HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)MS5837_ADDR, msg, 1, 50) != 0)
{
//printf("I2C ERROR\n");
return 2;
}
// Wait for reset to complete
delay_ms(10);
// Read calibration values and CRC
for ( uint8_t i = 0 ; i < 7 ; i++ )
{
msg[0] = MS5837_PROM_READ + i*2;
HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)MS5837_ADDR, msg, 1, 50);
HAL_I2C_Master_Receive(&hi2c1, (uint16_t)MS5837_ADDR, data, 2, 50);
MS5837_C[i] = (data[0] << 8) | data[1];
val = val | MS5837_C[i];
//printf("C%d:%d \r\n",i,MS5837_C[i]);
}
// Verify that data is correct with CRC
uint8_t crcRead = MS5837_C[0] >> 11;
uint8_t crcCalculated = MS5837_crc4(MS5837_C);
//printf("val %d",val);
if ( (crcCalculated == crcRead) && (val)) {
return 0; // Initialization success
}
return 1; // CRC fail
}
struct MS5837RES MS5837_read(void) //read after init
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET);
delay_ms(50);
HAL_I2C_MspInit(&hi2c1);
if(MS5837_init() == 0)
{
uint8_t msg[] = {MS5837_CONVERT_D1_8192};
uint8_t data[3];
// Request D1 conversion
HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)MS5837_ADDR, msg, 1, 0xff);
//HAL_Delay(20);//
HAL_Delay(20);//delay_ms(20); // Max conversion time per datasheet
msg[0] = MS5837_ADC_READ;
HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)MS5837_ADDR, msg, 1, 0xff);
HAL_I2C_Master_Receive(&hi2c1, (uint16_t)MS5837_ADDR, data, 3, 0xff);
MS5837_D1 = 0;
//MS5837_D1 = (data[0] << 16) | (data[1] << 8) | data[2];
MS5837_D1 = (data[0] << 16) | (data[1] << 8) | data[2];
//printf("d1 :%d \r\n",MS5837_D1);
// Request D2 conversion
msg[0] = MS5837_CONVERT_D2_8192;
HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)MS5837_ADDR, msg, 1, 0xff);
HAL_Delay(20);//delay_ms(20); // Max conversion time per datasheet
msg[0] = MS5837_ADC_READ;
HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)MS5837_ADDR, msg, 1, 0xff);
HAL_I2C_Master_Receive(&hi2c1, (uint16_t)MS5837_ADDR, data, 3, 0xff);
HAL_I2C_MspDeInit(&hi2c1);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);
MS5837_D2 = 0;
MS5837_D2 = (data[0] << 16) | (data[1] << 8) | data[2];
//printf("d2 :%d \r\n",MS5837_D2);
MS5837_calculate();//output MS5837 (with temperature and pressure)
return MS5837;
}else{
HAL_I2C_MspDeInit(&hi2c1);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);
MS5837.TEMP = 0;
MS5837.P = 0;
return MS5837;
}
}
void MS5837_calculate(void)
{
// Given C1-C6 and D1, D2, calculated TEMP and P
// Do conversion first and then second order temp compensation
int32_t dT = 0;
int64_t SENS = 0;
int64_t OFF = 0;
int32_t SENSi = 0;
int32_t OFFi = 0;
int32_t Ti = 0;
int64_t OFF2 = 0;
int64_t SENS2 = 0;
// Terms called
dT = MS5837_D2 - (uint32_t)(MS5837_C[5]) * 256l;
SENS = (int64_t)(MS5837_C[1]) * 32768l+((int64_t)(MS5837_C[3]) * dT)/256l;
OFF = (int64_t)(MS5837_C[2]) * 65536l+((int64_t)(MS5837_C[4]) * dT)/128l;
MS5837.P = (MS5837_D1 * SENS/(2097152l) - OFF)/(8192l);
// Temperature conversion
MS5837.TEMP = 2000l + (int64_t)(dT) * MS5837_C[6] / 8388608LL;
//Second order compensation
if((MS5837.TEMP/100)<20){ //Low temp
Ti = (3 * (int64_t)(dT)*(int64_t)(dT))/(8589934592LL);
OFFi = (3 * (MS5837.TEMP-2000) * (MS5837.TEMP-2000))/2;
SENSi = (5 * (MS5837.TEMP-2000) * (MS5837.TEMP-2000))/8;
if((MS5837.TEMP/100) < -15){ //Very low temp
OFFi = OFFi + 7 * (MS5837.TEMP + 1500l) * (MS5837.TEMP + 1500l);
SENSi = SENSi + 4 * (MS5837.TEMP + 1500l) * (MS5837.TEMP + 1500l);
}
}else if((MS5837.TEMP / 100) >= 20){ //High temp
Ti = 2 * (dT * dT) / (137438953472LL);
OFFi = (1 * (MS5837.TEMP - 2000) * (MS5837.TEMP - 2000))/16;
SENSi = 0;
}
OFF2 = OFF - OFFi; //Calculate pressure and temp second order
SENS2 = SENS - SENSi;
MS5837.TEMP = (MS5837.TEMP - Ti);
MS5837.P = (((MS5837_D1 * SENS2) / 2097152l - OFF2) / 8192l);
//printf("P :%d \r\n",MS5837.P);
//printf("T :%d \r\n",MS5837.TEMP );
}
uint8_t MS5837_crc4(uint16_t n_prom[]) {
uint16_t n_rem = 0;
n_prom[0] = ((n_prom[0]) & 0x0FFF);
n_prom[7] = 0;
for ( uint8_t i = 0 ; i < 16; i++ ) {
if ( i%2 == 1 ) {
n_rem ^= (uint16_t)((n_prom[i>>1]) & 0x00FF);
} else {
n_rem ^= (uint16_t)(n_prom[i>>1] >> 8);
}
for ( uint8_t n_bit = 8 ; n_bit > 0 ; n_bit-- ) {
if ( n_rem & 0x8000 ) {
n_rem = (n_rem << 1) ^ 0x3000;
} else {
n_rem = (n_rem << 1);
}
}
}
n_rem = ((n_rem >> 12) & 0x000F);
return n_rem ^ 0x00;
}
//delay function, just delay
void delay_ms(int32_t nms)
{
int i=0;
while(nms--)
{
i=2000;
while(i--);
}
}