一、前言
隨著人們對(duì)花卉養(yǎng)殖的需求不斷增長,花卉溫室的建設(shè)和管理成為了一個(gè)重要的課題。在花卉溫室中,溫度是一個(gè)至關(guān)重要的環(huán)境參數(shù),對(duì)花卉的生長和發(fā)展有著直接的影響。為了提供一個(gè)穩(wěn)定的生長環(huán)境,控制溫室的溫度變得非常重要。
本項(xiàng)目設(shè)計(jì)一個(gè)基于STM32微控制器的花卉溫室控溫系統(tǒng)。該系統(tǒng)利用STM32F103C8T6作為主控芯片,通過與DS18B20溫度傳感器和0.96寸OLED顯示屏等硬件模塊的連接,實(shí)現(xiàn)對(duì)溫室內(nèi)溫度的監(jiān)測(cè)和控制。同時(shí),系統(tǒng)還配備了兩個(gè)獨(dú)立按鍵,用于設(shè)置溫度閥值。
溫度傳感器采用DS18B20,能夠準(zhǔn)確地監(jiān)測(cè)溫室內(nèi)的溫度。通過與STM32微控制器的通信,可以實(shí)時(shí)獲取溫度數(shù)據(jù)。顯示屏采用SPI協(xié)議的0.96寸OLED顯示屏,用于顯示當(dāng)前環(huán)境的溫度以及溫度閥值。用戶可以通過按鍵設(shè)置溫度閥值,以便系統(tǒng)能夠根據(jù)設(shè)定的閥值進(jìn)行溫度控制。
當(dāng)溫度低于設(shè)定的溫度閥值時(shí),系統(tǒng)將通過繼電器控制熱風(fēng)機(jī)進(jìn)行加熱,吹出熱風(fēng)來控制室溫。通過實(shí)時(shí)監(jiān)測(cè)溫度并根據(jù)設(shè)定的閥值進(jìn)行控制,系統(tǒng)能夠保持溫室內(nèi)的溫度在一個(gè)適宜的范圍,為花卉提供一個(gè)穩(wěn)定的生長環(huán)境。
項(xiàng)目的設(shè)計(jì)用于提高花卉溫室的自動(dòng)化程度,減輕人工管理的負(fù)擔(dān),同時(shí)提供一個(gè)穩(wěn)定的溫度控制方案,以促進(jìn)花卉的生長和發(fā)展。通過使用STM32微控制器和相關(guān)硬件模塊,該系統(tǒng)能夠?qū)崿F(xiàn)溫度的實(shí)時(shí)監(jiān)測(cè)和自動(dòng)控制,為花卉溫室管理者提供了一種方便、高效的解決方案。
加上遠(yuǎn)程控制之后的最終系統(tǒng)模型圖:
二、硬件選型介紹
以下是基于STM32的花卉溫室控溫系統(tǒng)的硬件選型:
【1】主控芯片:STM32F103C8T6
- STM32F103系列具有良好的性能和豐富的外設(shè),適合嵌入式應(yīng)用。
- STM32F103C8T6是一款32位ARM Cortex-M3內(nèi)核的微控制器,具有64KB的Flash存儲(chǔ)器和20KB的RAM。
【2】溫度傳感器:DS18B20
- DS18B20是一款數(shù)字溫度傳感器,采用單總線接口進(jìn)行通信。
- 具有高精度、防水防塵等特點(diǎn),非常適合測(cè)量溫室內(nèi)的溫度。
- 通過引腳連接到STM32的GPIO口,并使用OneWire協(xié)議進(jìn)行數(shù)據(jù)通信。
【3】顯示屏:0.96寸OLED顯示屏
- 選擇支持SPI協(xié)議的0.96寸OLED顯示屏作為顯示設(shè)備,可以方便地顯示環(huán)境溫度和溫度閥值。
- OLED顯示屏具有低功耗、高對(duì)比度、視角廣等優(yōu)點(diǎn),適合嵌入式應(yīng)用。
【4】按鍵:兩個(gè)獨(dú)立按鍵
- 選擇兩個(gè)獨(dú)立按鍵用于設(shè)置溫度閥值,可以通過按下按鈕增加或減小溫度閥值。
【5】繼電器:用于控制熱風(fēng)機(jī)加熱
- 根據(jù)溫度閥值和實(shí)時(shí)溫度數(shù)據(jù),通過STM32的GPIO口控制繼電器的開關(guān),從而控制熱風(fēng)機(jī)的加熱。
- 繼電器的選型要根據(jù)熱風(fēng)機(jī)的額定電流和電壓來確定,確保能夠正常工作。
三、設(shè)計(jì)思路
軟件邏輯設(shè)計(jì)思路:
【1】初始化STM32外設(shè),包括GPIO、SPI、USART等。
【2】設(shè)置溫度閥值的初始值,并通過按鍵調(diào)節(jié)閥值。
【3】循環(huán)讀取DS18B20溫度傳感器的數(shù)據(jù),并將讀取到的溫度值與閥值進(jìn)行比較。
【4】如果當(dāng)前溫度低于閥值,則控制繼電器閉合,熱風(fēng)機(jī)開始加熱;否則,打開繼電器,停止加熱。
【5】將溫度值和閥值顯示在OLED屏幕上,通過USART串口輸出給用戶。
【6】不斷循環(huán)執(zhí)行以上步驟,實(shí)現(xiàn)溫室的自動(dòng)控溫功能。
偽代碼:
// 定義變量
float temperature; // 當(dāng)前溫度值
float threshold; // 溫度閥值
// 初始化硬件和外設(shè)
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() {
// 讀取按鍵的狀態(tài),并調(diào)節(jié)閥值
// 返回閥值
}
// 控制加熱器
void controlHeater(float currTemperature, float currThreshold) {
if (currTemperature < currThreshold) {
// 溫度低于閥值,控制繼電器閉合,熱風(fēng)機(jī)加熱
} else {
// 溫度高于或等于閥值,打開繼電器,停止加熱
}
}
// 顯示溫度和閥值
void displayTemperature(float currTemperature, float currThreshold) {
// 在OLED屏幕上顯示溫度值和閥值
// 通過USART串口輸出溫度值和閥值
}
// 主函數(shù)
int main() {
initialize(); // 初始化
while (1) {
temperature = readTemperature(); // 讀取溫度值
threshold = readThreshold(); // 讀取閥值
controlHeater(temperature, threshold); // 控制加熱器
displayTemperature(temperature, threshold);// 顯示溫度和閥值
}
return 0;
}
以上是基本的軟件邏輯設(shè)計(jì)思路和偽代碼。
四、代碼實(shí)現(xiàn)
4.1 讀取溫度顯示
下面是使用STM32F103C8T6讀取DS18B20溫度傳感器數(shù)據(jù),并將溫度顯示到OLED顯示屏上的實(shí)現(xiàn)代碼:
#include "stm32f10x.h"
#include "delay.h"
#include "onewire.h"
#include "ds18b20.h"
#include "ssd1306.h"
int main(void)
{
// 初始化延遲函數(shù)
delay_init();
// 初始化OLED顯示屏
SSD1306_Init();
// 初始化DS18B20溫度傳感器
DS18B20_Init();
float temperature = 0.0;
char tempStr[10];
while (1)
{
// 讀取DS18B20溫度傳感器數(shù)據(jù)
temperature = DS18B20_GetTemp();
// 將溫度轉(zhuǎn)換為字符串
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();
// 延時(shí)一段時(shí)間
delay_ms(1000);
}
}
代碼中,使用了封裝好庫文件,包括延遲函數(shù)(delay.h)、OneWire總線(onewire.h)、DS18B20溫度傳感器(ds18b20.h)和SSD1306 OLED顯示屏(ssd1306.h)的庫文件。
在主函數(shù)中,初始化延遲函數(shù)和OLED顯示屏,初始化DS18B20溫度傳感器。然后進(jìn)入無限循環(huán),在循環(huán)中讀取DS18B20溫度傳感器的溫度數(shù)據(jù),將溫度顯示到OLED顯示屏上。溫度數(shù)據(jù)通過sprintf函數(shù)轉(zhuǎn)換為字符串,使用SSD1306庫函數(shù)在OLED顯示屏上進(jìn)行顯示。通過延時(shí)函數(shù)延時(shí)一段時(shí)間,實(shí)現(xiàn)溫度的定時(shí)更新。
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函數(shù)聲明
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時(shí)鐘
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);
// 將引腳拉低一段時(shí)間
GPIO_ResetBits(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN);
delay_us(500);
// 將引腳拉高一段時(shí)間
GPIO_SetBits(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN);
delay_us(80);
// 等待DS18B20的響應(yīng)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStructure);
delay_us(80);
}
// 向DS18B20寫入一個(gè)字節(jié)的數(shù)據(jù)
void DS18B20_WriteByte(uint8_t data)
{
uint8_t i;
// 將引腳設(shè)置為推挽輸出
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);
// 寫入數(shù)據(jù)
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讀取一個(gè)字節(jié)的數(shù)據(jù)
uint8_t DS18B20_ReadByte(void)
{
uint8_t i, data = 0;
// 將引腳設(shè)置為推挽輸出
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);
// 讀取數(shù)據(jù)
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溫度數(shù)據(jù)
float DS18B20_GetTemp(void)
{
uint8_t tempLSB, tempMSB;
int16_t tempData;
float temperature;
// 發(fā)送溫度轉(zhuǎn)換命令
DS18B20_WriteByte(0xCC); // 跳過ROM操作
DS18B20_WriteByte(0x44); // 發(fā)送溫度轉(zhuǎn)換命令
// 等待溫度轉(zhuǎn)換完成
while (!GPIO_ReadInputDataBit(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN));
// 發(fā)送讀取溫度命令
DS18B20_WriteByte(0xCC); // 跳過ROM操作
DS18B20_WriteByte(0xBE); // 發(fā)送讀取溫度命令
// 讀取溫度數(shù)據(jù)
tempLSB = DS18B20_ReadByte();
tempMSB = DS18B20_ReadByte();
// 計(jì)算溫度值
tempData = (tempMSB << 8) | tempLSB;
if (tempData & 0x8000) // 溫度為負(fù)數(shù)
{
tempData = ~tempData + 1;
temperature = -((float)tempData / 16.0);
}
else // 溫度為正數(shù)
{
temperature = (float)tempData / 16.0;
}
return temperature;
}
4.3 OLED顯示屏代碼
頭文件:
#ifndef SSD1306_H
#define SSD1306_H
#include "stm32f10x.h"
#include "fonts.h"
// SSD1306顯示屏參數(shù)定義
#define SSD1306_I2C_ADDR 0x78 // I2C地址
#define SSD1306_WIDTH 128 // 顯示屏寬度
#define SSD1306_HEIGHT 64 // 顯示屏高度
// SSD1306函數(shù)聲明
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發(fā)送初始化命令
uint8_t initCommands[] = {
0xAE, // 關(guān)閉顯示
0xD5, 0x80, // 設(shè)置時(shí)鐘分頻因子
0xA8, 0x3F, // 設(shè)置驅(qū)動(dòng)路數(shù)
0xD3, 0x00, // 設(shè)置顯示偏移
0x40, // 設(shè)置顯示開始行
0x8D, 0x14, // 設(shè)置電荷泵
0x20, 0x00, // 設(shè)置內(nèi)存地址模式
0xA1, // 設(shè)置段重定義
0xC8, // 設(shè)置COM掃描方向
0xDA, 0x12, // 設(shè)置COM引腳配置
0x81, 0xCF, // 設(shè)置對(duì)比度控制
0xD9, 0xF1, // 設(shè)置預(yù)充電周期
0xDB, 0x40, // 設(shè)置VCOMH電壓倍率
0xA4, // 全局顯示開啟
0xA6, // 設(shè)置顯示方式
0xAF // 開啟顯示
};
for (uint8_t i = 0; i < sizeof(initCommands); i++)
{
I2C_WriteByte(SSD1306_I2C_ADDR, 0x00, initCommands[i]);
}
// 清空緩沖區(qū)
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++;
}
}
五、總結(jié)
本項(xiàng)目設(shè)計(jì)了基于STM32的花卉溫室控溫系統(tǒng),通過使用DS18B20溫度傳感器、OLED顯示屏和繼電器等硬件模塊,實(shí)現(xiàn)了對(duì)溫室內(nèi)溫度的監(jiān)測(cè)和控制。該系統(tǒng)能夠根據(jù)預(yù)設(shè)的溫度閥值,自動(dòng)控制熱風(fēng)機(jī)的加熱,以維持溫室內(nèi)的適宜溫度,從而保證花卉的生長環(huán)境。
在軟件邏輯設(shè)計(jì)方面,采用了STM32的外設(shè)和中斷機(jī)制,結(jié)合合適的算法和狀態(tài)判斷,實(shí)現(xiàn)了溫度數(shù)據(jù)的獲取和比較,并根據(jù)結(jié)果控制繼電器的開關(guān)。通過OLED顯示屏和USART串口,能夠及時(shí)地將溫度值和閥值反饋給用戶,方便用戶了解當(dāng)前環(huán)境并進(jìn)行調(diào)節(jié)。
本項(xiàng)目的設(shè)計(jì)和實(shí)現(xiàn)為溫室控溫系統(tǒng)提供了一個(gè)具體的解決方案,通過合理的硬件選型和軟件邏輯設(shè)計(jì),能夠滿足花卉種植對(duì)溫度控制的需求。在未來的發(fā)展中,系統(tǒng)將在農(nóng)業(yè)領(lǐng)域發(fā)揮重要作用,并為人們創(chuàng)造更舒適、高效的溫控環(huán)境。