项目案例:单片机设计的大棚温湿度智能控制系统
随着现代社会对健康和环保理念的日益重视,蔬菜大棚作为现代农业的一种重要模式,其意义愈发凸显。蔬菜大棚为农民提供了调控环境条件的可能,使他们能在不同季节种植蔬菜,并根据蔬菜生长需求调整环境条件。精确控制如温度和湿度等关键因素,对于蔬菜的生长和产量具有决定性作用。
传统的蔬菜大棚管理方式主要依赖于人工监测与调节,这种方法存在明显不足。人工监测可能产生误差,且反应速度较慢,特别是在管理大规模蔬菜大棚时,人工调节的工作量巨大,效率低下。因此,开发一种基于智能控制系统的蔬菜大棚温湿度管理方案成为了当务之急。
基于STM32微控制器的蔬菜大棚温湿度智能控制系统正是为了解决这个问题而设计的。该系统结合STM32微控制器的强大计算和控制能力,以及温湿度传感器和执行器等硬件设备,实现了对蔬菜大棚环境的实时监测与精准控制。
通过这一系统,农民可以随时随地掌握大棚内的温度和湿度信息,并根据预设的目标范围进行自动调节。系统能自动控制温室内的加热器、通风设备和加湿器等设备,确保蔬菜始终处于最适宜的生长环境中。该方案的目标在于提升蔬菜大棚的生产效率和质量,降低能源消耗,同时减少人力投入。
借助这一智能控制系统,农民可以更加轻松、高效地管理蔬菜大棚,实现农业的可持续发展,为社会提供更多健康、优质的蔬菜产品。这不仅有利于农民的增产增收,也有助于满足消费者对健康食品的日益增长的需求,推动整个农业产业的升级与发展。
二、系统设计流程
2.1 硬件选型
硬件选型是设计蔬菜大棚温湿度智能控制系统的重要环节。
【1】主控芯片:STM32F103ZET6 这款主控芯片采用的是STM32F103ZET6,它是一款具有高性能的ARM Cortex-M3内核微控制器。该芯片具有丰富的外设资源和强大的处理能力,能够充分满足该项目对控制和数据处理的需求。
【2】温湿度传感器:DHT11 空气的温湿度信息采集是通过使用DHT11传感器来完成的。这款传感器采用数字信号输出,具有简单、低成本以及较好的精度,非常适合用于大棚环境的温湿度监测。
【3】土壤湿度传感器 土壤湿度的采集是通过使用专门的土壤湿度传感器完成的,通过模拟-数字转换器(ADC)接口来采集土壤湿度数据。这款传感器能够准确测量土壤湿度,从而为农作物提供合适的灌溉水量。
【4】通风风机:5V小风扇+继电器 为了实现通风控制,我们选择了5V的小风扇作为通风设备,并通过继电器来控制其开关状态。根据温度数据和设定阈值,可以通过STM32的GPIO口来控制继电器的高低电平,从而实现通风风扇的启停控制。
【5】照明灯:LED白色灯模块 为了提供适当的照明条件,我们选择了LED白色灯模块作为照明设备。该模块可以通过STM32的GPIO口来控制其开关状态,从而实现灯光的开启和关闭。
【6】灌溉系统:抽水电机+继电器 灌溉系统采用了抽水电机作为水源,并通过继电器来控制其开启和关闭。通过单片机来控制继电器的高低电平,从而控制抽水电机的工作状态,实现灌溉系统的自动化操作。
【7】显示模块:LCD显示屏 为了方便用户观察当前的温湿度等数据,选用了LCD显示屏进行数据的显示。可以通过STM32的数字接口与LCD显示屏进行通信,将采集到的数据实时显示在屏幕上。
2.2 软件设计思路
1. 系统初始化:对STM32微控制器进行初始化配置,这包括设置引脚功能、配置时钟源以及初始化其他相关外设。同时,LCD显示屏也需要进行初始化,以便后续能够正确显示数据。
2. 数据采集:利用DHT11传感器来采集大棚内的温度和湿度数据,同时使用土壤湿度传感器来获取土壤湿度信息。这些传感器通过适当的接口与STM32微控制器通信,确保采集到的数据能够准确传输到主控系统。
3. 数据处理与决策:采集到的温湿度和土壤湿度数据需要经过处理和分析。系统会判断当前温度是否在设定的适宜范围内,以及土壤湿度是否低于预设的阈值。这些判断结果将直接影响后续的控制决策。
4. 执行器控制:根据数据处理和判断的结果,系统会通过控制相应的执行器来调节大棚的环境条件。例如,如果温度过高,系统可能会启动通风风扇或开启加湿器;如果土壤湿度过低,系统可能会触发灌溉系统来补充水分。
5. 信息显示:通过LCD显示屏,系统会将采集到的温湿度和土壤湿度数据实时显示出来,让农民或其他用户可以直观地了解大棚内的环境条件。
6. 用户交互:系统还提供了用户交互功能,允许用户通过按键或其他输入方式设置土壤湿度阈值、调整温度范围等。这样,用户可以根据自己的需求灵活调整大棚的环境参数。
7. 循环监控:以上所有步骤都会组成一个循环监控的程序,确保系统能够持续不断地采集数据、进行处理和判断、控制执行器,并实时显示信息。这样,大棚内的环境条件就能得到持续的监控和调整,确保蔬菜始终处于最佳的生长环境中。
三、代码实现
3.1 DHT11温湿度读取
读取DHT11传感器环境温湿度并通过串口打印出来。
#include "stm32f10x.h"
#include "stdio.h"
// 定义DHT11数据引脚
#define DHT11_PIN GPIO_Pin_0
#define DHT11_PORT GPIOA
// DHT11初始化函数
void DHT11_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 使能GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 配置DHT11引脚为推挽输出
GPIO_InitStructure.GPIO_Pin = DHT11_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DHT11_PORT, &GPIO_InitStructure);
}
// 延时函数,单位为微秒
void Delay_us(uint32_t nCount)
{
uint32_t i;
for(i=0; i<nCount; i++);
}
// 软件延时函数,单位为毫秒
void Delay_ms(uint32_t nCount)
{
uint32_t i;
for(i=0; i<nCount*1000; i++);
}
// 从DHT11读取一位数据
uint8_t DHT11_ReadBit(void)
{
uint8_t retries = 0;
while(GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN) == Bit_RESET)
{
if (retries++ > 100) return 0;
Delay_us(1);
}
Delay_us(40); // 延时40us
if (GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN) == Bit_SET)
retries = 100; // 超时标识
else
retries = 0;
while(GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN) == Bit_SET)
{
if (retries++ > 100) return 0;
Delay_us(1);
}
return 1;
}
// 从DHT11读取一个字节数据
uint8_t DHT11_ReadByte(void)
{
uint8_t i, temp = 0;
for(i=0; i<8; i++)
{
temp <<= 1;
temp |= DHT11_ReadBit();
}
return temp;
}
// 读取DHT11的温湿度值
uint8_t DHT11_ReadData(uint8_t* temperature, uint8_t* humidity)
{
uint8_t data[5], checksum;
// 主机将总线拉低至少18ms
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = DHT11_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DHT11_PORT, &GPIO_InitStructure);
GPIO_ResetBits(DHT11_PORT, DHT11_PIN);
Delay_ms(20);
GPIO_SetBits(DHT11_PORT, DHT11_PIN);
Delay_us(30);
// 设置为输入模式
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(DHT11_PORT, &GPIO_InitStructure);
// 等待 DHT11 响应
if (GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN) == Bit_RESET)
{
while(GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN) == Bit_RESET);
while(GPIO_ReadInputDataBit(DHT11_PORT, DHT11_PIN) == Bit_SET);
// 读取5字节数据
for(uint8_t i=0; i<5; i++)
data[i] = DHT11_ReadByte();
// 读取校验和
checksum = DHT11_ReadByte();
// 校验数据
if((data[0] + data[1] + data[2] + data[3]) != checksum)
return 0;
*humidity = data[0];
*temperature = data[2];
return 1;
}
else
{
return 0;
}
}
// 初始化USART1
void USART1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// 使能USART1和GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
// 配置USART1的引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // TX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // RX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置USART1
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
// 使能USART1
USART_Cmd(USART1, ENABLE);
}
// 发送字符到USART1
void USART1_SendChar(char ch)
{
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
USART_SendData(USART1, (uint8_t)ch);
}
// 发送字符串到USART1
void USART1_SendString(const char* str)
{
while(*str)
{
USART1_SendChar(*str++);
}
}
int main(void)
{
uint8_t temperature, humidity;
// 初始化DHT11和USART1
DHT11_Init();
USART1_Init();
while(1)
{
if (DHT11_ReadData(&temperature, &humidity))
{
// 发送温湿度数据到串口
char buffer[50];
sprintf(buffer, "Temperature: %d°C, Humidity: %d%%\r\n", temperature, humidity);
USART1_SendString(buffer);
}
Delay_ms(2000); // 2秒钟读取一次数据
}
}
将代码下载到STM32F103ZET6开发板上,接上DHT11。当成功运行时,环境温湿度数据会通过USART1串口打印出来。
3.2 读取土壤湿度值
通过ADC1的通道1采集土壤传感器的湿度值,打印到串口.
#include "stm32f10x.h"
#include "stdio.h"
// 函数声明
void ADC_Configuration(void);
void UART_Configuration(void);
void USART1_SendChar(char ch);
int main(void)
{
// 初始化ADC和串口
ADC_Configuration();
UART_Configuration();
while (1)
{
// 启动ADC转换
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
// 等待转换完成
while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
// 读取ADC值
uint16_t adcValue = ADC_GetConversionValue(ADC1);
// 将ADC值转换为湿度百分比
float humidity = (float)adcValue / 4095 * 100;
// 将湿度值打印到串口
char buffer[20];
sprintf(buffer, "Humidity: %.2f%%\r\n", humidity);
for (int i = 0; buffer[i] != '\0'; i++)
{
USART1_SendChar(buffer[i]);
}
// 延时一段时间
for (int i = 0; i < 1000000; i++);
}
}
// ADC配置
void ADC_Configuration(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
// 使能ADC1和GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
// 配置GPIOA.1为模拟输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// ADC配置
ADC_DeInit(ADC1);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
// 配置ADC1的通道1为采样通道
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);
// 使能ADC1
ADC_Cmd(ADC1, ENABLE);
// ADC校准
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1));
}
// 串口配置
void UART_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// 使能USART1和GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
// 配置USART1引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// USART配置
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
// 使能USART1
USART_Cmd(USART1, ENABLE);
}
// 发送字符到USART1
void USART1_SendChar(char ch)
{
USART_SendData(USART1, (uint8_t)ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
以上代码使用STM32的标准库函数进行配置和操作。在ADC_Configuration
函数中进行ADC的初始化配置,包括GPIO引脚配置、ADC时钟使能、通道配置等。 在UART_Configuration
函数中进行串口USART1的初始化配置,包括GPIO引脚配置、波特率设置等。
在主函数中,进入一个无限循环。在循环中,启动ADC转换,并等待转换完成。 通过ADC_GetConversionValue
函数读取ADC转换结果,将其转换为湿度百分比。 使用sprintf
函数将湿度值格式化为字符串,并使用USART1_SendChar
函数将字符串逐个字符发送到USART1串口。 通过延时函数进行一段时间的延时,以控制打印速率。
3.3 大棚补光灯控制
以下是使用STM32F103ZET6读取BH1750光照传感器输出的光照强度,并根据阈值控制LED补光灯灯开关实现代码:
#include "stm32f10x.h"
#include "i2c.h"
#include "delay.h"
#define BH1750_ADDRESS 0x23
void BH1750_Init()
{
// 初始化I2C总线
I2C_Init();
}
void BH1750_Start()
{
// 启动BH1750测量
uint8_t cmd = 0x01; // 单次高分辨率模式
I2C_Start();
I2C_SendByte(BH1750_ADDRESS);
I2C_WaitAck();
I2C_SendByte(cmd);
I2C_WaitAck();
I2C_Stop();
}
uint16_t BH1750_Read()
{
// 读取BH1750测量结果
uint16_t lux;
I2C_Start();
I2C_SendByte(BH1750_ADDRESS + 1); // 发送读命令
I2C_WaitAck();
lux = I2C_ReceiveByte() << 8; // 读取高字节
I2C_Ack();
lux |= I2C_ReceiveByte(); // 读取低字节
I2C_NAck();
I2C_Stop();
return lux;
}
void LED_Control(uint8_t state)
{
// 控制LED照明灯开关
if (state)
GPIO_SetBits(GPIOA, GPIO_Pin_8); // 打开LED
else
GPIO_ResetBits(GPIOA, GPIO_Pin_8); // 关闭LED
}
int main(void)
{
// 初始化GPIO口
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 初始化BH1750传感器
BH1750_Init();
while (1)
{
// 启动测量
BH1750_Start();
// 延时等待测量完成
DelayMs(200);
// 读取光照强度
uint16_t lux = BH1750_Read();
// 判断阈值并控制LED
if (lux > 1000)
LED_Control(1); // 光照强度高于阈值,打开LED
else
LED_Control(0); // 光照强度低于阈值,关闭LED
}
}
代码中初始化I2C总线和BH1750传感器,通过BH1750_Init()
函数实现。在主循环中,启动测量延时等待测量完成。使用BH1750_Read()
函数读取测量结果,即光照强度。根据阈值判断光照强度是否高于设定值,通过LED_Control()
函数控制LED的开关状态。
四、总结
本项目基于STM32微控制器实现了一个蔬菜大棚温湿度智能控制系统。系统的主控芯片采用了STM32F103ZET6,用于控制和协调各个硬件模块的工作。系统包括空气温湿度采集模块(DHT11)、土壤湿度采集模块(ADC接口)、通风风机(5V小风扇+继电器控制)、照明灯(LED白色灯模块)、灌溉系统(抽水电机+继电器控制)以及LCD显示屏。
系统的功能包括温湿度的实时监测、土壤湿度的检测、通风风扇的自动控制、灌溉系统的自动控制和数据的显示。通过按键设置土壤湿度阈值,实现自动浇水功能,当土壤湿度低于阈值时,系统自动开启灌溉系统进行浇水。同时,根据设定的温度阈值,系统自动控制通风风扇进行降温。
- 点赞
- 收藏
- 关注作者
评论(0)