STM32に基づく花き温室温度制御システムの設計

I.はじめに

花卉栽培に対する人々の需要が高まるにつれ、花卉温室の建設と管理が重要な課題となっています。花の温室では、温度は花の成長と発育に直接影響を与える重要な環境パラメータです。安定した生育環境を提供するためには、温室の温度管理が非常に重要になります。

このプロジェクトは、STM32 マイクロコントローラーに基づいて花の温室温度制御システムを設計します。このシステムは、STM32F103C8T6 をメイン制御チップとして使用し、DS18B20 温度センサーや 0.96 インチ OLED ディスプレイなどのハードウェア モジュールとの接続を通じて温室内の温度を監視および制御します。同時に、システムには温度しきい値を設定するための 2 つの独立したボタンも装備されています。

温度センサーには温室内の温度を正確に監視できるDS18B20を使用しています。STM32マイコンとの通信により温度データをリアルタイムに取得できます。ディスプレイには、SPI プロトコルを備えた 0.96 インチ OLED ディスプレイが使用されており、現在の環境の温度と温度しきい値を表示するために使用されます。ユーザーはボタンを使用して温度しきい値を設定できるため、システムは設定されたしきい値に従って温度を制御できます。

温度が設定温度しきい値より低い場合、システムはリレーを介して熱風ファンを制御し、熱風を加熱して吹き出し、室温を制御します。温度をリアルタイムに監視し、設定した閾値に従って制御することで、温室内の温度を適切な範囲に維持し、花の安定した生育環境を提供します。

このプロジェクトは、花き温室の自動化を推進し、手動管理の負担を軽減するとともに、花の成長と発育を促進する安定した温度管理ソリューションを提供することを目的としています。STM32 マイクロコントローラーと関連ハードウェア モジュールを使用することにより、システムは温度のリアルタイム監視と自動制御を実現し、花き温室管理者に便利で効率的なソリューションを提供します。

画像-20230802154655957

リモコンを追加した後の最終的なシステム モデル図:

画像-20230802154537086

2. ハードウェア選択の概要

以下は、STM32 に基づく花き温室温度制御システムのハードウェアの選択です。

【1】メイン制御チップ:STM32F103C8T6

  • STM32F103 シリーズは優れたパフォーマンスと豊富なペリフェラルを備えているため、組み込みアプリケーションに適しています。
  • STM32F103C8T6 は、64KB フラッシュ メモリと 20KB RAM を搭載した 32 ビット ARM Cortex-M3 コア マイクロコントローラです。

【2】温度センサー:DS18B20

  • DS18B20 は、通信に単一のバス インターフェイスを使用するデジタル温度センサーです。
  • 高精度、防水、防塵の特徴があり、温室内の温度測定に非常に適しています。
  • ピンを介して STM32 の GPIO ポートに接続し、データ通信には OneWire プロトコルを使用します。

【3】ディスプレイ:0.96インチOLEDディスプレイ

  • 表示デバイスとして SPI プロトコルをサポートする 0.96 インチ OLED ディスプレイを選択すると、周囲温度と温度しきい値を簡単に表示できます。
  • OLED ディスプレイには、低消費電力、高コントラスト、広い視野角という利点があり、組み込み用途に適しています。

【4】ボタン:独立した2つのボタン

  • 温度しきい値を設定するには、2 つの独立したボタンを選択します。ボタンを押すと、しきい値を増減できます。

【5】リレー:熱風ファンの加熱制御に使用

  • 温度しきい値とリアルタイムの温度データに従って、STM32 の GPIO ポートを介してリレーのスイッチが制御され、熱風ファンの加熱が制御されます。
  • リレーの選択は、熱風送風機の定格電流と定格電圧に基づいて決定し、正常に動作するようにする必要があります。

3. デザインアイデア

ソフトウェアロジック設計のアイデア:

【1】GPIO、SPI、USARTなどを含むSTM32ペリフェラルを初期化します。

【2】温度閾値の初期値を設定し、ボタンで閾値を調整します。

【3】DS18B20温度センサーのデータを読み取り、読み取った温度値と閾値を比較するループ。

【4】現在の温度が閾値より低い場合、制御リレーが閉じて熱風ファンが加熱を開始し、それ以外の場合、リレーが開き、加熱を停止します。

【5】OLED画面に温度値と閾値を表示し、USARTシリアルポート経由でユーザーに出力します。

【6】上記のステップをサイクルで継続的に実行し、温室の自動温度制御機能を実現します。

疑似コード:

// 定义变量
float temperature;  // 当前温度值
float threshold;    // 温度阀值

// 初始化硬件和外设
void initialize() {
    
    
    initialize_GPIO();     // 初始化GPIO
    initialize_SPI();      // 初始化SPI
    initialize_USART();    // 初始化USART
    initialize_DS18B20();  // 初始化DS18B20
    initialize_OLED();     // 初始化OLED显示屏
    initialize_Button();   // 初始化按键
    initialize_Relay();    // 初始化继电器
}

// 读取温度值
float readTemperature() {
    
    
    // 通过DS18B20读取温度值
    // 返回温度值
}

// 读取阀值
float readThreshold() {
    
    
    // 读取按键的状态,并调节阀值
    // 返回阀值
}

// 控制加热器
void controlHeater(float currTemperature, float currThreshold) {
    
    
    if (currTemperature < currThreshold) {
    
    
        // 温度低于阀值,控制继电器闭合,热风机加热
    } else {
    
    
        // 温度高于或等于阀值,打开继电器,停止加热
    }
}

// 显示温度和阀值
void displayTemperature(float currTemperature, float currThreshold) {
    
    
    // 在OLED屏幕上显示温度值和阀值
    // 通过USART串口输出温度值和阀值
}

// 主函数
int main() {
    
    
    initialize();  // 初始化
    
    while (1) {
    
    
        temperature = readTemperature();          // 读取温度值
        threshold = readThreshold();              // 读取阀值
        controlHeater(temperature, threshold);     // 控制加热器
        displayTemperature(temperature, threshold);// 显示温度和阀值
    }

    return 0;
}

以上が基本的なソフトウェアロジック設計の考え方と擬似コードです。

4. コードの実装

4.1 温度表示を読み取る

以下は、STM32F103C8T6 を使用して DS18B20 温度センサー データを読み取り、OLED ディスプレイに温度を表示するための実装コードです。

#include "stm32f10x.h"
#include "delay.h"
#include "onewire.h"
#include "ds18b20.h"
#include "ssd1306.h"

int main(void)
{
    
    
    // 初始化延迟函数
    delay_init();
    
    // 初始化OLED显示屏
    SSD1306_Init();
    
    // 初始化DS18B20温度传感器
    DS18B20_Init();
    
    float temperature = 0.0;
    char tempStr[10];
    
    while (1)
    {
    
    
        // 读取DS18B20温度传感器数据
        temperature = DS18B20_GetTemp();
        
        // 将温度转换为字符串
        sprintf(tempStr, "%.2f C", temperature);
        
        // 清空OLED显示屏
        SSD1306_Clear();
        
        // 在OLED显示屏上显示温度
        SSD1306_GotoXY(0, 0);
        SSD1306_Puts("Temperature:", &Font_7x10, SSD1306_COLOR_WHITE);
        SSD1306_GotoXY(0, 20);
        SSD1306_Puts(tempStr, &Font_11x18, SSD1306_COLOR_WHITE);
        
        // 刷新OLED显示屏
        SSD1306_UpdateScreen();
        
        // 延时一段时间
        delay_ms(1000);
    }
}

コードでは、遅延関数 (delay.h)、OneWire バス (onewire.h)、DS18B20 温度センサー (ds18b20.h)、および SSD1306 OLED ディスプレイ (ssd1306.h) のライブラリ ファイルを含む、カプセル化されたライブラリ ファイルが使用されます。

メイン関数では、遅延機能と OLED ディスプレイを初期化し、DS18B20 温度センサーを初期化します。次に、無限ループに入り、ループ内で DS18B20 温度センサーの温度データを読み取り、OLED ディスプレイに温度を表示します。温度データは sprintf 関数によって文字列に変換され、SSD1306 ライブラリ関数を使用して OLED ディスプレイに表示されます。温度を定期的に更新するために、遅延関数を使用して一定期間遅延させます。

4.2 DS18B20 コード

ヘッダーファイルのコード:

#ifndef DS18B20_H
#define DS18B20_H

#include "stm32f10x.h"

// DS18B20引脚定义
#define DS18B20_GPIO_PORT   GPIOA
#define DS18B20_GPIO_PIN    GPIO_Pin_0

// DS18B20函数声明
void DS18B20_Init(void);
void DS18B20_WriteByte(uint8_t data);
uint8_t DS18B20_ReadByte(void);
float DS18B20_GetTemp(void);

#endif

ソースファイルコード:

#include "ds18b20.h"
#include "delay.h"

// 初始化DS18B20温度传感器
void DS18B20_Init(void)
{
    
    
    GPIO_InitTypeDef GPIO_InitStructure;
    
    // 使能GPIOA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    // 配置GPIOA引脚为推挽输出
    GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStructure);
    
    // 将引脚拉低一段时间
    GPIO_ResetBits(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN);
    delay_us(500);
    
    // 将引脚拉高一段时间
    GPIO_SetBits(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN);
    delay_us(80);
    
    // 等待DS18B20的响应
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStructure);
    delay_us(80);
}

// 向DS18B20写入一个字节的数据
void DS18B20_WriteByte(uint8_t data)
{
    
    
    uint8_t i;
    
    // 将引脚设置为推挽输出
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStructure);
    
    // 写入数据
    for (i = 0; i < 8; i++)
    {
    
    
        GPIO_ResetBits(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN);
        delay_us(2);
        if (data & 0x01)
        {
    
    
            GPIO_SetBits(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN);
        }
        delay_us(60);
        GPIO_SetBits(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN);
        delay_us(2);
        data >>= 1;
    }
}

// 从DS18B20读取一个字节的数据
uint8_t DS18B20_ReadByte(void)
{
    
    
    uint8_t i, data = 0;
    
    // 将引脚设置为推挽输出
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStructure);
    
    // 读取数据
    for (i = 0; i < 8; i++)
    {
    
    
        GPIO_ResetBits(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN);
        delay_us(2);
        GPIO_SetBits(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN);
        delay_us(2);
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
        GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStructure);
        delay_us(2);
        data >>= 1;
        if (GPIO_ReadInputDataBit(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN))
        {
    
    
            data |= 0x80;
        }
        delay_us(60);
    }
    
    return data;
}

// 获取DS18B20温度数据
float DS18B20_GetTemp(void)
{
    
    
    uint8_t tempLSB, tempMSB;
    int16_t tempData;
    float temperature;
    
    // 发送温度转换命令
    DS18B20_WriteByte(0xCC);     // 跳过ROM操作
    DS18B20_WriteByte(0x44);     // 发送温度转换命令
    
    // 等待温度转换完成
    while (!GPIO_ReadInputDataBit(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN));
    
    // 发送读取温度命令
    DS18B20_WriteByte(0xCC);     // 跳过ROM操作
    DS18B20_WriteByte(0xBE);     // 发送读取温度命令
    
    // 读取温度数据
    tempLSB = DS18B20_ReadByte();
    tempMSB = DS18B20_ReadByte();
    
    // 计算温度值
    tempData = (tempMSB << 8) | tempLSB;
    if (tempData & 0x8000)      // 温度为负数
    {
    
    
        tempData = ~tempData + 1;
        temperature = -((float)tempData / 16.0);
    }
    else                        // 温度为正数
    {
    
    
        temperature = (float)tempData / 16.0;
    }
    
    return temperature;
}

4.3 OLED ディスプレイコード

ヘッド ファイル:

#ifndef SSD1306_H
#define SSD1306_H

#include "stm32f10x.h"
#include "fonts.h"

// SSD1306显示屏参数定义
#define SSD1306_I2C_ADDR      0x78    // I2C地址
#define SSD1306_WIDTH         128     // 显示屏宽度
#define SSD1306_HEIGHT        64      // 显示屏高度

// SSD1306函数声明
void SSD1306_Init(void);
void SSD1306_Clear(void);
void SSD1306_UpdateScreen(void);
void SSD1306_GotoXY(uint16_t x, uint16_t y);
void SSD1306_Puts(const char* str, FontDef_t* font, uint8_t color);

#endif

ソースファイル:

#include "ssd1306.h"
#include "i2c.h"

static uint8_t SSD1306_Buffer[SSD1306_WIDTH * SSD1306_HEIGHT / 8];

void SSD1306_Init(void)
{
    
    
    // 初始化I2C总线
    I2C_Init();
    
    // 向SSD1306发送初始化命令
    uint8_t initCommands[] = {
    
    
        0xAE,           // 关闭显示
        0xD5, 0x80,     // 设置时钟分频因子
        0xA8, 0x3F,     // 设置驱动路数
        0xD3, 0x00,     // 设置显示偏移
        0x40,           // 设置显示开始行
        0x8D, 0x14,     // 设置电荷泵
        0x20, 0x00,     // 设置内存地址模式
        0xA1,           // 设置段重定义
        0xC8,           // 设置COM扫描方向
        0xDA, 0x12,     // 设置COM引脚配置
        0x81, 0xCF,     // 设置对比度控制
        0xD9, 0xF1,     // 设置预充电周期
        0xDB, 0x40,     // 设置VCOMH电压倍率
        0xA4,           // 全局显示开启
        0xA6,           // 设置显示方式
        0xAF            // 开启显示
    };
    
    for (uint8_t i = 0; i < sizeof(initCommands); i++)
    {
    
    
        I2C_WriteByte(SSD1306_I2C_ADDR, 0x00, initCommands[i]);
    }
    
    // 清空缓冲区
    SSD1306_Clear();
    
    // 更新显示屏
    SSD1306_UpdateScreen();
}

void SSD1306_Clear(void)
{
    
    
    memset(SSD1306_Buffer, 0x00, sizeof(SSD1306_Buffer));
}

void SSD1306_UpdateScreen(void)
{
    
    
    for (uint8_t i = 0; i < 8; i++)
    {
    
    
        I2C_WriteBuffer(SSD1306_I2C_ADDR, 0x40, &SSD1306_Buffer[SSD1306_WIDTH * i], SSD1306_WIDTH);
    }
}

void SSD1306_GotoXY(uint16_t x, uint16_t y)
{
    
    
    if (x >= SSD1306_WIDTH || y >= SSD1306_HEIGHT)
        return;
    
    SSD1306_Buffer[(x + (y / 8) * SSD1306_WIDTH)] |= (1 << (y % 8));
}

void SSD1306_Puts(const char* str, FontDef_t* font, uint8_t color)
{
    
    
    while (*str)
    {
    
    
        for (uint8_t i = 0; i < font->FontWidth; i++)
        {
    
    
            uint8_t temp = font->data[(*str - 32) * font->FontWidth + i];
            for (uint8_t j = 0; j < font->FontHeight; j++)
            {
    
    
                if (temp & (1 << j))
                {
    
    
                    SSD1306_GotoXY(font->FontWidth * i + j, font->FontHeight * i + j);
                    SSD1306_Buffer[(font->FontWidth * i + j + (font->FontHeight * i + j) / 8 * SSD1306_WIDTH)] |= (1 << ((font->FontHeight * i + j) % 8));
                }
                else
                {
    
    
                    SSD1306_GotoXY(font->FontWidth * i + j, font->FontHeight * i + j);
                    SSD1306_Buffer[(font->FontWidth * i + j + (font->FontHeight * i + j) / 8 * SSD1306_WIDTH)] &= ~(1 << ((font->FontHeight * i + j) % 8));
                }
            }
        }
        
        str++;
    }
}

5. まとめ

このプロジェクトは、STM32 に基づいて花卉温室温度制御システムを設計し、DS18B20 温度センサー、OLED ディスプレイ、リレーなどのハードウェア モジュールを使用して、温室内の温度を監視および制御します。このシステムは、事前に設定された温度しきい値に従って熱風ファンの加熱を自動的に制御し、温室内の適切な温度を維持し、花の生育環境を確保します。

ソフトウェアロジック設計の面では、STM32のペリフェラルと割り込みメカニズムを使用し、適切なアルゴリズムとステータス判断を組み合わせて、温度データの取得と比較を実現し、その結果に基づいてリレーのスイッチングを制御します。OLED ディスプレイと USART シリアル ポートを通じて、温度値としきい値をタイムリーにユーザーにフィードバックできるため、ユーザーは現在の環境を理解し、調整することが容易になります。

このプロジェクトの設計と実装は、温室の温度制御システムに特化したソリューションを提供し、合理的なハードウェアの選択とソフトウェアのロジック設計を通じて、花を植える際の温度制御のニーズを満たすことができます。将来の開発では、このシステムは農業分野で重要な役割を果たし、人々にとってより快適で効率的な温度管理環境を作り出すでしょう。

おすすめ

転載: blog.csdn.net/xiaolong1126626497/article/details/133266452