基于STM32+SHT30设计的环境温度与湿度检测系统(IIC模拟时序)

发布者:和谐的24号最新更新时间:2023-07-17 来源: elecfans关键字:STM32  SHT30  环境温度  IIC  模拟时序 手机看文章 扫描二维码
随时随地手机看文章

一、项目功能介绍

当前介绍基于STM32F103ZCT6芯片设计的环境温度与湿度检测系统设计过程。当前系统通过SHT30温湿度传感器采集环境温度和湿度数据,并通过模拟IIC时序协议将数据传输到STM32芯片上。然后,STM32芯片通过处理这些数据并将它们显示在0.91寸OLED显示屏上,以便用户能够方便地观察环境温度和湿度的变化情况。


系统的主控芯片采用了STM32F103ZCT6,这是一款高性能的32位ARM Cortex-M3微控制器,具有丰富的外设和存储器资源,可满足各种应用的需求。温湿度检测传感器采用了SHT30,这是一款高精度的数字式温湿度传感器,具有快速响应、低功耗、高可靠性等特点。


为了实现数据的显示,系统采用了0.91寸OLED显示屏,驱动芯片是SSD1306,接口是IIC协议。OLED显示屏也是通过模拟IIC时序进行驱动,这种方式具有简单、可靠、低功耗等优点。


(1)开发板连接SHT30实物图

image-20230609113818437

(2)OLED显示屏

image-20230609114023918

image-20230609114008368

image-20230609113953194

image-20230609113858711

(3)测量的温度湿度串口打印

image-20230609113933518

二、设计思路

2.1 系统硬件设计

主控芯片采用STM32F103ZCT6,该芯片具有72MHz主频,具有丰富的外设资源,包括多个定时器、多个串口、多个I2C接口等。温湿度传感器采用IIC接口的SHT30,该传感器具有高精度、低功耗、数字输出等特点,可提供温度和湿度数据。OLED显示屏采用0.91寸OLED显示屏,驱动芯片是SSD1306,接口也是是IIC协议。


2.2 系统软件设计

系统软件设计采用STM32CubeMX和Keil MDK-ARM工具进行开发。


实现步骤:


(1)使用STM32CubeMX进行芯片引脚配置和初始化代码生成。


(2)编写SHT30温湿度传感器的IIC通信驱动程序。


(3)编写SSD1306 OLED显示屏的IIC通信驱动程序。


(4)编写温湿度检测程序,通过SHT30传感器读取温度和湿度数据,并将数据显示在OLED显示屏上。


(5)编写主程序,将以上各个程序整合在一起,并进行系统初始化和数据处理。


2.3 系统实现

(1)系统硬件实现


系统硬件实现包括主控板、SHT30传感器模块和OLED显示屏模块。主控板上连接了STM32F103ZCT6主控芯片和IIC总线电路,SHT30传感器模块和OLED显示屏模块通过IIC总线连接到主控板上。


(2)系统软件实现


系统软件实现主要包括SHT30传感器的IIC通信驱动程序、SSD1306 OLED显示屏的IIC通信驱动程序、温湿度检测程序和主程序。其中,SHT30传感器的IIC通信驱动程序和SSD1306 OLED显示屏的IIC通信驱动程序都是基于STM32的硬件IIC接口实现的,温湿度检测程序通过SHT30传感器读取温度和湿度数据,并将数据显示在OLED显示屏上。主程序将以上各个程序整合在一起,并进行系统初始化和数据处理。


三、代码实现

3.1 主程序代码

以下是基于STM32设计的环境温度与湿度检测系统的主函数main.c的代码实现:


#include "stm32f10x.h"

 #include "systick.h"

 #include "sht30.h"

 #include "i2c.h"

 #include "oled.h"

 

 #define OLED_ADDR 0x78

 #define SHT30_ADDR 0x44

 

 uint8_t oled_buf[128][8];

 

 void show_temp_humi(float temp, float humi) {

     char str[20];

     int temp_int = (int)(temp * 10);

     int humi_int = (int)(humi * 10);

     sprintf(str, "Temp: %d.%d C", temp_int / 10, temp_int % 10);

     oled_show_chinese16x16(0, 0, oled_buf, "温度");

     oled_show_chinese16x16(32, 0, oled_buf, ":");

     oled_show_string16x16(48, 0, oled_buf, str);

     sprintf(str, "Humi: %d.%d %%", humi_int / 10, humi_int % 10);

     oled_show_chinese16x16(0, 2, oled_buf, "湿度");

     oled_show_chinese16x16(32, 2, oled_buf, ":");

     oled_show_string16x16(48, 2, oled_buf, str);

     oled_refresh(0, 7, oled_buf);

 }

 

 int main(void)

 {

     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

 

     i2c_init();

     systick_init(72);

     sht30_init(SHT30_ADDR);

 

     oled_init();

 

     while(1)

     {

         float temp, humi;

         sht30_read_temp_humi(&temp, &humi);

         show_temp_humi(temp, humi);

         delay_ms(1000);

     }

 }

代码中主要实现了以下功能:


(1)初始化IIC总线、SHT30传感器和OLED显示屏。


(2)定时读取SHT30传感器的温度和湿度数据。


(3)将温度和湿度显示在OLED显示屏上。


代码中使用了systick.h、sht30.h、i2c.h和oled.h等库文件,需要将这些文件添加到工程中。其中oled.h文件提供了显示中文、字符串和刷新缓冲区等接口,可以在OLED显示屏上显示信息。具体代码实现可以参考oled.c文件。


测试时,需要将OLED显示屏和SHT30传感器按照对应的引脚连接好,并将代码烧录到STM32F103ZCT6芯片中。如果一切正常,OLED显示屏上就会不断地显示当前温度和湿度值。


3.2 SHT30驱动代码

以下是SHT30的驱动代码:


sht30.h:


#ifndef __SHT30_H

 #define __SHT30_H

 

 #include "stm32f10x.h"

 

 void sht30_init(uint8_t addr);

 void sht30_read_temp_humi(float *temp, float *humi);

 

 #endif /* __SHT30_H */

sht30.c:


#include "sht30.h"

 #include "i2c.h"

 

 #define SHT30_CMD_HIGH 0x2C

 #define SHT30_CMD_MIDDLE 0x06

 

 void sht30_init(uint8_t addr)

 {

     uint8_t cmd[] = { 0x22, 0x36 };

     i2c_write_data(addr, cmd, sizeof(cmd));

 }

 

 void sht30_read_temp_humi(float *temp, float *humi)

 {

     uint8_t buf[6];

     uint16_t temp_raw, humi_raw;

 

     i2c_start();

     i2c_write_byte(SHT30_ADDR < < 1);

     if (!i2c_wait_ack()) {

         return;

     }

     i2c_write_byte(SHT30_CMD_HIGH);

     i2c_wait_ack();

     i2c_write_byte(SHT30_CMD_MIDDLE);

     i2c_wait_ack();

     i2c_stop();

 

     delay_ms(10);

 

     i2c_start();

     i2c_write_byte((SHT30_ADDR < < 1) | 0x01);

     if (!i2c_wait_ack()) {

         return;

     }

     for (int i = 0; i < 6; ++i) {

         buf[i] = i2c_read_byte(i == 5 ? 0 : 1);

     }

     i2c_stop();

 

     humi_raw = (buf[0] < < 8) | buf[1];

     temp_raw = (buf[3] < < 8) | buf[4];

 

     *humi = 100.0f * ((float)humi_raw / 65535.0f);

     *temp = -45.0f + 175.0f * ((float)temp_raw / 65535.0f);

 }

代码中定义了SHT30_CMD_HIGH和SHT30_CMD_MIDDLE两个命令,用于启动温湿度转换。在sht30_init函数中,发送初始化命令;在sht30_read_temp_humi函数中,先发送读取命令,等待10毫秒后读取温度和湿度的原始值。最后根据公式计算出实际的温度和湿度值,并将它们保存到temp和humi指针所指向的内存中。


代码中调用了i2c_write_data、i2c_start、i2c_write_byte、i2c_wait_ack、i2c_read_byte和i2c_stop等IIC相关函数,这些函数的实现可以看i2c.c文件。在使用SHT30传感器之前,需要初始化IIC总线和SHT30传感器。


3.3 OLED显示屏驱动代码

以下是OLED显示屏相关代码:


oled.h:


#ifndef __OLED_H

 #define __OLED_H

 

 #include "stm32f10x.h"

 

 void oled_init(void);

 void oled_show_chinese16x16(uint8_t x, uint8_t y, uint8_t (*buf)[8], const char *str);

 void oled_show_string16x16(uint8_t x, uint8_t y, uint8_t (*buf)[8], const char *str);

 void oled_refresh(uint8_t page_start, uint8_t page_end, uint8_t (*buf)[8]);

 

 #endif /* __OLED_H */

oled.c:


#include "oled.h"

 #include < string.h >

 

 #define OLED_WIDTH 128

 #define OLED_HEIGHT 64

 

 static void oled_write_cmd(uint8_t cmd)

 {

     uint8_t tx_buf[2];

     tx_buf[0] = 0x00;

     tx_buf[1] = cmd;

     i2c_write_data(OLED_ADDR, tx_buf, sizeof(tx_buf));

 }

 

 static void oled_write_data(uint8_t data)

 {

     uint8_t tx_buf[2];

     tx_buf[0] = 0x40;

     tx_buf[1] = data;

     i2c_write_data(OLED_ADDR, tx_buf, sizeof(tx_buf));

 }

 

 static void oled_set_pos(uint8_t x, uint8_t y)

 {

     oled_write_cmd(0xb0 + y);

     oled_write_cmd(((x & 0xf0) > > 4) | 0x10);

     oled_write_cmd(x & 0x0f);

 }

 

 void oled_init(void)

 {

     oled_write_cmd(0xAE); //Display Off

     oled_write_cmd(0x00); //Set Lower Column Address

     oled_write_cmd(0x10); //Set Higher Column Address

     oled_write_cmd(0x40); //Set Display Start Line

     oled_write_cmd(0xB0); //Set Page Address

     oled_write_cmd(0x81); //Contrast Control

     oled_write_cmd(0xFF); //128 Segments

     oled_write_cmd(0xA1); //Set Segment Re-map

     oled_write_cmd(0xA6); //Normal Display

     oled_write_cmd(0xA8); //Multiplex Ratio

     oled_write_cmd(0x3F); //Duty = 1/64

     oled_write_cmd(0xC8); //Com Scan Direction

     oled_write_cmd(0xD3); //Set Display Offset

     oled_write_cmd(0x00);

     oled_write_cmd(0xD5); //Set Display Clock Divide Ratio/Oscillator Frequency

     oled_write_cmd(0x80);

     oled_write_cmd(0xD9); //Set Pre-charge Period

     oled_write_cmd(0xF1);

     oled_write_cmd(0xDA); //Set COM Pins

     oled_write_cmd(0x12);

     oled_write_cmd(0xDB); //Set VCOMH Deselect Level

     oled_write_cmd(0x40);

     oled_write_cmd(0xAF); //Display On

 

     memset(oled_buf, 0, sizeof(oled_buf));

 }

 

 void oled_show_chinese16x16(uint8_t x, uint8_t y, uint8_t (*buf)[8], const char *str)

 {

     uint16_t offset = (uint16_t)(str[0] - 0x80) * 32 + (uint16_t)(str[1] - 0x80) * 2;

     const uint8_t *font_data = &font_16x16[offset];

 

     for (int i = 0; i < 16; ++i) {

         for (int j = 0; j < 8; ++j) {

             uint8_t byte = font_data[i * 2 + j / 8];

             uint8_t bit = (byte > > (7 - j % 8)) & 0x01;

             buf[y + i][x + j] = bit ? 0xff : 0x00;

         }

     }

 }

 

 void oled_show_string16x16(uint8_t x, uint8_t y, uint8_t (*buf)[8], const char *str)

 {

     while (*str != '') {

         oled_show_chinese16x16(x, y, buf, str);

         x += 16;

         str += 2;

     }

 }

 

 void oled_refresh(uint8_t page_start, uint8_t page_end, uint8_t (*buf)[8])

 {

     for (int i = page_start; i <= page_end; ++i) {

         oled_set_pos(0, i);

         for (int j = 0; j < OLED_WIDTH; ++j) {

             oled_write_data(buf[i][j]);

         }

     }

 }

代码中定义了OLED_WIDTH和OLED_HEIGHT两个常量,表示OLED显示屏的宽度和高度。在oled_init函数中,发送初始化命令,将OLED显示屏设置为正常显示模式。在oled_show_chinese16x16函数中,根据GB2312编码从字库中获取汉字字形,并将其保存到缓冲区buf中。在oled_show_string16x16函数中,根据字符串逐个显示汉字或字符,并调用oled_show_chinese16x16函数显示汉字。在oled_refresh函数中,设置页地址和列地址,并将缓冲区buf中的数据写入到OLED显示屏上。


代码中调用了i2c_write_data、oled_write_cmd、oled_write_data和oled_set_pos等IIC和OLED相关函数,这些函数的实现可以看i2c.c文件。

[1] [2] [3]
关键字:STM32  SHT30  环境温度  IIC  模拟时序 引用地址:基于STM32+SHT30设计的环境温度与湿度检测系统(IIC模拟时序)

上一篇:STM32芯片系统结构
下一篇:STM32系列之LCD驱动接口与驱动程序介绍

推荐阅读最新更新时间:2024-10-28 06:30

循环冗余校验技术,以及在STM32中的一些具体使用体会
在嵌入式产品应用中,常常需要应对系统数据在存储或者传输过程中的完整性问题。 所谓完整性是指数据在其生命周期中的准确性和一致性。这些数据可能存储在EEPROM/FLASH里,或者基于通信协议进行传输,它们有可能因为外界干扰或者程序错误,甚至系统入侵而导致被破坏。如果这些数据在使用前不做校验,产品功能可能失效。在一些特定领域,严重时可能会危及用户财产甚至生命安全。 本文就来聊聊使用较为广泛的循环冗余校验技术,以及在STM32中的一些具体使用体会。 所谓循环冗余校验(CRC:Cyclic Redundancy Check)是一种错误检测算法,通常在通信协议中或存储设备中用于检测原始数据的意外变动。可以简单理解成对有用数据按照一定的算法进
[单片机]
循环冗余校验技术,以及在<font color='red'>STM32</font>中的一些具体使用体会
STM32学习笔记(1):GPIO口的使用
摸索了很久之后终于把ARM开发板上的LED灯点亮了,虽然是很简单的一个IO口操作,但是由于以前从来都没有什么经验,所以浪费了很多时间,也查找了很多资料。现在可以操作IO口了,证明迈出了学习ARM的第一步。 实验平台清单如下: 开发板: 奋斗STRIVE V3 核心芯片: STM32F103VET6 开发环境: RealView MDK-ARM Version:3.50 PC操作系统: Windows 7 家庭普通版 仿真器: SEGGER J-Link 其中,STM32F103VET6芯片是基于ARM Cortex-M3内核的,具体技术参数请参考ST公司给出的芯片资料(http
[单片机]
基于CORTEX的STM32的三相电能表方案
  背景   电能表是用来测量电能的仪表,又称电度表,火表,电能表,千瓦小时表,指测量各种电学量的仪表。基于ARM的方案已经出现,但是适合应用的ARM7 TDMI在性能上不尽人意,同时外设资源不足;而更高端的ARM9系统的复杂程度很高,成本也较高。所以要研究一种廉价的,满足客户需求的电能表,来填补这个空缺。   一、关于CORTEX-M3与STM32   最新一代ARM v7内核,命名为Cortex,同ARM7/9/10/11相比在架构上有了革命性突破。它采用高效的哈佛结构三级流水线,达到1.25DMIPS/MHz,在功耗上更是达到0.06mW/MHz。Cortex-M3使用Thumb-2指令集,自动16/32位混合排列。单
[单片机]
基于CORTEX的<font color='red'>STM32</font>的三相电能表方案
stm32怎么读取io口输入电平
要读取STM32的IO口输入电平,你可以使用GPIO外设来完成。GPIO是通用输入输出端口,它可以配置成输入模式,用于读取外部信号的电平。 首先,你需要定义一个GPIO_InitTypeDef类型的结构体变量,用于配置GPIO的相关参数。这个结构体包含了GPIO端口号、模式、速度、上拉下拉等参数。 接下来,你需要使用HAL库中的HAL_GPIO_Init()函数来初始化GPIO端口。这个函数会使用结构体中定义的参数来配置相应的GPIO端口。 GPIO_InitTypeDef GPIO_InitStruct; // 配置GPIO端口 GPIO_InitStruct.Pin = GPIO_PIN_0; // 设置GPI
[单片机]
STM32简易多级菜单(数组查表法)显示方法
单片机开发中,有时会用到屏幕来显示内容,当需要逐级显示内容时,就需要使用多级菜单的形式了。 1 多级菜单 多级菜单的实现,大体分为两种设计思路: 通过双向链表实现 通过数组查表实现 总体思路都是把菜单的各个界面联系起来,可以从上级菜单跳到下级菜单,也可从下级菜单返回上级菜单。 数组查表的方式比较简单,易于理解,本篇就来使用数组查表发在STM32上实现多级菜单的显示。 2 代码实现 2.1 数组查表 首先需要定义一个结构体: typedef struct { uchar current; uchar up;//向上翻索引号 uchar down;//向下翻索引号 uchar ent
[单片机]
<font color='red'>STM32</font>简易多级菜单(数组查表法)显示方法
STM32学习记录17 串口一键下载
1.MCUISP串口软件一键下载设置: DTR低电平复位,RTS高电平进入bootload串口下载 在ch340芯片对应DTR和RTS输出电平与电脑软件设置的电平相反。一键下载电路根据ch340芯片对应引脚的控制信号完成对应功能具体实现过程如下: 2.单片机启动设置单片机低电平复位 Boot0=0,boot1=x,从用户区flash启动Boot0=1,boot1=0,进入串口下载区Boot0=1,boot1=1,从SRAM启动改变boot0电平就可以从不同区域启动 3.一键下载电路如下: 4.当MUCISP软件点击下载后(需要选中下载后执行):DTR#,RTS#信号由MUCISP软件控制MUCISP软件设置为:
[单片机]
<font color='red'>STM32</font>学习记录17 串口一键下载
示波器分析IIC波形图
测试设备: 1.MCU:STM32G0 2.IIC设备:lis2dh12(ST的三轴加速度计) 3.示波器:普源RIGOL DS1054Z 知识点: 1.开始信号:SCL在高电平期间,SDA由高变低即为开始信号 2.停止信号:SCL在高电平期间,SDA由低变高即为停止信号 3.应答信号ACK: 八位数据位发送完之后,第九个时钟即是ACK,0表示有ack,1表示nack 4.发送八位数据位的时候,电平变化总是发生在低电平期间,SCL为高电平器件不可以变动,只有开始信号和停止信号是在SCL为高器件变动 5.空闲态:SCL和SDA都为高 6.在切换数据的传输方向时,可以不必先产生停止条件再开始下次传输,而
[单片机]
示波器分析<font color='red'>IIC</font>波形图
用Keil编译STM32工程出现下面错误
Keil提示:*.axf: Error: L6967E: Entry point (0x08000000) points to a Thumb instruction but is not a valid Thumb code pointer. 解决办法: 1、菜单 options for target- linker- misc controls加入 --entry Reset_Handler --first __Vectors 2、options for target- asm- Include Paths 然后倒入startup_stm32f10x_hd.s或者startup_stm32f10x_md.s(说明:不同的
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
  • 学习ARM开发(16)
    ARM有很多东西要学习,那么中断,就肯定是需要学习的东西。自从CPU引入中断以来,才真正地进入多任务系统工作,并且大大提高了工作效率。采 ...
  • 学习ARM开发(17)
    因为嵌入式系统里全部要使用中断的,那么我的S3C44B0怎么样中断流程呢?那我就需要了解整个流程了。要深入了解,最好的方法,就是去写程序 ...
  • 学习ARM开发(18)
    上一次已经了解ARM的中断处理过程,并且可以设置中断函数,那么它这样就可以工作了吗?答案是否定的。因为S3C44B0还有好几个寄存器是控制中 ...
  • 嵌入式系统调试仿真工具
    嵌入式硬件系统设计出来后就要进行调试,不管是硬件调试还是软件调试或者程序固化,都需要用到调试仿真工具。 随着处理器新品种、新 ...
  • 最近困扰在心中的一个小疑问终于解惑了~~
    最近在驱动方面一直在概念上不能很好的理解 有时候结合别人写的一点usb的例子能有点感觉,但是因为arm体系里面没有像单片机那样直接讲解引脚 ...
  • 学习ARM开发(1)
  • 学习ARM开发(2)
  • 学习ARM开发(4)
  • 学习ARM开发(6)
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved