气压计 MS5611-01BA03 数据读取

1、简介及注意事项

  气压计MS5611-01BA03 采用24位的气压和温度AD转换值,SPIIIC接口协议读取,采用256、512、1024、2048和4096的过采样率提高采样精度。256的过采样率最低转换时间为0.5ms。
  该气压计仅仅只有5个基本指令:复位读ProM校准值D1启动温度转换D2启动气压转换读取ADC转换值结果。

  1. 关于初始化

  • 在上电之后,需要执行复位指令,确保校准值Prom都载入到寄存器中。

  • Prom寄存器值,读取一次即可。Prom值中从0xA0-0xAE,最后一位始终为0,所以共八个指令,第一个是厂商信息,2-7是六个系数信息,8是CRC校验信息。

  • SPI模式可以采用0和3模式,即:SPI_CPOL_Low和SPI_CPHA_1Edge、SPI_CPOL_High和SPI_CPHA_2Edge。

  • 在启动AD转换之后,需要等待相应的时间去读取,否则读取的时候可能为0;连续读取两次数据也为0;
    2. 关于数据计算
      在读完数据计算温度和气压的时候,需要注意变量的位数,比如OFF和SENS是64位的变量,如果定义成32位的就会出现数据丢失,计算错误的情况。

  • 在计算温度时,
    T=2000+DT*((float)PROM[5]/8388608); 一定要注意其中的float强制转换,否则会出现数据跳变,有些人强制转换成整形,也是不对的。

  • 在计算气压时,
    OFF=((int64_t)PROM[1]<<16)+(((int64_t)PROM[3]*DT)>>7);
    SENS=((int64_t)PROM[0]<<15)+(((int64_t)PROM[2]*DT)>>8);
    P=((int64_t)((CovData[0]*SENS)>>21)-OFF)>>15;
    要转化成更高的位数,否则也会出现数据丢失的情况。
    3. 关于协议时序图

  • 气压、温度转换数据读取
    在这里插入图片描述
      在发送完0x48(OSR 4096)之后,需要等待8.22ms,之后再去读取数据,读取数据的时候,也需要发送相应的数据,才能传回数据。

  • Prom数据读取
    在这里插入图片描述
      PORM数据只需要读取一次即可,这些数据都是厂家出厂时就校准好的,之后也不会更改。以下是楼主读到的参数,每个气压计参数都不一样,如果不一样也无需要考虑这个。

2、数据读取

  刚发出这篇博文之后,阅读数立即飙到1000多,我当时就想这个气压计就这么多人开始搞么,当时手头货还没到,到了立即开始调试,虽然途中也遇到了坑,但总归数据是出来了。
  以下是温度、气压(毫巴)、高度
在这里插入图片描述
  接下来话不多说,直接上代码,使用定时器中断控制转换时间来读取数据。

//首先是初始化代码
u16 PROM[6];        //存储6个校准系数
u32 CovData[2];     //存储两个24位ADC值,温度和气压

void Spi3IOInit(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  // Enable GPIOC clocks 
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  // Connect SPI2 pins to AF5
  GPIO_PinAFConfig(MS_SPI_PORT, GPIO_PinSource10, GPIO_AF_SPI3);  // SCK
  GPIO_PinAFConfig(MS_SPI_PORT, GPIO_PinSource11, GPIO_AF_SPI3);  // MISO
  GPIO_PinAFConfig(MS_SPI_PORT, GPIO_PinSource12, GPIO_AF_SPI3);  // MOSI
  
  // SPI SCK、MOSI pin configuration
  GPIO_InitStructure.GPIO_Pin = MS_SPI_SCK_PIN|MS_SPI_MOSI_PIN|MS_SPI_MISO_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//GPIO_PuPd_DOWN;//GPIO_PuPd_UP;//GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_Init(MS_SPI_PORT, &GPIO_InitStructure);
  
  //SPI2 NSS pin in output pushpull mode 
  GPIO_InitStructure.GPIO_Pin = MS_SPI_CS_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;  //GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	
  MS_SPI_CS_HIGH();  // cs default state is high
  MS_SPI_CS_LOW(); 
  MS_SPI_CS_HIGH(); 
}

void SPI3Init(void)
{
  SPI_InitTypeDef  SPI_InitStructure;

  SPI_I2S_DeInit(SPI3);
  //Enable the SPI periph 
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
  Spi3IOInit();
  
  // SPI configuration
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;  // SPI_CPHA_2Edge;
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;

  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_CRCPolynomial = 7;
  SPI_Init(SPI3, &SPI_InitStructure);

  // Enable the SPI3
  SPI_Cmd(SPI3, ENABLE);
}

void Timer2Init(u32 Frequency)                                //使用定时器中断,定时读取ADC值
{
  u32 Period = SystemCoreClock/168/Frequency;
  TIM_TimeBaseInitTypeDef    TIM_TimeBaseInitTypeDefStructure;
  NVIC_InitTypeDef   NVIC_InitStructure;
  
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
  
  TIM_DeInit(TIM2);
  
  TIM_TimeBaseInitTypeDefStructure.TIM_Period=(Period-1); 
  TIM_TimeBaseInitTypeDefStructure.TIM_Prescaler=(42-1);        
  TIM_TimeBaseInitTypeDefStructure.TIM_CounterMode=TIM_CounterMode_Up;
  TIM_TimeBaseInitTypeDefStructure.TIM_ClockDivision=TIM_CKD_DIV1;

  TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitTypeDefStructure);
  
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;            //外部中断8
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;  //抢占优先级1
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;         //子优先级2
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;               //使能外部中断通道
  NVIC_Init(&NVIC_InitStructure);   
  
  TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
  TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
  
  TIM_Cmd(TIM2,ENABLE);
  
}

void ReadMS5611PROMData()
{
  PROM[0] = SpiReadPromCmd(0xA2);
  PROM[1] = SpiReadPromCmd(0xA4);
  PROM[2] = SpiReadPromCmd(0xA6);
  PROM[3] = SpiReadPromCmd(0xA8);
  PROM[4] = SpiReadPromCmd(0xAA);
  PROM[5] = SpiReadPromCmd(0xAC);
}

void MS5611Init()      //先复位,再读取系数
{
  SPI3Init();
  SpiWriteCmd(0x1E);
  Delay_ms(3); 
  ReadMS5611PROMData();
  Timer2Init(800);
}

u8 ReadFlag=0;
void TIM2_IRQHandler()                            //定时读取ADC值,读完之后,Readflag=2.去处理数据。
{
  if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
  {
    if(ReadFlag==0)
    {
      CovData[0]=SpiReadCovCmd(0x00);
      SpiWriteCmd(0x50);
      ReadFlag=1;
    }
    else if(ReadFlag==1)
    {
      CovData[1]=SpiReadCovCmd(0x00);
      SpiWriteCmd(0x40);
      ReadFlag=2;
    }
    TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
  }
}
void SpiWriteCmd(u8 cmd)
{
  MS_SPI_CS_LOW(); 
	
  while((SPI3->SR &0x0002)==0);  
  SPI3->DR = (cmd);
  while((SPI3->SR &0x0001)==0);
  SPI_I2S_ReceiveData(SPI3); 

  MS_SPI_CS_HIGH();
}
u32 SpiReadPromCmd(u8 cmd)
{
  u32 returnvalue;
  
  MS_SPI_CS_LOW(); 
  
  while((SPI3->SR &0x0002)==0);  
  SPI3->DR = cmd;
  while((SPI3->SR &0x0001)==0);
  (unsigned char)(SPI_I2S_ReceiveData(SPI3)); // Return the Byte read from the SPI bus
  
  while((SPI3->SR &0x0002)==0);  
  SPI3->DR = 0x00;
  while((SPI3->SR &0x0001)==0);
  returnvalue = (unsigned char)(SPI_I2S_ReceiveData(SPI3)); // Return the Byte read from the SPI bus

  returnvalue=returnvalue<<8;
  
  while((SPI3->SR &0x0002)==0);  
  SPI3->DR = 0x00;
  while((SPI3->SR &0x0001)==0);
  returnvalue|=(unsigned char)(SPI_I2S_ReceiveData(SPI3)); // Return the Byte read from the SPI bus

  
  MS_SPI_CS_HIGH();
  
  return(returnvalue);  
}

u32 SpiReadCovCmd(u8 cmd)
{
  u32 returnvalue;
  
  MS_SPI_CS_LOW(); 
  
  while((SPI3->SR &0x0002)==0);  
  SPI3->DR = cmd;
  while((SPI3->SR &0x0001)==0);
  (unsigned char)(SPI_I2S_ReceiveData(SPI3)); // Return the Byte read from the SPI bus
  
  while((SPI3->SR &0x0002)==0);  
  SPI3->DR = 0x01;
  while((SPI3->SR &0x0001)==0);
  returnvalue = (unsigned char)(SPI_I2S_ReceiveData(SPI3)); // Return the Byte read from the SPI bus

  returnvalue=returnvalue<<8;
  
  while((SPI3->SR &0x0002)==0);  
  SPI3->DR = 0x01;
  while((SPI3->SR &0x0001)==0);
  returnvalue|=(unsigned char)(SPI_I2S_ReceiveData(SPI3)); // Return the Byte read from the SPI bus

  returnvalue=returnvalue<<8;
  
  while((SPI3->SR &0x0002)==0);  
  SPI3->DR = 0x01;
  while((SPI3->SR &0x0001)==0);
  returnvalue|=(unsigned char)(SPI_I2S_ReceiveData(SPI3)); // Return the Byte read from the SPI bus

  MS_SPI_CS_HIGH();
  
  return(returnvalue);
}
void Delay_ms(u32 nTime)      //滴答定时器做延时,
{
  TimeDelay=nTime;
  while(TimeDelay!=0x00);
}



  接下来是最重要的数据计算了,很多同学都读出数据了,但是就是在计算上出问题,数据一直都出不来。其中很重要的原因就是变量位数不对,很少人知道32位的单片机还可以定义64位的变量,而且还可以处理,以下就是变量的位数定义。
在这里插入图片描述


void ReadMS5611CovData()
{
  unsigned char StrBuff[50];
   
  int32_t DT,T,P;     //根据数据手册,定义相应位数的变量存储数据。
  int64_t OFF,SENS;

  float H;
  float T2,Aux,OFF2,SENS2;
  
  if(ReadFlag==2)
  {
    ReadFlag=0;
    DT=CovData[1]-((u32)PROM[4]<<8);
    T=2000+DT*((float)PROM[5]/8388608);         //一定要用float强制转换,否则数据会跳变出错。
    
    OFF=((int64_t)PROM[1]<<16)+(((int64_t)PROM[3]*DT)>>7);   //强制转换到更高的位数上,否则出现数据丢失的情况。
    SENS=((int64_t)PROM[0]<<15)+(((int64_t)PROM[2]*DT>>8);
    
    if(T<2000)
    {
      T2 = (float)(DT*DT)/0x80000000;
      Aux = (T-2000)*(T-2000);
      OFF2 = 2.5*Aux;
      SENS2 = 1.25*Aux;
      if(T < -1500)
      {
        Aux = (T+1500)*(T+1500);
        OFF2 = OFF2 + 7*Aux;
        SENS2 = SENS + 5.5*Aux;
      }
    }
    else  
    {
        T2 = 0;
        OFF2 = 0;
        SENS2 = 0;
    }	
    T = T - T2;
    OFF = OFF - OFF2;
    SENS = SENS - SENS2;
    
    P=((int64_t)((CovData[0]*SENS)>>21)-OFF)>>15;     //先左移21位-OFF之后,再强制转换,否则出现2倍的关系
    H=(float)(44330.0f*(1.0f - pow((float)P/101325.0f, 0.190295f)));
    
    //sprintf((char *)StrBuff,"%d***%d***%.2f C***%lld***%lld***%.2f mbar\r\n",CovData[0],CovData[1],T/100.0,OFF,SENS,P/100.0);
    sprintf((char *)StrBuff,"%.2f ℃    %.2f mbar    %.2f m\r\n",T/100.0,P/100.0,H);
    SendData(StrBuff,strlen((char *)StrBuff));
  }
}

  楼主分享一个完整的工程文件,用STM32F405使用SPI协议读取MS5611气压计的数据,温度、气压计数据均正常,并计算出海拔高度。
下载链接: keil 工程文件

如有雷同,纯属我抄你,有问题可以直接联系邮箱,在个人资料里面。
  • 13
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 15
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张一西

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值