概述

项目上使用此款IC,在此写了一版demo,顺手做个笔录。注:气压计要想更加精准,需要要做校准的 手动补偿。

一、开发平台

  1. 环境:keil

  1. stm32

二、代码

  1. bsp_msp880.c

/******************** (C) COPYRIGHT 2019~2023 MEMSENSING **********************
* File Name          : bas_msp880.c
* Author             : champion
* Version            : V1.1
* Date               : 2023-02-13
* Description        : MSP data Handle
*******************************************************************************/
#include "st_bas_msp.h"
#include "msp.h"
#include "math.h"

#ifdef MSP_USING_FIX_POINT
        MSP_OTP_INT32_Typedef MSP_OTP_INT32_Structure;
#endif

#ifdef MSP_USING_FLOATING_POINT
        MSP_OTP_Typedef MSP_OTP_Structure;
#endif

MSP_Press_Typedef MSP_Press_Structure;
MSP_Temperature_Typedef  MSP_Temperature_Structure;


/*******************************************************************************
* Function Name  : st_delay_us
* Description    : us delay for STM32F429, HLK 168Mhz
* Input          : time_cnt 
* Output         : None
* Return         : None
*******************************************************************************/
void st_delay_us(uint16_t delay)
{
    uint32_t i;
    while(delay--)
    {    
        i = 42;
        while(i--);    
    }
}

/*******************************************************************************
* Function Name  : msa_DelayMS
* Description    : delay ms
* Input          : time_cnt 
* Output         : None
* Return         : None
*******************************************************************************/
void msa_DelayMS(uint16_t delay)
{
    uint32_t i=0;

    for(i=0; i<delay; i++)
    {
        st_delay_us(700);
    }
}

void MSP_Delay_ms(uint16_t delay_time)
{
    msa_DelayMS(delay_time);
}

/*******************************************************************************
* Function Name  : i2c_read_block_data
* Description    : MSP data read , I2C mode
* Input          : address , sizeof(data_read) , data_return
* Output         : None
* Return         : -1:read fail      sizeif(data_read):read success
*******************************************************************************/
int32_t i2c_read_block_data(uint8_t base_addr, uint8_t count, uint8_t *data)
{    
    int32_t i = 0;
    
    for(i = 0; i < count;i++)
    {
        if(i2c_read_byte_data(base_addr+i,(data+i)))
        {
            return -1;                    
        }
    }    
    return count;
}

/*******************************************************************************
* Function Name  : i2c_read_byte_data
* Description    : MSP data read , I2C mode
* Input          : address ,  data_return
* Output         : None
* Return         : 0:read success     others: read fail
*******************************************************************************/
int32_t  i2c_read_byte_data(uint8_t addr, uint8_t *data)
{
    int status = 0;
    status = msp_ReadBytes(data,addr);
    return (!status);
}

/*******************************************************************************
* Function Name  : msp_ReadBytes
* Description    : MSP byte read, I2C mode
* Input          : address ,  data_return
* Output         : None
* Return         : 0:read fail     1:read success
*******************************************************************************/

bool msp_ReadBytes(uint8_t* Data, uint8_t RegAddr)
{
    SW_i2c_start();                        //start bit
    ms_SendByte(MS_I2C_Addr << 1);        //slave address|write bit
    if(FALSE == ms_ChkAck())        //check Ack bit
    {
        //TO_DO: display ack check fail when send write id        
        SW_i2c_stop();
        return FALSE;
    }

    ms_SendByte(RegAddr);                //send RegAddr
    if(FALSE == ms_ChkAck())        //check Ack bit
    {
        //TO_DO: display ack check fail when send RegAddr
        SW_i2c_stop();
        return FALSE;
    }

    ms_Restart();                        //restart bit

  ms_SendByte(MS_I2C_Addr<<1 | MS_I2C_Addr_Read);        //slave address|read bit
    if(FALSE == ms_ChkAck())
    {
        //TO_DO: display ack check fail when send read id        
        SW_i2c_stop();
        return FALSE;
    }

    *Data = ms_ReadByteNAck();

    SW_i2c_stop();                        //stop bit

    //TO_DO: add debug code to display the data received

    return TRUE;
    
}
/*******************************************************************************
* Function Name  : msp_WriteBytes
* Description    : MSP date write, I2C mode
* Input          : address ,  data_write
* Output         : None
* Return         : 0:write fail     1:write success
*******************************************************************************/
bool msp_WriteBytes(uint8_t RegAddr, uint8_t Data)
{
    SW_i2c_start();                        //start bit

    ms_SendByte(MS_I2C_Addr<<1 | MS_I2C_Addr_Write);        //slave address|write bit
    if(FALSE == ms_ChkAck())        //check Ack bit
    {
        //TO_DO: display check ack fail when send write id
        SW_i2c_stop();
        return FALSE;
    }

    ms_SendByte(RegAddr);                //send RegAddr
    if(FALSE == ms_ChkAck())        //check Ack bit
    {
        //TO_DO: display check ack fail when send RegAddr

        SW_i2c_stop();
        return FALSE;
    }

    ms_SendByte(Data);                    //send parameter
    if(FALSE == ms_ChkAck())
    {
        //TO_DO: display check ack fail when send data

        SW_i2c_stop();
        return FALSE;
    }

    SW_i2c_stop();                        //stop bit

    return TRUE;
}


/*******************************************************************************
* Function Name  : ms_SendByte
* Description    : MSP send byte, I2C mode
* Input          : data
* Output         : None
* Return         : 0:read fail     1:read success
*******************************************************************************/

void ms_SendByte(uint8_t Data) 
{
  int32_t i;
    
    for (i=7; i>=0; i--) 
    {            
        if ((Data>>i)&0x01) 
        {               
            MS_I2C_DATA_HIGH;                  
        } 
        else 
        { 
            MS_I2C_DATA_LOW;                  
        }
        SW_i2c_one_clk();                        
    }        
}

/*******************************************************************************
* Function Name  : SW_i2c_start
* Description    : I2C start, software mode
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void SW_i2c_start(void)
{
    MS_SCL_OUT;

    MS_SDA_OUT;
    
    MS_I2C_DATA_HIGH;
    MS_I2C_CLK_HIGH;
    st_delay_us(40);        //40us
    MS_I2C_DATA_LOW;
    st_delay_us(20);        //20us
    MS_I2C_CLK_LOW;
    st_delay_us(20);        //20us
}

/*******************************************************************************
* Function Name  : SW_i2c_stop
* Description    : I2C stop, software mode
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void SW_i2c_stop(void)
{
    MS_SCL_OUT;
    MS_SDA_OUT;

    MS_I2C_DATA_LOW;
    st_delay_us(20);        //20us
    MS_I2C_CLK_HIGH;
    st_delay_us(20);        //20us
    MS_I2C_DATA_HIGH;
  st_delay_us(20);        //20us
}
/*******************************************************************************
* Function Name  : ms_Restart
* Description    : I2C restart, software mode
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/

void ms_Restart(void)
{
    MS_SCL_OUT;
    MS_SDA_OUT;

    st_delay_us(40);    //40us
    MS_I2C_DATA_HIGH;
    st_delay_us(20);        //20us
    MS_I2C_CLK_HIGH;
    st_delay_us(40);
    MS_I2C_DATA_LOW;
    st_delay_us(40);        //20us
    MS_I2C_CLK_LOW;
    st_delay_us(20);        //20us
}

/*******************************************************************************
* Function Name  : SW_i2c_one_clk   
* Description    : I2C one clk send
* Input          : None
* Output         : None
* Return         : None
* Notice         : the max frequence of i2c clk is 400K, then the min clk is 2.5us
*******************************************************************************/
void SW_i2c_one_clk(void)
{
    st_delay_us(10);        //10us
    MS_I2C_CLK_HIGH;
    st_delay_us(20);        //20us
    MS_I2C_CLK_LOW;
    st_delay_us(10);        //10us
}

/*******************************************************************************
* Function Name  : ms_ChkAck   
* Description    : I2C Ack
* Input          : None
* Output         : None
* Return         : 1:Ack    0:no Ack
*******************************************************************************/
bool ms_ChkAck(void)
{
    MS_SDA_IN;
    
    st_delay_us(10);        //10us
    MS_I2C_CLK_HIGH;
    st_delay_us(10);        //10us

    if(MS_I2C_GET_BIT)        //Non-ack
    {
        st_delay_us(10);    //10us
        MS_I2C_CLK_LOW;
        st_delay_us(10);    //10us
    
        MS_SDA_OUT;
        MS_I2C_DATA_LOW;
        
        return FALSE;
    }
    else                    //Ack
    {
        st_delay_us(10);    //10us
        MS_I2C_CLK_LOW;
        st_delay_us(10);    //10us
    
        MS_SDA_OUT;
        MS_I2C_DATA_LOW;

        return TRUE;
    }
}

/*******************************************************************************
* Function Name  : ms_ReadByteNAck   
* Description    : I2C data read without ack
* Input          : None
* Output         : None
* Return         : data read
*******************************************************************************/
uint8_t ms_ReadByteNAck(void)
{
    int32_t i;
    uint8_t data;

    MS_SDA_IN;
    data = 0; 
    
    for (i=7; i>=0; i--) 
    {
        if (MS_I2C_GET_BIT)
        {
            data |= (0x01<<i);
        }
        SW_i2c_one_clk();
    }                                            

    MS_SDA_OUT;                                          
    MS_I2C_DATA_HIGH;
    SW_i2c_one_clk();                         
    
    return data;
}

/*******************************************************************************
* Function Name  : msp_read_pressure
* Description    : MSP pressure data read , I2C mode
* Input          : *pressure
* Output         : None
* Return         : None
*******************************************************************************/
void msp_read_press(uint32_t *press)
{
    uint8_t  temp_data[3] = {0,0,0};
        
    //press read signal, OSR 8192
    msp_WriteBytes(MS_REG_CONFIGURE,MS_PRESS_READ);
        
    MSP_Delay_ms(30); //30ms delay,wait for ADC convert

    if (msp_register_read_continuously(MS_REG_PRESS_MSB, 3, temp_data) == 0) {
        MSP_LOG("error ");
          return;
    }
    
    *press = temp_data[0]<<16 |  temp_data[1]<<8 |  temp_data[2];
}

/*******************************************************************************
* Function Name  : msp_read_temperature
* Description    : MSP temperature data read , I2C mode
* Input          : *temperature
* Output         : None
* Return         : None
*******************************************************************************/
void msp_read_temperature(uint32_t *temperature)
{
    uint8_t  temp_data[2] = {0,0};
        
    //temperature read signal, OSR 1024
    msp_WriteBytes(MS_REG_CONFIGURE,MS_TEMPERATURE_READ);
        
    MSP_Delay_ms(10); //10ms delay,wait for ADC convert

    if (msp_register_read_continuously(MS_REG_TEMPERATURE_MSB, 2, temp_data) == 0) {
        MSP_LOG("error ");
          return;
    }
        
    *temperature = ((temp_data[0]&0x7F)<<8) | temp_data[1];
}

/*******************************************************************************
* Function Name  : ST_USER_GetPressParam
* Description    : MSP press data read
* Input          : MSP_Press_Typedef
* Output         : None
* Return         : None
*******************************************************************************/
void ST_USER_GetPressParam(MSP_Press_Typedef *Press)
{    
    msp_read_press(&Press->Data_Read);
}

/*******************************************************************************
* Function Name  : ST_USER_GetAllParam
* Description    : MSP data read
* Input          : MSP_Pre_Typedef
* Output         : None
* Return         : None
*******************************************************************************/
void ST_USER_GetTemperatureParam(MSP_Temperature_Typedef *Temperature)
{    
    msp_read_temperature(&Temperature->Data_Read);
}

/*******************************************************************************
* Function Name  : MSP_Para_Calculate
* Description    : MSP parameter calculate ( fix point data)
* Input          : 
* Output         : None
* Return         : None
*******************************************************************************/
#ifdef MSP_USING_FIX_POINT

void MSP_Para_Calculate_INT32(MSP_Press_Typedef *Press , MSP_Temperature_Typedef *Temperature)
{
    int32_t deltaT,Ptemp,Ttemp;
    int64_t var1,var2,p;    
    Ttemp = Temperature->Data_Read >> 1;
    Temperature->Temperature_INT32[Temperature->Cnt] = ((((Ttemp * Ttemp) >> 5 ) * (MSP_OTP_INT32_Structure.Temp_a >> 5)) >>13 )+ \
                                                        (((Ttemp >> 2)* (MSP_OTP_INT32_Structure.Temp_b >> 3)) >> 10 ) + \
                                                          (MSP_OTP_INT32_Structure.Temp_c >> 2);
    
/*
    Ttemp = Temperature->Data_Read >> 3;
    
    Temperature->Temperature_INT32[Temperature->Cnt] = ((((Ttemp * Ttemp) >> 8 ) * MSP_OTP_INT32_Structure.Temp_a) >>11 )+ \
                                                                                                            ((Ttemp * MSP_OTP_INT32_Structure.Temp_b) >> 13 ) + \
                                                                                                            (MSP_OTP_INT32_Structure.Temp_c >> 2);
*/            
    deltaT = (Temperature->Temperature_INT32[Temperature->Cnt] / 100) - (MSP_OTP_INT32_Structure.Tbase >> 4);                
    Ptemp = Press->Data_Read;    
    
    //var2 << 29
    var1 = (1<<29) + (MSP_OTP_INT32_Structure.stc1 << 7 ) * deltaT + MSP_OTP_INT32_Structure.stc2 * deltaT * deltaT;
    //var2 << 29
    var2 = (Ptemp <<6) - (MSP_OTP_INT32_Structure.f0 <<14) - (MSP_OTP_INT32_Structure.ftc1 <<7 ) * deltaT - MSP_OTP_INT32_Structure.ftc2  * deltaT * deltaT ;
    
    var2 *= 1250;
    p = (MSP_OTP_INT32_Structure.s0 >> 3) * (var1 >> 15)* (var2 >> 15);
    p>>= 25;
    Press->Press_INT32[Press->Cnt] = ((p * 10000) >> 10) + ((MSP_OTP_INT32_Structure.ks >> 5)* (p >> 11) * (p >> 11) >> 9);
    Press->Press_INT32[Press->Cnt] /= 1000;
}
#endif

/*******************************************************************************
* Function Name  : MSP_Para_Calculate
* Description    : MSP parameter calculate
* Input          : 
* Output         : None
* Return         : None
*******************************************************************************/
#ifdef MSP_USING_FLOATING_POINT
void MSP_Para_Calculate(MSP_Press_Typedef *Press , MSP_Temperature_Typedef *Temperature)
{
    float  P,P1,P2,P3, T;
     
    T = Temperature->Data_Read / 16384.0f;
    Temperature->Temperature = T*1.1307*128.0f+10.428f;

    P  = Press->Data_Read * (1.0f / 262144.0f);
    P1 = MSP_OTP_Structure.C00 + MSP_OTP_Structure.C10*P + MSP_OTP_Structure.C20*P*P;
    P2 = MSP_OTP_Structure.C01*T + MSP_OTP_Structure.C11*T*P + MSP_OTP_Structure.C21*T*P*P;
    P3 = MSP_OTP_Structure.C02*T*T +MSP_OTP_Structure.C12*P*T*T;
    
    Press->Press  = P1 + P2 + P3;
    //H=44300* (1- (P/P0)^ (1/5.256)) :H,P0=(0,101.325kPa)    
    Press->Height = 44330.0 * (1.0 - pow((float)(Press->Press)/101325.0, (1.0/5.255)));     
        
    RtkWristbandSys.barometer.temperature    = Temperature->Temperature;
    RtkWristbandSys.barometer.hPaValue         = Press->Press / 100;
    RtkWristbandSys.barometer.elevation     = Press->Height;
    
    MSP_LOG("Temperature->Data_Read:%d, T:%lf, Press->Data_Read:%d, P:%lf, Press->Press:%lf, Press->Press/100:%lf", Temperature->Data_Read, T, Press->Data_Read, P, Press->Press, Press->Press/100);
    MSP_LOG("Temperature->Temperature:%lf, hPaValue:%lf, elevation:%d", Temperature->Temperature, RtkWristbandSys.barometer.hPaValue, RtkWristbandSys.barometer.elevation);
}
#endif
/*******************************************************************************
* Function Name  : MSP_Configuration
* Description    : MSP parameter init and setting
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void MSP_Configuration(void)
{
    uint8_t  temp_data[16] = {0};
    int32_t  temp;
 
    MSP_Write_Reg(0x5C,0x00);
    
    MSP_Delay_ms(20);

    if (MSP_MultiRead_Reg(MS_REG_OTP_PARA, temp_data, 16) == 1)
    {
        MSP_LOG("error ");
        return;
    }
    
    for(uint8_t i = 0; i < 16; i++) {
        MSP_LOG("temp_data[%d] = 0x%x", i, temp_data[i]);
    }
    
    //C00
    temp = temp_data[0]<<8|temp_data[1];
    MSP_OTP_Structure.C00 = temp *10.0f; 
    
    //C10
    temp = temp_data[2]<<8|temp_data[3];
    MSP_OTP_Structure.C10 =temp*1.0f; 
    
    //C20
    temp = temp_data[4]<<8|temp_data[5];
    MSP_OTP_Structure.C20 = temp*(-1.0f / 1000.0f);
    
    //C01
    temp = temp_data[6]<<8|temp_data[7];
    if(temp>8191)
        MSP_OTP_Structure.C01 =(temp-16383)*10.0f; 
    else
        MSP_OTP_Structure.C01 =temp*10.0f;
    
    //C11
    temp = temp_data[8]<<8|temp_data[9];
    if(temp <8191)
         MSP_OTP_Structure.C11 =temp*1.0f ; 
    else
        MSP_OTP_Structure.C11 = (temp-16384)*1.0f;
    
    //C21
    temp = temp_data[10]<<8|temp_data[11];
    if(temp >4095)
         MSP_OTP_Structure.C21 =(temp-8191)*(1.0f / 1000.0f); 
    else
        MSP_OTP_Structure.C21 = temp*(1.0f /1000.0f);
    
    //C02
    temp = temp_data[12]<<8|temp_data[13];
    if(temp >16383)
         MSP_OTP_Structure.C02 =(temp-32767)*1.0f;
    else
        MSP_OTP_Structure.C02 = temp*1.0f; 
    //C12
    temp = (temp_data[14]&0x0f)<<8|temp_data[15];
    if(temp <2047)
         MSP_OTP_Structure.C12 =temp*1.0f ; 
    else
        MSP_OTP_Structure.C12 = (temp-4095)/10.0f;    
        
}

void MSP_Init(void)
{
    uint8_t id = 0;
    
    MSP_Delay_ms(40);
    MSP_Read_Reg(MSP_ID, &id);
    MSP_LOG("MSP - 0x10 : %d",id);    
    
    RtkWristbandSys.mp_function_state.bit.barometer = ((id>=0) && (id<=32))? 1:0;
    
    if ((id>=0) && (id<=32)) {
        MSP_LOG("Read MSP Success");
    } else {
        MSP_LOG("Read MSP Fail");
    }
}

void MSP_UpDate(void)
{
    ST_USER_GetTemperatureParam(&MSP_Temperature_Structure);
    ST_USER_GetPressParam(&MSP_Press_Structure);
    MSP_Para_Calculate(&MSP_Press_Structure, &MSP_Temperature_Structure);
}
    
void MSP_Bpm_algo_handler(void)
{    
    MSP_UpDate();
}

void MSP_Enable(void)
{
    MSP_Configuration();
}    

void MSP_Disable(void)
{
    //enter dlps 低功耗
    MSP_Write_Reg(0x5B,0x00);
}

/************************ (C) COPYRIGHT MEMSENSING *****END OF FILE****/
  1. bsp_msp880.h

/******************** (C) COPYRIGHT 2019~2023 MEMSENSING **********************
* File Name          : bas_msp880.h
* Author             : champion
* Version            : V1.1
* Date               : 2023-02-13
* Description        : MSP data Handle
*******************************************************************************/

#ifndef _ST_BAS_MSP_H_
#define _ST_BAS_MSP_H_

#include <stdint.h>  


#define MSP_USING_FLOATING_POINT
//#define MSP_USING_FIX_POINT

#define Press_Buff_Length             20
#define Temperature_Buff_Length      20

#define MSP880_7BITI2C_ADDRESS        0x6C /*SDO external pull high or float , pull down 0x6C   */

#define MSP880_ID                    0x10 /* 0~32 */

#define MS_PRESS_READ               0xF3 //press osr 8192
#define MS_TEMPERATURE_READ         0xB3 //Temperature osr 1024

#define MS_REG_SOFT_RESET           0x50
#define MS_REG_PRESS_MSB              0x55
#define MS_REG_TEMPERATURE_MSB      0x58
#define MS_REG_CONFIGURE            0x5B
#define MS_REG_OTP_PARA             0x14

typedef struct{
    float C00;
    float C10;
    float C20;
    float C01;
    float C11;
    float C21;
    float C02;
    float C12;
}MSP_OTP_Typedef,*pMSP_OTP_Typedef;

extern MSP_OTP_Typedef MSP_OTP_Structure;

typedef struct{
    int32_t s0;
    int32_t stc1;
    int32_t stc2;
    int32_t ftc1;
    int32_t ftc2;
    int32_t f0;
    int32_t ks;
    int32_t Tbase;
    int32_t Temp_a;
    int32_t Temp_b;
    int32_t Temp_c;
}MSP_OTP_INT32_Typedef,*pMSP_OTP_INT32_Typedef;

extern MSP_OTP_INT32_Typedef MSP_OTP_INT32_Structure;

typedef struct{
    uint32_t Data_Read;
    float Standard_Pressure;
    int Measured_Standard_Value;
    float Press;
    float Height;
}MSP_Press_Typedef,*pMSP_Press_Typedef;

extern MSP_Press_Typedef MSP_Press_Structure;

typedef struct{
    uint32_t Data_Read;
    float Temperature;
}MSP_Temperature_Typedef,*pMSP_Temperature_Typedef;

extern MSP_Temperature_Typedef  MSP_Temperature_Structure;

void ST_USER_GetPressParam(MSP_Press_Typedef *Press);
void ST_USER_GetTemperatureParam(MSP_Temperature_Typedef *Temperature);
void MSP_Para_Calculate(MSP_Press_Typedef *Press , MSP_Temperature_Typedef *Temperature);
void MSP_Para_Calculate_INT32(MSP_Press_Typedef *Press , MSP_Temperature_Typedef *Temperature);
void MSP_Configuration(void);
void MSP_Init(void);
void MSP_Bpm_algo_handler(void);
void MSP_Enable(void);
void MSP_Disable(void);

#endif /* _ST_BAS_MSP_H_ */

/************************ (C) COPYRIGHT MEMSENSING *****END OF FILE****/
  1. main.c

.
.
.
#include "bsp_msp880.h"

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_DMA_Init();
  MX_FATFS_Init();
  /* USER CODE BEGIN 2 */
    MSP_Init();
    MSP_Enable();
  /* USER CODE END 2 */

  /* Init scheduler */
  osKernelInitialize();  /* Call init function for freertos objects (in freertos.c) */
  MX_FREERTOS_Init();
  /* Start scheduler */
  osKernelStart();

  /* We should never get here as control is now taken by the scheduler */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    MSP880_Bpm_algo_handler();
    HAL_Delay(200);
    /* USER CODE BEGIN 3 */
      
  }
  /* USER CODE END 3 */
}

三、运行结果

四、总结

好了,就介绍到此为止。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐