ESP32-硬件IIC读取温湿度传感器SHT30

news/2024/12/30 4:06:07/

简介

esp32 使用硬件I2C读取温湿度传感器SHT30,例程基于EDP-IDF-4.4.X 的I2C Simple Example 例程修改

工程创建

  1. 打开 VSCODE ,通过 查看-- 命令面板(快捷键Ctrl+Shift+P),打开 ESP-IDF 的例程后,选择 i2c_simple 例程,点击 Create project using example i2c_simple,选择自己要存储的目录。【PS:工程的目录不要有中文路径】
    在这里插入图片描述
  2. 打开刚刚创建的 i2c_simple 例程,该例程是使用 I2C 读取三轴加速度传感器 MPU9250,我们在这个基础上开始修改 ,首先删除 MPU9250 相关的函数,具体如下:
    在这里插入图片描述

在这里插入图片描述
3. 工程添加 SHT3X 温湿度传感器的驱动

创建components/sht3x/src、components/sht3x/include 这两个文件夹,将 i2c_sht3x.c 和i2c_sht3x.h 分别放入 src 和 include 文件夹中;复制CMakeLists.txt、component.mk到components/sht3x下。工程目录结构如下:
在这里插入图片描述

  • i2c_sht3x.c
#include "i2c_sht3x.h"#define ACK_CHECK_EN   0x1     /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS  0x0     /*!< I2C master will not check ack from slave */
#define ACK_VAL    0x0         /*!< I2C ack value */
#define NACK_VAL   0x1         /*!< I2C nack value *//* 
1. 在使用SHT3X传感器的驱动之前,需要先调用 
esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_buf_len, size_t slv_tx_buf_len,int intr_alloc_flags) 
初始化I2C
2. 在 i2c_sht3x.h 中根据实际使用的I2C总线修改宏定义 SHT3X_I2C_BUS 的值 */
/*** @brief  I2Cx-写从设备的寄存器值*      - 带有写器件寄存器的方式,适用于 MPU6050、ADXL345、HMC5983、MS5611、BMP280等绝大多数I2C设备*      - 例:i2c_master_write_slave_reg(I2C_NUM_0, 0x68, 0x75, &test, 1, 100 / portTICK_RATE_MS);* * ____________________________________________________________________________________* | start | slave_addr + wr_bit + ack | reg_addr + ack | write n bytes + ack  | stop |* --------|---------------------------|----------------|----------------------|------|* * @param  i2c_num I2C端口号。I2C_NUM_0 / I2C_NUM_1* @param  slave_addr I2C写从机的器件地址* @param  reg_addr I2C写从机的寄存器地址* @param  data_wr 写入的值的指针,存放写入进的数据* @param  size 写入的寄存器数目* @param  ticks_to_wait 超时等待时间* * @return*     - esp_err_t*/
esp_err_t i2c_master_write_slave_reg(i2c_port_t i2c_num, uint8_t slave_addr, uint8_t reg_addr, uint8_t *data_wr, size_t size, TickType_t ticks_to_wait)
{i2c_cmd_handle_t cmd = i2c_cmd_link_create();i2c_master_start(cmd);i2c_master_write_byte(cmd, (slave_addr << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN);i2c_master_write_byte(cmd, reg_addr, ACK_CHECK_EN);i2c_master_write(cmd, data_wr, size, ACK_CHECK_EN);i2c_master_stop(cmd);esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, ticks_to_wait);i2c_cmd_link_delete(cmd);return ret;
}/*** @brief  I2Cx-读从设备的寄存器值(寄存器地址 或 命令 为2字节的器件)*      - 带有读器件寄存器的方式,适用于 SHT20、GT911 这种寄存器地址为16位的I2C设备*      - 例:i2c_master_read_slave_reg_16bit(I2C_NUM_0, 0x44, 0xE000, &test, 6, 100 / portTICK_RATE_MS);* * ____________________________________________________________________________________________________________________________________________________* | start | slave_addr + rd_bit + ack | reg_addr(2byte) + ack | start | slave_addr + wr_bit + ack | read n-1 bytes + ack | read 1 byte + nack | stop |* --------|---------------------------|-------------------------------|---------------------------|----------------------|--------------------|------|* * @param  i2c_num I2C端口号。I2C_NUM_0 / I2C_NUM_1* @param  slave_addr I2C读从机的器件地址* @param  reg_addr I2C读从机的寄存器地址(2byte)* @param  data_rd 读出的值的指针,存放读取出的数据* @param  size 读取的寄存器数目* @param  ticks_to_wait 超时等待时间* * @return*     - esp_err_t*/
esp_err_t i2c_master_read_slave_reg_16bit(i2c_port_t i2c_num, uint8_t slave_addr, uint16_t reg_addr, uint8_t *data_rd, size_t size, TickType_t ticks_to_wait)
{if (size == 0) {return ESP_OK;}i2c_cmd_handle_t cmd = i2c_cmd_link_create();i2c_master_start(cmd);i2c_master_write_byte(cmd, (slave_addr << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN);i2c_master_write_byte(cmd, reg_addr>>8, ACK_CHECK_EN);i2c_master_write_byte(cmd, reg_addr, ACK_CHECK_EN);i2c_master_start(cmd);i2c_master_write_byte(cmd, (slave_addr << 1) | I2C_MASTER_READ, ACK_CHECK_EN);if (size > 1) {i2c_master_read(cmd, data_rd, size - 1, ACK_VAL);}i2c_master_read_byte(cmd, data_rd + size - 1, NACK_VAL);i2c_master_stop(cmd);esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, ticks_to_wait);i2c_cmd_link_delete(cmd);return ret;
}/*** @brief    向SHT3x发送一条指令(16bit)* * @param    cmd —— SHT3x指令(在SHT3x_MODE中枚举定义)* * @retval    成功返回HAL_OK(ESP_OK)
*/
static uint8_t SHT3X_Send_Cmd(SHT30_CMD cmd)
{uint8_t cmd_buffer[2];cmd_buffer[0] = cmd >> 8;cmd_buffer[1] = cmd;return i2c_master_write_slave_reg(SHT3X_I2C_BUS, SHT3X_SLAVE_ADDRESS, cmd_buffer[0], cmd_buffer+1, 1, SHT3X_TICKS_TO_WAIT);
}/*** @brief    复位SHT3X* * @param    none* * @retval    none
*/
void sht3x_reset(void)
{SHT3X_Send_Cmd(SOFT_RESET_CMD);vTaskDelay(20 / portTICK_PERIOD_MS);
}/*** @brief    初始化SHT30* * @param    none* * @retval    成功返回HAL_OK(ESP_OK)* * @note    周期测量模式
*/
esp_err_t sht3x_init(void)
{return SHT3X_Send_Cmd(MEDIUM_2_CMD);
}/*** @brief    从SHT3X读取一次数据* * @param    dat —— 存储读取数据的地址(6个字节数组)* * @retval    成功 —— 返回HAL_OK(ESP_OK)
*/
esp_err_t sht3x_read_th_raw_dat(uint8_t* dat)
{return i2c_master_read_slave_reg_16bit(SHT3X_I2C_BUS, SHT3X_SLAVE_ADDRESS, READOUT_FOR_PERIODIC_MODE, dat, 6, SHT3X_TICKS_TO_WAIT);
}#define CRC8_POLYNOMIAL 0x31static uint8_t SHT3X_CheckCrc8(uint8_t* const message, uint8_t initial_value)
{uint8_t  remainder;        //余数uint8_t  i = 0, j = 0;  //循环变量/* 初始化 */remainder = initial_value;for(j = 0; j < 2;j++){remainder ^= message[j];/* 从最高位开始依次计算  */for (i = 0; i < 8; i++){if (remainder & 0x80){remainder = (remainder << 1)^CRC8_POLYNOMIAL;}else{remainder = (remainder << 1);}}}/* 返回计算的CRC码 */return remainder;
}/*** @brief    将SHT30接收的6个字节数据进行CRC校验,并转换为温度值和湿度值* * @param    dat  —— 存储接收数据的地址(6个字节数组)* * @retval    校验成功  —— 返回0*            校验失败  —— 返回1,并设置温度值和湿度值为0
*/
uint8_t sht3x_dat2float(uint8_t* const dat, float* temperature, float* humidity)
{uint16_t recv_temperature = 0;uint16_t recv_humidity = 0;/* 校验温度数据和湿度数据是否接收正确 */if(SHT3X_CheckCrc8(dat, 0xFF) != dat[2] || SHT3X_CheckCrc8(&dat[3], 0xFF) != dat[5])return 1;/* 转换温度数据 */recv_temperature = ((uint16_t)dat[0]<<8)|dat[1];*temperature = -45 + 175*((float)recv_temperature/65535);/* 转换湿度数据 */recv_humidity = ((uint16_t)dat[3]<<8)|dat[4];*humidity = 100 * ((float)recv_humidity / 65535);return 0;
}
  • i2c_sht3x.h
#ifndef __I2C_SHT3X_H__
#define __I2C_SHT3X_H__#include "driver/i2c.h"
#include "esp_log.h"#define SHT3X_TICKS_TO_WAIT           (100 / portTICK_RATE_MS)    // I2C读写的超时等待时间#define SHT3X_I2C_BUS                 I2C_NUM_0 // SHT30所在的I2C总线#define SHT3X_SLAVE_ADDRESS           0x44    // SHT30在I2C总线上的从机器件地址// SHT30命令列表
typedef enum
{/* 软件复位命令 */SOFT_RESET_CMD = 0x30A2,    /*单次测量模式命名格式:Repeatability_CS_CMDCS:Clock stretching*/HIGH_ENABLED_CMD    = 0x2C06,MEDIUM_ENABLED_CMD  = 0x2C0D,LOW_ENABLED_CMD     = 0x2C10,HIGH_DISABLED_CMD   = 0x2400,MEDIUM_DISABLED_CMD = 0x240B,LOW_DISABLED_CMD    = 0x2416,/*周期测量模式命名格式:Repeatability_MPS_CMDMPS:measurement per second*/HIGH_0_5_CMD   = 0x2032,MEDIUM_0_5_CMD = 0x2024,LOW_0_5_CMD    = 0x202F,HIGH_1_CMD     = 0x2130,MEDIUM_1_CMD   = 0x2126,LOW_1_CMD      = 0x212D,HIGH_2_CMD     = 0x2236,MEDIUM_2_CMD   = 0x2220,LOW_2_CMD      = 0x222B,HIGH_4_CMD     = 0x2334,MEDIUM_4_CMD   = 0x2322,LOW_4_CMD      = 0x2329,HIGH_10_CMD    = 0x2737,MEDIUM_10_CMD  = 0x2721,LOW_10_CMD     = 0x272A,/* 周期测量模式读取数据命令 */READOUT_FOR_PERIODIC_MODE = 0xE000,
} SHT30_CMD;/*** @brief    复位SHT3X* * @param    none* * @retval    none
*/
void sht3x_reset(void);/*** @brief    初始化SHT3X* * @param    none* * @retval    成功返回HAL_OK(ESP_OK)* * @note    周期测量模式
*/
uint8_t sht3x_init(void);/*** @brief    从SHT3X读取一次数据* * @param    dat —— 存储读取数据的地址(6个字节数组)* * @retval    成功 —— 返回HAL_OK(ESP_OK)
*/
uint8_t sht3x_read_dat(uint8_t* dat);/*** @brief    将SHT3X接收的6个字节数据进行CRC校验,并转换为温度值和湿度值* * @param    dat  —— 存储接收数据的地址(6个字节数组)* * @retval    校验成功  —— 返回0*            校验失败  —— 返回1,并设置温度值和湿度值为0
*/
uint8_t sht3x_dat2float(uint8_t* const dat, float* temperature, float* humidity);#endif
  • CMakeLists.txt
set(sht3x_srcs "src/i2c_sht3x.c")idf_component_register(SRCS "${sht3x_srcs}"INCLUDE_DIRS "include")

在这里插入图片描述

  • component.mk
#
# Component Makefile
#
COMPONENT_ADD_INCLUDEDIRS := includeCOMPONENT_SRCDIRS := src

在这里插入图片描述

  1. 删除不需要的代码后,我们根据实际使用的 I2C 引脚,对 I2C 进行配置,并且编写读取 sht30 传感器的函数
/* i2c - Simple exampleSimple I2C example that shows how to initialize I2Cas well as reading and writing from and to registers for a sensor connected over I2C.The sensor used in this example is a MPU9250 inertial measurement unit.For other examples please check:https://github.com/espressif/esp-idf/tree/master/examplesSee README.md file to get detailed usage of this example.This example code is in the Public Domain (or CC0 licensed, at your option.)Unless required by applicable law or agreed to in writing, thissoftware is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES ORCONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "esp_log.h"
#include "driver/i2c.h"
#include "i2c_sht3x.h" static const char *TAG = "i2c-sht3x";//"i2c-simple-example";#define I2C_MASTER_SCL_IO           GPIO_NUM_14//CONFIG_I2C_MASTER_SCL      /*!< GPIO number used for I2C master clock */
#define I2C_MASTER_SDA_IO           GPIO_NUM_4//CONFIG_I2C_MASTER_SDA      /*!< GPIO number used for I2C master data  */
#define I2C_MASTER_NUM              0                          /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */
#define I2C_MASTER_FREQ_HZ          400000                     /*!< I2C master clock frequency */
#define I2C_MASTER_TX_BUF_DISABLE   0                          /*!< I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE   0                          /*!< I2C master doesn't need buffer */
#define I2C_MASTER_TIMEOUT_MS       1000/*** @brief i2c master initialization*/
static 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,.scl_io_num = I2C_MASTER_SCL_IO,.sda_pullup_en = GPIO_PULLUP_ENABLE,.scl_pullup_en = GPIO_PULLUP_ENABLE,.master.clk_speed = I2C_MASTER_FREQ_HZ,};i2c_param_config(i2c_master_port, &conf);return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
}// i2c_sht3x_task 任务。初始化 SHT3x工作于周期测量模式,获取环境温湿度数据
void i2c_sht3x_task(void* arg)
{// 配置I2C0-主机模式,400K,指定 SCL-14,SDA-4i2c_master_init();uint8_t recv_dat[6] = {0};float temperature = 0.0;float humidity = 0.0;ESP_LOGI(TAG, "esp32 sht3x project starting ……");sht3x_reset(); // 复位SHT3Xif(sht3x_init() == ESP_OK) // 初始化SHT3X(周期测量模式)ESP_LOGI(TAG, "sht3x init ok.\n");elseESP_LOGE(TAG, "sht3x init fail.\n");vTaskDelay(1000 / portTICK_PERIOD_MS); //延时1s 等待SHT3X传感器内部采样完成for (;;){if(sht3x_read_th_raw_dat(recv_dat) == ESP_OK) // 从SHT3X读取一次数据(周期测量模式下){// 将SHT3X接收的6个字节数据进行CRC校验,并转换为温度值和湿度值if(sht3x_dat2float(recv_dat, &temperature, &humidity) == 0){ESP_LOGI(TAG, "temperature = %.2f ℃,humidity = %.2f %%RH", temperature, humidity);}else{ESP_LOGE(TAG, "crc check fail.\n");}}else{ESP_LOGE(TAG, "read data from sht3x fail.\n");}vTaskDelay(1000 / portTICK_PERIOD_MS);}
}void app_main(void)
{// 创建 i2c_sht3x_task 任务。初始化 SHT30工作于周期测量模式,获取环境温湿度数据xTaskCreate(i2c_sht3x_task, "i2c_sht3x_task", 2048, NULL, 3, NULL);
}
  1. 点击 VSCODE IDF 插件的 编译,下载,数据监测,即可在终端处查看 SHT30 传感器测量到的温湿度的值
    在这里插入图片描述

工程下载

可以点击此处下载工程,工程是不需要积分的,随意下载,如果觉得文章对您有帮助,请关注分享!
PS:该工程需要电脑已经安装了 ESP-IDF 才能编译通过


http://www.ppmy.cn/news/56392.html

相关文章

【2023/04/21-04/28】回溯算法

学习链接&#xff1a; 回溯算法解题套路框架回溯算法秒杀所有排列-组合-子集问题一文秒杀所有岛屿题目 1.分割回文串 题目来源&#xff1a;131.分割回文串 题解&#xff1a; class Solution { public:vector<vector<int>> f;vector<vector<string>&g…

前端开发在本地开发与后台进行联调阶段时,接口自动重定向https、HSTS 与 307 状态码

开发者在本地开发与后台进行联调阶段时&#xff0c;Chrome 浏览器上出现 307 状态码&#xff0c;并跳转到 https 版 但是 307 代码是什么含义呢&#xff1f;页面又为何会出现 307 状态码呢&#xff1f;我之前都没见过这个状态码&#xff0c;查了才知道原来它也是一种重定向。 …

Web3 游戏全景图:各类玩家群像解读

作者&#xff1a;lesleyfootprint.network 主要观点 即使市场深陷寒冬&#xff0c;但 web3 游戏每天依然有八十万的用户。 Web3 游戏正在逐步完善&#xff0c;从 DeFi 演变出的 Web3 游戏 &#xff0c;到增强了叙事的 X2E&#xff0c;再到 AAA 游戏和元宇宙。 未来&#xff…

H7-TOOL的CANFD Trace全解析功能制作完成,历时一个月(2023-04-28)

为了完成这个功能&#xff0c;差不多耗费了一个月时间&#xff0c;精神状态基本已经被磨平了。 当前已经支持&#xff1a; 1、LUA小程序控制&#xff0c;使用灵活。 2、采用SWD接口直接访问目标板芯片的CANFD外设寄存器和CANFD RAM区实现&#xff0c;支持USB&#xff0c;以太网…

ChatGPT镜像站收集【Free ChatGPT】(一)

文章目录 Free ChatGPT Site ListLast synced:BeiJingT 2023-04-18妙站站点列表Free ChatGPT Site List 这儿收集了一些免费好用的ChatGPT镜像站点 ⭐:使用不受限🔑:需要进行登录⛔:有限地使用次数后需提供key或进行充值❓ :未测试,未进行标注也为未测试Last synced:BeiJin…

如何将Postman API测试转换为JMeter以进行扩展

许多测试工程师使用Postman进行API测试自动化。他们发现端点&#xff0c;发出请求&#xff0c;创建测试数据&#xff0c;运行回归测试&#xff0c;使用Newman等实现API测试的持续集成。但是&#xff0c;Postman有一定的测试限制。希望获得更多负载测试能力的开发人员&#xff0…

Redis高级——键值对设计

1、Redis键值设计 1.1、优雅的key结构 Redis的Key虽然可以自定义&#xff0c;但最好遵循下面的几个最佳实践约定&#xff1a; 遵循基本格式&#xff1a;[业务名称]:[数据名]:[id]长度不超过44字节不包含特殊字符 例如&#xff1a;我们的登录业务&#xff0c;保存用户信息&a…

【Java笔试强训 30】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、选择题 二、编程题 &#x1f525;最难的问…