温湿度SHT20——轮询

一、原理图

1. STM32F103RET6

原理图及参考手册:https://pan.baidu.com/s/1O9LNB4pi_CoMYQlFxnAu-w?pwd=xwud 提取码: xwud

言瑾

2. 温湿度SHT20


言瑾

二、传感器数据手册

https://pan.baidu.com/s/1X9wXWY5LKW6fhXTOVIz4YA?pwd=9g9g 提取码: 9g9g --来自百度网盘超级会员v3的分享

三、硬件配置

1. 配置GPIO

2. 配置I2C2

3. 开启外部时钟

4. 配置UART1

5. 时钟配置

6. 工程配置

四、实现代码

#include "main.h"

#include "i2c.h"

#include "usart.h"

#include "gpio.h"

#include "stdio.h"


// SHT20 从机地址(7位地址为0x40)

uint8_t SHT20_ADDR = 0x40;

// 测量命令(保持主机模式,即主机控制SCL线等待测量完成)

uint8_t SHT20_CMD_TEMP = 0xE3;  // 温度测量命令

uint8_t SHT20_CMD_HUMI = 0xE5;  // 湿度测量命令

uint8_t data_buf[3] = {0};      // 存储读取的3字节数据(16位数据+8位CRC)

uint16_t raw_temp = 0;          // 温度原始值

uint16_t raw_humi = 0;          // 湿度原始值

float temp = 0.0f;              // 实际温度(℃)

float humi = 0.0f;              // 实际湿度(%RH)


void SystemClock_Config(void);


int main(void)

{

  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();

  MX_I2C2_Init();

  MX_USART1_UART_Init();


  while (1)

  {

        // 读取温度

        // 1. 发送温度测量命令

        HAL_I2C_Master_Transmit(&hi2c2, (SHT20_ADDR << 1), &SHT20_CMD_TEMP, 1, 1000);

        HAL_Delay(90);  // SHT20温度测量最长需85ms,预留余量

        // 2. 读取3字节数据(16位温度+8位CRC)

        HAL_I2C_Master_Receive(&hi2c2, (SHT20_ADDR << 1) | 1, data_buf, 3, 1000);

        // 3. 解析温度原始值(屏蔽低2位状态位)

        raw_temp = (data_buf[0] << 8) | data_buf[1];

        raw_temp &= 0xFFFC;  // SHT20数据格式要求:低2位为状态位,需清除

        // 4. 转换为实际温度(公式来自SHT20数据手册)

        temp = -46.85f + (175.72f * raw_temp) / 65536.0f;


        // 读取湿度

        // 1. 发送湿度测量命令

        HAL_I2C_Master_Transmit(&hi2c2, (SHT20_ADDR << 1), &SHT20_CMD_HUMI, 1, 1000);

        HAL_Delay(30);  // SHT20湿度测量最长需29ms,预留余量

        // 2. 读取3字节数据(16位湿度+8位CRC)

        HAL_I2C_Master_Receive(&hi2c2, (SHT20_ADDR << 1) | 1, data_buf, 3, 1000);

        // 3. 解析湿度原始值(屏蔽低2位状态位)

        raw_humi = (data_buf[0] << 8) | data_buf[1];

        raw_humi &= 0xFFFC;  // 清除低2位状态位

        // 4. 转换为实际湿度(公式来自SHT20数据手册)

        humi = -6.0f + (125.0f * raw_humi) / 65536.0f;


        // 打印结果

        printf("Temp:%.2f ℃\n\r", temp);

        printf("Humi:%.2f %%RH\n\r", humi);

        HAL_Delay(2000);  // 2秒刷新一次

  }

}


//printf重定向到UART1

int fputc(int ch, FILE *f)

{

    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 500);

    return ch;

}

五、实验效果

言瑾
言瑾

六、多文件编译——轮询

1. sht20.h

#ifndef SHT20_H

#define SHT20_H

#include "stdint.h"

#include "stm32f1xx_hal.h"

// SHT20 设备参数

#define SHT20_ADDR        0x40        // 7位I2C地址

#define SHT20_CMD_RESET    0xFE        // 软复位命令

// 测量命令(声明为全局变量,用于取地址)

extern uint8_t SHT20_CMD_TEMP;  // 温度测量命令(0xE3)

extern uint8_t SHT20_CMD_HUMI;  // 湿度测量命令(0xE5)

extern uint16_t raw_temp; // 温度原始数据

extern uint16_t raw_humi; // 湿度原始数据

extern float temp;  // 温度值

extern float humi;  // 湿度值

// 函数声明

void SHT20_Reset(I2C_HandleTypeDef *hi2c);                  // 软复位

float SHT20_ReadTemperature(I2C_HandleTypeDef *hi2c);      // 读取温度

float SHT20_ReadHumidity(I2C_HandleTypeDef *hi2c);        // 读取湿度

#endif  // SHT20_H

2. sht20.c

#include "sht20.h"

#include "stm32f1xx_hal.h"

#include "stdio.h"  // 用于调试打印

// 测量命令定义(全局变量,分配内存)

uint8_t SHT20_CMD_TEMP = 0xE3;  // 温度测量命令

uint8_t SHT20_CMD_HUMI = 0xE5;  // 湿度测量命令

uint16_t raw_temp = 0;

uint16_t raw_humi = 0;

// 内部数据缓冲区(仅本文件使用)

static uint8_t data_buf[3] = {0};

/**

* @brief  SHT20软复位

* @param  hi2c: I2C句柄指针

*/

void SHT20_Reset(I2C_HandleTypeDef *hi2c) {

    uint8_t reset_cmd = SHT20_CMD_RESET;

    if (HAL_I2C_Master_Transmit(hi2c, (SHT20_ADDR << 1), &reset_cmd, 1, 1000) != HAL_OK) {

        printf("SHT20 reset failed!\n\r");

    } else {

        printf("SHT20 reset success!\n\r");

    }

    HAL_Delay(15);  // 复位后需等待15ms

}

/**

* @brief  读取温度

* @param  hi2c: I2C句柄指针

* @return 温度值(℃),失败返回-1000.0f

*/

float SHT20_ReadTemperature(I2C_HandleTypeDef *hi2c) {


    // 发送温度测量命令

    if (HAL_I2C_Master_Transmit(hi2c, (SHT20_ADDR << 1), &SHT20_CMD_TEMP, 1, 1000) != HAL_OK) {

        printf("Temp transmit failed!\n\r");

        return -1000.0f;

    }

    HAL_Delay(100);  // 等待测量完成(最长85ms,留余量)

    // 读取3字节数据(16位数据+8位CRC)

    if (HAL_I2C_Master_Receive(hi2c, (SHT20_ADDR << 1) | 1, data_buf, 3, 1000) != HAL_OK) {

        printf("Temp receive failed!\n\r");

        return -1000.0f;

    }

    // 解析数据(清除低2位状态位)

    raw_temp = (data_buf[0] << 8) | data_buf[1];

    raw_temp &= 0xFFFC;

    // 转换为实际温度(公式来自数据手册)

    return -46.85f + (175.72f * raw_temp) / 65536.0f;

}

/**

* @brief  读取湿度

* @param  hi2c: I2C句柄指针

* @return 湿度值(%RH),失败返回-1.0f

*/

float SHT20_ReadHumidity(I2C_HandleTypeDef *hi2c) {

    // 发送湿度测量命令

    if (HAL_I2C_Master_Transmit(hi2c, (SHT20_ADDR << 1), &SHT20_CMD_HUMI, 1, 1000) != HAL_OK) {

        printf("Humi transmit failed!\n\r");

        return -1.0f;

    }

    HAL_Delay(40);  // 等待测量完成(最长29ms,留余量)

    // 读取3字节数据

    if (HAL_I2C_Master_Receive(hi2c, (SHT20_ADDR << 1) | 1, data_buf, 3, 1000) != HAL_OK) {

        printf("Humi receive failed!\n\r");

        return -1.0f;

    }

    // 解析数据

    raw_humi = (data_buf[0] << 8) | data_buf[1];

    raw_humi &= 0xFFFC;

    // 转换为实际湿度

    return -6.0f + (125.0f * raw_humi) / 65536.0f;

}

3. main.c

#include "main.h"

#include "i2c.h"

#include "usart.h"

#include "gpio.h"

#include "stdio.h"

#include "sht20.h"  // 引入SHT20驱动

void SystemClock_Config(void);

int main(void)

{

  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();

  MX_I2C2_Init();

  MX_USART1_UART_Init();

float temp = 0.0f;  // 温度值

float humi = 0.0f;  // 湿度值

printf("System initialized!\n\r");

  SHT20_Reset(&hi2c2);  // 初始化时复位SHT20

  while (1)

  {

    // 读取温湿度

    temp = SHT20_ReadTemperature(&hi2c2);

    humi = SHT20_ReadHumidity(&hi2c2);

    // 打印结果

    if (temp != -1000.0f && humi != -1.0f) {

          printf("Temp:%.2f ℃\n\r", temp);

          printf("Humi:%.2f %%RH\n\r", humi);

    } else {

          printf("I2C communication error!\n\r");

    }

    HAL_Delay(2000);  // 2秒刷新一次

  }

}

/* 重定向fputc函数,该函数会在使用printf等输出函数时被调用 */

int fputc(int ch, FILE *f)

{

    uint8_t temp[1] = {ch};  /* 将字符转换为uint8_t类型 */

    HAL_UART_Transmit(&huart1, temp, 1, 2); /* 通过UART1发送字符,超时时间为2ms */

    return ch; /* 返回写入的字符 */

}

方法一: 解决按复位按键,串口不输出温湿度数据问题

方法二:半主机模式,解决按复位按键串口不输出温湿度数据问题

/* 引入特殊编译选项,告知编译器不要使用标准主机环境的函数和功能 */

#pragma import(__use_no_semihosting)           

/* 自定义FILE结构体,替代标准库中的版本 */

struct __FILE

{

    int handle;  /* 文件句柄,用于标识不同的文件或设备 */

};

/* 定义标准输出文件对象 */

FILE __stdout;     

/* 系统退出函数,在嵌入式系统中可能不需要真正退出,所以这里只是空操作 */

void _sys_exit(int x)

{

    x = x;  /* 防止未使用参数的警告 */

}

/* 重定向fputc函数,该函数会在使用printf等输出函数时被调用 */

int fputc(int ch, FILE *f)

{

    uint8_t temp[1] = {ch};  /* 将字符转换为uint8_t类型 */

    HAL_UART_Transmit(&huart1, temp, 1, 2); /* 通过UART1发送字符,超时时间为2ms */

    return ch; /* 返回写入的字符 */

}

最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
禁止转载,如需转载请通过简信或评论联系作者。

相关阅读更多精彩内容

友情链接更多精彩内容