压力温度传感器MS5837-C语言-适用于STM32,HAL库

文章提供了将C++代码改写成适用于STM32、基于HAL库和Keil开发的压力传感器MS5837的C/Lua源代码。该传感器用于高度计、气压计等应用,代码包括初始化、数据读取和CRC校验功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 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--);    
   }
}


### STM32 HAL与DS18B20温度传感器交互的方法 #### 初始化配置 为了使STM32能够通过HAL读取来自DS18B20的数据,初始化阶段至关重要。这涉及到硬件连接以及软件上的GPIO和I/O口配置。 对于单线协议的一线总线设备如DS18B20来说,在初始化过程中需要特别注意的是设置好用于通信的那个IO端口,并确保其工作模式被设定为开漏输出或者推挽输出以便于实现上拉电阻的功能[^2]。 ```c // GPIO Initialization Function static void MX_GPIO_Init(void) { /* Configure the GPIO pins */ GPIO_InitTypeDef GPIO_InitStruct = {0}; // Enable GPIO Clock __HAL_RCC_GPIOA_CLK_ENABLE(); // Configure PA0 as output push-pull mode for OneWire bus of DS18B20 GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } ``` #### 数据传输过程中的延时处理 由于DS18B20的操作依赖严格的时序控制来完成数据交换,因此在编写程序时还需要加入精确到微秒级别的延迟函数以满足这些需求。这里给出了一种基于定时器中断的方式来进行亚毫秒级的时间等待: ```c void DelayUs(uint16_t us) { TIM_HandleTypeDef tim_handle; htim.Instance = TIM2; // Choose your timer instance here. __HAL_TIM_SET_COUNTER(&htim, 0); // Set counter value to 0 __HAL_TIM_ENABLE(&htim); // Start counting up while (__HAL_TIM_GET_COUNTER(&htim) < us);// Wait until enough counts have passed __HAL_TIM_DISABLE(&htim); // Stop timing after delay is over } ``` 此部分代码实现了对指定时间长度内的循环等待操作,从而可以用来模拟所需的短暂停顿效果[^3]。 #### 主逻辑流程设计 当一切准备就绪之后就可以按照如下方式构建主应用程序框架了:先发送复位脉冲给DS18B20唤醒它;接着发出ROM命令选择特定器件;最后再执行转换指令并获取测量结果返回给MCU做进一步分析处理。 ```c #include "stm32f4xx_hal.h" #define ONE_WIRE_PORT GPIOA #define ONE_WIRE_PIN GPIO_PIN_0 int main(void){ uint8_t rom_code[8]; // Store ROM code read from sensor HAL_Init(); SystemClock_Config(); // Initialize system clock configuration MX_GPIO_Init(); // Call our custom initialization function above // Reset and detect presence pulse on one-wire line OW_Reset(ONE_WIRE_PORT, ONE_WIRE_PIN); // Skip ROM command or match specific device's address if multiple sensors are connected OW_WriteByte(SKIP_ROM_CMD); // Request temperature conversion start OW_WriteByte(CONVERT_T_CMD); // Wait some time before reading back data... DelayMs(750); // Conversion takes about ~750ms at most resolutions // Read scratchpad memory containing raw temp readings etc. OW_ReadScratchPad(temp_data_array); // Process received bytes into actual Celsius degrees float number... while (1){} // Infinite loop waiting for user interaction } // Note: The functions like `OW_Reset`, `OW_WriteByte` should be implemented according to datasheet specifications. ``` 上述代码片段展示了如何利用STM32 HAL配合简单的C语言编程技巧去访问外部接驳的DS18B20数字温度计芯片,并从中提取有用的环境参数信息.
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值