硬件I2C sht3x温湿度传感器


  • stm32的硬件I2C,非中断方式
  • 代码及stm32工程分享
  • 软件方式实现传送门
  • sht3x温湿度传感器的资料解析

背景

  • 在此之前,对sht3x这款传感器的开发也是用的软件I2C模拟验证的,但项目中要求不能有阻塞行为,故软件I2C中的delay等操作就不能用了,那么stm32有硬件I2C,为什么不能用呢。(虽然网上大量搜索表明stm32的I2C的坑很深。)

代码及stm32工程分享

  • stm32工程的都放在了github空中的stm32f407VE_TestProj这个仓库中。见下方链接。
    stm32f407VE_TestProj传送门

软件I2C方式实现传送门

软件I2C sht3x温湿度传感器 学习过程记录


sht3x温湿度传感器的资料解析

  • 之前在软件I2C实现篇幅中解析过,见下链接。
    sht3x温湿度传感器的资料解析传送门

定义硬件I2C底层实现

sensirion_sw_i2c_implementation.c

#include <stm32f4xx.h>
#include <stdint.h>
#include "sensirion_arch_config.h"
#include "sensirion_i2c.h"static I2C_InitTypeDef hi2c1;
static GPIO_InitTypeDef gpioinit;
static uint32_t I2Cx_TIMEOUT_UserCallback(char value);#define I2Cx_FLAG_TIMEOUT         ((uint32_t) 900)
#define I2Cx_LONG_TIMEOUT           ((uint32_t)(300 * I2Cx_FLAG_TIMEOUT))
#define WAIT_FOR_FLAG(flag, value, timeout, errorcode)  I2CTimeout = timeout;\while(I2C_GetFlagStatus(I2C1, flag) != value){\if((I2CTimeout--) == 0) return I2Cx_TIMEOUT_UserCallback(errorcode);\}\

#define CLEAR_ADDR_BIT          I2C_ReadRegister(I2C1, I2C_Register_SR1);\I2C_ReadRegister(I2C1, I2C_Register_SR2);\

static uint32_t I2Cx_TIMEOUT_UserCallback(char value)
{I2C_InitTypeDef hi2c1;I2C_GenerateSTOP(I2C1, ENABLE);I2C_SoftwareResetCmd(I2C1, ENABLE);I2C_SoftwareResetCmd(I2C1, DISABLE);I2C_DeInit(I2C1);hi2c1.I2C_ClockSpeed = 100000;hi2c1.I2C_Mode = I2C_Mode_I2C;hi2c1.I2C_DutyCycle = I2C_DutyCycle_2;hi2c1.I2C_OwnAddress1 = 0;hi2c1.I2C_Ack = I2C_Ack_Enable;hi2c1.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;I2C_Cmd(I2C1, ENABLE);I2C_Init(I2C1, &hi2c1);//Console::Instance()->printf("I2C1 Restarted. \n");return 1;
}s8 I2C_WriteBlock(uint8_t w_addr, const uint8_t* p_data, uint16_t len)
{uint16_t i = 0;__IO uint32_t I2CTimeout = I2Cx_LONG_TIMEOUT;WAIT_FOR_FLAG(I2C_FLAG_BUSY,RESET,I2Cx_LONG_TIMEOUT,1);  I2C_GenerateSTART(I2C1, ENABLE);WAIT_FOR_FLAG(I2C_FLAG_SB, SET, I2Cx_FLAG_TIMEOUT, 2);I2C_Send7bitAddress(I2C1,(w_addr << 1), I2C_Direction_Transmitter);WAIT_FOR_FLAG(I2C_FLAG_ADDR, SET, I2Cx_FLAG_TIMEOUT, 3);CLEAR_ADDR_BIT;while (i < len) {I2C_SendData(I2C1, *p_data);WAIT_FOR_FLAG(I2C_FLAG_TXE, SET, I2Cx_FLAG_TIMEOUT, 4);i++; p_data++;}WAIT_FOR_FLAG(I2C_FLAG_BTF, SET, I2Cx_FLAG_TIMEOUT, 5);I2C_GenerateSTOP(I2C1, ENABLE);return 0;
}s8 I2C_ReadBlock(uint8_t r_addr, uint8_t* p_data, uint16_t len)
{__IO uint32_t I2CTimeout = I2Cx_LONG_TIMEOUT;WAIT_FOR_FLAG(I2C_FLAG_BUSY,RESET,I2Cx_LONG_TIMEOUT,6);I2C_GenerateSTART(I2C1, ENABLE);WAIT_FOR_FLAG(I2C_FLAG_SB, SET, I2Cx_FLAG_TIMEOUT, 7);I2C_Send7bitAddress(I2C1, (r_addr << 1), I2C_Direction_Transmitter);WAIT_FOR_FLAG(I2C_FLAG_ADDR, SET, I2Cx_FLAG_TIMEOUT, 8);CLEAR_ADDR_BIT;WAIT_FOR_FLAG (I2C_FLAG_TXE, SET, I2Cx_FLAG_TIMEOUT, 9);I2C_SendData(I2C1,r_addr);WAIT_FOR_FLAG (I2C_FLAG_TXE, SET, I2Cx_FLAG_TIMEOUT, 10); I2C_GenerateSTART(I2C1, ENABLE);WAIT_FOR_FLAG (I2C_FLAG_SB, SET, I2Cx_FLAG_TIMEOUT, 11);I2C_Send7bitAddress(I2C1,(r_addr << 1), I2C_Direction_Receiver);WAIT_FOR_FLAG (I2C_FLAG_ADDR, SET, I2Cx_FLAG_TIMEOUT, 12);/*规定死就2个长度*/while(len) {if (len == 1){I2C_AcknowledgeConfig(I2C1, DISABLE);I2C_GenerateSTOP(I2C1, ENABLE);}if (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)){*p_data = I2C_ReceiveData(I2C1);p_data++;len--;}}I2C_AcknowledgeConfig(I2C1, ENABLE);return 0;
} void sensirion_i2c_init()
{RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);gpioinit.GPIO_Mode = GPIO_Mode_OUT;gpioinit.GPIO_OType = GPIO_OType_PP;gpioinit.GPIO_PuPd = GPIO_PuPd_UP;gpioinit.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_7;gpioinit.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &gpioinit);GPIO_SetBits(GPIOB, GPIO_Pin_7);GPIO_SetBits(GPIOB, GPIO_Pin_8);I2C_SoftwareResetCmd(I2C1, ENABLE);gpioinit.GPIO_Mode = GPIO_Mode_AF;gpioinit.GPIO_OType = GPIO_OType_OD;gpioinit.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_7;gpioinit.GPIO_PuPd = GPIO_PuPd_NOPULL;gpioinit.GPIO_Speed = GPIO_Speed_50MHz;GPIO_PinAFConfig(GPIOB,GPIO_PinSource8,GPIO_AF_I2C1);GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_I2C1);GPIO_Init(GPIOB, &gpioinit);RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);hi2c1.I2C_ClockSpeed = 100000;hi2c1.I2C_Mode = I2C_Mode_I2C;hi2c1.I2C_DutyCycle = I2C_DutyCycle_16_9;hi2c1.I2C_OwnAddress1 = 0;hi2c1.I2C_Ack = I2C_Ack_Enable;hi2c1.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;I2C_Cmd(I2C1, ENABLE);I2C_Init(I2C1, &hi2c1);/* Enable the remapping of Pins 6/7 to 8/9 and the I2C clock before the initialization of the GPIO Pins*/
}s8 sensirion_i2c_read(u8 address, u8 *data, u16 count)
{return (s8) I2C_ReadBlock(address, data, count);
}s8 sensirion_i2c_write(u8 address, const u8 *data, u16 count)
{return (s8) I2C_WriteBlock(address,data, count);
}/*** Sleep for a given number of microseconds. The function should delay the* execution for at least the given time, but may also sleep longer.** @param useconds the sleep time in microseconds*/
void sensirion_sleep_usec(u32 useconds) {// 没用到
}
  • SDA、SCL引脚根据自己的实际情况配置,这里复用了一个管脚,硬件设计上只剩下这种管脚了。
  • sensirion_sleep_usec()函数不需要用。
  • I2Cx_TIMEOUT_UserCallback()用来应对超时处理的,防止因为I2C总线出现的各种问题卡死在while中,一出问题就重新初始化I2C进行恢复。
  • WAIT_FOR_FLAG()用宏定义封装了超时处理及判断I2C中的EV等事件的发生。见stm32官方手册。
  • I2C_ReadBlock()读函数,规定死了2的bytes的长度,有想用的要自己改下。
  • I2C_WriteBlock()写函数,这个没有规定长度,可以任意发送,w_addr是写入设备的地址。

sht3x.c

#include "sensirion_arch_config.h"
#include "sensirion_common.h"
#include "sensirion_i2c.h"
#include "sht.h"
#include "sht_common.h"/* all measurement commands return T (CRC) RH (CRC) */
#if USE_SENSIRION_CLOCK_STRETCHING
static const u8 CMD_MEASURE_HPM[]     = { 0x2C, 0x06 };
static const u8 CMD_MEASURE_LPM[]     = { 0x2C, 0x10 };
#else
static const u8 CMD_MEASURE_HPM[]     = { 0x24, 0x00 };
static const u8 CMD_MEASURE_LPM[]     = { 0x24, 0x16 };
#endif /* USE_SENSIRION_CLOCK_STRETCHING */
static const u8 CMD_READ_STATUS_REG[] = { 0xF3, 0x2D };
static const u8 COMMAND_SIZE = sizeof(CMD_MEASURE_HPM);
#ifdef SHT_ADDRESS
static const u8 SHT3X_ADDRESS = SHT_ADDRESS;
#else
static const u8 SHT3X_ADDRESS = 0x44;
#endifstatic const u16 MEASUREMENT_DURATION_USEC = 15000;static const u8 *cmd_measure = CMD_MEASURE_HPM;s8 sht_measure_blocking_read(s32 *temperature, s32 *humidity)
{s8 ret = sht_measure();if (ret == STATUS_OK) {sensirion_sleep_usec(MEASUREMENT_DURATION_USEC);ret = sht_read(temperature, humidity);}return ret;
}s8 sht_measure()
{return sensirion_i2c_write(SHT3X_ADDRESS, CMD_MEASURE_HPM, COMMAND_SIZE);
}s8 sht_read(s32 *temperature, s32 *humidity)
{return sht_common_read_measurement(SHT3X_ADDRESS, temperature, humidity);
}s8 sht_probe()
{u8 data[3];sensirion_i2c_init();s8 ret = sensirion_i2c_write(SHT3X_ADDRESS, CMD_READ_STATUS_REG, COMMAND_SIZE);if (ret)return ret;ret = sensirion_i2c_read(SHT3X_ADDRESS, data, sizeof(data));if (ret)return ret;ret = sensirion_common_check_crc(data, 2, data[2]);if (ret)return ret;return STATUS_OK;
}s8 sht_disable_sleep(u8 disable_sleep)
{return STATUS_FAIL; /* sleep mode not supported */
}void sht_enable_low_power_mode(u8 enable_low_power_mode)
{cmd_measure = enable_low_power_mode ? CMD_MEASURE_LPM : CMD_MEASURE_HPM;
}//const char *sht_get_driver_version()
//{//    return SHT_DRV_VERSION_STR;
//}u8 sht_get_configured_sht_address()
{return SHT3X_ADDRESS;
}
  • const char *sht_get_driver_version()需要注掉,并没有定义驱动版本,你也可以自己定义,否则会报错。
  • 有很多封装好的函数可以调用,睡眠,低功耗模式等等(其实鸟用也没用,反正我没用)
  • sht_probe()探针,用来检测是不是正常的,主程序中会用到。
  • 还有一些开头定义的命令数组及地址

mian.c

while (sht_probe() != STATUS_OK) {LED_D2_D3(GPIO_Pin_6);/* printf("SHT sensor probing failed\n"); */}GPIO_SetBits(GPIOA, GPIO_Pin_6);LED_D2_D3(GPIO_Pin_7);/*printf("SHT sensor probing successful\n"); */while (1) {s32 temperature, humidity;/* Measure temperature and relative humidity and store into variables* temperature, humidity (each output multiplied by 1000).*/s8 ret = sht_measure_blocking_read(&temperature, &humidity);if (ret == STATUS_OK) {/* printf("measured temperature: %0.2f degreeCelsius, ""measured humidity: %0.2f percentRH\n",temperature / 1000.0f,humidity / 1000.0f); */LED_D2_D3(GPIO_Pin_6);} else {//printf("error reading measurement\n");LED_D2_D3(GPIO_Pin_7);}delay_ms(1000);}
}void LED_D2_D3(uint32_t GPIO_Pin_x)
{RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIOInit;GPIOInit.GPIO_Mode = GPIO_Mode_OUT;GPIOInit.GPIO_OType = GPIO_OType_PP;GPIOInit.GPIO_Pin = GPIO_Pin_x;GPIOInit.GPIO_PuPd = GPIO_PuPd_NOPULL;GPIOInit.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIOInit);
}

完整读取的时间:16ms(传感器自身测量占了15ms见手册)

硬件I2C sht3x温湿度传感器 学习过程记录相关推荐

  1. vb6编写dll读取dat文件_【STM32Cube_15】使用硬件I2C读取温湿度传感器数据(SHT30)...

    寻求更好的阅读体验,请移步Mculover666的个人博客: [STM32Cube_15]使用硬件I2C读取温湿度传感器数据(SHT30)​www.mculover666.cn 本篇详细的记录了如何使 ...

  2. 【STM32Cube_15】使用硬件I2C读取温湿度传感器数据(SHT30)

    上一篇:[STM32Cube_14]使用硬件I2C读写环境光强度传感器(BH1750) 寻求更好的阅读体验,请移步:Mculover666的个人博客. 本篇详细的记录了如何使用STM32CubeMX配 ...

  3. STM32CubeMX | 29-使用硬件I2C读取甲醛传感器SGP30

    本篇详细的记录了如何使用STM32CubeMX配置STM32L431RCT6的硬件I2C外设读取环境光强度传感器数据(BH1750). 1. 准备工作 开发板 首先需要准备一个开发板,这里我准备的是S ...

  4. 使用RT-Thread Studio DIY 迷你桌面时钟(二)| 获取温湿度传感器数据(I2C设备驱动+SHT3x软件包)

    寻求更清爽的阅读体验,请移步:Mculover666的个人博客. 1. 项目进度 桌面Mini时钟项目用来演示如何使用RT-Thread Stduio开发项目,整个项目的架构如下: 在上一篇博文中简单 ...

  5. 使用RT-Thread Studio DIY 迷你桌面时钟| 获取温湿度传感器数据(I2C设备驱动+SHT3x软件包)...

    1. 项目进度 桌面Mini时钟项目用来演示如何使用RT-Thread Stduio开发项目,整个项目的架构如下: 在上一篇博文中简单的介绍了RT-ThreadStudio一站式工具,基于STM32L ...

  6. STM32读取SHT3x系列温湿度传感器,标准库和HAL库

    STM32读取SHT3x系列(SHT30.SHT31.SHT35)温湿度传感器的数据并显示在0.96寸OLED屏上. 我下面提供两份代码,一份是标准库使用硬件I2C的,另一份是HAL库使用软件模拟II ...

  7. zigbee CC2530 系列教程 15 温湿度传感器DHT11实验

    所有课程见此链接: zigbee CC2530 系列教程 0 课程介绍 4.12温湿度传感器DHT11实验 4.12.1 实验目的 学习使用温湿度传感器DHT11,并在串口显示温湿度数据. 4.12. ...

  8. STM32使用温湿度传感器

    前言 MDK5(Keil5)软件:uVision5 IDE 集成开发环境,是目前针对 ARM 处理器,尤其是 Cortex M 内核处理器的最佳开发工具. 本项目采用ARM结构中最为代表的Cortex ...

  9. STM32单片机硬件I2C读取AHT10温湿度传感器数据

    STM32使用硬件IIC读取AHT10温湿度传感器的数据并显示在0.96寸OLED屏上. 我用的单片机是STM32F103C8T6,程序用的是ST标准库写的. STM32使用硬件I2C读取SHTC3温 ...

最新文章

  1. python使用笔记:sys.argv[]的使用
  2. “面试不败计划”:垃圾垃圾回收
  3. sublime使用技巧(4)-- 其他技巧【持续更新】
  4. maximo 自定义高级数据选择对话框(非表域实现)
  5. oracle中directory的使用
  6. 『ExtJS』表单(一)常用表单控件及内置验证
  7. p=(1 r) 2c语言编程,菜鸟编程~!1.2
  8. 整数的二进制表示中 1 的个数
  9. svn拒绝访问是什么原因_为什么Windows无法访问U盘|电脑U盘被拒绝访问
  10. UVA-12661 Funny Car Racing (dijkstra)
  11. 时尚圈美女撰文主攻方向
  12. 自身免疫性脑炎的诊疗现状及进展
  13. java实现gif动画效果(java显示动态图片)
  14. 跟着老猫来搞GO-内建容器Map
  15. YOLOv5的Tricks | 【Trick13】YOLOv5的detect.py脚本的解析与简化
  16. 树链剖分——树链剖分模板
  17. 2018-10-29 直播课笔记
  18. python数字1 3怎么表示_Python3数据类型之数字
  19. Mybatis报错Clock moved backwards. Refusing to generate id for xxx milliseconds
  20. 智慧化工之化工厂二道门人员定位系统-化工厂定位解决方案-新导智能

热门文章

  1. 多旋翼无人机进阶教程
  2. WPF 精修篇 窗体从属关系 Owner
  3. 收银怎样挂单和取单_6、银豹收银台-收银/挂单取单/货流/交接班
  4. 《全球互联网金融商业模式:格局与发展》——第1章,第1节互联网银行1.0
  5. 3步即可完成在线压缩gif文件大小
  6. Matlab求矩阵最大值最小值以及元素和
  7. 数智十年,向新而行:2022 第十届CCF大数据与计算智能大赛在京启动
  8. 软件设计师笔记之计算机硬件基础(一)
  9. 尚硅谷Redis6视频课程
  10. 北师大计算机试题六答案,2019年度全国计算机二级考试-试题资料题库(附答案解析).doc...