Bootstrap

超详细!新手必看!STM32基础-IIC串行通信协议-IO口模拟IIC操作BMP180


  
  IIC(Inter-Integrated Circuit)是一种常用的串行通信协议,通常用于连接微控制器和各种外部设备(例如传感器、存储器、显示器等)。

●IIC、UART、SPI的比较:

通信协议UARTIICSPI
通信特征异步串行全双工同步串行半双工同步串行全双工
接口TX、RXSCL、SDAMOSI、MISO、SCL、CS/NSS
速度多种波特率100Khz、400Khz、3.4Mhz
数据帧格式起始位+数据位+校验位+停止位起始条件+位传输+应答+停止条件四种模式:MODE0~MODE3
主从设备通信没有主从有主从有主从
总线结构一对一一对多一对多

一、知识点


1. 12C总线两线制包括: 串行数据SDA (Serial Data)、串行时钟SCL(Serial Clock)。

2. I2C总线上有主机和从机之分,可以有多个主机和多个从机。IIC总线上的电容不超过400pf,只要不超过这个电容量,任意挂多少个从机都可以。但是在通信的时刻,只能有一个作为主机,其他的都为从机。

3. 器件发送数据到总线上,则定义为发送器,器件接收数据则定义为接收器。主器件和从器件都可以工作于接收和发送状态(都可以作为发送器和接收器)。从机永远不会主动给主机发送数据

4. 时钟线SCL必须由主机控制主机控制时钟线SCL产生跳变沿, 谁控制SCL时钟线,谁就是主机!

5. 每个IIC设备都有一个唯一的地址。在通信开始之前,你需要知道要与主机进行通信的设备的地址。每个设备都有一个唯一的7位地址(4位固定地址+3位可编程地址),用于在总线上区分不同的设备。注:有些从设备的7位地址商家已经给固定好了,所以就不需要自行设计,查看商家给的手册就可以知道该地址。
在这里插入图片描述
如:AT24C02芯片中的A0、A1、A2就是可编程地址位,可以自行设计该位。下图中A0、A1、A2接地,则都为0。
在这里插入图片描述

6. 数据的有效性: 时钟线产生下降沿,发送方准备/发送数据。时钟线产生上升沿,接收方采集数据。
   SDA数据线在 SCL 的每个时钟周期传输一位数据。传输时:
  (1)SCL 为高电平的时候 SDA 表示的数据有效,即此时的 SDA 为高电平时表示数据 “1”,为低电平时表示数据“ 0”。
  (2)当 SCL为低电平时,SDA 的数据无效,一般在这个时候 SDA 进行电平切换,为下一次表示数据做好准备。
在这里插入图片描述

  1. 主机与从机通信
      无论主机是向从机写数据还是读取数据,主机发送给从机的第一个字节必须是从机设备地址和写方向位。主机跟哪个从机通讯,把从机的地址发出去。发送数据是8个bit,这8个bit位中前7个bit位是从机的地址,最后1个bit位是用来表示读或者写的。1表示读,0表示写;这个过程相当于主机往SDA上发了8个bit的数据。
      主机发送的第一个字节主要是为了寻找与其通信的从机。

●如果你已知从机的七位地址(0111 100)。
要进行写操作:Write_IIC_Byte (0x78); // (0111 1000)
要进行读操作:Write_IIC_Byte (0x79); // (0111 1001)

二、硬件IIC内部

  1. 为了搞清楚IIC的内部结构图,我们需要首先明白一个知识点:器件芯片是如何输出高低电平的?
      答:芯片内部有两个mos管,一个接高电平,一个接低电平。当上面的mos管导通时,输出高电平。下面的mos管导通时输出低电平。
    在这里插入图片描述
  2. IIC内部有多个从机,如果一个从机发出高电平,一个从机发出低电平。那么这个数据线上到底是高电平还是低电平呢?
      答:如果一个从机发出高电平,一个从机发出低电平,那么这两个从机的芯片内部会被导通,那么必定有一个元器件会被烧毁。所以IIC通信对从机设备的IO进行了阉割,那就是去掉了上面的mos管,这样就不会造成短路烧毁元器件了,并且从机只能输出低电平。这样数据线上肯定为低电平了。但是这样会有另一个问题:即从机只能输出低电平,如何输出高电平呢?
    在这里插入图片描述
  3. 如何解决从机只能输出低电平的问题呢?
    在这里插入图片描述
      答:即在IIC总线上加上上拉电阻。这样当总线空闲时,默认为高电平,从机设备想输出低电平,则只需要把下面的mos管打开,则总线变为了低电平。如果想输出高电平,则关闭mos管即可。可以使用GPIO的开漏输出功能,来拉低端口电平。

三、软件模拟IIC基础

  当我们使用端口来模拟IIC时序从而控制从机设备时,我们可以选择任意两个IO口作为SCL和SDA端,只要这两个IO口可以正常输入输出即可!并不是固定的IIC端口。

1. 端口模式选择

  我认为这部分是一个比较重要的地方!我在查看其他博客时发现模式的选择多种多样。主要为以下几种。

(1)SDA、SCL:都为开漏输出模式。
  这种模式适用于开发板设计的电路原理图中,一条IIC总线上挂载了多个从机元器件,为了防止烧毁器件,所以设置为开漏输出模式。至于为什么端口设置了开漏输出模式还是可以读取值,请查看这篇文章:端口模式问题详情。

(2)SCL:推挽输出模式,SDA:主机读–输入,主机写–输出
  这种模式适用于一个IIC总线上只有一个从机设备,不需要担心被烧毁的问题。

  这里我们选择第二种模式进行编写IIC时序。因为我们只是任意用两个IO口作为SCL和SDA来进行连接设备通信,且只能连接一个设备。

//使用寄存器来配置模式
#define SDA_IN()  {GPIOA->CRH&=0XFFF0FFFF; GPIOA->CRH|=8<<16;}  //输入模式
#define SDA_OUT() {GPIOA->CRH&=0XFFF0FFFF; GPIOA->CRH|=3<<16;}  //输出模式

#define IIC_SCL    PAout(11) //SCL
#define IIC_SDA    PAout(12) //SDA	 
#define READ_SDA   PAin(12)  //读取SDA值 

void IIC_Init(void)
{			
	GPIO_InitTypeDef GPIO_InitStructure;  
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA, ENABLE );
	   
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);    
}

2. 选择目标设备地址(制造商预先分配,查看手册获取)

  每个I2C设备都有一个唯一的地址。在通信开始之前,你需要知道你要与之通信的设备的地址。每个设备都有一个唯一的7位地址,用于在总线上区分不同的设备。

3. IIC起始信号

  主机发送一个启动信号来开始I2C通信(唤醒所有的从机设备)。起始信号的生成标志着I2C通信的开始,接着就可以发送目标设备的地址和读写位来开始通信。

在这里插入图片描述

  步骤:初始SDA、SCL线都为高电平,维持一小段时间。然后SCL为高电平时,SDA由高变为低电平(起始信号),再维持一小段时间。然后SCL再变为低电平,这就是启动信号的完整步骤。

int IIC_Start(void)
{
	SDA_OUT();     //SDA配置为输出模式
	IIC_SDA=1;
	IIC_SCL=1;
	delay_us(1);
	
 	IIC_SDA=0;   //START:when CLK is high,DATA change form high to low 
	delay_us(1);
	IIC_SCL=0;  //发送方准备数据
	return 1;
}

4. IIC停止信号

发送停止信号以结束I2C通信。
在这里插入图片描述

  步骤:初始都先为低电平,稳定一段时间后SCL先拉高,SDA再拉高,再稳定一小段时间。这就是IIC的停止信号。即SCL为高电平时,SDA线由低电平变为高电平。

void IIC_Stop(void)
{
    SDA_OUT(); // 将SDA配置为输出模式
    IIC_SCL = 0; // 将SCL线拉低,准备结束通信
    IIC_SDA = 0; // 将SDA线拉低,准备停止条件
    delay_us(1); // 延迟1微秒,确保SDA和SCL稳定
    
    IIC_SCL = 1; // 将SCL线拉高,准备停止条件
    IIC_SDA = 1; // 在SCL为高电平时,将SDA线拉高,形成停止条件
    delay_us(1); // 延迟1微秒,确保停止条件稳定
}

5. 主机发送 应答和非应答信号

void IIC_Ack(void)  //应答信号
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=0;
	delay_us(1);
	IIC_SCL=1;
	delay_us(1);
	IIC_SCL=0;
}
	    
void IIC_NAck(void) //非应答信号
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=1;
	delay_us(1);
	IIC_SCL=1;
	delay_us(1);
	IIC_SCL=0;
}

6. 主机 等待从机的应答信号

  从机的应答信号不需要我们来编写,因为从机接收到数据后会自己进行应答,我们只需要等待接收从机的应答即可。
在这里插入图片描述
  从上图中可以看出,在保持SCL高电平的状态下,通过读取SDA线的电平状态来判断从机是否应答,由于SDA默认是为高电平(即非应答),所以当从机应答时会操作SDA线,将SDA线拉低,而不动则视为非应答。

int IIC_Wait_Ack(void)
{
	u8 ucErrTime=0;  //超时时间
	SDA_IN();    
	IIC_SDA=1;  //默认为非应答
	delay_us(1);	   
	IIC_SCL=1;
	delay_us(1);	 
	while(READ_SDA) //读取SDA线
	{
		ucErrTime++;
		if(ucErrTime>50)
		{
			IIC_Stop();
			return 0;
		}
	  delay_us(1);
	}
	IIC_SCL=0;
	return 1;  
} 

7. 主机向从机某个寄存器写数据

①时钟线SCL产生下降沿,发送方准备/发送数据。时钟线SCL产生上升沿,接收方采集数据。
②每次8bit的数据传输完成,都要有个应答信号,谁接收数据,谁来应答。

通信流程如下:
在这里插入图片描述

void IIC_Send_Byte(u8 txd)
{                        
    u8 i;   
	SDA_OUT(); 	    
    IIC_SCL=0; //发送方准备发送数据
    for(i=0; i<8; i++)
    {              
        IIC_SDA=(txd &0x80 )>>7;  //SDA数据线发送数据,从数据的最高位开始发送。
        txd<<=1; 	  
		delay_us(1);   
		IIC_SCL=1;  //接受方采集数据
		delay_us(1); 
		IIC_SCL=0;	  //发送方发送数据
		delay_us(1);
    }	 
} 	

//写数据
int i2cWrite(uint8_t addr, uint8_t reg, uint8_t len, uint8_t *data)  
{
	int i;
    if (!IIC_Start()) return 1;
    IIC_Send_Byte(addr << 1 ); //将从机地址左移一位,包含上了读写位。写:0,读:1
    
    if (!IIC_Wait_Ack()) {
        IIC_Stop();
        return 1;
    }
    IIC_Send_Byte(reg);
    IIC_Wait_Ack();
    
	for (i = 0; i < len; i++) {
		IIC_Send_Byte(data[i]);
		if (!IIC_Wait_Ack()) {
			IIC_Stop();
			return 0;
		}
	}
    IIC_Stop();
    return 0;
}

8. 主机读取从机某个寄存器的数据

①时钟线SCL产生下降沿,发送方准备/发送数据。时钟线SCL产生上升沿,接收方采集数据。
②每次8bit的数据传输完成,都要有个应答信号,谁接收数据,谁来应答。

通信流程如下:
在这里插入图片描述

u8 IIC_Read_Byte(unsigned char ack)
{
    unsigned char i, receive = 0;
    SDA_IN(); // SDA配置为输入模式
    for (i = 0; i < 8; i++)
    {
        IIC_SCL = 0; 
        delay_us(2);
        IIC_SCL = 1;
        receive <<= 1;
        if (READ_SDA) receive++;   
        delay_us(2); 
    }                     
    if (ack)
        IIC_Ack(); // 发送ACK信号
    else
        IIC_NAck(); // 发送NACK信号
    return receive;
}

//读取从机地址,寄存器上的数据。
int i2cRead(uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf)
{
    if (!IIC_Start())
        return 1;
    IIC_Send_Byte(addr << 1);  //将从机地址和写方向
    if (!IIC_Wait_Ack()) {
        IIC_Stop();
        return 1;
    }
    IIC_Send_Byte(reg);
    IIC_Wait_Ack();
    
    IIC_Start();
    IIC_Send_Byte((addr << 1) +1);
    IIC_Wait_Ack();
    
    while (len) {
        if (len == 1)
            *buf = IIC_Read_Byte(0);  //最后一个数据发送非应答信号。
        else
            *buf = IIC_Read_Byte(1);
        buf++;
        len--;
    }
    IIC_Stop();
    return 0;
}

四、通用IIC文件

如需要更改IIC引脚,请查看文章附录部分:寄存器下IIC引脚如何更换。

iic.c

#include "iic.h"
#include "sys.h"
#include "delay.h"


void IIC_Init(void)
{			
		
	GPIO_InitTypeDef GPIO_InitStructure;  
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA, ENABLE );	
	   
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;  
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);      
}


//开始信号
int IIC_Start(void)
{
	SDA_OUT();  
	IIC_SDA=1;
	if(!READ_SDA)return 0;	
	IIC_SCL=1;
	delay_us(1);
 	IIC_SDA=0;
	if(READ_SDA)return 0;
	delay_us(1);
	IIC_SCL=0;
	return 1;
}

//停止信号  
void IIC_Stop(void)
{
	SDA_OUT();
	IIC_SCL=0;
	IIC_SDA=0;
 	delay_us(1);
	IIC_SCL=1; 
	IIC_SDA=1;
	delay_us(1);							   	
}


//主机等待应答
int 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>50)
		{
			IIC_Stop();
			return 0;
		}
	  delay_us(1);
	}
	IIC_SCL=0;	   
	return 1;  
} 

//应答信号  
void IIC_Ack(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=0;
	delay_us(1);
	IIC_SCL=1;
	delay_us(1);
	IIC_SCL=0;
}
	
//非应答信号    
void IIC_NAck(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=1;
	delay_us(1);
	IIC_SCL=1;
	delay_us(1);
	IIC_SCL=0;
}


//IIC 写
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(1);   
		IIC_SCL=1;
		delay_us(1); 
		IIC_SCL=0;	
		delay_us(1);
    }	 
} 	 
  

int i2cWrite(uint8_t addr, uint8_t reg, uint8_t len, uint8_t *data)
{
		int i;
    if (!IIC_Start())
        return 1;
    IIC_Send_Byte(addr << 1 );
    if (!IIC_Wait_Ack()) {
        IIC_Stop();
        return 1;
    }
    IIC_Send_Byte(reg);
    IIC_Wait_Ack();
		for (i = 0; i < len; i++) {
        IIC_Send_Byte(data[i]);
        if (!IIC_Wait_Ack()) {
            IIC_Stop();
            return 0;
        }
    }
    IIC_Stop();
    return 0;
}

// IIC 读
u8 IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	SDA_IN();//SDA?????????
    for(i=0;i<8;i++ )
	{
        IIC_SCL=0; 
        delay_us(2);
		    IIC_SCL=1;
        receive<<=1;
        if(READ_SDA)receive++;   
		delay_us(2); 
    }					 
    if (ack)
        IIC_Ack(); 
    else
        IIC_NAck();
    return receive;
}


int i2cRead(uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf)
{
    if (!IIC_Start())
        return 1;
    IIC_Send_Byte(addr << 1);
    if (!IIC_Wait_Ack()) {
        IIC_Stop();
        return 1;
    }
    IIC_Send_Byte(reg);
    IIC_Wait_Ack();
    IIC_Start();
    IIC_Send_Byte((addr << 1)+1);
    IIC_Wait_Ack();
    while (len) {
        if (len == 1)
            *buf = IIC_Read_Byte(0);
        else
            *buf = IIC_Read_Byte(1);
        buf++;
        len--;
    }
    IIC_Stop();
    return 0;
}

iic.h

#ifndef __IOI2C_H
#define __IOI2C_H
#include "stm32f10x.h"


#define SDA_IN()  {GPIOA->CRH&=0XFFF0FFFF;GPIOA->CRH|=8<<16;}
#define SDA_OUT() {GPIOA->CRH&=0XFFF0FFFF;GPIOA->CRH|=3<<16;}

#define IIC_SCL    PAout(11) //SCL
#define IIC_SDA    PAout(12) //SDA	 
#define READ_SDA   PAin(12)  //????SDA 



void IIC_Init(void);               		 
int IIC_Start(void);				
void IIC_Stop(void);	  		
int IIC_Wait_Ack(void); 			
void IIC_Ack(void);				
void IIC_NAck(void);			
void IIC_Send_Byte(u8 txd);		
int i2cWrite(uint8_t addr, uint8_t reg, uint8_t len, uint8_t *data);
	
u8 IIC_Read_Byte(unsigned char ack);
int i2cRead(uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf);

#endif

五、实验(获取BMP180温度/气压)

从机设备地址:0x77。具体操作流程请查看文章:BMO180通信软件编写流程。

bmp180.c

#include "bmp180.h"
#include "iic.h"
#include "delay.h"


int32_t b5;  // 在全局范围内声明b5
extern BMP180_Calibration bmp180_calibration;

//读取校准参数
int BMP180_ReadCalibrationData(BMP180_Calibration *calibration) {
    uint8_t buffer[22];
    if (i2cRead(0x77, BMP180_CAL_AC1, 22, buffer)) {
        return 1;
    }
    calibration->ac1 = (buffer[0] << 8) | buffer[1];
    calibration->ac2 = (buffer[2] << 8) | buffer[3];
    calibration->ac3 = (buffer[4] << 8) | buffer[5];
    calibration->ac4 = (buffer[6] << 8) | buffer[7];
    calibration->ac5 = (buffer[8] << 8) | buffer[9];
    calibration->ac6 = (buffer[10] << 8) | buffer[11];
    calibration->b1 = (buffer[12] << 8) | buffer[13];
    calibration->b2 = (buffer[14] << 8) | buffer[15];
    calibration->mb = (buffer[16] << 8) | buffer[17];
    calibration->mc = (buffer[18] << 8) | buffer[19];
    calibration->md = (buffer[20] << 8) | buffer[21];
    return 0;
}

读取未校准的温度值
int BMP180_ReadTemperature(int32_t *temperature) {
    int32_t ut;
    uint8_t buffer[2];
    uint8_t cmd = BMP180_READ_TEMP_CMD;  // 使用中间变量存储命令
    if (i2cWrite(0x77, BMP180_CONTROL, 1, &cmd)) {
        return 1;
    }
    delay_ms(5);
    if (i2cRead(0x77, BMP180_TEMP_DATA, 2, buffer)) {
        return 1;
    }
    ut = (buffer[0] << 8) | buffer[1];
    // 根据校准数据计算真实温度
    int32_t x1 = ((ut - bmp180_calibration.ac6) * bmp180_calibration.ac5) >> 15;
    int32_t x2 = (bmp180_calibration.mc << 11) / (x1 + bmp180_calibration.md);
    b5 = x1 + x2;  // 计算b5并存储在全局变量中
    *temperature = (b5 + 8) >> 4;
    return 0;
}

//读取未校准的气压值
int BMP180_ReadPressure(int32_t *pressure, uint8_t oss) {
    int32_t up;
    uint8_t buffer[3];
    uint8_t cmd = BMP180_READ_PRESSURE_CMD + (oss << 6);  // 使用中间变量存储命令
    if (i2cWrite(0x77, BMP180_CONTROL, 1, &cmd)) {
        return 1;
    }
    delay_ms(2 + (3 << oss));
    if (i2cRead(0x77, BMP180_PRESSURE_DATA, 3, buffer)) {
        return 1;
    }
    up = ((buffer[0] << 16) | (buffer[1] << 8) | buffer[2]) >> (8 - oss);
    // 根据校准数据计算真实压力
    int32_t b6 = b5 - 4000;  // 使用之前计算的b5
    int32_t x1 = (bmp180_calibration.b2 * (b6 * b6 >> 12)) >> 11;
    int32_t x2 = (bmp180_calibration.ac2 * b6) >> 11;
    int32_t x3 = x1 + x2;
    int32_t b3 = (((bmp180_calibration.ac1 * 4 + x3) << oss) + 2) >> 2;
    x1 = (bmp180_calibration.ac3 * b6) >> 13;
    x2 = (bmp180_calibration.b1 * (b6 * b6 >> 12)) >> 16;
    x3 = ((x1 + x2) + 2) >> 2;
    uint32_t b4 = (bmp180_calibration.ac4 * (uint32_t)(x3 + 32768)) >> 15;
    uint32_t b7 = ((uint32_t)up - b3) * (50000 >> oss);
    if (b7 < 0x80000000) {
        *pressure = (b7 * 2) / b4;
    } else {
        *pressure = (b7 / b4) * 2;
    }
    x1 = (*pressure >> 8) * (*pressure >> 8);
    x1 = (x1 * 3038) >> 16;
    x2 = (-7357 * *pressure) >> 16;
    *pressure += (x1 + x2 + 3791) >> 4;
    return 0;
}

bmp180.h

#ifndef __BMP180_H
#define __BMP180_H

#include "stm32f10x.h"

// BMP180寄存器地址
#define BMP180_CAL_AC1    0xAA
#define BMP180_CAL_AC2    0xAC
#define BMP180_CAL_AC3    0xAE
#define BMP180_CAL_AC4    0xB0
#define BMP180_CAL_AC5    0xB2
#define BMP180_CAL_AC6    0xB4
#define BMP180_CAL_B1     0xB6
#define BMP180_CAL_B2     0xB8
#define BMP180_CAL_MB     0xBA
#define BMP180_CAL_MC     0xBC
#define BMP180_CAL_MD     0xBE
#define BMP180_CONTROL    0xF4
#define BMP180_TEMP_DATA  0xF6
#define BMP180_PRESSURE_DATA 0xF6
#define BMP180_READ_TEMP_CMD  0x2E
#define BMP180_READ_PRESSURE_CMD 0x34

// 校准系数结构体
typedef struct {
    int16_t ac1;
    int16_t ac2;
    int16_t ac3;
    uint16_t ac4;
    uint16_t ac5;
    uint16_t ac6;
    int16_t b1;
    int16_t b2;
    int16_t mb;
    int16_t mc;
    int16_t md;
} BMP180_Calibration;

// 函数声明
void BMP180_Init(void);

int BMP180_ReadCalibrationData(BMP180_Calibration *calibration);
int BMP180_ReadTemperature(int32_t *temperature);
int BMP180_ReadPressure(int32_t *pressure, uint8_t oss);

#endif

main.c

#include "stm32f10x.h"
#include "iic.h"
#include "bmp180.h"
#include "stdio.h"

int32_t temperature, pressure;
BMP180_Calibration bmp180_calibration;

int main(void) 
{
	delay_init();  //必须要有这个
	IIC_Init();
	BMP180_ReadCalibrationData(&bmp180_calibration);

    while(1)
		{
			BMP180_ReadTemperature(&temperature);  // 读取温度
			BMP180_ReadPressure(&pressure, 0);  // 读取压力
			
			temperature=temperature/10;
			pressure=pressure/100;
			delay(1000);
    }
}
;