目录
一、硬件电路设计
本项目使用的传感器是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]);
}
}