基于STM32标准库的多个相同设备并行数据读取——MS5837传感器

目录

一、硬件电路设计

二、并行程序设计

1、I2C底层协议改写

2、MS5837程序移植

3、中断函数编写

4、代码测试


一、硬件电路设计

本项目使用的传感器是MS5837-02BA压力传感器,采用I2C通信协议。为了节省stm32f4的引脚资源,将所有的传感器SCL挂在公共的总线上,通过SDA信号线来区分从机设备。自己在主板上做了接口,在拓展板上接插传感器。一共使用到11个MS5837压力传感器。

对于多个从机设备挂在一个总线上的情况,单片机内部上拉的驱动能力可能不够,需要加上拉电阻,否则会因为驱动能力不足导致通信失败。对于上拉电阻的选择,如果阻值过小,VDD灌入端口的电流将较大,这导致端口输出的低电平值增大(I2C协议规定,端口输出低电平的最高允许值为0.4V),甚至损坏端口。但对于多从机设备的总线,可以选择较小的上拉电阻,为每个设备提供足够的电流,通常上拉电阻应选取不低于1KΩ的电阻。同时上拉电阻阻值不宜过大,一般不高于10KΩ。否则线上等效负载电容较大会导致电平变化缓慢,I2C底层通信错误。因此一般选取4.7KΩ的电阻。

硬件实物图:

二、并行程序设计

1、I2C底层协议改写

I2C总线上如果挂在多个相同从机设备,地址是相同的,所以不能通过轮询地址的方式来依次和从机通信。这时需要通过轮询使能SDA,公共总线SCL_Pub保持和各个设备的正常连接。

(1)编写头文件“myiic.h”如下

尽可能使用宏定义来区分各个从机的I2C操作

#ifndef __MYIIC_H
#define __MYIIC_H
#include "sys.h" 
  	   		   

//IO操作	 
#define IIC_SCL     PAout(2) //SCL
#define IIC_SDA1    PCout(0) //SDA1	 
#define READ_SDA1   PCin(0)  //输入SDA1 
#define IIC_SDA2    PCout(1) //SDA2	 
#define READ_SDA2   PCin(1)  //输入SDA2 
#define IIC_SDA3    PCout(2) //SDA3	 
#define READ_SDA3   PCin(2)  //输入SDA3 
#define IIC_SDA4    PCout(3) //SDA4	 
#define READ_SDA4   PCin(3)  //输入SDA4 
#define IIC_SDA5    PCout(4) //SDA5 
#define READ_SDA5   PCin(4)  //输入SDA5
#define IIC_SDA6    PCout(5) //SDA6	 
#define READ_SDA6   PCin(5)  //输入SDA6
#define IIC_SDA7    PAout(3) //SDA7	 
#define READ_SDA7   PAin(3)  //输入SDA7 
#define IIC_SDA8    PAout(15) //SDA8 
#define READ_SDA8   PAin(15)  //输入SDA8 
#define IIC_SDA9    PBout(12) //SDA9 
#define READ_SDA9   PBin(12)  //输入SDA9
#define IIC_SDA10    PBout(13) //SDA10	 
#define READ_SDA10   PBin(13)  //输入SDA10 
#define IIC_SDA11    PDout(3) //SDA11	 
#define READ_SDA11   PDin(3)  //输入SDA11 
//IIC所有操作函数
void SDA_IN(void);
void SDA_OUT(void);
void IIC_Init(void);                //IIC初始化				 
void IIC_Start(void);				//发送IIC信号
void IIC_Stop(void);	  			//发送IIC停止信号
void IIC_Send_Byte(u8 txd);			//IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void); 				//IIC等待ACK信号
void IIC_Ack(void);					//IIC发送ACK信号
void IIC_NAck(void);				//IIC不发送IIC信号

void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 IIC_Read_One_Byte(u8 daddr,u8 addr);	  
#endif
















(2)编写 c文件“myiic.c”如下

从新定义底层函数,使用flag来区分各个从机的数据线SDA

#include "myiic.h"
#include "delay.h"
#include "sys.h" 
u16 flag=1; //定义一个全局变量flag来选择不同的压强传感器

void SDA_IN(void) 
{
	if(flag==1) {GPIOC->MODER&=~(3<<(0*2));GPIOC->MODER|=0<<0*2;} //SDA1_PC0
	else if(flag==2) {GPIOC->MODER&=~(3<<(1*2));GPIOC->MODER|=0<<1*2;}//SDA2_PC1
	else if(flag==3) {GPIOC->MODER&=~(3<<(2*2));GPIOC->MODER|=0<<2*2;}//SDA3_PC2
	else if(flag==4) {GPIOC->MODER&=~(3<<(3*2));GPIOC->MODER|=0<<3*2;}//SDA4_PC3
	else if(flag==5) {GPIOC->MODER&=~(3<<(4*2));GPIOC->MODER|=0<<4*2;}//SDA5_PC4
	else if(flag==6) {GPIOC->MODER&=~(3<<(5*2));GPIOC->MODER|=0<<5*2;}//SDA6_PC5
	else if(flag==7) {GPIOE->MODER&=~(3<<(3*2));GPIOE->MODER|=0<<3*2;}//SDA7_PE3
	else if(flag==8) {GPIOA->MODER&=~(3<<(15*2));GPIOA->MODER|=0<<15*2;}//SDA8_PA15
	else if(flag==9) {GPIOB->MODER&=~(3<<(12*2));GPIOB->MODER|=0<<12*2;}//SDA9_PB12
	else if(flag==10) {GPIOB->MODER&=~(3<<(13*2));GPIOB->MODER|=0<<13*2;}//SDA10_PB13
	else if(flag==11) {GPIOD->MODER&=~(3<<(3*2));GPIOD->MODER|=0<<3*2;}//SDA11_PD3
}

void SDA_OUT(void)
{
	if(flag==1) {GPIOC->MODER&=~(3<<(0*2));GPIOC->MODER|=1<<0*2;} //SDA1_PC0
	else if(flag==2) {GPIOC->MODER&=~(3<<(1*2));GPIOC->MODER|=1<<1*2;}//SDA2_PC1
	else if(flag==3) {GPIOC->MODER&=~(3<<(2*2));GPIOC->MODER|=1<<2*2;}//SDA3_PC2
	else if(flag==4) {GPIOC->MODER&=~(3<<(3*2));GPIOC->MODER|=1<<3*2;}//SDA4_PC3
	else if(flag==5) {GPIOC->MODER&=~(3<<(4*2));GPIOC->MODER|=1<<4*2;}//SDA5_PC4
	else if(flag==6) {GPIOC->MODER&=~(3<<(5*2));GPIOC->MODER|=1<<5*2;}//SDA6_PC5
	else if(flag==7) {GPIOE->MODER&=~(3<<(3*2));GPIOE->MODER|=1<<3*2;}//SDA7_PE3
	else if(flag==8) {GPIOA->MODER&=~(3<<(15*2));GPIOA->MODER|=1<<15*2;}//SDA8_PA15
	else if(flag==9) {GPIOB->MODER&=~(3<<(12*2));GPIOB->MODER|=1<<12*2;}//SDA9_PB12
	else if(flag==10) {GPIOB->MODER&=~(3<<(13*2));GPIOB->MODER|=1<<13*2;}//SDA10_PB13
	else if(flag==11) {GPIOD->MODER&=~(3<<(3*2));GPIOD->MODER|=1<<3*2;}//SDA11_PD3
}
//产生I2C信号
void IIC_Start(void)
{
	SDA_OUT();     //SDA线输出
	if(flag==1){IIC_SDA1=1;}
	else if(flag==2){IIC_SDA2=1;}
	else if(flag==3){IIC_SDA3=1;}
	else if(flag==4){IIC_SDA4=1;}
	else if(flag==5){IIC_SDA5=1;}
	else if(flag==6){IIC_SDA6=1;}
	else if(flag==7){IIC_SDA7=1;}
	else if(flag==8){IIC_SDA8=1;}
	else if(flag==9){IIC_SDA9=1;}
	else if(flag==10){IIC_SDA10=1;}
	else if(flag==11){IIC_SDA11=1;}	
	delay_us(1);	
	IIC_SCL=1;
	delay_us(4);
	if(flag==1){IIC_SDA1=0;}
	else if(flag==2){IIC_SDA2=0;}
	else if(flag==3){IIC_SDA3=0;}
	else if(flag==4){IIC_SDA4=0;}
	else if(flag==5){IIC_SDA5=0;}
	else if(flag==6){IIC_SDA6=0;}
	else if(flag==7){IIC_SDA7=0;}
	else if(flag==8){IIC_SDA8=0;}
	else if(flag==9){IIC_SDA9=0;}
	else if(flag==10){IIC_SDA10=0;}
	else if(flag==11){IIC_SDA11=0;}//START:when CLK is high,DATA change form high to low 
	delay_us(4);
	IIC_SCL=0;//钳住I2C总线,准备发送或接收数据

}	  
//产生I2C停止信号
void IIC_Stop(void)
{
	SDA_OUT();//SDA线输出
	IIC_SCL=0;
	delay_us(1);
	if(flag==1){IIC_SDA1=0;}
	else if(flag==2){IIC_SDA2=0;}
	else if(flag==3){IIC_SDA3=0;}
	else if(flag==4){IIC_SDA4=0;}
	else if(flag==5){IIC_SDA5=0;}
	else if(flag==6){IIC_SDA6=0;}
	else if(flag==7){IIC_SDA7=0;}
	else if(flag==8){IIC_SDA8=0;}
	else if(flag==9){IIC_SDA9=0;}
	else if(flag==10){IIC_SDA10=0;}
	else if(flag==11){IIC_SDA11=0;}//STOP:when CLK is high DATA change form low to high
 	delay_us(4);
	IIC_SCL=1; 
	delay_us(4);//当SCL为高时,SDA由低变高,延时等待SCL变高
	if(flag==1){IIC_SDA1=1;}
	else if(flag==2){IIC_SDA2=1;}
	else if(flag==3){IIC_SDA3=1;}
	else if(flag==4){IIC_SDA4=1;}
	else if(flag==5){IIC_SDA5=1;}
	else if(flag==6){IIC_SDA6=1;}
	else if(flag==7){IIC_SDA7=1;}
	else if(flag==8){IIC_SDA8=1;}
	else if(flag==9){IIC_SDA9=1;}
	else if(flag==10){IIC_SDA10=1;}
	else if(flag==11){IIC_SDA11=1;}//发送I2C总线结束信号		
	delay_us(4);	
}
//等待应答信号到来
//返回值:1,接收应答失败
//       0,接收应答成功
uint8_t IIC_Wait_Ack(void)
{
	uint8_t ucErrTime=0;
	SDA_IN();      //SDA设置为输入 
	if(flag==1){IIC_SDA1=1;}
	else if(flag==2){IIC_SDA2=1;}
	else if(flag==3){IIC_SDA3=1;}
	else if(flag==4){IIC_SDA4=1;}
	else if(flag==5){IIC_SDA5=1;}
	else if(flag==6){IIC_SDA6=1;}
	else if(flag==7){IIC_SDA7=1;}
	else if(flag==8){IIC_SDA8=1;}
	else if(flag==9){IIC_SDA9=1;}
	else if(flag==10){IIC_SDA10=1;}
	else if(flag==11){IIC_SDA11=1;}
	delay_us(4);	   
	IIC_SCL=1;
	delay_us(4);
	if(flag==1){
		while(READ_SDA1)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	}
	else if(flag==2){while(READ_SDA2)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}}
	else if(flag==3){while(READ_SDA3)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}}
	else if(flag==4){while(READ_SDA4)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}}
	else if(flag==5){while(READ_SDA5)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}}
	else if(flag==6){while(READ_SDA6)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}}
	else if(flag==7){while(READ_SDA7)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}}
	else if(flag==8){while(READ_SDA8)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}}
	else if(flag==9){while(READ_SDA9)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}}
	else if(flag==10){while(READ_SDA10)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}}
	else if(flag==11){while(READ_SDA11)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}}	
	IIC_SCL=0;//时钟输出0	   
	return 0;  
} 
//产生ACK信号
void IIC_Ack(void)
{
	IIC_SCL=0;
	SDA_OUT();
	if(flag==1){IIC_SDA1=0;}
	else if(flag==2){IIC_SDA2=0;}
	else if(flag==3){IIC_SDA3=0;}
	else if(flag==4){IIC_SDA4=0;}
	else if(flag==5){IIC_SDA5=0;}
	else if(flag==6){IIC_SDA6=0;}
	else if(flag==7){IIC_SDA7=0;}
	else if(flag==8){IIC_SDA8=0;}
	else if(flag==9){IIC_SDA9=0;}
	else if(flag==10){IIC_SDA10=0;}
	else if(flag==11){IIC_SDA11=0;}
	delay_us(4);
	IIC_SCL=1;
	delay_us(4);
	IIC_SCL=0;
}
//不产生ACK应答		    
void IIC_NAck(void)
{
	IIC_SCL=0;
	SDA_OUT();
	if(flag==1){IIC_SDA1=1;}
	else if(flag==2){IIC_SDA2=1;}
	else if(flag==3){IIC_SDA3=1;}
	else if(flag==4){IIC_SDA4=1;}
	else if(flag==5){IIC_SDA5=1;}
	else if(flag==6){IIC_SDA6=1;}
	else if(flag==7){IIC_SDA7=1;}
	else if(flag==8){IIC_SDA8=1;}
	else if(flag==9){IIC_SDA9=1;}
	else if(flag==10){IIC_SDA10=1;}
	else if(flag==11){IIC_SDA11=1;}
	delay_us(4);
	IIC_SCL=1;
	delay_us(4);
	IIC_SCL=0;
}					 				     
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答		  
void IIC_Send_Byte(uint8_t txd)
{                        
    uint8_t t;   
		SDA_OUT(); 	    
    IIC_SCL=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
      	if(flag==1){IIC_SDA1=(txd&0x80)>>7;;}
				else if(flag==2){IIC_SDA2=(txd&0x80)>>7;;}
				else if(flag==3){IIC_SDA3=(txd&0x80)>>7;;}
				else if(flag==4){IIC_SDA4=(txd&0x80)>>7;;}
				else if(flag==5){IIC_SDA5=(txd&0x80)>>7;;}
				else if(flag==6){IIC_SDA6=(txd&0x80)>>7;;}
				else if(flag==7){IIC_SDA7=(txd&0x80)>>7;;}
				else if(flag==8){IIC_SDA8=(txd&0x80)>>7;;}
				else if(flag==9){IIC_SDA9=(txd&0x80)>>7;;}
				else if(flag==10){IIC_SDA10=(txd&0x80)>>7;;}
				else if(flag==11){IIC_SDA11=(txd&0x80)>>7;;}  
        txd<<=1; 	  
		delay_us(4);   
		IIC_SCL=1;
		delay_us(4); 
		IIC_SCL=0;	
		delay_us(4);
    }	 
} 	    
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
uint8_t IIC_Read_Byte(uint8_t ack)
{
	unsigned char i,receive=0;
	SDA_IN();//SDA设置为输入		
    for(i=0;i<8;i++ )
	{
        IIC_SCL=0; 
        delay_us(4);
				IIC_SCL=1;
        receive<<=1;
				if(flag==1){if(READ_SDA1)receive++;}
				else if(flag==2){if(READ_SDA2)receive++;}
				else if(flag==3){if(READ_SDA3)receive++;}
				else if(flag==4){if(READ_SDA4)receive++;}
				else if(flag==5){if(READ_SDA5)receive++;}
				else if(flag==6){if(READ_SDA6)receive++;}
				else if(flag==7){if(READ_SDA7)receive++;}
				else if(flag==8){if(READ_SDA8)receive++;}
				else if(flag==9){if(READ_SDA9)receive++;}
				else if(flag==10){if(READ_SDA10)receive++;}
				else if(flag==11){if(READ_SDA11)receive++;}  
				delay_us(4); 
    }					 
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK   
    return receive;
}

2、MS5837程序移植

(1)编写头文件“MS5837.h”如下

#ifndef __MS5837_H_
#define __MS5837_H_
#include "stm32f4xx.h"

extern int s_num;
void MS583702BA_RESET(void);
void MS5837_init(void);
uint32_t *MS583702BA_getConversion(uint8_t command);
void MS5837_Getdata(float * outTemp, float * outPress);
unsigned char MS5837_02BA_Crc4(void);
void MS5837_Initialize(void);
void MS5837_Calibration(float *PRESSURE);
void tempcom_fit(void);
#endif

(2)编写 c文件“MS5837.c”如下

对单个MS5837传感器的程序进行了移植和改写,主要是不同传感器的数值存储数组设置;增加了传感器初始压力校准程序。由于传感器受温度的影响较大,温漂较大,实际测试发现官方数据手册自带的温漂补偿效果不是特别明显,所以在每次初始化时做了一个温度漂移曲线的拟合,实际温度和压力值漂移呈线性关系,所以用最小二乘法做了一个简单的温漂补偿。

为了使多个压强传感器采集频率提高,单纯的轮询方法不能满足需求,但是为了节省资源使用的公共时钟总线不能做到每个从机设备都有独立I2C时钟线,所以找到最耗时的环节,即MS5837进行ADC转换,根据不同的精度,转换时间也不同。所以在通信环节采用对各个传感器轮询的方式,然后让所有传感器同时等待ADC转换,这样可以在保证最高精度的同时将所有传感器的采用频率做到50HZ。

#include "MS5837.h"
#include "myiic.h"
#include "delay.h"
#include "stdio.h"
#include "NVIC.h"

#if SYSTEM_SUPPORT_OS
#include "includes.h" 
#endif

extern u16 flag;
int s_num;
/*
C1  压力灵敏度 SENS|T1
C2  压力补偿 OFF|T1
C3	温度压力灵敏度系数TCS
C4	温度系数的压力补偿 TCo
C5	参考遇度 T|REE
C6 	温度系数的温度 TEMPSENS
*/
/*********** 压传配置参数***********/
uint16_t Cal_C[11][7]; //用于存放PROM中的c1-C6
int start=0; 							//压传读数开始标志,即进入中断标志
int num=1;     						//传感器个数,需要手动修改num和air pressure[num]
float air_pressure[11];		//定义大气压数组,默认大气压(正常是99000-101000之间),单位pa
float TEMPERATURE[11];				//传感器测量温度,单位℃
float PRESSURE[11];					//传感器测量绝对压力,单位pa
float a[2][11];
/*
dT 实际和参考温度之间的差异
Temperature 实际温摩	
*/
int32_t dT, Temperature, Aux;
/*
OFF 实际温度补偿
SENS 实际温度灵敏度
*/
int64_t SENS, OFF_, OFF2, OFFi=0,  SENS2, SENSi=0;
uint32_t *D1_Pres, *D2_Temp;		 //数字压力值,数字温度值
uint32_t TEMP2, Ti=0, T2; //温度校验值
int32_t P;               //一阶补偿后的压力
int32_t Pressure;			  //二阶补偿后的压力
int32_t Depth;
float Atmdsphere_Pressure; //大气压
extern float rel_pressure[];

/*******************************************************************************
  * 函数名称 MS583702BA RESET
  * @函数说明  复位 Ms5837
  * @输入参数  无
  * @输出参数  无
  * @返回函数  无
*******************************************************************************/
void MS583702BA_RESET(void)
{
	IIC_Start();
	IIC_Send_Byte(0xEC); //发送写命今
	IIC_Wait_Ack();
	IIC_Send_Byte(0x1E); //发送复位命令
	IIC_Wait_Ack();
	IIC_Stop();
}

/*******************************************************************************
  * 函数名称  MS583702BA init
  * @函数说明  初始化 Ms5837
  * @输入参数  无
  * @输出参数  无
  * @返回函数  无
*******************************************************************************/
void MS5837_init(void)
{
	u8 inth, intl;
	u8 i;
//	float air_temp, air_press, air_depth;

	IIC_Init();
	MS583702BA_RESET(); // Reset Device MS5837
	delay_ms(20);		//必要的延时,具体可查看数据手册

	
	for (i = 0; i <= 6; i++)
	{
		IIC_Start();
		IIC_Send_Byte(0xEC);
		IIC_Wait_Ack();
		delay_us(4);
		IIC_Send_Byte(0xA0 + (i * 2));
		IIC_Wait_Ack();
		IIC_Stop();
		delay_us(4);
		IIC_Start();
		IIC_Send_Byte(0xEC + 0x01); //进入接收模式
		delay_us(4);
		IIC_Wait_Ack();
		delay_us(4);
		inth = IIC_Read_Byte(1); //带ACK的读数据
		delay_us(4);
		intl = IIC_Read_Byte(0); //最后一个字节nACK
		delay_us(4);
		IIC_Stop();
		delay_us(4);
		Cal_C[flag-1][i] = (((uint16_t)inth << 8) | intl);	
		
	}
	
	
}

/**************************实现函数********************************************
*函数原型:unsigned long MS561101BA_getConversion(void)
*功能:读取MS5837的转换结果
*******************************************************************************/
uint32_t *MS583702BA_getConversion(uint8_t command)
{
	
	uint32_t static conversion[11];
	uint32_t temp[3];
	for(flag=1;flag<=11;flag++)
	{
		IIC_Start();
		IIC_Send_Byte(0xEC); //写地址
		IIC_Wait_Ack();
		delay_us(4);
		IIC_Send_Byte(command); //写转换命令
		IIC_Wait_Ack();
		IIC_Stop();
	}	
	delay_ms(10);			// 同时等待ADC完成
	for(flag=1;flag<=11;flag++)
	{
	IIC_Start();
	IIC_Send_Byte(0xEC); //写地址
	IIC_Wait_Ack();
	delay_us(4);
	IIC_Send_Byte(0x00); // start read sequence
	IIC_Wait_Ack();
	IIC_Stop();
	delay_us(4);

	IIC_Start();
	IIC_Send_Byte(0xEC + 0x01); //进入接收模式
	IIC_Wait_Ack();
	delay_us(4);
	temp[0] = IIC_Read_Byte(1); //带ACK的读数据  bit 23-16
	delay_us(4);
	temp[1] = IIC_Read_Byte(1); //带ACK的读数据  bit 8-15
	delay_us(4);
	temp[2] = IIC_Read_Byte(0); //带nACK的读数据 bit 0-7
	IIC_Stop();
	delay_us(4);
	
	conversion[flag-1] = (temp[0]<<16) + (temp[1]<<8) + temp[2];
	
	}
	return conversion;
}

///***********************************************
//  * @brief  读取气压
//  * @param  None
//  * @retval None
//************************************************/

/*******************MS5837-02BA************************/
void MS5837_Getdata(float * outTemp, float * outPress)
{
	D1_Pres = MS583702BA_getConversion(0x48);

	D2_Temp = MS583702BA_getConversion(0x58);

	for(s_num=0;s_num<=num-1;s_num++)
	{
		
		if (D2_Temp[s_num] > (((uint32_t)Cal_C[s_num][5]) * 256))
		{
			dT = D2_Temp[s_num] - (((uint32_t)Cal_C[s_num][5]) * 256);
			Temperature = 2000 + dT * ((uint32_t)Cal_C[s_num][6]) / 8388608;
			OFF_ = (uint32_t)Cal_C[s_num][2] * 131072 + ((uint32_t)Cal_C[s_num][4] * dT) / 64;
			SENS = (uint32_t)Cal_C[s_num][1] * 65536 + ((uint32_t)Cal_C[s_num][3] * dT) / 128;
		}
		else
		{
			dT = (((uint32_t)Cal_C[s_num][5]) * 256) - D2_Temp[s_num];
			Temperature = 2000 - dT * ((uint32_t)Cal_C[s_num][6]) / 8388608;
			OFF_ = (uint32_t)Cal_C[s_num][2] * 131072 - ((uint32_t)Cal_C[s_num][4] * dT) / 64;
			SENS = (uint32_t)Cal_C[s_num][1] * 65536 - ((uint32_t)Cal_C[s_num][3] * dT) / 128;
		}
		
		if (Temperature < 2000) // low temp
		{
			Aux = (2000 - Temperature) * (2000 - Temperature);
			Ti = 11 * (dT * dT) / 34359738368;
			OFFi = 31 * Aux / 8;
			SENSi = 63 * Aux / 32;
		}

		OFF2 = OFF_ - OFFi;
		SENS2 = SENS - SENSi;

		outTemp[s_num] = (float)(Temperature - Ti) / 100.0f;
		outPress[s_num] =(float)((D1_Pres[s_num] * SENS2 / 2097152 - OFF2) / 32768) / 100.0f;
	}

}

/********************************************************/
unsigned char MS5837_02BA_Crc4()
{
	int cnt;
	int t;
	unsigned int n_rem=0;
	unsigned char n_bit;	
	unsigned char  a=0;
	unsigned char  b=0;
	unsigned short  int n_prom[8];
	
	for( t=0;t<7;t++)
{
   n_prom[t]=Cal_C[flag-1][t];
}	
	n_prom[0]=((n_prom[0]) & 0x0FFF);
	n_prom[7]=0;
	for (cnt = 0; cnt < 16; cnt++)
		{
	if (cnt%2==1) n_rem ^= (unsigned short) ((n_prom[cnt>>1]) & 0x00FF);	
	else n_rem ^= (unsigned short) (n_prom[cnt>>1]>>8);		
	for (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);	
    a=(n_rem ^ 0x00);
	  b=Cal_C[flag-1][0]>>12;
		printf("\r\na£º%d   b£º%d\r\n",a,b);
		if (a==b)
		{
		   return 1;
		}
		else return 0;
	
}
//压强传感器初始化校验函数
void MS5837_Initialize()
{
	for(flag=1;flag<=num;flag++)										//逐个进行CRC校验
		{
			while(1)
			{
				MS5837_init();
				delay_ms(100);
					if(!MS5837_02BA_Crc4())                                              
						{
							printf("  MS5837_02BA-%d初始化失败\r\n",flag); 
							printf("  请检查接线是否正确\r\n");
							delay_ms(500);
						//if(flag==7){break;}
						}
				else 
				{
							printf("  初始化成功\r\n"); 
							printf("  检测到MS5837_02BA-%d\r\n\r\n",flag); 
							break;
				}
			}		
		}
}
//压强传感器初始数值校准函数
 void MS5837_Calibration(float *PRESSURE)
 {
		float cali[11][3];	 
		int cali_count=1;
		float cali_sum[11];
		float cali_average[11];
		float d_cali_1[11],d_cali_2[11];
	  int i;
		for(cali_count=1;cali_count<=3;cali_count++) //连续三次采集同一个传感器的数值
		{
			
			MS5837_Getdata(TEMPERATURE,PRESSURE);

			for(i=0; i<=10; i++)
			{
				cali[i][cali_count-1]=PRESSURE[i];
				cali_sum[i]=cali_sum[i]+cali[i][cali_count-1];
			
				d_cali_1[i]=cali[i][1]-cali[i][0];
				d_cali_2[i]=cali[i][2]-cali[i][1];
			}
		}
		for(i=0; i<=10; i++)
		{
			while(1)
			{
					if(-1<=d_cali_1[i]<=1 && -1<=d_cali_2[i]<=1) //传感器校准判断,相邻两次读数在0.1mbar内认为大气压稳定
				{
					cali_average[i]=cali_sum[i]/3;
					air_pressure[i] = cali_average[i]; //将连续三次读数的均值作为该传感器的校准大气压
					printf("air_pressure_%d=%lf Calibration Succeed!\r\n",i+1,air_pressure[i]); //校准成功
					break;
				}
				else{printf("Calibration Failed!\r\n");} //校准失败
			}
		}
		delay_ms(200);
		//start=1;
 }
 
/*********************最小二乘法补偿传感器温漂*********************************/
u8 len = 100;
float X[100][11],Y[100][11];	//Y=kX+b
void tempcom_fit(void)
{
	static u8 i,j;
	float sum_up[11],sum_down[11];
	float X_sum[11],Y_sum[11],X_aver[11],Y_aver[11];
	//生成你和变量X,Y数组
	for(i=0;i<=len-1;i++)
	{
		MS5837_Getdata(TEMPERATURE,PRESSURE);
		for(j=0;j<=num-1;j++)
		{
			X[i][j] = TEMPERATURE[j];
			Y[i][j] = PRESSURE[j] - air_pressure[j];
		}
	}
	//求X Y平均值
	for(j=0;j<=num-1;j++)
	{
		X_sum[j]=0;
		Y_sum[j]=0;
		for(i=0;i<=len-1;i++)
		{
			X_sum[j]+=X[i][j];
			Y_sum[j]+=Y[i][j];
		}
		X_aver[j]=X_sum[j]/len;
		Y_aver[j]=Y_sum[j]/len;
	}
	//求k和b
	for(j=0;j<=num-1;j++)
	{
		for(i=0;i<=len-1;i++)
		{
			sum_up[j]+=X[i][j]*Y[i][j]-X_aver[j]*Y_aver[j];
			sum_down[j]+=X[i][j]*X[i][j]-X_aver[j]*X_aver[j];
		}
		a[0][j]=sum_up[j]/sum_down[j];
		a[1][j]=Y_aver[j]-a[0][j]*X_aver[j];
		printf("a[o]&a[1]=%f %f\r\n",a[0][j],a[1][j]);
	}
	start=1;
}

3、中断函数编写

把压强传感器的数据采集函数放到了定时器中断里,此外由于压传数据信噪比较低,所以后续也可以增加平滑滤波来获得更好的数据。

#include "sys.h"
#include "MS5837.h"
#include "NVIC.h"
	float w_temperature,w_pressure,w_depth;
	extern int start;
	extern int num;
	extern float PRESSURE[];					//传感器测量绝对压力,单位pa
	extern float air_pressure[];
	extern float TEMPERATURE[];
	float rel_pressure[11];
	int i;
	float p_tempcom[11]; //温度补偿后的压力值
	float p_filtered[11]; //滤波后的压力值
//定时器中断服务函数
void TIM3_IRQHandler(void)
{
	
	if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断
	{
			
		if(start == 1)
		{																//清楚中断标志位
		sensorReadMS5837(&w_temperature,&w_pressure,&w_depth);
		}		
	}
	TIM_ClearITPendingBit(TIM3,TIM_IT_Update);  //Çå³ýÖжϱê־λ		

}	
//压传数据采集函数
void sensorReadMS5837(float *TEMP,float *PRES, float *DEPTH)
{
	//¿ÉÓÃSDA£º1 3 4 7 8 9 10 11		
			extern float a[2][11];
			MS5837_Getdata(TEMPERATURE,PRESSURE); 								//»ñÈ¡µ±Ç°Æøѹ
			for(i=0;i<=num-1;i++)
			{
				rel_pressure[i] = PRESSURE[i] - air_pressure[i]; 			//获取当前气压
				//压传温漂多项式补偿
				p_tempcom[i]=rel_pressure[i]-(a[1][i] + a[0][i]*TEMPERATURE[i]);	//温度补偿后的压力值
				//压传输出数据滤波平滑
				p_filtered[i]=p_tempcom[i];
				//串口打印监视数据
				//printf("%d:\r\n",i+1);																		//´òÓ¡ÏÔʾ´«¸ÐÆ÷ÐòÊý
				printf("\%f\r\n",p_tempcom[i]);				 
				printf("\%lf\r\n",rel_pressure[i]); 	
				printf("\%f\r\n",TEMPERATURE[i]);				  
			}
}

4、代码测试

  • 10
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
以下是基于STM32F103ZET6小系统板实现MS5837温深传感器的代码,仅供参考: ``` #include "stm32f10x.h" #include "delay.h" #include "i2c.h" #define MS5837_ADDR 0xEC // MS5837传感器地址 #define MS5837_CMD_RESET 0x1E // 复位命令 #define MS5837_CMD_CONV_D1_256 0x40 // 深度转换命令(256次采样) #define MS5837_CMD_CONV_D2_256 0x50 // 温度转换命令(256次采样) #define MS5837_CMD_PROM_READ 0xA0 // 读取补偿系数命令 #define MS5837_COEF_NUM 8 // 补偿系数数量 uint16_t ms5837_coef[MS5837_COEF_NUM]; // 补偿系数数组 // 初始化MS5837传感器 void MS5837_Init(void) { uint8_t cmd = MS5837_CMD_RESET; I2C_Write(MS5837_ADDR, &cmd, 1); DelayMs(10); for(int i = 0; i < MS5837_COEF_NUM; i++) { cmd = MS5837_CMD_PROM_READ + i * 2; I2C_Read(MS5837_ADDR, &cmd, 1, (uint8_t *)&ms5837_coef[i], 2); } } // 读取温度或深度数据 uint32_t MS5837_Read(uint8_t cmd) { uint32_t data = 0; I2C_Write(MS5837_ADDR, &cmd, 1); switch(cmd) { case MS5837_CMD_CONV_D1_256: DelayMs(20); break; case MS5837_CMD_CONV_D2_256: DelayMs(20); break; default: break; } I2C_Read(MS5837_ADDR, &cmd, 1, (uint8_t *)&data, 3); return data; } // 计算温度值 float MS5837_CalculateTemperature(uint32_t D2) { int32_t dT = D2 - (ms5837_coef[5] << 8); int32_t TEMP = 2000 + ((dT * ms5837_coef[6]) >> 23); return (float)TEMP / 100; } // 计算深度值 float MS5837_CalculateDepth(uint32_t D1, uint32_t D2) { int64_t dT = D2 - (ms5837_coef[5] << 8); int64_t SENS = ms5837_coef[1] + ((dT * ms5837_coef[3]) >> 7); int64_t OFF = ms5837_coef[2] + ((dT * ms5837_coef[4]) >> 8); int64_t P = ((D1 * SENS) >> 21) - OFF; return (float)P / 10000; } int main(void) { float temperature, depth; I2C_Init(); MS5837_Init(); while(1) { uint32_t D1 = MS5837_Read(MS5837_CMD_CONV_D1_256); uint32_t D2 = MS5837_Read(MS5837_CMD_CONV_D2_256); temperature = MS5837_CalculateTemperature(D2); depth = MS5837_CalculateDepth(D1, D2); // 将温度和深度值输出到串口 printf("Temperature: %.2f C\n", temperature); printf("Depth: %.2f m\n", depth); DelayMs(1000); } } ``` 需要注意的是,以上代码只是一个大致的实现,具体实现还需要根据MS5837传感器的具体规格和STM32F103ZET6小系统板的具体接口来进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值