一、项目功能介绍
当前介绍基于STM32F103ZCT6芯片设计的环境温度与湿度检测系统设计过程。当前系统通过SHT30温湿度传感器采集环境温度和湿度数据,并通过模拟IIC时序协议将数据传输到STM32芯片上。然后,STM32芯片通过处理这些数据并将它们显示在0.91寸OLED显示屏上,以便用户能够方便地观察环境温度和湿度的变化情况。
系统的主控芯片采用了STM32F103ZCT6,这是一款高性能的32位ARM Cortex-M3微控制器,具有丰富的外设和存储器资源,可满足各种应用的需求。温湿度检测传感器采用了SHT30,这是一款高精度的数字式温湿度传感器,具有快速响应、低功耗、高可靠性等特点。
为了实现数据的显示,系统采用了0.91寸OLED显示屏,驱动芯片是SSD1306,接口是IIC协议。OLED显示屏也是通过模拟IIC时序进行驱动,这种方式具有简单、可靠、低功耗等优点。
(1)开发板连接SHT30实物图
(2)OLED显示屏
(3)测量的温度湿度串口打印
二、设计思路
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文件。
上一篇:STM32芯片系统结构
下一篇:STM32系列之LCD驱动接口与驱动程序介绍
推荐阅读最新更新时间:2024-10-28 06:30