目录
概述
1 软硬件接口
1.1 MCU与SHT20接口
1.2 开发软硬件信息
1.3 SHT-20模块电路
2 I2C软件接口实现
2.1 MCU相关接口
2.2 软件接口实现
2.3 初始化struct I2C
3 SHT20驱动程序实现
3.1 SHT20驱动调用I2C接口
3.2 驱动源代码文件
4 测试
4.1 测试代码实现
4.2 运行程序
源代码下载地址:
通用性I2C接口的应用之驱动SHT20(N32G45XVL-STB)资源-CSDN文库
概述
本文主要介绍使用通用性I2C接口的驱动SHT20 sensor,文中介绍了如何初始化I2C port。笔者使用N32G45XVL-STB板卡作为主控。文中介绍了IO的配置方法。还介绍了device驱动中如何调用i2c的接口。最后设计一个测试程序以验证驱动是否能够正常工作。
1 软硬件接口
1.1 MCU与SHT20接口
MCU接口 | SHT20 | 功能 |
---|---|---|
PB6 | SDA | I2C数据端口 |
PB7 | SCL | I2C时钟接口 |
1.2 开发软硬件信息
软硬件信息 | 版本信息 |
---|---|
N32G45x MCU | N32G457VEL7 |
Keil | MDK ARM 5.38 |
调试工具:CMSIS-DAP | NS-LINK |
1.3 SHT-20模块电路
1)SHT20硬件接口图
2) sensor模块电路
2 I2C软件接口实现
2.1 MCU相关接口
在i2c_master.c文件中,和i2c相关的接口函数 已经实现出来了。在使用这些接口之前,struct I2C中的数据结构必须被初始化,这样接口函数才能调用struct I2C中的函数参数,例如:
I2C stru_Sht2xDrv;// 初始化函数接口
void i2c_Sht2xDrvRegisterPort(void)
{stru_Sht2xDrv.IIC_InitPort = i2c_init_port;stru_Sht2xDrv.IIC_READ_SCL = i2c_SCL_READ;stru_Sht2xDrv.IIC_READ_SCL = i2c_SDA_READ;stru_Sht2xDrv.IIC_SCL_H = set_i2c_scl_1;stru_Sht2xDrv.IIC_SCL_L = set_i2c_scl_0;stru_Sht2xDrv.IIC_SDA_H = set_i2c_sda_1;stru_Sht2xDrv.IIC_SDA_L = set_i2c_sda_0;
}// 调用方法
static void demo_WriteRegister(uint8_t val, uint8_t reg)
{ i2c_master_Start(&stru_Sht2xDrv);i2c_master_SendByte( &stru_Sht2xDrv, DEMO_ADDRESS ); //Slave address,SA0=0 i2c_master_WaitAck( &stru_OledDrv );i2c_master_SendByte( &stru_Sht2xDrv, reg ); //write register i2c_master_WaitAck( &stru_Sht2xDrv);i2c_master_SendByte( &stru_Sht2xDrv, val ); i2c_master_WaitAck( &stru_Sht2xDrv);i2c_master_Stop( &stru_Sht2xDrv);
}
struct I2C的定义如下:
2.2 软件接口实现
1)IO相关的端口定义
在项目文件中,创建一个sht2x_port.c文件,在该文件中实现和MCU IO相关的接口
代码第23行: 定义总线时钟接口
代码第25行:定义GPIO Port
代码第26行:SCL 对应的pin
代码第27行:SDA对应的pin
代码第29~30行:SCL Pin电平变化定义
代码第32~33行:SDA Pin电平变化定义
2) MCU IO端口初始化
代码第36行:定义I2C数据结构
代码第41~54行:初始化I2C接口对应的两个IO
3) 读pin电平函数
代码第57~74行: 读SDA pin电平
代码第76~93行: 读SCL pin电平
4) 设置SCL和SDA电平引脚函数
2.3 初始化struct I2C
在完成I2C要求的函数定义之后,就可以初始化struct I2C ,其具体方法如下:
3 SHT20驱动程序实现
3.1 SHT20驱动调用I2C接口
在文件sht2x_port.c文件中已经定义了数据结构I2C stru_Sht2xDrv, 那么在其驱动文件sht2x.c只需调用该数据结构即可。
代码第365行: 初始化i2c 端口
代码第248行: 调用i2c_master_Start
代码第249行: 调用i2c_master_SendByte,发送一个byte
代码第249行: 调用i2c_master_WaitAck
3.2 驱动源代码文件
1)创建sht2x.c文件,编写如下代码:
/** \file$Id: sht2x.c 40486 2018-08-12 13:50:21Z tangmingfei2013@126.com $Copyright (c)tangmingfei2013@126.com Holding B.V.
All Rights Reserved.This source code and any compilation or derivative thereof is the proprietary
information of mingfei.tang Lighting Holding B.V. and is confidential in nature.
Under no circumstances is this software to be combined with any
Open Source Software in any way or placed under an Open Source License
of any type without the express written permission of mingfei.tang Holding B.V.
*//*******************************************************************************
* EXPORT INCLUDE FILES
*******************************************************************************/
#include "sht2x_port.h"
#include "sht2x.h"/******************************************************************************
* LOCAL MACROS AND DEFINITIONS
******************************************************************************/
#define i2c_master_ADDRESS (0x40 << 1)
#define POLY 0x131; //P(x)=x^8+x^5+x^4+1 = 100110001#define DELAY_CNT 4500 //for N32G45, sleep time is 6.4 ms static shtOpt s_ShtOpt;
/******************************************************************************
* LOCAL FUNCTION DECLARATIONS
******************************************************************************/
static void i2c_master_Delay(uint16_t value );
static uint8_t sht2xdrv_CheckCrc(uint8_t data[], uint8_t nbrOfBytes, uint8_t checksum);
static uint8_t sht2xdrv_CheckOk(void);
static int32_t sht2xdrv_CalcTemperatureC(uint16_t u16sT);
static int32_t sht2xdrv_CalcRH(uint16_t u16sRH);static void i2c_master_Delay(uint16_t value )
{uint16_t i;for (i = 0; i < value; i++);
}static uint8_t sht2xdrv_CheckCrc(uint8_t data[], uint8_t nbrOfBytes, uint8_t checksum)
{uint8_t res = 0;uint8_t crc = 0;uint8_t byteCtr;//calculates 8-Bit checksum with given polynomialfor (byteCtr = 0; byteCtr < nbrOfBytes; ++byteCtr){crc ^= (data[byteCtr]);for (uint8_t bit = 8; bit > 0; --bit){if (crc & 0x80){crc = (crc << 1) ^ POLY;}else{crc = (crc << 1);}}}if (crc != checksum){res = 1;}return res;
}static uint8_t sht2xdrv_CheckOk(void)
{if (i2c_master_CheckDevice(&stru_Sht2xDrv, i2c_master_ADDRESS ) == 0){/* sensor is online*/return 1;}else{/* fail: send stop */i2c_master_Stop( &stru_Sht2xDrv );return 0;}
}static uint8_t sht2xdrv_ReadUserRegister( uint8_t *pRegisterValue )
{uint8_t ret = SHT2x_STATUS_OK;uint8_t cmd = USER_REG_R;// write address i2c_master_Start( &stru_Sht2xDrv );i2c_master_SendByte( &stru_Sht2xDrv, i2c_master_ADDRESS | I2C_MATER_W ); // Device address if (i2c_master_WaitAck(&stru_Sht2xDrv) != 0){goto cmd_fail;}i2c_master_SendByte( &stru_Sht2xDrv, cmd);if (i2c_master_WaitAck( &stru_Sht2xDrv ) != 0){goto cmd_fail;}//Read register value i2c_master_Start( &stru_Sht2xDrv );i2c_master_SendByte( &stru_Sht2xDrv, i2c_master_ADDRESS | I2C_MATER_R);if (i2c_master_WaitAck( &stru_Sht2xDrv ) != 0){goto cmd_fail;} *pRegisterValue = i2c_master_ReadByte( &stru_Sht2xDrv );i2c_master_NAck( &stru_Sht2xDrv );i2c_master_Stop( &stru_Sht2xDrv );return ret;cmd_fail: i2c_master_Stop( &stru_Sht2xDrv );ret = SHT2x_STATUS_ERR_BAD_DATA;return ret;
}static int32_t sht2xdrv_CalcTemperatureC(uint16_t u16sT)
{int32_t temperatureC; // variable for resultu16sT &= ~0x0003; // clear bits [1..0] (status bits)/** Formula T = -46.85 + 175.72 * ST / 2^16 from data sheet 6.2,* optimized for integer fixed point (3 digits) arithmetic*/temperatureC = (((uint32_t)17572 * u16sT) >> 16) - 4685;return (int32_t)temperatureC;
}static int32_t sht2xdrv_CalcRH(uint16_t u16sRH)
{uint32_t humidityRH; // variable for resultu16sRH &= ~0x0003; // clear bits [1..0] (status bits)/** Formula RH = -6 + 125 * SRH / 2^16 from data sheet 6.1,* optimized for integer fixed point (3 digits) arithmetic*/humidityRH = (((uint32_t)12500 * u16sRH) >> 16) - 600;return (int32_t)humidityRH;
}uint8_t sht2xdrv_ResetSht2x( void )
{uint8_t ret = SHT2x_STATUS_OK;uint8_t cmd = SOFT_RESET;i2c_master_Start( &stru_Sht2xDrv );i2c_master_SendByte( &stru_Sht2xDrv, i2c_master_ADDRESS | I2C_MATER_W ); // Device address if (i2c_master_WaitAck( &stru_Sht2xDrv ) != 0){goto cmd_fail;}i2c_master_SendByte(&stru_Sht2xDrv, cmd);if (i2c_master_WaitAck( &stru_Sht2xDrv ) != 0){goto cmd_fail;}cmd_fail: i2c_master_Stop( &stru_Sht2xDrv );ret = SHT2x_STATUS_ERR_TIMEOUT;return ret;
}uint8_t sht2xdrv_GetBatteryStatus(void)
{uint8_t reg;uint8_t error = SHT2x_STATUS_OK;error = sht2xdrv_ReadUserRegister(®);if (error != SHT2x_STATUS_OK){return error;}return (reg & 0x40);
}uint8_t sht2xdrv_GetHeaterStatus(void)
{uint8_t reg;uint8_t error = SHT2x_STATUS_OK;error = sht2xdrv_ReadUserRegister(®);if (error != SHT2x_STATUS_OK){return error;}return (reg & 0x04);
}uint8_t sht2xdrv_GetResolution(sht2xResolution_t *pResolution)
{uint8_t error = SHT2x_STATUS_OK;uint8_t reg = 0;error = sht2xdrv_ReadUserRegister(®);if (error != SHT2x_STATUS_OK){return error;}*pResolution = (sht2xResolution_t)(reg & SHT2x_RES_MASK);return error;
}static void sht2xdrv_readVal(uint8_t cmd, shtdrv *pShtdrv )
{uint8_t checksum; //checksumuint8_t data[3] = {0, 0, 0}; //data array for checksum vuint8_t cmd_fail = 0;if( pShtdrv->finish )return;pShtdrv->ret = SHT2x_STATUS_ERR_BAD_DATA;switch( pShtdrv->_step ){default:case 0:i2c_master_Start( &stru_Sht2xDrv );i2c_master_SendByte( &stru_Sht2xDrv, i2c_master_ADDRESS | I2C_MATER_W ); // Device address if (i2c_master_WaitAck( &stru_Sht2xDrv ) != 0){cmd_fail = 1;break;}pShtdrv->_step = 1;break;case 1:// send command and prepare to reading data value i2c_master_SendByte( &stru_Sht2xDrv, cmd);if (i2c_master_WaitAck( &stru_Sht2xDrv ) != 0){cmd_fail = 1;break;}pShtdrv->_step = 2;pShtdrv->_tryCnt = 0;break;case 2:// set the address for reading data i2c_master_Start( &stru_Sht2xDrv );i2c_master_SendByte( &stru_Sht2xDrv, i2c_master_ADDRESS | I2C_MATER_R);if (i2c_master_WaitAck( &stru_Sht2xDrv ) != 0){pShtdrv->_tryCnt ++;if( pShtdrv->_tryCnt > 10 ){cmd_fail = 1;break;}}pShtdrv->_step = 3;pShtdrv->_tryCnt = 0;break;case 3:// Notes: convert time must >= 4 ms i2c_master_Delay( 3 );pShtdrv->_tryCnt ++;if( pShtdrv->_tryCnt > 4500 ){pShtdrv->_tryCnt = 0;pShtdrv->_step = 4;}break;case 4:// read sensor's datadata[0] = i2c_master_ReadByte( &stru_Sht2xDrv );i2c_master_Ack( &stru_Sht2xDrv );data[1] = i2c_master_ReadByte( &stru_Sht2xDrv );i2c_master_Ack( &stru_Sht2xDrv );data[2] = i2c_master_ReadByte( &stru_Sht2xDrv );i2c_master_NAck( &stru_Sht2xDrv );i2c_master_Stop( &stru_Sht2xDrv );checksum = data[2];pShtdrv->ret = sht2xdrv_CheckCrc(data, 2, checksum);if ( pShtdrv->ret != SHT2x_STATUS_OK){pShtdrv->_step = 2;break;}pShtdrv->_binValue = ((uint16_t)data[0] << 8) | data[1];pShtdrv->_step = 0;pShtdrv->finish = 1;break;}if( cmd_fail ){pShtdrv->finish = 1;pShtdrv->_tryCnt =0;pShtdrv->_step = 0;pShtdrv->ret = SHT2x_STATUS_ERR_BAD_DATA;i2c_master_Stop( &stru_Sht2xDrv );}
}static void sht2xdrv_readTempOrRH( uint8_t cmd, shtdrv *pShtdrv )
{switch( cmd ){case TRIG_T_MEASUREMENT_HM:sht2xdrv_readVal(cmd, pShtdrv);if( pShtdrv->ret == SHT2x_STATUS_OK){pShtdrv->outValue = sht2xdrv_CalcTemperatureC( pShtdrv->_binValue );pShtdrv->dataValid = 1;}break;case TRIG_RH_MEASUREMENT_POLL:sht2xdrv_readVal(cmd, pShtdrv);if( pShtdrv->ret == SHT2x_STATUS_OK){pShtdrv->outValue = sht2xdrv_CalcRH( pShtdrv->_binValue );pShtdrv->dataValid = 1;}break;}
}static void _sht2xdrv_Init( shtOpt *pshtOpt )
{sht2xResolution_t sht2xResolutionvalue;stru_Sht2xDrv.IIC_InitPort();uint8_t _res = sht2xdrv_CheckOk();if( _res ){sht2xdrv_ResetSht2x();sht2xdrv_GetBatteryStatus();sht2xdrv_GetResolution( &sht2xResolutionvalue );return;}pshtOpt->errorCode |= SHT2x_RES_ERR;
}/******************************************************************************
* EXPORTED FUNCTIONS
******************************************************************************/
void sht2xdrv_Init( void )
{_sht2xdrv_Init( &s_ShtOpt );
}shtOpt *sht2xdrv_getResult( void )
{return &s_ShtOpt;
}void sht2xdrv_ClearReadFlag( shtdrv *pShtdrv )
{pShtdrv->dataValid = 0;
}void sht2xdrv_readValue( shtOpt *pshtOpt )
{static uint8_t _step = TRIG_T_MEASUREMENT_HM;shtdrv *pTempData = &pshtOpt->st_Temp;shtdrv *pRhData = &pshtOpt->st_RH;if( pshtOpt ->errorCode & SHT2x_RES_ERR )return;switch ( _step ){default:case TRIG_T_MEASUREMENT_HM:sht2xdrv_readTempOrRH( TRIG_T_MEASUREMENT_HM,pTempData );if( pTempData->finish ){_step = TRIG_RH_MEASUREMENT_POLL;pTempData->finish = 0;}break;case TRIG_RH_MEASUREMENT_POLL:sht2xdrv_readTempOrRH( TRIG_RH_MEASUREMENT_POLL, pRhData);if( pRhData->finish ){_step = TRIG_T_MEASUREMENT_HM;pRhData->finish = 0;}break;}
}void SHT2X_test( void )
{sht2xdrv_readValue( &s_ShtOpt );
}/* End of this file */
2) 创建sht2x.h文件,编写如下代码:
/** \file$Id: sht2x.h 40486 2018-08-12 13:50:21Z tangmingfei2013@126.com $Copyright (c)tangmingfei2013@126.com Holding B.V.
All Rights Reserved.This source code and any compilation or derivative thereof is the proprietary
information of mingfei.tang Lighting Holding B.V. and is confidential in nature.
Under no circumstances is this software to be combined with any
Open Source Software in any way or placed under an Open Source License
of any type without the express written permission of mingfei.tang Holding B.V.
*/
#ifndef __SHT2X_H
#define __SHT2X_H/******************************************************************************
* C++ DECLARATION WRAPPER
******************************************************************************/
#include "n32g45x.h"#ifdef __cplusplus
extern "C" {
#endiftypedef enum sht2xOptErrorCode
{SHT2x_RES_ERR = 0X01,
}sht2xOptErrorCode;/******************************************************************************
* EXPORTED MACROS AND DEFINITIONS
******************************************************************************/
typedef enum sht2xResolution_t
{SHT2x_RES_12_14BIT = 0x00, // RH=12bit, T=14bitSHT2x_RES_8_12BIT = 0x01, // RH= 8bit, T=12bitSHT2x_RES_10_13BIT = 0x80, // RH=10bit, T=13bitSHT2x_RES_11_11BIT = 0x81, // RH=11bit, T=11bitSHT2x_RES_MASK = 0x81 // Mask for res. bits (7,0) in user reg.
} sht2xResolution_t;typedef enum sht2xStatusCode {SHT2x_STATUS_OK = 0x00,SHT2x_STATUS_VALID_DATA = 0x01,SHT2x_STATUS_NO_CHANGE = 0x02,SHT2x_STATUS_ABORTED = 0x03,SHT2x_STATUS_BUSY = 0x04,SHT2x_STATUS_SUSPEND = 0x05,SHT2x_STATUS_ERR_IO = 0x06,SHT2x_STATUS_ERR_BAD_DATA = 0x07,SHT2x_STATUS_ERR_TIMEOUT = 0x08
}sht2xStatusCode;// sensor command
typedef enum{TRIG_T_MEASUREMENT_HM = 0xE3, // command trig. temp meas. hold masterTRIG_RH_MEASUREMENT_HM = 0xE5, // command trig. humidity meas. hold masterTRIG_T_MEASUREMENT_POLL = 0xF3, // command trig. temp meas. no hold masterTRIG_RH_MEASUREMENT_POLL = 0xF5, // command trig. humidity meas. no hold masterUSER_REG_W = 0xE6, // command writing user registerUSER_REG_R = 0xE7, // command reading user registerSOFT_RESET = 0xFE // command soft reset
}sht2xCommand_t;typedef enum {SHT2x_EOB_ON = 0x40, // end of batterySHT2x_EOB_MASK = 0x40, // Mask for EOB bit(6) in user reg.
} sht2xEob_t;typedef enum {SHT2x_HEATER_ON = 0x04, // heater onSHT2x_HEATER_OFF = 0x00, // heater offSHT2x_HEATER_MASK = 0x04, // Mask for Heater bit(2) in user reg.
} etSHT2xHeater;// measurement signal selection
typedef enum{HUMIDITY,TEMP
}etSHT2xMeasureType;typedef enum{I2C_ADR_W = 128, // sensor I2C address + write bitI2C_ADR_R = 129 // sensor I2C address + read bit
}etI2cHeader;typedef struct {uint8_t _step;uint8_t ret;uint8_t finish; //1: finished, 0: idleuint8_t dataValid; //1: valid, 0: invalidint32_t _tryCnt;int32_t _binValue; // primordial value from sht20 register int32_t outValue; // true temperature or humidity
} shtdrv;typedef struct {shtdrv st_Temp;shtdrv st_RH;int32_t errorCode;
}shtOpt;/******************************************************************************
* EXPORTED FUNCTIONS
******************************************************************************/
void sht2xdrv_Init( void );
void sht2xdrv_readValue( shtOpt *pshtOpt );
shtOpt *sht2xdrv_getResult( void );void SHT2X_test( void );
/******************************************************************************
* END OF C++ DECLARATION WRAPPER
******************************************************************************/#ifdef __cplusplus
}
#endif#endif /* __SHT2X_H */
4 测试
4.1 测试代码实现
代码第138行: 读取sht2x的数据
代码第141~146行:判断温度数据是否有效,格式化和打印数据
代码第149~154行:判断湿度数据是否有效,格式化和打印数据
4.2 运行程序
1) 使用NS-LINK调试代码
2) 串口log输出数据