<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>
0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

基于STM32+SHT30設計的環境溫度與濕度檢測系統(IIC模擬時序)

DS小龍哥-嵌入式技術 ? 來源:DS小龍哥-嵌入式技術 ? 作者:DS小龍哥-嵌入式技 ? 2023-06-20 09:16 ? 次閱讀

一、項目功能介紹

當前介紹基于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文件。

3.4 IIC模擬時序代碼(SHT30)

i2c.h:

#ifndef __I2C_H
 #define __I2C_H
 ?
 #include "stm32f10x.h"
 ?
 void i2c_init(void);
 uint8_t i2c_write_data(uint8_t addr, uint8_t *data, uint8_t len);
 uint8_t i2c_read_data(uint8_t addr, uint8_t *data, uint8_t len);
 ?
 #endif /* __I2C_H */

i2c.c:

#include "i2c.h"
 ?
 #define I2C_SCL_PIN GPIO_Pin_6
 #define I2C_SDA_PIN GPIO_Pin_7
 #define I2C_SCL_PORT GPIOB
 #define I2C_SDA_PORT GPIOB
 ?
 static void i2c_delay(void)
 {
     volatile int i = 7;
     while (i) { --i; }
 }
 ?
 static void i2c_start(void)
 {
     GPIO_SetBits(I2C_SCL_PORT, I2C_SCL_PIN);
     GPIO_SetBits(I2C_SDA_PORT, I2C_SDA_PIN);
     i2c_delay();
     GPIO_ResetBits(I2C_SDA_PORT, I2C_SDA_PIN);
     i2c_delay();
     GPIO_ResetBits(I2C_SCL_PORT, I2C_SCL_PIN);
     i2c_delay();
 }
 ?
 static void i2c_stop(void)
 {
     GPIO_ResetBits(I2C_SDA_PORT, I2C_SDA_PIN);
     GPIO_SetBits(I2C_SCL_PORT, I2C_SCL_PIN);
     i2c_delay();
     GPIO_SetBits(I2C_SDA_PORT, I2C_SDA_PIN);
     i2c_delay();
 }
 ?
 static uint8_t i2c_write_byte(uint8_t byte)
 {
     uint8_t ack_bit = 0;
     for (int i = 0; i < 8; ++i) {
         if ((byte & 0x80) == 0x80) {
             GPIO_SetBits(I2C_SDA_PORT, I2C_SDA_PIN);
         } else {
             GPIO_ResetBits(I2C_SDA_PORT, I2C_SDA_PIN);
         }
         byte < <= 1;
         i2c_delay();
         GPIO_SetBits(I2C_SCL_PORT, I2C_SCL_PIN);
         i2c_delay();
         GPIO_ResetBits(I2C_SCL_PORT, I2C_SCL_PIN);
         i2c_delay();
     }
 ?
     GPIO_SetBits(I2C_SDA_PORT, I2C_SDA_PIN);
     i2c_delay();
     GPIO_SetBits(I2C_SCL_PORT, I2C_SCL_PIN);
     i2c_delay();
     if (GPIO_ReadInputDataBit(I2C_SDA_PORT, I2C_SDA_PIN)) {
         ack_bit = 1;
     }
     GPIO_ResetBits(I2C_SCL_PORT, I2C_SCL_PIN);
     i2c_delay();
 ?
     return ack_bit;
 }
 ?
 static uint8_t i2c_read_byte(uint8_t ack)
 {
     uint8_t ret = 0;
     GPIO_SetBits(I2C_SDA_PORT, I2C_SDA_PIN);
     for (int i = 0; i < 8; ++i) {
         ret < <= 1;
         GPIO_SetBits(I2C_SCL_PORT, I2C_SCL_PIN);
         i2c_delay();
         if (GPIO_ReadInputDataBit(I2C_SDA_PORT, I2C_SDA_PIN)) {
             ret |= 0x01;
         }
         GPIO_ResetBits(I2C_SCL_PORT, I2C_SCL_PIN);
         i2c_delay();
     }
 ?
     if (ack) {
         GPIO_ResetBits(I2C_SDA_PORT, I2C_SDA_PIN);
     } else {
         GPIO_SetBits(I2C_SDA_PORT, I2C_SDA_PIN);
     }
     i2c_delay();
     GPIO_SetBits(I2C_SCL_PORT, I2C_SCL_PIN);
     i2c_delay();
     GPIO_ResetBits(I2C_SCL_PORT, I2C_SCL_PIN);
     i2c_delay();
 ?
     return ret;
 }
 ?
 void i2c_init(void)
 {
     GPIO_InitTypeDef GPIO_InitStruct;
 ?
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
 ?
     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
     GPIO_InitStruct.GPIO_Pin = I2C_SCL_PIN | I2C_SDA_PIN;
     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
     GPIO_Init(I2C_SCL_PORT, &GPIO_InitStruct);
 ?
     GPIO_SetBits(I2C_SCL_PORT, I2C_SCL_PIN);
     GPIO_SetBits(I2C_SDA_PORT, I2C_SDA_PIN);
 }
 ?
 uint8_t i2c_write_data(uint8_t addr, uint8_t *data, uint8_t len)
 {
     i2c_start();
     if (i2c_write_byte(addr < < 1) == 1) {
         i2c_stop();
         return 1;
     }
     for (int i = 0; i < len; ++i) {
         if (i2c_write_byte(data[i]) == 1) {
             i2c_stop();
             return 1;
         }
     }
     i2c_stop();
 ?
     return 0;
 }
 ?
 uint8_t i2c_read_data(uint8_t addr, uint8_t *data, uint8_t len)
 {
     i2c_start();
     if (i2c_write_byte(addr < < 1) == 1) {
         i2c_stop();
         return 1;
     }
     for (int i = 0; i < len; ++i) {
         data[i] = i2c_read_byte((i == len - 1) ? 1 : 0);
     }
     i2c_stop();
 ?
     return 0;
 }

上面的代碼是SHT30的IIC模擬時序代碼,利用GPIO模擬SCL和SDA信號線。

在i2c_init函數中,初始化SCL和SDA引腳為開漏輸出模式。在i2c_start函數中,發送起始位。在i2c_stop函數中,發送停止位。在i2c_write_byte函數中,按位寫入字節并接收應答位。在i2c_read_byte函數中,按位讀取字節并發送應答位。在i2c_write_data函數中,先發送起始位,然后發送設備地址和寫方向,再發送數據,最后發送停止位。在i2c_read_data函數中,先發送起始位,然后發送設備地址和讀方向,接著按字節讀取數據,最后發送停止位。

3.5 OLED顯示屏完整代碼(包含IIC時序)

下面是使用模擬IIC時序驅動OLED顯示屏的完整代碼:

(在OLED驅動代碼中,根據OLED的數據手冊進行初始化和寫入命令/數據。)

oled.h:

#ifndef __OLED_H
 #define __OLED_H
 ?
 #include "stm32f10x.h"
 ?
 void oled_init(void);
 void oled_clear(void);
 void oled_display_on(void);
 void oled_display_off(void);
 void oled_draw_point(uint8_t x, uint8_t y, uint8_t mode);
 void oled_draw_line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t mode);
 void oled_draw_rectangle(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t mode);
 void oled_draw_circle(int8_t x, int8_t y, uint8_t r, uint8_t mode);
 void oled_show_char(uint8_t x, uint8_t y, uint8_t chr, uint8_t size, uint8_t mode);
 void oled_show_string(uint8_t x, uint8_t y, const char *str, uint8_t size, uint8_t mode);
 void oled_show_digit(uint8_t x, uint8_t y, uint8_t n, uint8_t size, uint8_t mode);
 ?
 #endif /* __OLED_H */

oled.c:

#include "oled.h"
#include "i2c.h"

#define OLED_WIDTH 128
#define OLED_HEIGHT 64

#define OLED_ADDRESS 0x78

#define OLED_CMD_MODE 0x00
#define OLED_DATA_MODE 0x40

static uint8_t oled_buffer[OLED_WIDTH * OLED_HEIGHT / 8];

static void oled_write_cmd(uint8_t cmd)
{
    uint8_t data[2] = {OLED_CMD_MODE, cmd};
    i2c_write_data(OLED_ADDRESS, data, 2);
}

static void oled_write_data(uint8_t *data, uint16_t len)
{
    uint8_t buffer[17];
    buffer[0] = OLED_DATA_MODE;
    for (int i = 0; i < len; ++i) {
        buffer[i + 1] = data[i];
    }
    i2c_write_data(OLED_ADDRESS, buffer, len + 1);
}

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) | 0x01);
}

void oled_init(void)
{
    i2c_init();

    oled_write_cmd(0xAE); //display off
    oled_write_cmd(0x20); //Set Memory Addressing Mode   
    oled_write_cmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
    oled_write_cmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7
    oled_write_cmd(0xc8); //Set COM Output Scan Direction
    oled_write_cmd(0x00); //---set low column address
    oled_write_cmd(0x10); //---set high column address
    oled_write_cmd(0x40); //--set start line address
    oled_write_cmd(0x81); //--set contrast control register
    oled_write_cmd(0xff);
    oled_write_cmd(0xa1); //--set segment re-map 0 to 127
    oled_write_cmd(0xa6); //--set normal display
    oled_write_cmd(0xa8); //--set multiplex ratio(1 to 64)
    oled_write_cmd(0x3f); //
    oled_write_cmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
    oled_write_cmd(0xd3); //-set display offset
    oled_write_cmd(0x00); //-not offset

    oled_write_cmd(0xd5); //--set display clock divide ratio/oscillator frequency
    oled_write_cmd(0xf0); //--set divide ratio

    oled_write_cmd(0xd9); //--set pre-charge period
    oled_write_cmd(0x22); //

    oled_write_cmd(0xda); //--set com pins hardware configuration
    oled_write_cmd(0x12);

    oled_write_cmd(0xdb); //--set vcomh
    oled_write_cmd(0x20); //0x20,0.77xVcc

    oled_write_cmd(0x8d); //--set DC-DC enable
    oled_write_cmd(0x14); //
    oled_write_cmd(0xaf); //--turn on oled panel

    oled_clear();
}

void oled_clear(void)
{
    for (int i = 0; i < sizeof(oled_buffer); ++i) {
        oled_buffer[i] = 0x00;
    }
    for (int i = 0; i < OLED_HEIGHT / 8; ++i) {
        oled_set_pos(0, i);
        oled_write_data(oled_buffer + OLED_WIDTH * i, OLED_WIDTH);
    }
}

void oled_display_on(void)
{
    oled_write_cmd(0xAF);
}

void oled_display_off(void)
{
    oled_write_cmd(0xAE);
}

void oled_draw_point(uint8_t x, uint8_t y, uint8_t mode)
{
    if ((x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) {
        return;
    }

    if (mode) {
        oled_buffer[x + (y / 8) * OLED_WIDTH] |= (1 < < (y % 8));
    } else {
        oled_buffer[x + (y / 8) * OLED_WIDTH] &= ~(1 < < (y % 8));
    }

    oled_set_pos(x, y / 8);
    oled_write_data(&oled_buffer[x + (y / 8) * OLED_WIDTH], 1);
}

void oled_draw_line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t mode)
{
    int dx, dy, sx, sy, err, e2;

    dx = abs((int)x2 - (int)x1);
    dy = abs((int)y2 - (int)y1);

    if (x1 < x2) {
        sx = 1;
    } else {
        sx = -1;
    }

    if (y1 < y2) {
        sy = 1;
    } else {
        sy = -1;
    }

    err = dx - dy;

    while (1) {
        oled_draw_point(x1, y1, mode);
        if ((x1 == x2) && (y1 == y2)) {
            break;
        }
        e2 = 2 * err;
        if (e2 > -dy) {
            err = err - dy;
            x1 = x1 + sx;
        }
        if (e2 < dx) {
            err = err + dx;
            y1 = y1 + sy;
        }
    }
}

void oled_draw_rectangle(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t mode)
{
    oled_draw_line(x1, y1, x2, y1, mode);
    oled_draw_line(x1, y1, x1, y2, mode);
    oled_draw_line(x1, y2, x2, y2, mode);
    oled_draw_line(x2, y1, x2, y2, mode);
}

void oled_draw_circle(int8_t x, int8_t y, uint8_t r, uint8_t mode)
{
    int a, b, num;

    a = 0;
    b = r;
    while (2 * b * b >= r * r) {
        oled_draw_point(x + a, y - b, mode);
        oled_draw_point(x - a, y - b, mode);
        oled_draw_point(x - a, y + b, mode);
        oled_draw_point(x + a, y + b, mode);

        oled_draw_point(x + b, y + a, mode);
        oled_draw_point(x + b, y - a, mode);
        oled_draw_point(x - b, y - a, mode);
        oled_draw_point(x - b, y + a, mode);

        a++;
        num = -((int)a * a + (int)b * b - (int)r * r);
        if (num > 0) {
            b--;
            a--;
        }
    }
}

void oled_show_char(uint8_t x, uint8_t y, uint8_t chr, uint8_t size, uint8_t mode)
{
    uint8_t font_size = (size / 8 + ((size % 8) ? 1 : 0)) * (size / 2);
    uint8_t font[font_size];

    for (int i = 0; i < font_size; ++i) {
        #ifdef OLED_USE_FONT_8x16
        font[i] = font_8x16[(chr - ' ') * font_size + i];
        #else
        font[i] = font_6x8[(chr - ' ') * font_size + i];
        #endif
    }

    for (int i = 0; i < size / 2; ++i) {
        for (int j = 0; j < size / 8; ++j) {
            for (int k = 0; k < 8; ++k) {
                if (font[j + i * (size / 8)] & (1 < < k)) {
                    oled_draw_point(x + j * 8 + k, y + i * 8, mode);
                }
            }
        }
    }
}

void oled_show_string(uint8_t x, uint8_t y, const char *str, uint8_t size, uint8_t mode)
{
    while (*str) {
        oled_show_char(x, y, *str, size, mode);
        x += size / 2;
        str++;
    }
}

void oled_show_digit(uint8_t x, uint8_t y, uint8_t n, uint8_t size, uint8_t mode)
{
    char str[2];
    str[0] = n + '0';
    str[1] = '';
    oled_show_string(x, y, str, size, mode);
}

上面代碼里oled_init函數用于初始化OLED,包括打開I2C接口、依次發送多條命令以設置OLED參數。oled_clear函數用于清除OLED屏幕上的所有顯示內容。oled_display_on和oled_display_off函數用于控制OLED的開關。oled_draw_point函數用于繪制一個像素點。oled_draw_line函數用于繪制一條直線。oled_draw_rectangle函數用于繪制一個矩形。oled_draw_circle函數用于繪制一個圓形。oled_show_char函數用于繪制一個ASCII字符。oled_show_string函數可以顯示一個字符串。oled_show_digit函數可以顯示一個數字。

四、總結

本項目是基于STM32F103ZCT6芯片設計的環境溫度與濕度檢測系統。系統通過SHT30溫濕度傳感器采集環境溫度和濕度數據,并通過模擬IIC時序協議將數據傳輸到STM32芯片上。然后,STM32芯片通過處理這些數據并將它們顯示在0.91寸OLED顯示屏上,以便用戶能夠方便地觀察環境溫度和濕度的變化情況。

在本項目中,選擇了STM32F103ZCT6作為主控芯片。該芯片具有高性能、低功耗、豐富的外設和存儲器資源等特點,非常適合用于嵌入式系統設計。然后,選擇了SHT30溫濕度傳感器作為環境溫度和濕度的檢測器。該傳感器具有高精度、快速響應、低功耗等特點,可以準確地測量環境溫度和濕度。

為了實現數據的顯示,采用了0.91寸OLED顯示屏,驅動芯片是SSD1306,接口是IIC協議。OLED顯示屏也是通過模擬IIC時序進行驅動,這種方式具有簡單、可靠、低功耗等優點。

在軟件設計方面,使用了Keil MDK作為開發工具,并使用STM32CubeMX進行芯片初始化和外設配置。然后,使用C語言編寫了程序,通過模擬IIC時序協議將SHT30傳感器采集到的溫度和濕度數據傳輸到STM32芯片上,并將這些數據顯示在OLED顯示屏上。同時還添加了溫度和濕度的校準、數據的存儲和讀取等功能。

在系統實現方面,進行了硬件設計、軟件開發、系統調試和測試等工作。通過不斷的優化和調試,最終實現了一個功能穩定、性能優良的環境溫度與濕度檢測系統。

審核編輯 黃宇

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 芯片
    +關注

    關注

    447

    文章

    48106

    瀏覽量

    410565
  • STM32
    +關注

    關注

    2243

    文章

    10683

    瀏覽量

    349346
  • IIC
    IIC
    +關注

    關注

    11

    文章

    287

    瀏覽量

    37874
  • 環境溫度
    +關注

    關注

    0

    文章

    24

    瀏覽量

    7807
  • 濕度檢測
    +關注

    關注

    0

    文章

    5

    瀏覽量

    6366
收藏 人收藏

    評論

    相關推薦

    基于51單片機+SHT30設計的環境溫度濕度檢測設備(IIC模擬時序)

    在本項目中,使用了51單片機作為主控芯片,SHT30傳感器作為溫濕度傳感器,LCD顯示屏作為數據顯示模塊。通過51單片機的GPIO口模擬IIC通信協議,實現了與
    的頭像 發表于 06-19 09:02 ?1732次閱讀
    基于51單片機+<b class='flag-5'>SHT30</b>設計的<b class='flag-5'>環境溫度</b>與<b class='flag-5'>濕度</b><b class='flag-5'>檢測</b>設備(<b class='flag-5'>IIC</b><b class='flag-5'>模擬</b><b class='flag-5'>時序</b>)

    超低溫環境溫度變送器

    `超低溫環境溫度變送器產品特點:即使在小量程的情況下也有很高的精度快速響應(模擬電路取代數字采樣)穩定性好,抗干擾能力強環境工作:溫度 -40 -- +85°C -40 -- +85°
    發表于 07-01 15:54

    基于labview的環境溫度檢測

    基于labview的環境溫度檢測
    發表于 03-31 19:29

    環境溫度傳感器檢測

      當用診斷儀診斷到故障碼DTC12、DTC13時,應對傳感器進行檢修?! z修時應先測量環境溫度,再拆下蓄電池負極搭鐵線及傳感器,測量傳感器兩端子間電阻。其檢測值應符合圖規定值,若不符合,則應更換傳感器?! D 環境溫度傳感器
    發表于 11-15 16:05

    STM32+SHT30(DS18B20)+0.96寸OLED(IIC)的溫度濕度顯示程序

    程序,顯示SHT30濕度模塊的溫濕度。OLED(IIC接口)屏幕的溫濕度顯示,串口數據輸出。為了作對比,我順便把DS18B20的
    發表于 03-16 10:31

    SHT11傳感器的溫度濕度監控報警系統單片機Proteus設計

    注:資源分享請見文末…概述系統通過SHT11溫濕度傳感器感應周圍的環境溫度濕度,通過單片機對
    發表于 07-21 06:11

    SHT30濕度模塊怎么使用

    SHT30濕度模塊使用本次我們使用STM32F103C8T6最小系統板和STM32cubeMX來教學流程我全部寫在下面了:1、配置我們的下
    發表于 02-15 06:28

    怎樣通過單片機普通IO口去模擬IIC時序

    一、實驗目的:通過單片機普通IO口,模擬IIC時序,掌握IIC通訊協議。二、實驗用到的主控芯片:STM32F103RCT6,
    發表于 02-17 06:30

    外殼溫度環境溫度

    當你想要控制一個設備的溫度時,關于系統環境溫度的模糊性會導致降額曲線的不精確。測量外殼溫度而不是環境溫度可以簡化和提高熱測試過程的準確性。
    發表于 07-19 11:09 ?24次下載
    外殼<b class='flag-5'>溫度</b>與<b class='flag-5'>環境溫度</b>

    dfrobot SHT30模擬濕度傳感器簡介

    SHT30高精度溫濕度測量,內部自動校準,線性模擬電壓輸出
    的頭像 發表于 01-07 10:45 ?1.6w次閱讀
    dfrobot <b class='flag-5'>SHT30</b><b class='flag-5'>模擬</b>溫<b class='flag-5'>濕度</b>傳感器簡介

    STM32F103 模擬IIC時序

    STM32F103 模擬IIC時序
    發表于 11-25 09:51 ?34次下載
    <b class='flag-5'>STM32</b>F103  <b class='flag-5'>模擬</b><b class='flag-5'>IIC</b><b class='flag-5'>時序</b>

    STM32入門開發: 介紹IIC總線、讀寫AT24C02(EEPROM)(采用模擬時序)

    一、環境介紹編程軟件: keil5操作系統: win10MCU型號: STM32F103ZET6STM32編程方式: 寄存器開發 (方便程序移植到其他單片機)IIC總線:
    發表于 11-25 20:06 ?39次下載
    <b class='flag-5'>STM32</b>入門開發: 介紹<b class='flag-5'>IIC</b>總線、讀寫AT24C02(EEPROM)(采用<b class='flag-5'>模擬</b><b class='flag-5'>時序</b>)

    STM32F1 & SHT3x溫濕度模塊

    一、STM32CubeMX工程配置二、程序&說明1.模擬IIC程序2,SHT3x底層3,使用說明一、STM32CubeMX工程配置說
    發表于 12-04 18:36 ?27次下載
    <b class='flag-5'>STM32</b>F1 & <b class='flag-5'>SHT</b>3x溫<b class='flag-5'>濕度</b>模塊

    SHT30濕度模塊使用

    SHT30濕度模塊使用本次我們使用STM32F103C8T6最小系統板和STM32cubeMX來教學流程我全部寫在下面了:1、配置我們的下
    發表于 12-16 16:53 ?71次下載
    <b class='flag-5'>SHT30</b>溫<b class='flag-5'>濕度</b>模塊使用

    STM32IIC通訊-SHT30濕度采集

    一、實驗目的:通過單片機普通IO口,模擬IIC時序,掌握IIC通訊協議。二、實驗用到的主控芯片:STM32F103RCT6,
    發表于 12-22 18:49 ?36次下載
    <b class='flag-5'>STM32</b>之<b class='flag-5'>IIC</b>通訊-<b class='flag-5'>SHT30</b>溫<b class='flag-5'>濕度</b>采集
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
    <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
    <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
    <acronym id="s8ci2"></acronym>
    <acronym id="s8ci2"><center id="s8ci2"></center></acronym>