首页 > 分享 > 基于STM32的花卉温室控温系统设计

基于STM32的花卉温室控温系统设计

一、前言

随着人们对花卉养殖的需求不断增长,花卉温室的建设和管理成为了一个重要的课题。在花卉温室中,温度是一个至关重要的环境参数,对花卉的生长和发展有着直接的影响。为了提供一个稳定的生长环境,控制温室的温度变得非常重要。

本项目设计一个基于STM32微控制器的花卉温室控温系统。该系统利用STM32F103C8T6作为主控芯片,通过与DS18B20温度传感器和0.96寸OLED显示屏等硬件模块的连接,实现对温室内温度的监测和控制。同时,系统还配备了两个独立按键,用于设置温度阀值。

温度传感器采用DS18B20,能够准确地监测温室内的温度。通过与STM32微控制器的通信,可以实时获取温度数据。显示屏采用SPI协议的0.96寸OLED显示屏,用于显示当前环境的温度以及温度阀值。用户可以通过按键设置温度阀值,以便系统能够根据设定的阀值进行温度控制。

当温度低于设定的温度阀值时,系统将通过继电器控制热风机进行加热,吹出热风来控制室温。通过实时监测温度并根据设定的阀值进行控制,系统能够保持温室内的温度在一个适宜的范围,为花卉提供一个稳定的生长环境。

项目的设计用于提高花卉温室的自动化程度,减轻人工管理的负担,同时提供一个稳定的温度控制方案,以促进花卉的生长和发展。通过使用STM32微控制器和相关硬件模块,该系统能够实现温度的实时监测和自动控制,为花卉温室管理者提供了一种方便、高效的解决方案。

image-20230802154655957

加上远程控制之后的最终系统模型图:

image-20230802154537086

二、硬件选型介绍

以下是基于STM32的花卉温室控温系统的硬件选型:

【1】主控芯片:STM32F103C8T6

STM32F103系列具有良好的性能和丰富的外设,适合嵌入式应用。STM32F103C8T6是一款32位ARM Cortex-M3内核的微控制器,具有64KB的Flash存储器和20KB的RAM。

【2】温度传感器:DS18B20

DS18B20是一款数字温度传感器,采用单总线接口进行通信。具有高精度、防水防尘等特点,非常适合测量温室内的温度。通过引脚连接到STM32的GPIO口,并使用OneWire协议进行数据通信。

【3】显示屏:0.96寸OLED显示屏

选择支持SPI协议的0.96寸OLED显示屏作为显示设备,可以方便地显示环境温度和温度阀值。OLED显示屏具有低功耗、高对比度、视角广等优点,适合嵌入式应用。

【4】按键:两个独立按键

选择两个独立按键用于设置温度阀值,可以通过按下按钮增加或减小温度阀值。

【5】继电器:用于控制热风机加热

根据温度阀值和实时温度数据,通过STM32的GPIO口控制继电器的开关,从而控制热风机的加热。继电器的选型要根据热风机的额定电流和电压来确定,确保能够正常工作。

三、设计思路

软件逻辑设计思路:

【1】初始化STM32外设,包括GPIO、SPI、USART等。

【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; }

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455

以上是基本的软件逻辑设计思路和伪代码。

四、代码实现

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

1234567891011121314151617181920212223242526272829303132333435363738394041424344

代码中,使用了封装好库文件,包括延迟函数(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

1234567891011121314151617

源文件代码:

#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; }

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129

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

1234567891011121314151617181920

源文件:

#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++; } }

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889

五、总结

本项目设计了基于STM32的花卉温室控温系统,通过使用DS18B20温度传感器、OLED显示屏和继电器等硬件模块,实现了对温室内温度的监测和控制。该系统能够根据预设的温度阀值,自动控制热风机的加热,以维持温室内的适宜温度,从而保证花卉的生长环境。

在软件逻辑设计方面,采用了STM32的外设和中断机制,结合合适的算法和状态判断,实现了温度数据的获取和比较,并根据结果控制继电器的开关。通过OLED显示屏和USART串口,能够及时地将温度值和阀值反馈给用户,方便用户了解当前环境并进行调节。

本项目的设计和实现为温室控温系统提供了一个具体的解决方案,通过合理的硬件选型和软件逻辑设计,能够满足花卉种植对温度控制的需求。在未来的发展中,系统将在农业领域发挥重要作用,并为人们创造更舒适、高效的温控环境。

相关知识

基于STM32的花卉温室控温系统设计
基于STM32单片机的鲜花售卖机系统设计
基于STM32单片机远程浇花花盆GSM短信浇水补光灌溉系统
温室育苗自动覆膜控温移动苗床
基于STM32单片机智能养花灌溉土壤湿度检测无线云平台设计21
开题报告 基于单片机智能花卉浇水系统的设计电气工程专业
几种温室花卉灰霉病的发生与防治初探
家庭盆栽花卉的简单管理
基于Java的花卉销售系统的设计与实现/管理系统/鲜花网站
鲜花市场遭遇寒冬,温室花卉种植环境监测系统助力花农增产增收

网址: 基于STM32的花卉温室控温系统设计 https://m.huajiangbk.com/newsview87433.html

所属分类:花卉
上一篇: 安定区逾百亩温室花卉:农民花样生
下一篇: 花具二唇,下唇膨大似荷包,颜色有