ESP32-C3入门教程 基础篇(四、I2C总线 — 与SHT21温湿度传感器通讯)
测试第四课,了解ESP32-C3的 I2C 总线使用,与SHT21 温湿度传感器通讯
这一课把基础介绍放在前面,先看基本流程,再去修改代码
目录
- 前言
- 1、 ESP32-C3 I2C基础介绍
- 1.1 I2C初始化
- 1.2 I2C读写
- 2、 I2C 示例测试 — SHT21驱动移植
- 2.1 驱动移植修改
- 2.2 测试
前言
接下来的ESP32-C3 功能测试都是基于自己设计的开发板:
自己画一块ESP32-C3 的开发板(第一次使用立创EDA)(PCB到手)
开发环境是乐鑫官方的 ESP-IDF, 基于VScode插件搭建好的:
ESP32-C3 VScode开发环境搭建(基于乐鑫官方ESP-IDF——Windows和Ubuntu双环境)
在开发板上面,我画了一个 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使用步骤如下:
- 设置参数,使用
i2c_config_t
结构体可以统一设置:
例如示例中:
示例中,最后使用了i2c_param_config
配置好I2C的所有参数,除了自己定义的,其他的参数会被配置成 I2C 总线协议规范中定义的默认值。
和 UART 一样,I2C的这些默认值 也可以使用一些函数对某些参数单独进行设置:
- 使用
i2c_driver_install
函数进行 I2C 设备的初始化,其中包括 端口好、通讯模式,发送接收缓存区, 中断标志:
以示例中的主机初始化为例:
1.2 I2C读写
- 完成,上述步骤以后,下面就可以发起通讯,在官方文档中的说明有一张流程图:
流程说明如下:
通过示例说明一下上述流程:
最后放一张官方介绍的 I2C 工作的整体流程图:
2、 I2C 示例测试 — SHT21驱动移植
通过示例工程i2c_self_test
创建好工程,通过上面的基础介绍和分析,基本上知道了I2C通讯的步骤和方式了,因为示例代码是与 BH1750
传感器进行的 通讯,所以这里示例代码是无法测试的,直接修改 SHT21 的代码。
2.1 驱动移植修改
因为SHT21驱动函数以前在 STM32上用过,这里就相当于移植过来,先把sht21.c
和sht21.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 resultu16RH &= ~0x0003; // clear bits [1..0] (status bits)//-- calculate relative humidity [%RH] --humidityRH = (sint16)(-600 + (12500*(sint32)u16RH)/65536 ); // RH = -6 + 125 * SRH/2^16return humidityRH; // Return RH*100
}// -------------------------------------------------------------------
sint16 sht21_calcTemperature(uint16 u16T)
{sint16 temperature; // variable for resultu16T &= ~0x0003; // clear bits [1..0] (status bits)//-- calculate temperature [癈] --temperature= (sint16)(-4685 + (17572*(sint32)u16T)/65536); //T = -46.85 + 175.72 * ST/2^16return 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 datai2c_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 0x40cmd = 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 0001cmd = 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 byteaHumidity.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-/underflowelse if(aTemperature.value<0) aTemperature.value=0;if(aHumidity.value>10000) aTemperature.value=10000; //prevent temperature over-/underflowelse 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) {// CRCconst uint16 POLYNOMIAL = 0x131; //P(x)=x^8+x^5+x^4+1 = 100110001uint8 crc = 0; uint8 byteCtr;uint8 bitCtr;//calculates 8-Bit checksum with given polynomialfor (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
文件简单明了多了:
测试结果如下,正常:
ESP32-C3入门教程 基础篇(四、I2C总线 — 与SHT21温湿度传感器通讯)相关推荐
- ESP32-C3入门教程 基础篇⑪——Non-Volatile Storage (NVS) 非易失性存储参数的读写
文章目录 一.前言 二.NVS介绍 三.操作流程 3.1 读操作流程 3.2 写操作流程 四.关键函数 五.随机整数 读写示例 六.对象/数组 读写示例 七.总结 八.参考 一.前言 本文基于VS C ...
- ESP32-C3入门教程 基础篇②——GPIO口输入,按键的长按和短按
文章目录 一.前言 二.硬件准备 三.知识要点 3.1 GPIO使用 3.2 时钟节拍 四.参考例程 五.功能简述 六.源码实现 6.1 中断方式 6.2 定时扫描 七.源码详解 一.前言 本文基于V ...
- ESP32-C3入门教程 基础篇(八、NVS — 非易失性存储库的使用)
前面的7节课把开发板上基本的外设都测试过一边,接下来马上就要进入wifi和蓝牙应用的测试了 在此之前,还需要把掉电数据保存的功能给实现,在STM32中,可以使用内部的flash或者有些自带的EEPRO ...
- ESP32-C3入门教程 基础篇(三、UART模块 — 与Enocean无线模块串口通信)
测试第三课,ESP32-C3的串口通信测试 老样子,使用Enocean无线模块和ESP32-C3进行串口通信. 目录 前言 1.UART示例测试 1.1 UART 基础测试 1.2 与Enocean无 ...
- 泰凌微8258入门教程 基础篇④——sig_mesh_sdk架构介绍
文章目录 一.前言 二.SDK文件架构 三.SDK Demo Project 四.vendor文件架构 4.1 common 4.2 Demo Project目录 五.产品类型定义 一.前言 本系列的 ...
- ESP32-C3入门教程 基础篇(六、TIMG 硬件定时器 与 软件定时器)
到了测试第6课,还没有玩过ESP32-C3的基本定时器,虽然FreeRTOS,可以使用软件定时器 但是软件定时器毕竟也有不适用的时候,这个在我FreeRTOS博文中有单独说明. 所以硬件定时器也得熟悉 ...
- 泰凌微8258入门教程 基础篇⑤——发送数据流程
文章目录 一.Sig Mesh协议 二.Sig SDK 流程图 三.mesh_tx_cmd 四.增加Log 五.调试 一.Sig Mesh协议 二.Sig SDK 流程图 Created with R ...
- 泰凌微8258入门教程 基础篇①——Bluetooth® SIG Mesh 快速上手
文章目录 一.前言 1.1 Telink Bluetooth® Mesh开发工具 1.2 Bluetooth®SIG mesh演示 1.3 基于SDK的演示二进制文件 二.基于APP的节点控制 2.1 ...
- 泰凌微8258入门教程 基础篇⑬——群组(订阅)增删流程
文章目录 一.演示 二.源码分析 三.流程图梳理 3.1 添加群组(订阅) 3.2 删除群组(订阅) 四.增删群组日志 4.1 添加群组(Living Room) 4.2 添加群组(Kitchen) ...
最新文章
- java.lang.UnsatisfiedLinkError
- webpack学习之路
- 交互学习 Vue.js
- linux网络寻址顺序,51CTO博客-专业IT技术博客创作平台-技术成就梦想
- JavaWeb学习之路——SSM框架之Mybatis(三)
- [翻译]:怎样从C/C++代码中对C#进行回调
- 10天确定Python,运行环境(超详细步骤)
- 论文笔记_S2D.19_2018-PR_基于膨胀卷积神经网络与软加权和推理的分层融合单目深度估计
- 计算机串口程序配置,串口设置软件 串口调试工具如何使用
- c语言指针选择题库及答案,C语言指针练习习题及答案.doc
- c51编译器+linux,C51 开源编译器SDCC学习笔记-安装
- AngularJs的UI组件ui-Bootstrap——Datepicker Popup
- 客户机键盘某些键失灵
- 程序员工作9年月薪从1.5K到24K,网友:不如刚毕业985
- Dubbo官方入门实例
- Python:学习成绩管理系统
- Cast from pointer to smaller type 'int' loses information”
- 深圳二手房房源市场研究(上)
- 以51单片机为基础的自动循迹小车
- 教练技术培训系列篇二——明辨