21ic电子技术开发论坛
标题: HC32L136 NSHT30温湿度传感器 IIC通讯源代码分享 [打印本页]
作者: rickluo 时间: 2025-3-22 11:38
标题: HC32L136 NSHT30温湿度传感器 IIC通讯源代码分享
#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]);
}
作者: William1994 时间: 2025-3-23 06:53
有没有人给楼主编辑一下帖子,加个代码着色或者改一下等宽字体。
这么好的注释,因为字体原因偏了。
作者: alienmiller 时间: 2025-3-23 19:08
模拟I2C的程序,136有硬件I2C接口的,用它是否更好些。
作者: lidi911 时间: 2025-3-23 19:48
这个是国产纳芯微的温湿度传感器吧
作者: rickluo 时间: 2025-3-25 08:58
传感器一般用模拟的好些
作者: rickluo 时间: 2025-3-25 08:59
是的,国产 纳芯微的NSHT30 温湿度传感器,模块免费送,可以弄个玩玩
作者: lxs0026 时间: 2025-3-31 12:34
GET_I2C_SDA() 用来读取 SDA 引脚的当前状态,SET_I2C_SCL() 和 CLR_I2C_SCL() 用来控制 SCL 的高低电平,SET_I2C_SDA() 和 CLR_I2C_SDA() 用来控制 SDA 的高低电平。
作者: rickluo 时间: 2025-5-27 11:19
回答正确
作者: rickluo 时间: 2025-5-27 11:20
孵化器温室湿度计,
产品说明:
传感器型号:NSHT30、SC7A20H
MCU型号:PT32L076
此款产品设计全部采用国产电子元器件,主控MCU及传感器支持超低功耗,另外增加了三轴重力加速度传感器做震动检测,实现屏幕休眠或唤醒,进一步有效的降低产品功耗;
超长续航:实验室测试150mA锂电池可以持续不间断工作6个月以上;
温湿度校准:已集成到软件算法中,用户无需进行二次操作,简单便利;
高精准度:温度传感器 ±0.3℃ 工作范围:-40~125℃
湿度传感器 ±3%RH 工作范围:0%RH ~100%RH
锂电池可充电:带有智能充电管理芯片(首次使用建议先充满电,充电过程也是产品自动校准的过程,出现数据波动是正常现象)
按键说明:
REST为复位清屏键,按下后屏幕显示全部为0,等待5秒后会恢复正常显示;
KEY1屏幕刷新按键,屏幕默认5S刷新一次,通过KEY1按键可以进行实时刷新;
KEY2为震动检测(3D重力加速度)开启关闭控制键,出厂默认状态为关闭,如果需要开启,长按KEY2 3S会开启,开启后连续5分钟没有检测到任何震动,产品会进入自动息屏状态(这个状态下,温湿度传感器和MCU依然正常工作),再检测到震动后自动亮起,或者通过KEY2按键可以恢复点亮;
如需关闭震动检测功能,长按KEY2 3S会自动关闭;
使用注意事项:
1、 请勿将产品放置在高灰尘环境下(容易堵塞传感器检测窗口,造成检测数据不准确);
2、 请勿在阳光直射下使用该产品;
3、 使用过程注意防水,电子产品遇水会出现短路损坏问题;
作者: qidiao 时间: 2025-6-4 08:55
国产 纳芯微的NSHT30 温湿度传感器
作者: rickluo 时间: 2025-6-13 14:09
对的
欢迎光临 21ic电子技术开发论坛 (https://bbs.21ic.com/) |
Powered by Discuz! X3.5 |