六、基于alios things的esp32 devkitC学习笔记——I2C驱动SHT30获取温湿度

1、关于SHT30

  由于用gpio直接驱动ds18b20的失败,我只好将目光放到了I2c上,恰好在网络上也看到一篇关于esp23驱动sht30的详细文章可以参chao考xi,就买来准备解决温湿度监测的问题了。

  sht30有两种通信方式,这次一方面也想学学I2c所以选择I2c来通信了,但是没想到是个这么大的坑。用I2c感觉很像计网里学的什么东西,实现的技术原理看起来非常典型。一个I2c总线可以连接多个设备,并且能对他们的操作也是区分开的。其实esp32是直接支持I2c的,还有配套的API可用,不过看了他的API,发现里面充满了freertos的身影,那我要想在alios上使用岂不是还要移植,这个坑让我打消了使用官方API的念头,还是使用alios写得API好了。

  学习中主要参考了几个材料:

详细流程:ESP32读取SHT30的温湿度(IIC)

SHT30的驱动简易流程:SHT30使用的学习过程1SHT30工作模式介绍

DATASHEET:SHT30中文datasheet

2、alios things的I2C API

  首先需要说的是alios things的API适配还不够完全,至少对于esp32来说是这样的,不只是I2C的部分还有之前的PWM等。不过整体来说API的易用程度还是非常高的,是在官方API基础上更加深度的功能封装。

1.初始化

    在初始化上,alios提供了十分统一化的结构体来实现——i2c_dev_t,其中主要是两个成员,设备号port(主机指定从机所需),配置结构体config(包括了设备地址长度,频率,主从模式,设备地址),对其相应赋值即可:

    //I2C初始化
	SHT30_dev.port = 1;
	i2c_config_t sht30_cfg = {
		8 ,
		100000,
		I2C_MODE_MASTER,
		SHT30_WRITE_ADDR
	};
	SHT30_dev.config = sht30_cfg;
	hal_i2c_init(&SHT30_dev);

不过在这里需要注意API里有个小问题,配置里没有指定scl和sda的gpio口,他们被默认配置在i2c.c中,由于我的esp32 devkitC的scl和sda口分别在22和21,所以在这里改一下(这里预设了两个设备,我选的是第二个)

static i2c_resource_t g_dev[I2C_NUM_MAX] = {
    {(volatile i2c_dev_t *)0x60013000,23,22},
    {(volatile i2c_dev_t *)0x60027000,22,21}
};

 

    接着是关于SHT30的初始化,主要是向其发送控制命令,这个主要包括了发送地址——>MSB——>LSB,在这里就需要说一下alios的API逻辑。他所给的I2C API对于发送只需要一个函数hal_i2c_master_send,这其中包括了发送准备,发送地址,接受ack,结束发送等一系列操作,读取也是类似,只需先给予发送buf和字节数就可以实现一站式发送。

    但是我估计alios开发人员在写esp32的api时只写拉11位地址的操作,漏掉了7位地址的。。在试过直接使用API出不了结果后,之好去看i2c.c的详细函数实现,又发现了几个问题。

    问题一,从hal_i2c_master_send 向着i2c_write_bytes 传递设备地址参数dev_addr时将其往右移了一位,虽然在后面的代码中又移了回来,但是这不是相当于没移吗,只是把末尾置0了,而sht30地址末尾本就是0了,应该的是不要移位的,所以在这里我去掉了移位操作,仅留下赋值代码。

    问题二,在i2c_write_bytes 函数中运用了一个发送地址的函数i2c_send_addr 但是函数里只包括了处理11位地址设备的代码,而没有根据读写添加末位的代码,所以在这里应该加上读写位的操作

static void i2c_send_addr(i2c_dev_t * handle,uint8_t is_write,uint16_t addr_value,int8_t addr_width)
{

    uint8_t low_mask = (is_write)?(0xF0):(0xF1);
    if(addr_width) {
        handle->fifo_data.data = (((addr_value >> 8) & 0x6) | low_mask);
        handle->fifo_data.data = ((addr_value >> 1) & 0xFF);
        return;
    }
    //对读写标识符进行判断加入尾部操作位
    if(is_write){
        handle->fifo_data.data = addr_value & 0xFE;
    }
    else{
        handle->fifo_data.data = addr_value & 0xFF;
    }
}

    还有一点是上面函数中的地址宽度参数,是失去了其本来意思的,在i2c_dev_t结构体中其如果是7位就填0,11位就填1,后面几个地址宽参数变成了单纯的flag位

解决好上面的问题后基本就可以正常使用API了。

  2.获取数据

    由于可以直接使用API,获取数据也变得十分便捷,直接调用函数一箩筐地接数据。然后就是CRC校验,最后按照sht30的数据格式对接受到的6bytes数据进行解读。

int sht30_get_value(){
	int ret = 0;
	hal_i2c_master_recv(&SHT30_dev, SHT30_WRITE_ADDR, sht30_buf, 6, 100);

    if( (!SHT3X_CheckCrc(sht30_buf,2,sht30_buf[2])) && (!SHT3X_CheckCrc(sht30_buf+3,2,sht30_buf[5])) ){
        ret = 0;//成功
    }
    else{
        ret = 1;
    }
	return ret;
}

3、主函数代码

int application_start(int argc, char *argv[]){
	//I2C初始化
	SHT30_dev.port = 1;
	i2c_config_t sht30_cfg = {
		8 ,
		100000,
		I2C_MODE_MASTER,
		SHT30_WRITE_ADDR
	};
	SHT30_dev.config = sht30_cfg;
	hal_i2c_init(&SHT30_dev);
	//sht30初始化
	uint8_t data_hl[2] = {0x22, 0x36}; 
	hal_i2c_master_send(&SHT30_dev, SHT30_WRITE_ADDR, data_hl, 2, 100);
	aos_msleep(1000);


	while(1){
		if(!sht30_get_value()){
			for(int i  = 0; i < 6; i++)printf("%d", sht30_buf[i]);
			printf("\n");
			sht30_temp =((((sht30_buf[0]*256) + sht30_buf[1]) *175)/65535.0 - 45);
			sht30_rh = (((sht30_buf[3]*256) + (sht30_buf[4]))*100/65535.0);
			ESP_LOGI("SHT30", "temp:%4.2f C \r\n", sht30_temp);
			ESP_LOGI("SHT30", "hum:%4.2f %%RH \r\n", sht30_rh);
		}
		aos_msleep(3000);
	}

	return 0;
}

 

结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值