一、设计目标
本项目基于单片机设计一个智慧农业大棚检测系统,以提供实时监测和管理大棚环境的关键参数。系统支持环境温度、湿度检测,光照强度检测,并能根据预设的阀值进行报警提示。为了实现数据的显示和管理,该系统还利用Qt开发了一款对应的Android手机APP,通过蓝牙传输模块将单片机采集到的数据传递到手机APP上进行显示和管理。
具体功能如下:
【1】环境温度和湿度检测:系统采用SHT30温湿度传感器,能够实时监测大棚内的温度和湿度,并将数据传输给单片机进行处理。
【2】光照强度检测:系统采用BH1750光照传感器,能够实时监测大棚内的光照强度,并将数据传输给单片机进行处理。
【3】报警阀值设置:系统支持按键操作,用户可以通过按键调整报警阀值,以适应不同的农业环境需求。
【4】报警声音提示:当温度、湿度或光照强度超过设定的阀值时,系统将触发报警,通过连接的蜂鸣器发出声音提示,提醒用户注意。
【5】数据显示和管理:利用Qt开发的Android手机APP能够接收通过蓝牙传输模块从单片机端传递过来的数据,并在手机上进行实时显示和管理。用户可以通过手机APP查看当前的温度、湿度和光照强度数据,同时也可以设置报警阀值。
通过上述设计,该智慧农业大棚检测系统能够为农业生产提供实时的环境监测和报警功能,帮助农民有效管理大棚环境,提高农作物的产量和质量。同时,通过手机APP的使用,用户可以方便地查看和管理数据,实现远程监控和控制,提高农业生产的便捷性和智能化水平。
二、总体设计方案
2.1 硬件设计
- 主控芯片采用STM32F103RCT6,具有较高的性能和丰富的外设接口。
- 温湿度检测模块采用SHT30传感器,可准确采集环境温度和湿度数据。
- 光照强度检测模块采用BH1750传感器,能够实时监测大棚内的光照情况。
- 本地报警提示采用蜂鸣器,发出声音提醒农民进行处理。
- 通过蓝牙模块HC05,将STM32采集到的数据传输到Android手机APP上。
2.2 软件设计
- 在STM32中编写固件程序,实现温湿度传感器和光照强度传感器的数据采集和处理。
- 设计蜂鸣器的驱动程序,根据设定的阈值判断是否触发报警。
- 使用蓝牙模块HC05与Android手机APP进行通信,将采集到的数据传输到手机APP上。
- 在Android手机APP中,利用Qt开发界面,实现数据显示、阈值设定和报警提示等功能。
2.3 整体流程
- STM32通过SHT30和BH1750传感器采集环境温度、湿度和光照强度数据。
- 处理采集到的数据,判断是否触发报警条件。
- 如果达到报警条件,则通过蜂鸣器发出声音提示。
- 将数据通过蓝牙模块HC05传输到Android手机APP上。
- 在Android手机APP上,实时显示大棚内的温湿度和光照强度数据。
- 农民可以通过手机APP设置报警阈值,当超过或低于设定的阈值时,会触发报警提示。
该方案实现了温湿度、光照强度的实时检测和数据传输,并提供了报警功能。通过这个智慧农业大棚检测系统,农民可以方便地监测大棚内的环境状况,及时调控和管理,提高农作物的生长效果和产量。
三、硬件电路设计
本项目的硬件电路设计主要涉及主控芯片STM32F103RCT6的连接及传感器模块的接口设计。以下是项目的硬件电路设计概述:
3.1 主控芯片连接
STM32F103RCT6作为主控芯片,负责整个系统的控制和数据处理。它与其他模块通过引脚连接进行数据的接收和发送。 需要为主控芯片提供适当的电源供电,包括正常工作电压和逻辑电压。
3.2 温湿度传感器连接
温湿度传感器SHT30通过I2C总线连接到主控芯片。主控芯片上的I2C接口引脚(如SDA和SCL)与传感器的对应引脚相连,以实现数据的读取和控制。
3.3 光照传感器连接
光照传感器BH1750通过I2C总线连接到主控芯片。主控芯片上的I2C接口引脚与传感器的对应引脚相连,以实现数据的读取和控制。
3.4 报警蜂鸣器连接
报警蜂鸣器通过一个GPIO引脚与主控芯片相连。当报警条件触发时,主控芯片控制该引脚输出高电平信号,以激活蜂鸣器发出声音提示。
3.5 HC05蓝牙模块连接
HC05蓝牙模块用于实现单片机与Android手机APP之间的数据传输。它通过串口通信与主控芯片相连,主控芯片上的对应串口引脚(如UART_TX和UART_RX)与蓝牙模块的对应引脚相连。
四、软件设计
4.1 主控芯片模块
主控芯片(如STM32F103RCT6)负责整个系统的控制和数据处理。它与其他硬件模块相连接,接收传感器数据,进行数据处理和报警判断,并控制蜂鸣器的发声。
4.2 温湿度传感器模块
温湿度传感器(如SHT30)通过I2C总线与主控芯片相连,负责实时监测大棚内的温度和湿度。传感器模块将采集到的数据传输给主控芯片进行处理。
实现代码如下:
以下是STM32标准库驱动SHT30传感器读取温湿度,并将数据通过串口打印出来:
#include "stm32f10x.h"
#include "stdio.h"
#define SHT30_ADDR 0x44
void I2C1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
// 使能I2C1和GPIOB时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// I2C1引脚配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 开漏输出
GPIO_Init(GPIOB, &GPIO_InitStructure);
// I2C1配置
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; // 50%占空比
I2C_InitStructure.I2C_OwnAddress1 = 0x00; // 主机模式下无效
I2C_InitStructure.I2C_Ack = I2C_Ack_Disable; // 禁止应答
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 100000; // 100kHz的速度
I2C_Init(I2C1, &I2C_InitStructure);
// 使能I2C1
I2C_Cmd(I2C1, ENABLE);
}
void I2C1_Start(void)
{
// 发送起始信号
I2C_GenerateSTART(I2C1, ENABLE);
// 等待起始信号发送完成
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
;
}
void I2C1_Stop(void)
{
// 发送停止信号
I2C_GenerateSTOP(I2C1, ENABLE);
}
void I2C1_WriteByte(uint8_t byte)
{
// 发送一个字节的数据
I2C_SendData(I2C1, byte);
// 等待发送完成
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
;
}
uint16_t I2C1_ReadByteAck(void)
{
uint16_t data;
// 使能应答
I2C_AcknowledgeConfig(I2C1, ENABLE);
I2C_GenerateACK(I2C1, ENABLE);
// 等待接收完成
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))
;
// 读取接收到的数据
data = I2C_ReceiveData(I2C1);
return data;
}
uint16_t I2C1_ReadByteNack(void)
{
uint16_t data;
// 禁止应答
I2C_AcknowledgeConfig(I2C1, DISABLE);
I2C_GenerateACK(I2C1, DISABLE);
// 等待接收完成
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))
;
// 读取接收到的数据
data = I2C_ReceiveData(I2C1);
return data;
}
void SHT30_Init(void)
{
// 发送软件复位指令
I2C1_Start();
I2C1_WriteByte(SHT30_ADDR << 1);
I2C1_WriteByte(0x30);
I2C1_WriteByte(0xA2);
I2C1_Stop();
delay_ms(100);
}
void SHT30_Measure(float *temperature, float *humidity)
{
uint8_t buf[6];
uint16_t temperature_raw, humidity_raw;
// 发送测量指令
I2C1_Start();
I2C1_WriteByte(SHT30_ADDR << 1);
I2C1_WriteByte(0x2C);
I2C1_WriteByte(0x06);
I2C1_Stop();
delay_ms(20);
// 读取测量结果
I2C1_Start();
I2C1_WriteByte((SHT30_ADDR << 1) | 0x01);
buf[0] = I2C1_ReadByteAck();
buf[1] = I2C1_ReadByteAck();
buf[2] = I2C1_ReadByteAck();
buf[3] = I2C1_ReadByteAck();
buf[4] = I2C1_ReadByteAck();
buf[5] = I2C1_ReadByteNack();
I2C1_Stop();
// 计算温度值
temperature_raw = (buf[0] << 8) | buf[1];
*temperature = -45.0 + 175.0 * (float)temperature_raw / 65535.0;
// 计算湿度值
humidity_raw = (buf[3] << 8) | buf[4];
*humidity = 100.0 * (float)humidity_raw / 65535.0;
}
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;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
// USART1配置
USART_InitStructure.USART_BaudRate = 115200; // 波特率为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);
}
void USART1_SendChar(char ch)
{
// 等待发送缓冲区为空
while (!(USART1->SR & USART_FLAG_TXE))
;
// 发送一个字符
USART_SendData(USART1, ch);
}
int fputc(int ch, FILE *f)
{
// 将数据通过串口发送
USART1_SendChar((char)ch);
return ch;
}
void delay_ms(uint32_t ms)
{
while (ms--)
{
uint32_t count = 12000;
while (count--)
;
}
}
int main(void)
{
float temperature, humidity;
I2C1_Init();
USART1_Init();
SHT30_Init();
printf("SHT30 Temperature and Humidity Test\n");
while (1)
{
SHT30_Measure(&temperature, &humidity);
printf("Temperature: %.2f°C, Humidity: %.2f%%\n", temperature, humidity);
delay_ms(1000); // 每隔1秒测量一次温湿度
}
}
以上代码通过I2C总线驱动STM32F103读取SHT30温湿度传感器的数据,并通过USART1串口打印出温度和湿度值。
代码设计流程介绍:
【1】引入头文件:
#include "stm32f10x.h"
#include "stdio.h"
此处引入了STM32F10x系列微控制器的相关头文件以及标准输入输出库的头文件。
【2】定义宏和函数:
#define SHT30_ADDR 0x44
定义了SHT30传感器的I2C地址为0x44。
void I2C1_Init(void);
void I2C1_Start(void);
void I2C1_Stop(void);
void I2C1_WriteByte(uint8_t byte);
uint16_t I2C1_ReadByteAck(void);
uint16_t I2C1_ReadByteNack(void);
定义了一系列用于控制I2C总线的函数。
void SHT30_Init(void);
void SHT30_Measure(float *temperature, float *humidity);
定义了初始化SHT30传感器和测量温湿度的函数。
void USART1_Init(void);
void USART1_SendChar(char ch);
int fputc(int ch, FILE *f);
定义了初始化USART1串口和发送字符的函数,以及重定向标准输出流的函数。
void delay_ms(uint32_t ms);
定义了延时函数,用于在实现中添加延时。
【3】初始化函数:
void I2C1_Init(void)
该函数用于初始化I2C1总线和相关的引脚。使能了I2C1和GPIOB的时钟,然后配置了I2C1的引脚,包括引脚的速度和模式等。接着对I2C1进行配置,包括模式、占空比、从机地址等参数,并最后使能I2C1总线。
void USART1_Init(void)
该函数用于初始化USART1串口和相关的引脚。使能了USART1和GPIOA的时钟,然后配置了USART1的引脚,包括引脚的速度和模式等。接着对USART1进行配置,包括波特率、字长、停止位、校验位等参数,并最后使能USART1串口。
【4】I2C总线控制函数:
void I2C1_Start(void)
void I2C1_Stop(void)
void I2C1_WriteByte(uint8_t byte)
uint16_t I2C1_ReadByteAck(void)
uint16_t I2C1_ReadByteNack(void)
这些函数用于控制I2C总线的起始、停止、写数据和读数据操作。具体实现可以参考STM32的标准库函数。
【5】SHT30传感器初始化和测量函数:
void SHT30_Init(void)
void SHT30_Measure(float *temperature, float *humidity)
SHT30_Init
函数用于初始化SHT30传感器。在函数中,发送软件复位指令给传感器,然后延时一段时间等待传感器重置。
SHT30_Measure
函数用于测量温湿度数据。在函数中,发送测量指令给传感器,然后延时等待传感器完成测量。接着从传感器读取温湿度数据,并通过指针参数返回给主程序。
【6】串口控制函数:
void USART1_SendChar(char ch)
int fputc(int ch, FILE *f)
USART1_SendChar
函数用于通过USART1串口发送一个字符。在函数中,通过轮询USART状态寄存器的空闲标志位,判断发送缓冲区是否为空,然后把字符写入数据寄存器进行发送。
fputc
函数是C库函数的重定向函数,用于将标准输出的字符发送到USART1串口。这里对于每个调用printf
函数输出的字符,都会通过USART1_SendChar
函数发送出去。
【7】延时函数:
void delay_ms(uint32_t ms)
这个函数用于实现毫秒级的延时。在函数中,通过循环等待的方式实现了延时。
【8】主函数:
int main(void)
在主函数中,调用I2C1_Init
和USART1_Init
函数初始化I2C总线和USART1串口。然后调用SHT30_Init
函数初始化SHT30传感器。
进入主循环后,通过循环调用SHT30_Measure
函数测量温湿度数据,并通过printf
函数打印出来。最后通过delay_ms
函数延时1秒。
4.3 光照传感器模块
光照传感器(如BH1750)通过I2C总线与主控芯片相连,负责实时监测大棚内的光照强度。传感器模块将采集到的数据传输给主控芯片进行处理。
实现代码如下:
使用STM32标准库编写代码驱动BH1750读取环境光照强度。
#include "stm32f10x.h"
#include "stdio.h"
#define BH1750_ADDR 0x23
void I2C1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
// 使能I2C1和GPIOB时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// I2C1引脚配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 开漏输出
GPIO_Init(GPIOB, &GPIO_InitStructure);
// I2C1配置
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; // 50%占空比
I2C_InitStructure.I2C_OwnAddress1 = 0x00; // 主机模式下无效
I2C_InitStructure.I2C_Ack = I2C_Ack_Disable; // 禁止应答
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 100000; // 100kHz的速度
I2C_Init(I2C1, &I2C_InitStructure);
// 使能I2C1
I2C_Cmd(I2C1, ENABLE);
}
void I2C1_Start(void)
{
// 发送起始信号
I2C_GenerateSTART(I2C1, ENABLE);
// 等待起始信号发送完成
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
;
}
void I2C1_Stop(void)
{
// 发送停止信号
I2C_GenerateSTOP(I2C1, ENABLE);
}
void I2C1_WriteByte(uint8_t byte)
{
// 发送一个字节的数据
I2C_SendData(I2C1, byte);
// 等待发送完成
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
;
}
uint16_t BH1750_ReadData(void)
{
uint16_t data = 0;
// 设置BH1750模式(连续高分辨率测量模式)
I2C1_Start();
I2C1_WriteByte(BH1750_ADDR);
I2C1_WriteByte(0x10);
I2C1_Stop();
// 延时等待测量结束
delay_ms(20);
// 读取光照强度数据
I2C1_Start();
I2C1_WriteByte(BH1750_ADDR | 1);
data = (I2C_ReceiveData(I2C1) << 8);
I2C_AcknowledgeConfig(I2C1, DISABLE);
I2C1_Stop();
delay_ms(2);
I2C_AcknowledgeConfig(I2C1, ENABLE);
I2C1_Start();
I2C1_WriteByte(BH1750_ADDR | 1);
data |= I2C_ReceiveData(I2C1);
I2C1_Stop();
return data;
}
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;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
// USART1配置
USART_InitStructure.USART_BaudRate = 115200; // 波特率为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);
}
void USART1_SendChar(char ch)
{
// 等待发送缓冲区为空
while (!(USART1->SR & USART_FLAG_TXE))
;
// 发送一个字符
USART_SendData(USART1, ch);
}
int fputc(int ch, FILE *f)
{
// 将数据通过串口发送
USART1_SendChar((char)ch);
return ch;
}
void delay_ms(uint32_t ms)
{
while (ms--)
{
uint32_t count = 12000;
while (count--)
;
}
}
int main(void)
{
uint16_t lightIntensity;
I2C1_Init();
USART1_Init();
printf("BH1750 Light Intensity Test\n");
while (1)
{
lightIntensity = BH1750_ReadData();
printf("Light Intensity: %d lux\n", lightIntensity);
delay_ms(1000); // 每隔1秒读取一次光照强度
}
}
【1】上面代码里定义了BH1750的地址BH1750_ADDR
为0x23,这是BH1750的默认地址。
【2】在I2C1_Init()
函数中,初始化了I2C1总线和相关的GPIO引脚。通过RCC_APB1PeriphClockCmd和RCC_APB2PeriphClockCmd函数使能I2C1和GPIOB时钟,然后配置GPIOB的引脚6和7为开漏输出模式(GPIO_Mode_AF_OD)。接着,使用I2C_Init函数初始化I2C1,并设置其工作模式为I2C_Mode_I2C、占空比为50%、禁止应答、7位地址模式以及100kHz的通信速率。最后,通过I2C_Cmd函数使能I2C1。
【3】I2C1_Start()
函数用于发送I2C总线的起始信号。调用I2C_GenerateSTART
函数发送起始信号,并使用I2C_CheckEvent
函数等待起始信号发送完成。
【4】I2C1_Stop()
函数用于发送I2C总线的停止信号。调用I2C_GenerateSTOP
函数发送停止信号。
【5】I2C1_WriteByte()
函数用于向I2C设备发送一个字节的数据。通过I2C_SendData
函数发送数据,并使用I2C_CheckEvent
函数等待发送完成。
【6】BH1750_ReadData()
函数用于读取光照强度数据。,发送启动测量指令和模式设置指令(连续高分辨率测量模式)。然后等待测量结束的延时时间(20ms)。接着,通过两次读取数据寄存器的方式获取光照强度数据,并将其拼接为一个16位的无符号整数。
【7】USART1_Init()
函数用于初始化USART1串口和相关的GPIO引脚。使用RCC_APB2PeriphClockCmd函数使能USART1和GPIOA时钟,然后配置GPIOA的引脚9为复用推挽输出模式(GPIO_Mode_AF_PP)。接着,通过USART_Init函数初始化USART1,并设置其波特率为115200、数据位长度为8位、停止位为1位、无奇偶校验、无硬件流控制。最后,通过USART_Cmd函数使能USART1。
【8】USART1_SendChar()
函数用于发送一个字符到USART1串口。使用USART_SR
寄存器的USART_FLAG_TXE
标志位检查发送缓冲区是否为空,然后通过USART_SendData
函数发送字符数据。
【9】fputc()
函数重定向了输出流,使得通过printf
函数打印的字符可以发送到USART1串口。在该函数中调用USART1_SendChar
函数发送字符数据,并返回该字符。
【10】delay_ms()
函数用于进行延时,单位为毫秒。该函数使用嵌套循环实现了简单的延时功能,不同的系统时钟频率可能需要适当调整。
【11】在main()
函数中,依次调用I2C1_Init()
和USART1_Init()
函数进行初始化操作。然后,通过printf
函数向串口发送初始信息。
【12】在主循环中,通过调用BH1750_ReadData()
函数读取光照强度数据,并使用printf
函数将其打印到串口。然后通过delay_ms
函数进行1秒的延时,等待下一次读取。
4.4 报警蜂鸣器模块
报警蜂鸣器通过一个GPIO引脚与主控芯片相连。当报警条件满足时,主控芯片控制该引脚输出高电平信号,以激活蜂鸣器发出声音提示。
使用STM32F103标准库编写的蜂鸣器控制代码:
#include "stm32f10x.h"
#define BEEP_GPIO_PORT GPIOA
#define BEEP_GPIO_PIN GPIO_Pin_8
void BEEP_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 使能GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 配置蜂鸣器引脚为推挽输出模式
GPIO_InitStructure.GPIO_Pin = BEEP_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(BEEP_GPIO_PORT, &GPIO_InitStructure);
}
void BEEP_On(void)
{
GPIO_SetBits(BEEP_GPIO_PORT, BEEP_GPIO_PIN);
}
void BEEP_Off(void)
{
GPIO_ResetBits(BEEP_GPIO_PORT, BEEP_GPIO_PIN);
}
int main(void)
{
BEEP_Init();
while (1)
{
// 控制蜂鸣器开启和关闭
BEEP_On();
Delay_ms(500);
BEEP_Off();
Delay_ms(500);
}
}
在代码中,使用了GPIOA的第8个引脚作为蜂鸣器的控制引脚。BEEP_Init
函数用于初始化蜂鸣器引脚,将其配置为推挽输出模式。BEEP_On
和BEEP_Off
函数分别用于开启和关闭蜂鸣器。
在main
函数中,通过循环控制蜂鸣器以500ms的间隔进行开启和关闭操作。
4.5 HC05蓝牙模块模块
HC05蓝牙模块通过串口通信与主控芯片相连,负责实现与Android手机APP之间的数据传输和通信。它接收主控芯片发送的数据,并通过蓝牙与手机APP进行交互。
使用STM32标准库编写代码,用于通过串口2驱动HC05模块,并进行配置和数据通信:
#include "stm32f10x.h"
#include "stdio.h"
// HC05配置指令
#define AT_CMD_MODE "AT+CMODE=0\r\n" // 配置为从模式
#define AT_CMD_PW "AT+PSWD=1234\r\n" // 配对密码设置为1234
// 函数声明
void USART2_Init(void);
void USART2_SendChar(char ch);
void USART2_SendString(char* str);
char USART2_Receive(void);
int main(void)
{
// 初始化USART2串口
USART2_Init();
// 发送AT指令配置HC05为从模式
USART2_SendString(AT_CMD_MODE);
for(int i = 0; i < 1000000; i++); // 等待一段时间
// 发送AT指令配置配对密码
USART2_SendString(AT_CMD_PW);
for(int i = 0; i < 1000000; i++); // 等待一段时间
while(1)
{
// 接收手机发送的数据
char data = USART2_Receive();
// 处理接收到的数据,例如发送回应等
// ...
}
}
void USART2_Init(void)
{
// 使能USART2和GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
// 配置USART2的引脚
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; // USART2_TX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // GPIO速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; // USART2_RX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置USART2的参数
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600; // 波特率为9600
USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 数据位长度为8位
USART_InitStructure.USART_StopBits = USART_StopBits_1; // 停止位为1位
USART_InitStructure.USART_Parity = USART_Parity_No; // 无奇偶校验
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无硬件流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 支持收发模式
USART_Init(USART2, &USART_InitStructure);
// 使能USART2
USART_Cmd(USART2, ENABLE);
}
void USART2_SendChar(char ch)
{
while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET); // 等待发送缓冲区为空
USART_SendData(USART2, (uint16_t)ch); // 发送数据
}
void USART2_SendString(char* str)
{
while(*str)
{
USART2_SendChar(*str++);
}
}
char USART2_Receive(void)
{
while (USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == RESET); // 等待接收缓冲区非空
return (char)USART_ReceiveData(USART2);
}
以上代码通过USART2串口与HC05模块进行通信,并发送AT指令对其进行配置。其中,AT_CMD_MODE
用于将HC05配置为从模式,AT_CMD_PW
用于设置配对密码为1234。
代码设计思路介绍:
【1】引入头文件:
#include "stm32f10x.h"
#include "stdio.h"
引入了STM32F10x系列微控制器的相关头文件和标准输入输出库的头文件。
【2】定义宏和函数:
#define AT_CMD_MODE "AT+CMODE=0\r\n"
#define AT_CMD_PW "AT+PSWD=1234\r\n"
void USART2_Init(void);
void USART2_SendChar(char ch);
void USART2_SendString(char* str);
char USART2_Receive(void);
定义了用于配置HC05模块的AT指令,以及用于初始化USART2串口、发送字符和字符串、接收字符的函数。
【3】USART2串口初始化函数:
void USART2_Init(void)
该函数用于初始化USART2串口和相关引脚。使能了USART2和GPIOA的时钟,然后配置了USART2的引脚,包括引脚的模式和速度等。接着对USART2进行配置,设置波特率、数据位长度、停止位、奇偶校验位等参数,并最后使能USART2串口。
【4】发送字符和字符串函数:
void USART2_SendChar(char ch)
void USART2_SendString(char* str)
这些函数用于通过USART2串口发送字符和字符串。对于USART2_SendChar
函数,它会等待发送缓冲区为空,然后将字符写入数据寄存器进行发送。对于USART2_SendString
函数,它会遍历字符串中的每个字符,并调用USART2_SendChar
函数进行发送。
【5】接收字符函数:
char USART2_Receive(void)
该函数用于从USART2串口接收一个字符。它会等待接收缓冲区非空,然后读取数据寄存器的值并返回接收到的字符。此函数在主循环中可以用于接收HC05模块发送的数据。
【6】主函数:
int main(void)
在主函数中,调用USART2_Init
函数初始化USART2串口。然后使用USART2_SendString
函数依次发送配置指令AT_CMD_MODE
和AT_CMD_PW
给HC05模块。发送完指令后,通过循环调用USART2_Receive
函数接收HC05模块发送的数据。
五、调试过程
在项目设计完成后,进行测试和调试是非常重要的,以确保系统的正常运行和功能的有效性。
下面是本项目的测试和调试过程流程:
5.1 硬件测试
- 检查硬件组装和连接是否正确,包括主控芯片STM32F103RCT6、传感器模块SHT30和BH1750以及蓝牙模块HC05的连接。
- 使用示波器或多用途测试仪检测各个模块的电源供应和信号线连接是否正常。
- 测试温湿度传感器(SHT30)和光照强度传感器(BH1750)是否能够正确采集环境数据。
- 测试蜂鸣器是否能够发出合适的声音提示。
5.2 固件程序测试
- 在STM32开发环境中编译程序,将固件程序烧录到主控芯片STM32F103RCT6上。
- 使用串口调试助手等工具,与STM32建立通信连接,检查数据的传输和接收是否正常。
- 对温湿度传感器和光照强度传感器进行数据采集测试,观察是否能够准确读取传感器数据。
- 设置阈值并测试报警功能,确保报警触发条件和报警提示的准确性。
5.3 Android手机APP测试
- 安装开发好的Android手机APP到测试设备上,确保安装过程顺利。
- 打开APP,并与蓝牙模块HC05进行连接,观察是否能够成功建立通信。
- 测试数据的传输和接收功能,确保从STM32接收到的数据能够在APP界面上正确显示。
- 设置阈值并触发报警测试,确认报警提示(声音、震动、弹窗等)是否按照设定的条件正常工作。
5.4 系统整体测试
- 模拟实际环境,调整大棚温湿度和光照强度,观察系统是否能够准确检测并显示环境参数。
- 调整报警阈值,触发报警条件,验证报警提示是否按照预期工作。
- 进行长时间运行测试,确保系统的稳定性和可靠性。
六、关键问题讨论
6.1 本项目的核心与技术难点
【1】硬件集成:将主控芯片、传感器模块、蓝牙模块和蜂鸣器等多个硬件模块进行正确的连接和集成是一个挑战。需要仔细设计电路连接、通信协议和接口定义,确保各个模块能够正常协同工作。
【2】数据处理与算法:在主控芯片的固件程序中,需要对传感器采集到的数据进行处理和分析,判断是否触发报警条件。这可能涉及到数据滤波、阈值判定、异常检测等算法的设计和实现。
【3】蓝牙通信:与手机APP之间的蓝牙通信是一个难点。需要实现稳定可靠的数据传输和通信协议,确保数据的准确性和实时性。
6.2 本项目的实用性
【1】实时监测和报警功能:该项目能够实时监测大棚内的温度、湿度和光照强度,并在超过设定阀值时触发报警。这对于农业生产者来说非常实用,能够帮助他们及时发现问题并采取措施,以保证大棚内环境的稳定和作物的健康生长。
【2】远程监控和管理:通过与手机APP的蓝牙通信,用户可以远程监控大棚内的数据并进行管理。他们可以随时查看温湿度和光照强度的实时数据,设置报警阀值,接收报警通知,并对大棚环境进行远程调整和控制。
【3】自动化和智能化:该项目利用传感器和自动化控制技术,实现了对大棚环境的智能监测和控制。这不仅提高了农业生产的效率和质量,还减轻了人工管理的负担,具有较高的实用性和应用价值。
6.3 关键点总结
【1】传感器选择和集成:选择适合的温湿度传感器和光照强度传感器,并合理集成到硬件设计中。需要考虑传感器的精度、响应速度以及与主控芯片的通信协议等因素。
【2】数据采集和处理算法:设计合适的数据采集和处理算法,确保从传感器获取的数据准确可靠,并能够根据设定的阈值判断是否触发报警条件。
【3】报警机制:设计报警机制,根据设定的阈值和实时采集的数据进行比较,当达到报警条件时,触发报警提示,如声音、震动或弹窗等方式。
【4】蓝牙通信:确保蓝牙模块能够与主控芯片稳定通信,并能够成功传输采集的数据到Android手机APP上。需要考虑通信的稳定性、数据传输的速率和安全性等因素。
【5】Android手机APP设计:设计用户友好的界面,在手机APP上实时显示大棚内的温湿度和光照强度数据,并提供设置界面,允许农民设置报警阈值。同时,实现报警提示的功能,保证报警条件的准确性和报警方式的有效性。
【6】系统稳定性和可靠性:在测试和调试阶段,需要对整个系统进行全面的测试,包括硬件和软件的各个模块,以确保系统的稳定性和可靠性。同时,考虑到长时间运行的情况,还需进行长时间测试,以验证系统能够持续运行并正常工作。
七、设计总结与体会
本项目的目的是设计实现对农业大棚环境的智能监测和管理,通过传感器采集数据、主控芯片处理和判断、蓝牙通信与手机APP交互,以及报警蜂鸣器的控制,实现了对温度、湿度和光照强度等参数的实时监测和报警功能。
在项目开发过程中,也遇到了一些挑战和难点,比如:硬件的连接和集成、数据处理算法的设计和实现,以及与手机APP之间的蓝牙通信。通过细致的计划和分工,最终也是成功地克服了这些困难,得以完成了整个系统的开发。
在实施过程中,深刻认识到模块化设计的重要性。通过将系统划分为多个硬件模块和软件模块,能够更好地管理和调试每个模块,并且在需要时进行模块的替换和升级,提高了系统的可扩展性和可维护性。
在测试阶段,也意识到用户体验的重要性。通过与潜在用户的沟通和反馈,不断优化和改进系统的界面设计和功能实现,力求使用户能够轻松使用和管理该系统。这种用户导向的设计理念提高了系统的实用性和用户满意度。
总的来说,本项目的设计与实施过程对软硬件的协同工作、数据处理与算法设计、用户体验等方面有了更深入的理解。通过克服挑战和不断优化,成功地将智能农业大棚监测系统带入实际应用,并为农业生产者提供了一种方便、高效且可靠的解决方案。相信随着技术的不断发展,智慧农业将在未来发挥更大的作用,为农业生产带来更多的创新和改进。