|   
 
 #define GET_I2C_SDA()             GPIO_ReadDataBit(GPIOF,GPIO_Pin_7)    // 读取SDA端口 #define SET_I2C_SCL()             GPIO_SetBits(GPIOF,GPIO_Pin_6)          // 时钟线SCL输出高电平 #define CLR_I2C_SCL()             GPIO_ResetBits(GPIOF,GPIO_Pin_6)        // 时钟线SCL输出低电平 #define SET_I2C_SDA()             GPIO_SetBits(GPIOF,GPIO_Pin_7)          // 数据线SDA输出高电平 #define CLR_I2C_SDA()             GPIO_ResetBits(GPIOF,GPIO_Pin_7)        // 数据线SDA输出低电平     #define I2C_DELAY           10              static void GpioInit(void) {          /*配置I2C管脚的功能 */          GPIO_InitTypeDefGPIO_InitStructure;//定义一个GPIO_InitTypeDef类型的结构体            GPIO_InitStructure.GPIO_Pin= GPIO_Pin_6 | GPIO_Pin_7;//选择要控制的GPIO引脚          GPIO_InitStructure.GPIO_Mode= GPIO_Mode_OutOD;//设置引脚模式为          GPIO_InitStructure.GPIO_Pull= GPIO_Pull_NoPull;//模式            GPIO_Init(GPIOF,&GPIO_InitStructure);                     //GPIOF GPIO_Pin_7 I2C0 SDA //GPIOF GPIO_Pin_6 I2C0 SCL  }   /** ******************************************************************* * @param * @brief    SCL为高电平时, SDA由高电平向低电平跳变,开始传输数据*          生成下图所示的波形图,即为起始时序  *                1 2    3    4    *                    __________      *          SCL : __/          \_____  *                 ________           *          SDA :         \___________  ******************************************************************* */ static void I2CStart(void) {          SET_I2C_SDA();          // 1#数据线SDA输出高电平          SET_I2C_SCL();          // 2#时钟线SCL输出高电平             DelayNus(I2C_DELAY);            // 延时4us          CLR_I2C_SDA();          // 3#数据线SDA输出低电平           DelayNus(I2C_DELAY);            // 延时4us          CLR_I2C_SCL();          // 4#时钟线SCL输出低电平,保持I2C的时钟线SCL为低电平,准备发送或接收数据           DelayNus(I2C_DELAY);            // 延时4us }   /** ******************************************************************* * @function 产生IIC停止时序   * @param * @return  * @brief   SCL为高电平时,SDA由低电平向高电平跳变,结束传输数据  *         生成下图所示的波形图,即为停止时序  *                1 2   3 4    *                       _______________      *         SCL : ______/           *                __        ____________   *         SDA:    \______/ ******************************************************************* */ static void I2CStop(void) {          CLR_I2C_SDA();          //2#数据线SDA输出低电平          DelayNus(I2C_DELAY);            //延时4us          SET_I2C_SCL();          //3#时钟线SCL输出高电平          DelayNus(I2C_DELAY);            SET_I2C_SDA();          //4#数据线SDA输出高电平,发送I2C总线结束信号 }   /** ******************************************************************* * @function 发送一字节,数据从高位开始发送出去 * @param   byte * @return  * @brief   下面是具体的时序图  *                1 2     3     4 *                         ______ *          SCL: ________/      \______     *                ______________________     *          SDA: \\\___________________ ******************************************************************* */ static void I2CSendByte(uint8_t byte) {                                    for(uint8_t i = 0; i < 8; i++)   // 循环8次,从高到低取出字节的8个位          {                         if((byte & 0x80))            // 2#取出字节最高位,并判断为‘0’还是‘1’,从而做出相应的操作                    {                             SET_I2C_SDA();            // 数据线SDA输出高电平,数据位为‘1’                    }                    else                    {                               CLR_I2C_SDA();           // 数据线SDA输出低电平,数据位为‘0’                    }                                        byte<<= 1;                              // 左移一位,次高位移到最高位                                        DelayNus(I2C_DELAY);                     // 延时4us                    SET_I2C_SCL();                // 3#时钟线SCL输出高电平                    DelayNus(I2C_DELAY);                     // 延时4us                    CLR_I2C_SCL();                            // 4#时钟线SCL输出低电平                    DelayNus(I2C_DELAY);                  // 延时4us            }   }   /** ******************************************************************* * @function 读取一字节数据 * @param    * @return  读取的字节 * @brief   下面是具体的时序图 *                       ______ *          SCL: ______/      \___         *                ____________________     *          SDA: \\\\______________\\\ ******************************************************************* */ static uint8_t I2CReadByte(void) {          uint8_tbyte = 0;                             // byte用来存放接收的数据          SET_I2C_SDA();                      // 释放SDA          for(uint8_t i = 0; i < 8; i++)     // 循环8次,从高到低读取字节的8个位          {                    SET_I2C_SCL();                        //时钟线SCL输出高电平                    DelayNus(I2C_DELAY);                          //延时4us                    byte<<= 1;                               // 左移一位,空出新的最低位                      if(GET_I2C_SDA())                     // 读取数据线SDA的数据位                    {                             byte++;                                   //在SCL的上升沿后,数据已经稳定,因此可以取该数据,存入最低位                    }                    CLR_I2C_SCL();                        //时钟线SCL输出低电平                    DelayNus(I2C_DELAY);                          //延时4us          }            returnbyte;                                               // 返回读取到的数据 }   /** ******************************************************************* * @function 等待接收端的应答信号 * @param    * @return  1,接收应答失败;0,接收应答成功 * @brief   当SDA拉低后,表示接收到ACK信号,然后,拉低SCL, *          此处表示发送端收到接收端的ACK *                _______|____      *          SCL:        |    \_________     *                _______|      *          SDA:         \_____________  ******************************************************************* */ static bool I2CWaitAck(void) {          uint16_terrTimes = 0;                    SET_I2C_SDA();             // 释放SDA总线,很重要          DelayNus(I2C_DELAY);               // 延时4us                    SET_I2C_SCL();             // 时钟线SCL输出高电平          DelayNus(I2C_DELAY);               // 延时4us            while(GET_I2C_SDA())      // 读回来的数据如果是高电平,即接收端没有应答          {                    errTimes++;            // 计数器加1                      if(errTimes > 250)    // 如果超过250次,则判断为接收端出现故障,因此发送结束信号                    {                             I2CStop();         // 产生一个停止信号                             returnfalse;      // 返回值为1,表示没有收到应答信号                    }          }            CLR_I2C_SCL();             // 表示已收到应答信号,时钟线SCL输出低电平          DelayNus(I2C_DELAY);               // 延时4us                    returntrue;               // 返回值为0,表示接收应答成功   }   /** ******************************************************************* * @function 发送应答信号 * @param    * @return   * @brief   下面是具体的时序图  *                 1 2     3     4      5      *                         ______ *          SCL: ________/     \____________     *                __                     ______ *          SDA:   \___________________/         ******************************************************************* */ void I2CSendAck(void) {          CLR_I2C_SDA();          // 2#数据线SDA输出低电平          DelayNus(I2C_DELAY);            // 延时4us          SET_I2C_SCL();          // 3#时钟线SCL输出高电平,在SCL上升沿前就要把SDA拉低,为应答信号          DelayNus(I2C_DELAY);            // 延时4us          CLR_I2C_SCL();          // 4#时钟线SCL输出低电平          DelayNus(I2C_DELAY);            // 延时4us          SET_I2C_SDA();          // 5#数据线SDA输出高电平,释放SDA总线,很重要 }   /** ******************************************************************* * @function 发送非应答信号 * @param    * @return   * @brief   下面是具体的时序图  *               1 2     3     4 *                        ______ *         SCL: ________/      \______     *               __ ___________________     *         SDA: __/ ******************************************************************* */ void I2CSendNack(void) {          SET_I2C_SDA();          // 2#数据线SDA输出高电平          DelayNus(I2C_DELAY);            // 延时4us          SET_I2C_SCL();          // 3#时钟线SCL输出高电平,在SCL上升沿前就要把SDA拉高,为非应答信号          DelayNus(I2C_DELAY);            // 延时4us          CLR_I2C_SCL();          // 4#时钟线SCL输出低电平          DelayNus(I2C_DELAY);            // 延时4us }   #define NSHT30_DEV_ADDR                            0x44 //NSHT30的设备地址 #define NSHT30_I2C_WR                                       0                //写控制bit #define NSHT30_I2C_RD                1                // 读控制bit #define TRIG_TEMP_MEASUREMENT_HM          0xE3   // command trig. temp meas. hold master #define TRIG_HUMI_MEASUREMENT_HM                0xE5    // command trig. humiditymeas. hold master #define TRIG_TEMP_MEASUREMENT_POLL            0xF3    // command trig. tempmeas. no hold master #define TRIG_HUMI_MEASUREMENT_POLL    0xF5    // command trig. humiditymeas. no hold master   #define TRIG_TEMP_HUMI_MEASUREMENT    0x2C06   // command trig.humidity  temp meas #define NSHT30_SOFT_RESET                0x30A2    // command soft reset #define NSHT30_RESOLUTION_REG                         0xE6   // 设置分辨率寄存器地址 #define NSHT30_RESOLUTION_VAL                         0x83   // 设置分辨率bit7 = 1,bit0 = 0,对应湿度10bit,温度13bit #define NSHT30_READ_REG                                              0XE7   //NSHT30驱动代码 #define CMD_MEAS_SINGLE_H 0x2400 //measurement: SINGLE Mode high repeatability #define CMD_MEAS_SINGLE_M 0x240B //measurement: SINGLE Mode medium repeatability #define CMD_MEAS_SINGLE_L 0x2416 //measurement: SINGLE Mode low repeatability #define CMD_MEAS_PERI_05_H 0x2032 //measurement: periodic Mode 0.5 mps high repeatability #define CMD_MEAS_PERI_05_M 0x2024 //measurement: periodic Mode 0.5 mps medium repeat[1]ability #define CMD_MEAS_PERI_05_L 0x202F //measurement: periodic Mode 0.5 mps low repeatability #define CMD_MEAS_PERI_1_H 0x2130 //measurement: periodic Mode 1 mps high repeatability #define CMD_MEAS_PERI_1_M 0x2126 //measurement: periodic Mode 1 mps medium repeatability #define CMD_MEAS_PERI_1_L 0x212D //measurement: periodic Mode 1 mps low repeatability #define CMD_MEAS_PERI_2_H 0x2236 //measurement: periodic Mode 2 mps high repeatability #define CMD_MEAS_PERI_2_M 0x2220 //measurement: periodic Mode 2 mps medium repeatability #define CMD_MEAS_PERI_2_L 0x222B //measurement: periodic Mode 2 mps low repeatability #define CMD_MEAS_PERI_4_H 0x2334 //measurement: periodic Mode 4 mps high repeatability #define CMD_MEAS_PERI_4_M 0x2322 //measurement: periodic Mode 4 mps medium repeatability   #define CMD_MEAS_PERI_4_L 0x2329 //measurement: periodic Mode 4 mps low repeatability #define CMD_MEAS_PERI_10_H 0x2737 //measurement: periodic Mode 10 mps high repeatability #define CMD_MEAS_PERI_10_M 0x2721 //measurement: periodic Mode 10 mps medium repeat[1]ability #define CMD_MEAS_PERI_10_L 0x272A //measurement: periodic Mode 10 mps low repeatability   static bool Nsht30SoftReset(void)                     {          I2CStart();          I2CSendByte((NSHT30_DEV_ADDR<<1)| NSHT30_I2C_WR);          if(!I2CWaitAck())          {                    gotoi2c_err;          }                              I2CSendByte((NSHT30_SOFT_RESET&0xFF00)>>8);          if(!I2CWaitAck())          {                    gotoi2c_err;          }                    I2CSendByte(NSHT30_SOFT_RESET&0xFF);          if(!I2CWaitAck())          {                    gotoi2c_err;          }                              I2CStop();          returntrue;   i2c_err:          // 命令执行失败后,要发送停止信号,避免影响I2C总线上其他设备          I2CStop();          returnfalse; }       static bool Nsht30SetResolution(uint8_t*pBuffer) {          uint16_tnumToRead=5;                    I2CStart();          I2CSendByte((NSHT30_DEV_ADDR<<1)| NSHT30_I2C_WR);          if(!I2CWaitAck())          {                    gotoi2c_err;          }                    I2CSendByte((CMD_MEAS_SINGLE_L&0xFF00)>>8);          if(!I2CWaitAck())          {                    gotoi2c_err;          }                    I2CSendByte(CMD_MEAS_SINGLE_L&0xFF);          if(!I2CWaitAck())          {                    gotoi2c_err;          }                              I2CStop();                    DelayNms(I2C_DELAY);          I2CStart();                                        // 发送起始信号                    I2CSendByte((NSHT30_DEV_ADDR<<1)| NSHT30_I2C_RD);      // 发送器件地址和读写模式,1 0 1 0 x  x  x R/~W  0xA1                     if(!I2CWaitAck())                                // 等待应答          {                    gotoi2c_err;          }                    while(numToRead--)                                // 数据未读完          {                    *pBuffer++= I2CReadByte();                   // 逐字节读出存放到数据数组                    I2CSendAck();          }          *pBuffer= I2CReadByte();                        // 最后一个字节发送非应答          I2CSendNack();                      I2CStop(); i2c_err:          // 命令执行失败后,要发送停止信号,避免影响I2C总线上其他设备          I2CStop();          returnfalse; }       bool TempHumizhuanhuan(uint8_t *dat,double*pot) {          uint16_ttem,hum;                    tem= ((uint16_t)dat[0]<<8) | dat[1];          hum= ((uint16_t)dat[3]<<8) | dat[4];          if((crc8(dat,2)== dat[2]) && (crc8(dat+3,2) == dat[5]))          {                    pot[0]=(175.0*(double)tem/65535.0-45.0) ;// T = -45 + 175 * tem / (2^16-1)                    pot[1]=(100.0*(double)hum/65535.0);// RH = hum*100 / (2^16-1)                     return1;           }          else          {                    return0;          } } float tempData, humiData; uint8_t buffer[10]; double rth[2]; void TempHumiDrvTest(void) {                          Nsht30SetResolution(buffer);          printf("Get%x %x %x %x %x%x\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5]);           TempHumizhuanhuan(buffer,rth);          printf("%3.4f,%3.6f%%\r\n",rth[0],rth[1]); } 
 
 |