写点什么

ESP32-C3 入门教程 基础篇(四、I2C 总线 — 与 SHT21 温湿度传感器通讯)

作者:矜辰所致
  • 2022 年 9 月 20 日
    江苏
  • 本文字数:6495 字

    阅读完需:约 21 分钟

ESP32-C3入门教程 基础篇(四、I2C总线 — 与SHT21温湿度传感器通讯)
测试第四课,了解ESP32-C3的 I2C 总线使用,与SHT21 温湿度传感器通讯这一课把基础介绍放在前面,先看基本流程,再去修改代码
复制代码


前言


测试使用的开发板:

自己画一块 ESP32-C3 的开发板(第一次使用立创 EDA)(PCB 到手)

https://xie.infoq.cn/article/30387388381a0d915b2494f91

测试使用的开发环境:

ESP32-C3 VScode 开发环境搭建(基于乐鑫官方 ESP-IDF——Windows 和 Ubuntu 双环境)

https://xie.infoq.cn/article/5b639e112cabba00cc1b8941a

基础篇系列相关博文:

ESP32-C3 入门教程 基础篇(一、ADC 采样)

https://xie.infoq.cn/article/78eff739dd2ed4971f445272a

ESP32-C3 入门教程 基础篇(二、GPIO 中断、按键驱动测试)

https://xie.infoq.cn/article/7d090d74fb0a9449986954810

ESP32-C3 入门教程 基础篇(三、UART 模块 — 与 Enocean 无线模块串口通信)

https://xie.infoq.cn/article/55d8a9cbd211b4d99b53935ee

1、GPIO 示例测试


在开发板上面,我画了一个 HTU21D I2C 温湿度传感器(和 SHT21 pin to pin,驱动也一样),使用的是 GPIO3 (SDA)和 GPIO10 (SCL):



示例程序我们选用i2c_self_test,要注意这个示例的说明,下图中右边介绍这一部分,好好看看:


1、 ESP32-C3 I2C 基础介绍

对于 ESP32-C3 I2C 的介绍,乐鑫的官网的说明链接如下:


乐鑫官方ESP32-C3 I2C部分说明


国产的芯片终于遇到个中文资料了,呵呵~


ESP32-C3 只有一个 I2C 接口,可做主机也可以做从机。


本文的测试以及说明是以 ESP23-C3 作为主机来说明。

1.1 I2C 初始化

根据官方文档,ESP32-C3 UART 使用步骤如下:


  1. 设置参数,使用i2c_config_t结构体可以统一设置:

  2. 例如示例中:

  3. 示例中,最后使用了i2c_param_config配置好 I2C 的所有参数,除了自己定义的,其他的参数会被配置成 I2C 总线协议规范中定义的默认值。和 UART 一样,I2C 的这些默认值 也可以使用一些函数对某些参数单独进行设置:

  4. 使用i2c_driver_install函数进行 I2C 设备的初始化,其中包括 端口好、通讯模式,发送接收缓存区, 中断标志:

  5. 以示例中的主机初始化为例:

1.2 I2C 读写

  1. 完成,上述步骤以后,下面就可以发起通讯,在官方文档中的说明有一张流程图:

  2. 流程说明如下:

  3. 通过示例说明一下上述流程:

  4. 最后放一张官方介绍的 I2C 工作的整体流程图:

2、 I2C 示例测试 — SHT21 驱动移植

通过示例工程i2c_self_test创建好工程,通过上面的基础介绍和分析,基本上知道了 I2C 通讯的步骤和方式了,因为示例代码是与 BH1750 传感器进行的 通讯,所以这里示例代码是无法测试的,直接修改 SHT21 的代码。

2.1 驱动移植修改

因为 SHT21 驱动函数以前在 STM32 上用过,这里就相当于移植过来,先把sht21.csht21.h文件放进来,当然得注意包含关系,宏定义等一些东西:



既然增加了驱动,所以代码就放在驱这两个文件里面,对于sht21.h 文件,宏定义放在此文件中,函数在sht21.c文件中实现(下面会放源码),在此处声明 :



sht21.c 中的温湿度读取函数是如何实现的呢, 先来看一张 STH21 读取的时序图,是我在另一篇博文中写好的:



上图出自:nRF52832学习记录(十一、TWI总线的应用 SHT21程序移植)


这里我就直接上源码 :


#include "sht21.h"
struct { sint16 value; uint16 raw; uint8 crc;} aTemperature, aHumidity;

esp_err_t i2c_master_init(void){ int i2c_master_port = I2C_MASTER_NUM; i2c_config_t conf = { .mode = I2C_MODE_MASTER, .sda_io_num = I2C_MASTER_SDA_IO, .sda_pullup_en = GPIO_PULLUP_ENABLE, .scl_io_num = I2C_MASTER_SCL_IO, .scl_pullup_en = GPIO_PULLUP_ENABLE, .master.clk_speed = I2C_MASTER_FREQ_HZ, // .clk_flags = 0, /*!< Optional, you can use I2C_SCLK_SRC_FLAG_* flags to choose i2c source clock here. */ }; esp_err_t err = i2c_param_config(i2c_master_port, &conf); if (err != ESP_OK) { return err; } return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);}

// fT = 175.72*u16T/65536.0 - 46.85;// fRH = 125.0*u16RH/65536.0 - 6.0;
// -------------------------------------------------------------------sint16 sht21_calcRH(uint16 u16RH){ sint16 humidityRH; // variable for result
u16RH &= ~0x0003; // clear bits [1..0] (status bits) //-- calculate relative humidity [%RH] --
humidityRH = (sint16)(-600 + (12500*(sint32)u16RH)/65536 ); // RH = -6 + 125 * SRH/2^16 return humidityRH; // Return RH*100}
// -------------------------------------------------------------------sint16 sht21_calcTemperature(uint16 u16T){ sint16 temperature; // variable for result
u16T &= ~0x0003; // clear bits [1..0] (status bits)
//-- calculate temperature [癈] -- temperature= (sint16)(-4685 + (17572*(sint32)u16T)/65536); //T = -46.85 + 175.72 * ST/2^16 return temperature; //return T*100}

// i2c_cmd_handle_t cmd = i2c_cmd_link_create();// i2c_master_start(cmd);// i2c_master_write_byte(cmd, BH1750_SENSOR_ADDR << 1 | WRITE_BIT, ACK_CHECK_EN);// i2c_master_write_byte(cmd, BH1750_CMD_START, ACK_CHECK_EN);// i2c_master_stop(cmd);// ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);// i2c_cmd_link_delete(cmd);// if (ret != ESP_OK) {// return ret;// }// vTaskDelay(30 / portTICK_RATE_MS);// cmd = i2c_cmd_link_create();// i2c_master_start(cmd);// i2c_master_write_byte(cmd, BH1750_SENSOR_ADDR << 1 | READ_BIT, ACK_CHECK_EN);// i2c_master_read_byte(cmd, data_h, ACK_VAL);// i2c_master_read_byte(cmd, data_l, NACK_VAL);// i2c_master_stop(cmd);// ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);// i2c_cmd_link_delete(cmd);
esp_err_t SHT2X_THMeasure(i2c_port_t i2c_num){ // uint8 u8Ack; int ret; uint8 t_value[3]; uint8 h_value[3];
#if (SHT2X_RESOLUTION != 0x00) // only needed if used resolution other than default // i2c_start(); // send start sequence (S) // u8Ack = i2c_write((SHT2X_SLAVEADDRESS<<1)|I2C_WRITE); // write to slave 0x40 // u8Ack = (u8Ack<<1)|i2c_write(SHT2X_CMD_RD_REG); // request to read from user register // i2c_start(); // send start sequence (S) // u8Ack = (u8Ack<<1)|i2c_write((SHT2X_SLAVEADDRESS<<1)|I2C_READ); // read from slave 0x40 // u8UserReg = i2c_read(I2C_NACK); // read user register // i2c_start(); // send start sequence (S) // u8Ack = i2c_write((SHT2X_SLAVEADDRESS<<1)|I2C_WRITE); // write to slave 0x40 // u8Ack = (u8Ack<<1)|i2c_write(SHT2X_CMD_WR_REG); // request to write user register // u8Ack = (u8Ack<<1)|i2c_write(SHT2X_RESOLUTION | (u8UserReg & ~0x81)); // write new user register data i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, SHT2X_SLAVEADDRESS<<1 | WRITE_BIT, ACK_CHECK_EN); i2c_master_write_byte(cmd, SHT2X_CMD_WR_REG, ACK_CHECK_EN); i2c_master_stop(cmd); ret = i2c_master_cmd_begin(i2c_num, cmd, 500 / portTICK_RATE_MS); i2c_cmd_link_delete(cmd); if (ret != ESP_OK) { return ret; }#endif//(SHT2X_RESOLUTION != 0x00) // -------------------- // measure temperature // -------------------- // i2c_start(); // send start sequence (S) // u8Ack = i2c_write((SHT2X_SLAVEADDRESS<<1)|I2C_WRITE);//----IIC???(8?)???7??IIC????0x80(???HT2X_SLAVEADDRESS=0x40)???DATA???(?R:1 ,?WRITE?0) //a write to slave 0x40 // u8Ack = (u8Ack<<1)|i2c_write(SHT2X_CMD_MEAS_T); //----SHT2X_CMD_MEAS_T=0xF3(??????,???)//request to measure temperature // i2c_stop();
i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, SHT2X_SLAVEADDRESS<<1 | WRITE_BIT, ACK_CHECK_EN); i2c_master_write_byte(cmd, SHT2X_CMD_MEAS_T, ACK_CHECK_EN); i2c_master_stop(cmd); ret = i2c_master_cmd_begin(i2c_num, cmd, 500 / portTICK_RATE_MS); i2c_cmd_link_delete(cmd); if (ret != ESP_OK) { return ret; }
vTaskDelay(SHT2X_TEMP_MEAS_TIME / portTICK_RATE_MS);
// shortTermSleep(SHT2X_TEMP_MEAS_TIME); // HAL_Delay(SHT2X_TEMP_MEAS_TIME); // time_wait(SHT2X_TEMP_MEAS_TIME); // i2c_start(); // send start sequence (SR) // u8Ack = i2c_write((SHT2X_SLAVEADDRESS<<1)|I2C_READ); //----IIC???(8?)???7??IIC????0x80(???HT2X_SLAVEADDRESS=0x40)???DATA???(?R:1 ,?WRITE?0) // a read from slave 0x40 cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, SHT2X_SLAVEADDRESS << 1 | READ_BIT, ACK_CHECK_EN); i2c_master_read_byte(cmd, &t_value[0], ACK_VAL); i2c_master_read_byte(cmd, &t_value[1], ACK_VAL); i2c_master_read_byte(cmd, &t_value[2], NACK_VAL); i2c_master_stop(cmd); ret = i2c_master_cmd_begin(i2c_num, cmd, 500 / portTICK_RATE_MS); i2c_cmd_link_delete(cmd);
// if(u8Ack==I2C_ACK) { // aTemperature.raw = i2c_read(I2C_ACK)<<8; // read hi byte // aTemperature.raw |= i2c_read(I2C_ACK); // read lo byte // aTemperature.crc = i2c_read(I2C_NACK); // read check sum and finish transfere // }else { // aTemperature.raw = 0; // } // i2c_stop(); aTemperature.raw = t_value[0]<<8; aTemperature.raw |= t_value[1]; aTemperature.crc = t_value[2];
// -------------------------// Humidity Measure // ------------------------- // i2c_start(); // send start sequence (S) // u8Ack = i2c_write((SHT2X_SLAVEADDRESS<<1)|I2C_WRITE); // a write to slave 0x40 1000 0000 // u8Ack = (u8Ack<<1)|i2c_write(SHT2X_CMD_MEAS_RH); // request to measure humidity F5 1110 0101 // i2c_stop(); cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, SHT2X_SLAVEADDRESS<<1 | WRITE_BIT, ACK_CHECK_EN); i2c_master_write_byte(cmd, SHT2X_CMD_MEAS_RH, ACK_CHECK_EN); i2c_master_stop(cmd); ret = i2c_master_cmd_begin(i2c_num, cmd, 500 / portTICK_RATE_MS); i2c_cmd_link_delete(cmd); if (ret != ESP_OK) { return ret; } // shortTermSleep(SHT2X_HUMI_MEAS_TIME); // HAL_Delay(SHT2X_HUMI_MEAS_TIME); vTaskDelay(SHT2X_HUMI_MEAS_TIME / portTICK_RATE_MS);
// i2c_start(); // send start sequence (SR) // u8Ack = i2c_write((SHT2X_SLAVEADDRESS<<1)|I2C_READ); // read from slave 0x40 1000 0001
cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, SHT2X_SLAVEADDRESS << 1 | READ_BIT, ACK_CHECK_EN); i2c_master_read_byte(cmd, &h_value[0], ACK_VAL); i2c_master_read_byte(cmd, &h_value[1], ACK_VAL); i2c_master_read_byte(cmd, &h_value[2], NACK_VAL); i2c_master_stop(cmd); ret = i2c_master_cmd_begin(i2c_num, cmd, 500 / portTICK_RATE_MS); i2c_cmd_link_delete(cmd);
// if(u8Ack==I2C_ACK) { // timeout // aHumidity.raw = i2c_read(I2C_ACK)<<8; // read hi byte // aHumidity.raw |= i2c_read(I2C_ACK); // read lo byte // aHumidity.crc = i2c_read(I2C_NACK); // read check sum and finish transfere // }else{ // aHumidity.raw = 0; // } // i2c_stop(); // PowerOff(); aHumidity.raw = h_value[0] <<8; // read hi byte aHumidity.raw |= h_value[1]; // read lo byte aHumidity.crc = h_value[2]; // read check sum and finish transfere
aTemperature.value = sht21_calcTemperature(aTemperature.raw); aHumidity.value = sht21_calcRH(aHumidity.raw); // signed value, temperature = aTemperature.value * 0.01? if(aTemperature.crc!= sht21_CRC((uint8*)&aTemperature.raw, 2)) {} if(aHumidity.crc!= sht21_CRC((uint8*)&aHumidity.raw, 2)) {} if(aTemperature.value>5100) aTemperature.value=5100; //prevent temperature over-/underflow else if(aTemperature.value<0) aTemperature.value=0; if(aHumidity.value>10000) aTemperature.value=10000; //prevent temperature over-/underflow else if(aTemperature.value<0) aTemperature.value=0;
return ret;}
uint16_t getTemperature() { return aTemperature.value;}
uint16_t getHumidity() { return aHumidity.value;}
//==============================================================================uint8 sht21_CRC(uint8 value[], uint8 u8Bytes) {// CRC const uint16 POLYNOMIAL = 0x131; //P(x)=x^8+x^5+x^4+1 = 100110001 uint8 crc = 0; uint8 byteCtr; uint8 bitCtr;
//calculates 8-Bit checksum with given polynomial for (byteCtr = 0; byteCtr < u8Bytes; ++byteCtr) { crc ^= (value[byteCtr]); for (bitCtr = 8; bitCtr > 0; --bitCtr) { if (crc & 0x80) crc = (crc << 1) ^ POLYNOMIAL; else crc = (crc << 1); } } return crc;}
复制代码

2.2 测试

最后只需要在任务中调用SHT2X_THMeasure 函数即可:



可以看一下整体,i2c_example_main.c文件简单明了多了:



测试结果如下,正常:



发布于: 刚刚阅读数: 6
用户头像

矜辰所致

关注

CSDN、知乎、微信公众号: 矜辰所致 2022.08.02 加入

不浮夸,不将就,认真对待学知识的我们,矜辰所致,金石为开! 为了活下去的嵌入式工程师,画画板子,敲敲代码,玩玩RTOS,搞搞Linux ...

评论

发布
暂无评论
ESP32-C3入门教程 基础篇(四、I2C总线 — 与SHT21温湿度传感器通讯)_I2C_矜辰所致_InfoQ写作社区