SM9541是SMI的MEMS低压压力传感器,结合了先进的信号调理IC,可提供完整的压力校准和温度补偿,用I2C通信。 SM9541的型号有很多种,但是读取的方法几乎一样,只不过每种传感器的量程和精确度可能有所差别。我用的是SM9541-010C-D-C-3-S,相对压力检测范围-10 to 10 cmH2O,耐压范围±1.5 PSI,冲击压力可达±3.0 PSI。温度补偿范围-5 to 65°C,精度1%。全数字式,I2C数字接口。符合ISO9001 and ISO/TS 16949标准。典型供电电压3.3V和5V,最大供电电压6V,工作温度范围-5 to 65°C,SOIC-16标准封装。 一种可能的应用场景:用它来测量赛车跑动时空套表面的风压,一根管插入车内,另一根管在车外,可以测量风压,提供可供空套工程师分析的数据。
首先提供一些I2C的一些基础操作的代码,封装好,之后读取数据的时候要用。最好是自己阅读I2C通信协议,对I2C通信的逻辑有所了解,这里只给出了一例子。
#include "I2C.h" #define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) #define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) #define SDA_IN() I2C_GPIOB_Pin7_In() #define SDA_OUT() I2C_GPIOB_Pin7_Out() #define IIC_SCL PBout(6) #define IIC_SDA PBout(7) #define READ_SDA PBin(7) void IIC_Init(void)//GPIO初始化,拉高SCL和SDA。 { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); IIC_SCL=1; IIC_SDA=1; } void IIC_Start(void)//起始位 { SDA_OUT(); IIC_SDA=1; IIC_SCL=1; delay_us(4); IIC_SDA=0; delay_us(4); IIC_SCL=0; } void IIC_Stop(void)//终止位 { SDA_OUT(); IIC_SCL=0; IIC_SDA=0; delay_us(4); IIC_SCL=1; IIC_SDA=1; delay_us(4); } u8 IIC_Wait_Ack(void)//等待位 { u8 ucErrTime=0; SDA_IN(); IIC_SDA=1; delay_us(1); IIC_SCL=1; delay_us(1); while(READ_SDA) { ucErrTime++; if(ucErrTime>250) { IIC_Stop(); return 1; } } IIC_SCL=0; return 0; } void IIC_Ack(void)//发送ACK { IIC_SCL=0; SDA_OUT(); IIC_SDA=0; delay_us(2); IIC_SCL=1; delay_us(2); IIC_SCL=0; delay_us(2); } void IIC_NAck(void)//发送NACK { IIC_SCL=0; SDA_OUT(); IIC_SDA=1; delay_us(2); IIC_SCL=1; delay_us(2); IIC_SCL=0; delay_us(2); } void IIC_Send_Byte(u8 txd)//发送函数 { u8 t; SDA_OUT(); IIC_SCL=0; for(t=0;t<8;t++) { IIC_SDA = (txd & 0x80) >> 7; txd <<= 1; delay_us(2); IIC_SCL=1; delay_us(2); IIC_SCL=0; delay_us(2); } } u8 IIC_Read_Byte_ACK(void)//接收函数,结尾ACK { unsigned char i,receive=0; SDA_IN(); for(i=0; i<8; i++ ) { IIC_SCL=0; delay_us(2); IIC_SCL=1; receive <<= 1; if(READ_SDA)receive++; delay_us(1); } IIC_Ack(); return receive; } u8 IIC_Read_Byte_NACK(void)//接收函数,结尾NACK { unsigned char i,receive=0; SDA_IN(); for(i=0; i<8; i++ ) { IIC_SCL=0; delay_us(2); IIC_SCL=1; receive <<= 1; if(READ_SDA)receive++; delay_us(1); } IIC_NAck(); return receive; }读取数据,应该阅读SMI给的数据手册,里面详尽的告诉了怎么读取数据
int main(void) { SysTick_Init(72); IIC_Init(); while(1) { IIC_Start();//开始位 IIC_Send_Byte(SM_Address1);//SM_Address在数据手册中给了,是0x28,根据数据手册,要线发送(SM_Address<<1)+1;表示要读取数据,之后会连续接收到四个字节 IIC_Wait_Ack(); I2C_BYTE1=IIC_Read_Byte_ACK();//I2C_BYTE1的数据类型是u8,以下是连续读取四个字节,其中前三个最后是ACK,最后一个是NACK I2C_BYTE2=IIC_Read_Byte_ACK(); I2C_BYTE3=IIC_Read_Byte_ACK(); I2C_BYTE4=IIC_Read_Byte_NACK(); IIC_Stop();//停止位 } }读取到四个字节的含义:绿色的两位是状态位,红色的14位,红色的11位是温度的数据。 压强的计算方法:
I2C_BYTE4>>=5; I2C_temperature=I2C_BYTE3*8+I2C_BYTE4; I2C_pressure=(0x3f&I2C_BYTE1)*256+I2C_BYTE2; I2C_status=I2C_BYTE1>>6;//先移位还原原始数据 temp1=20.0/(14745.0-1638.0); Pressure_In_cmH2O=(temp1*(I2C_pressure-1638.0)+(-10.0)); temp2=(float)I2C_temperature/2048.0; Temperature_In_Celsius=(temp2*200.0)-50.0;工程文件和SMI的数据手册以及官方所给的编程指南已打包上传,有需要的朋友可以下载。 debug的结果