一、設(shè)計目標(biāo)
本項目基于單片機設(shè)計一個智慧農(nóng)業(yè)大棚檢測系統(tǒng),以提供實時監(jiān)測和管理大棚環(huán)境的關(guān)鍵參數(shù)。系統(tǒng)支持環(huán)境溫度、濕度檢測,光照強度檢測,并能根據(jù)預(yù)設(shè)的閥值進行報警提示。為了實現(xiàn)數(shù)據(jù)的顯示和管理,該系統(tǒng)還利用Qt開發(fā)了一款對應(yīng)的Android手機APP,通過藍(lán)牙傳輸模塊將單片機采集到的數(shù)據(jù)傳遞到手機APP上進行顯示和管理。
具體功能如下:
【1】環(huán)境溫度和濕度檢測:系統(tǒng)采用SHT30溫濕度傳感器,能夠?qū)崟r監(jiān)測大棚內(nèi)的溫度和濕度,并將數(shù)據(jù)傳輸給單片機進行處理。
【2】光照強度檢測:系統(tǒng)采用BH1750光照傳感器,能夠?qū)崟r監(jiān)測大棚內(nèi)的光照強度,并將數(shù)據(jù)傳輸給單片機進行處理。
【3】報警閥值設(shè)置:系統(tǒng)支持按鍵操作,用戶可以通過按鍵調(diào)整報警閥值,以適應(yīng)不同的農(nóng)業(yè)環(huán)境需求。
【4】報警聲音提示:當(dāng)溫度、濕度或光照強度超過設(shè)定的閥值時,系統(tǒng)將觸發(fā)報警,通過連接的蜂鳴器發(fā)出聲音提示,提醒用戶注意。
【5】數(shù)據(jù)顯示和管理:利用Qt開發(fā)的Android手機APP能夠接收通過藍(lán)牙傳輸模塊從單片機端傳遞過來的數(shù)據(jù),并在手機上進行實時顯示和管理。用戶可以通過手機APP查看當(dāng)前的溫度、濕度和光照強度數(shù)據(jù),同時也可以設(shè)置報警閥值。
通過上述設(shè)計,該智慧農(nóng)業(yè)大棚檢測系統(tǒng)能夠為農(nóng)業(yè)生產(chǎn)提供實時的環(huán)境監(jiān)測和報警功能,幫助農(nóng)民有效管理大棚環(huán)境,提高農(nóng)作物的產(chǎn)量和質(zhì)量。同時,通過手機APP的使用,用戶可以方便地查看和管理數(shù)據(jù),實現(xiàn)遠(yuǎn)程監(jiān)控和控制,提高農(nóng)業(yè)生產(chǎn)的便捷性和智能化水平。
二、總體設(shè)計方案
2.1 硬件設(shè)計
- 主控芯片采用STM32F103RCT6,具有較高的性能和豐富的外設(shè)接口。
- 溫濕度檢測模塊采用SHT30傳感器,可準(zhǔn)確采集環(huán)境溫度和濕度數(shù)據(jù)。
- 光照強度檢測模塊采用BH1750傳感器,能夠?qū)崟r監(jiān)測大棚內(nèi)的光照情況。
- 本地報警提示采用蜂鳴器,發(fā)出聲音提醒農(nóng)民進行處理。
- 通過藍(lán)牙模塊HC05,將STM32采集到的數(shù)據(jù)傳輸?shù)紸ndroid手機APP上。
2.2 軟件設(shè)計
- 在STM32中編寫固件程序,實現(xiàn)溫濕度傳感器和光照強度傳感器的數(shù)據(jù)采集和處理。
- 設(shè)計蜂鳴器的驅(qū)動程序,根據(jù)設(shè)定的閾值判斷是否觸發(fā)報警。
- 使用藍(lán)牙模塊HC05與Android手機APP進行通信,將采集到的數(shù)據(jù)傳輸?shù)绞謾CAPP上。
- 在Android手機APP中,利用Qt開發(fā)界面,實現(xiàn)數(shù)據(jù)顯示、閾值設(shè)定和報警提示等功能。
2.3 整體流程
- STM32通過SHT30和BH1750傳感器采集環(huán)境溫度、濕度和光照強度數(shù)據(jù)。
- 處理采集到的數(shù)據(jù),判斷是否觸發(fā)報警條件。
- 如果達(dá)到報警條件,則通過蜂鳴器發(fā)出聲音提示。
- 將數(shù)據(jù)通過藍(lán)牙模塊HC05傳輸?shù)紸ndroid手機APP上。
- 在Android手機APP上,實時顯示大棚內(nèi)的溫濕度和光照強度數(shù)據(jù)。
- 農(nóng)民可以通過手機APP設(shè)置報警閾值,當(dāng)超過或低于設(shè)定的閾值時,會觸發(fā)報警提示。
該方案實現(xiàn)了溫濕度、光照強度的實時檢測和數(shù)據(jù)傳輸,并提供了報警功能。通過這個智慧農(nóng)業(yè)大棚檢測系統(tǒng),農(nóng)民可以方便地監(jiān)測大棚內(nèi)的環(huán)境狀況,及時調(diào)控和管理,提高農(nóng)作物的生長效果和產(chǎn)量。
三、硬件電路設(shè)計
本項目的硬件電路設(shè)計主要涉及主控芯片STM32F103RCT6的連接及傳感器模塊的接口設(shè)計。以下是項目的硬件電路設(shè)計概述:
3.1 主控芯片連接
STM32F103RCT6作為主控芯片,負(fù)責(zé)整個系統(tǒng)的控制和數(shù)據(jù)處理。它與其他模塊通過引腳連接進行數(shù)據(jù)的接收和發(fā)送。 需要為主控芯片提供適當(dāng)?shù)?a class="article-link" target="_blank" href="/tag/%E7%94%B5%E6%BA%90/">電源供電,包括正常工作電壓和邏輯電壓。
3.2 溫濕度傳感器連接
溫濕度傳感器SHT30通過I2C總線連接到主控芯片。主控芯片上的I2C接口引腳(如SDA和SCL)與傳感器的對應(yīng)引腳相連,以實現(xiàn)數(shù)據(jù)的讀取和控制。
3.3 光照傳感器連接
光照傳感器BH1750通過I2C總線連接到主控芯片。主控芯片上的I2C接口引腳與傳感器的對應(yīng)引腳相連,以實現(xiàn)數(shù)據(jù)的讀取和控制。
3.4 報警蜂鳴器連接
報警蜂鳴器通過一個GPIO引腳與主控芯片相連。當(dāng)報警條件觸發(fā)時,主控芯片控制該引腳輸出高電平信號,以激活蜂鳴器發(fā)出聲音提示。
3.5 HC05藍(lán)牙模塊連接
HC05藍(lán)牙模塊用于實現(xiàn)單片機與Android手機APP之間的數(shù)據(jù)傳輸。它通過串口通信與主控芯片相連,主控芯片上的對應(yīng)串口引腳(如UART_TX和UART_RX)與藍(lán)牙模塊的對應(yīng)引腳相連。
四、軟件設(shè)計
4.1 主控芯片模塊
主控芯片(如STM32F103RCT6)負(fù)責(zé)整個系統(tǒng)的控制和數(shù)據(jù)處理。它與其他硬件模塊相連接,接收傳感器數(shù)據(jù),進行數(shù)據(jù)處理和報警判斷,并控制蜂鳴器的發(fā)聲。
4.2 溫濕度傳感器模塊
溫濕度傳感器(如SHT30)通過I2C總線與主控芯片相連,負(fù)責(zé)實時監(jiān)測大棚內(nèi)的溫度和濕度。傳感器模塊將采集到的數(shù)據(jù)傳輸給主控芯片進行處理。
實現(xiàn)代碼如下:
以下是STM32標(biāo)準(zhǔn)庫驅(qū)動SHT30傳感器讀取溫濕度,并將數(shù)據(jù)通過串口打印出來:
#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; // 禁止應(yīng)答
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)
{
// 發(fā)送起始信號
I2C_GenerateSTART(I2C1, ENABLE);
// 等待起始信號發(fā)送完成
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
;
}
void I2C1_Stop(void)
{
// 發(fā)送停止信號
I2C_GenerateSTOP(I2C1, ENABLE);
}
void I2C1_WriteByte(uint8_t byte)
{
// 發(fā)送一個字節(jié)的數(shù)據(jù)
I2C_SendData(I2C1, byte);
// 等待發(fā)送完成
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
;
}
uint16_t I2C1_ReadByteAck(void)
{
uint16_t data;
// 使能應(yīng)答
I2C_AcknowledgeConfig(I2C1, ENABLE);
I2C_GenerateACK(I2C1, ENABLE);
// 等待接收完成
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))
;
// 讀取接收到的數(shù)據(jù)
data = I2C_ReceiveData(I2C1);
return data;
}
uint16_t I2C1_ReadByteNack(void)
{
uint16_t data;
// 禁止應(yīng)答
I2C_AcknowledgeConfig(I2C1, DISABLE);
I2C_GenerateACK(I2C1, DISABLE);
// 等待接收完成
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))
;
// 讀取接收到的數(shù)據(jù)
data = I2C_ReceiveData(I2C1);
return data;
}
void SHT30_Init(void)
{
// 發(fā)送軟件復(fù)位指令
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;
// 發(fā)送測量指令
I2C1_Start();
I2C1_WriteByte(SHT30_ADDR << 1);
I2C1_WriteByte(0x2C);
I2C1_WriteByte(0x06);
I2C1_Stop();
delay_ms(20);
// 讀取測量結(jié)果
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; // 復(fù)用推挽輸出
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)
{
// 等待發(fā)送緩沖區(qū)為空
while (!(USART1->SR & USART_FLAG_TXE))
;
// 發(fā)送一個字符
USART_SendData(USART1, ch);
}
int fputc(int ch, FILE *f)
{
// 將數(shù)據(jù)通過串口發(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 Testn");
while (1)
{
SHT30_Measure(&temperature, &humidity);
printf("Temperature: %.2f°C, Humidity: %.2f%%n", temperature, humidity);
delay_ms(1000); // 每隔1秒測量一次溫濕度
}
}
以上代碼通過I2C總線驅(qū)動STM32F103讀取SHT30溫濕度傳感器的數(shù)據(jù),并通過USART1串口打印出溫度和濕度值。
代碼設(shè)計流程介紹:
【1】引入頭文件:
#include "stm32f10x.h"
#include "stdio.h"
此處引入了STM32F10x系列微控制器的相關(guān)頭文件以及標(biāo)準(zhǔn)輸入輸出庫的頭文件。
【2】定義宏和函數(shù):
#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總線的函數(shù)。
void SHT30_Init(void);
void SHT30_Measure(float *temperature, float *humidity);
定義了初始化SHT30傳感器和測量溫濕度的函數(shù)。
void USART1_Init(void);
void USART1_SendChar(char ch);
int fputc(int ch, FILE *f);
定義了初始化USART1串口和發(fā)送字符的函數(shù),以及重定向標(biāo)準(zhǔn)輸出流的函數(shù)。
void delay_ms(uint32_t ms);
定義了延時函數(shù),用于在實現(xiàn)中添加延時。
【3】初始化函數(shù):
void I2C1_Init(void)
該函數(shù)用于初始化I2C1總線和相關(guān)的引腳。使能了I2C1和GPIOB的時鐘,然后配置了I2C1的引腳,包括引腳的速度和模式等。接著對I2C1進行配置,包括模式、占空比、從機地址等參數(shù),并最后使能I2C1總線。
void USART1_Init(void)
該函數(shù)用于初始化USART1串口和相關(guān)的引腳。使能了USART1和GPIOA的時鐘,然后配置了USART1的引腳,包括引腳的速度和模式等。接著對USART1進行配置,包括波特率、字長、停止位、校驗位等參數(shù),并最后使能USART1串口。
【4】I2C總線控制函數(shù):
void I2C1_Start(void)
void I2C1_Stop(void)
void I2C1_WriteByte(uint8_t byte)
uint16_t I2C1_ReadByteAck(void)
uint16_t I2C1_ReadByteNack(void)
這些函數(shù)用于控制I2C總線的起始、停止、寫數(shù)據(jù)和讀數(shù)據(jù)操作。具體實現(xiàn)可以參考STM32的標(biāo)準(zhǔn)庫函數(shù)。
【5】SHT30傳感器初始化和測量函數(shù):
void SHT30_Init(void)
void SHT30_Measure(float *temperature, float *humidity)
SHT30_Init
函數(shù)用于初始化SHT30傳感器。在函數(shù)中,發(fā)送軟件復(fù)位指令給傳感器,然后延時一段時間等待傳感器重置。
SHT30_Measure
函數(shù)用于測量溫濕度數(shù)據(jù)。在函數(shù)中,發(fā)送測量指令給傳感器,然后延時等待傳感器完成測量。接著從傳感器讀取溫濕度數(shù)據(jù),并通過指針參數(shù)返回給主程序。
【6】串口控制函數(shù):
void USART1_SendChar(char ch)
int fputc(int ch, FILE *f)
USART1_SendChar
函數(shù)用于通過USART1串口發(fā)送一個字符。在函數(shù)中,通過輪詢USART狀態(tài)寄存器的空閑標(biāo)志位,判斷發(fā)送緩沖區(qū)是否為空,然后把字符寫入數(shù)據(jù)寄存器進行發(fā)送。
fputc
函數(shù)是C庫函數(shù)的重定向函數(shù),用于將標(biāo)準(zhǔn)輸出的字符發(fā)送到USART1串口。這里對于每個調(diào)用printf
函數(shù)輸出的字符,都會通過USART1_SendChar
函數(shù)發(fā)送出去。
【7】延時函數(shù):
void delay_ms(uint32_t ms)
這個函數(shù)用于實現(xiàn)毫秒級的延時。在函數(shù)中,通過循環(huán)等待的方式實現(xiàn)了延時。
【8】主函數(shù):
int main(void)
在主函數(shù)中,調(diào)用I2C1_Init
和USART1_Init
函數(shù)初始化I2C總線和USART1串口。然后調(diào)用SHT30_Init
函數(shù)初始化SHT30傳感器。
進入主循環(huán)后,通過循環(huán)調(diào)用SHT30_Measure
函數(shù)測量溫濕度數(shù)據(jù),并通過printf
函數(shù)打印出來。最后通過delay_ms
函數(shù)延時1秒。
4.3 光照傳感器模塊
光照傳感器(如BH1750)通過I2C總線與主控芯片相連,負(fù)責(zé)實時監(jiān)測大棚內(nèi)的光照強度。傳感器模塊將采集到的數(shù)據(jù)傳輸給主控芯片進行處理。
實現(xiàn)代碼如下:
使用STM32標(biāo)準(zhǔn)庫編寫代碼驅(qū)動BH1750讀取環(huán)境光照強度。
#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; // 禁止應(yīng)答
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)
{
// 發(fā)送起始信號
I2C_GenerateSTART(I2C1, ENABLE);
// 等待起始信號發(fā)送完成
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
;
}
void I2C1_Stop(void)
{
// 發(fā)送停止信號
I2C_GenerateSTOP(I2C1, ENABLE);
}
void I2C1_WriteByte(uint8_t byte)
{
// 發(fā)送一個字節(jié)的數(shù)據(jù)
I2C_SendData(I2C1, byte);
// 等待發(fā)送完成
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
;
}
uint16_t BH1750_ReadData(void)
{
uint16_t data = 0;
// 設(shè)置BH1750模式(連續(xù)高分辨率測量模式)
I2C1_Start();
I2C1_WriteByte(BH1750_ADDR);
I2C1_WriteByte(0x10);
I2C1_Stop();
// 延時等待測量結(jié)束
delay_ms(20);
// 讀取光照強度數(shù)據(jù)
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; // 復(fù)用推挽輸出
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)
{
// 等待發(fā)送緩沖區(qū)為空
while (!(USART1->SR & USART_FLAG_TXE))
;
// 發(fā)送一個字符
USART_SendData(USART1, ch);
}
int fputc(int ch, FILE *f)
{
// 將數(shù)據(jù)通過串口發(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 Testn");
while (1)
{
lightIntensity = BH1750_ReadData();
printf("Light Intensity: %d luxn", lightIntensity);
delay_ms(1000); // 每隔1秒讀取一次光照強度
}
}
【1】上面代碼里定義了BH1750的地址BH1750_ADDR
為0x23,這是BH1750的默認(rèn)地址。
【2】在I2C1_Init()
函數(shù)中,初始化了I2C1總線和相關(guān)的GPIO引腳。通過RCC_APB1PeriphClockCmd和RCC_APB2PeriphClockCmd函數(shù)使能I2C1和GPIOB時鐘,然后配置GPIOB的引腳6和7為開漏輸出模式(GPIO_Mode_AF_OD)。接著,使用I2C_Init函數(shù)初始化I2C1,并設(shè)置其工作模式為I2C_Mode_I2C、占空比為50%、禁止應(yīng)答、7位地址模式以及100kHz的通信速率。最后,通過I2C_Cmd函數(shù)使能I2C1。
【3】I2C1_Start()
函數(shù)用于發(fā)送I2C總線的起始信號。調(diào)用I2C_GenerateSTART
函數(shù)發(fā)送起始信號,并使用I2C_CheckEvent
函數(shù)等待起始信號發(fā)送完成。
【4】I2C1_Stop()
函數(shù)用于發(fā)送I2C總線的停止信號。調(diào)用I2C_GenerateSTOP
函數(shù)發(fā)送停止信號。
【5】I2C1_WriteByte()
函數(shù)用于向I2C設(shè)備發(fā)送一個字節(jié)的數(shù)據(jù)。通過I2C_SendData
函數(shù)發(fā)送數(shù)據(jù),并使用I2C_CheckEvent
函數(shù)等待發(fā)送完成。
【6】BH1750_ReadData()
函數(shù)用于讀取光照強度數(shù)據(jù)。,發(fā)送啟動測量指令和模式設(shè)置指令(連續(xù)高分辨率測量模式)。然后等待測量結(jié)束的延時時間(20ms)。接著,通過兩次讀取數(shù)據(jù)寄存器的方式獲取光照強度數(shù)據(jù),并將其拼接為一個16位的無符號整數(shù)。
【7】USART1_Init()
函數(shù)用于初始化USART1串口和相關(guān)的GPIO引腳。使用RCC_APB2PeriphClockCmd函數(shù)使能USART1和GPIOA時鐘,然后配置GPIOA的引腳9為復(fù)用推挽輸出模式(GPIO_Mode_AF_PP)。接著,通過USART_Init函數(shù)初始化USART1,并設(shè)置其波特率為115200、數(shù)據(jù)位長度為8位、停止位為1位、無奇偶校驗、無硬件流控制。最后,通過USART_Cmd函數(shù)使能USART1。
【8】USART1_SendChar()
函數(shù)用于發(fā)送一個字符到USART1串口。使用USART_SR
寄存器的USART_FLAG_TXE
標(biāo)志位檢查發(fā)送緩沖區(qū)是否為空,然后通過USART_SendData
函數(shù)發(fā)送字符數(shù)據(jù)。
【9】fputc()
函數(shù)重定向了輸出流,使得通過printf
函數(shù)打印的字符可以發(fā)送到USART1串口。在該函數(shù)中調(diào)用USART1_SendChar
函數(shù)發(fā)送字符數(shù)據(jù),并返回該字符。
【10】delay_ms()
函數(shù)用于進行延時,單位為毫秒。該函數(shù)使用嵌套循環(huán)實現(xiàn)了簡單的延時功能,不同的系統(tǒng)時鐘頻率可能需要適當(dāng)調(diào)整。
【11】在main()
函數(shù)中,依次調(diào)用I2C1_Init()
和USART1_Init()
函數(shù)進行初始化操作。然后,通過printf
函數(shù)向串口發(fā)送初始信息。
【12】在主循環(huán)中,通過調(diào)用BH1750_ReadData()
函數(shù)讀取光照強度數(shù)據(jù),并使用printf
函數(shù)將其打印到串口。然后通過delay_ms
函數(shù)進行1秒的延時,等待下一次讀取。
4.4 報警蜂鳴器模塊
報警蜂鳴器通過一個GPIO引腳與主控芯片相連。當(dāng)報警條件滿足時,主控芯片控制該引腳輸出高電平信號,以激活蜂鳴器發(fā)出聲音提示。
使用STM32F103標(biāo)準(zhǔn)庫編寫的蜂鳴器控制代碼:
#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)
{
// 控制蜂鳴器開啟和關(guān)閉
BEEP_On();
Delay_ms(500);
BEEP_Off();
Delay_ms(500);
}
}
在代碼中,使用了GPIOA的第8個引腳作為蜂鳴器的控制引腳。BEEP_Init
函數(shù)用于初始化蜂鳴器引腳,將其配置為推挽輸出模式。BEEP_On
和BEEP_Off
函數(shù)分別用于開啟和關(guān)閉蜂鳴器。
在main
函數(shù)中,通過循環(huán)控制蜂鳴器以500ms的間隔進行開啟和關(guān)閉操作。
4.5 HC05藍(lán)牙模塊模塊
HC05藍(lán)牙模塊通過串口通信與主控芯片相連,負(fù)責(zé)實現(xiàn)與Android手機APP之間的數(shù)據(jù)傳輸和通信。它接收主控芯片發(fā)送的數(shù)據(jù),并通過藍(lán)牙與手機APP進行交互。
使用STM32標(biāo)準(zhǔn)庫編寫代碼,用于通過串口2驅(qū)動HC05模塊,并進行配置和數(shù)據(jù)通信:
#include "stm32f10x.h"
#include "stdio.h"
// HC05配置指令
#define AT_CMD_MODE "AT+CMODE=0rn" // 配置為從模式
#define AT_CMD_PW "AT+PSWD=1234rn" // 配對密碼設(shè)置為1234
// 函數(shù)聲明
void USART2_Init(void);
void USART2_SendChar(char ch);
void USART2_SendString(char* str);
char USART2_Receive(void);
int main(void)
{
// 初始化USART2串口
USART2_Init();
// 發(fā)送AT指令配置HC05為從模式
USART2_SendString(AT_CMD_MODE);
for(int i = 0; i < 1000000; i++); // 等待一段時間
// 發(fā)送AT指令配置配對密碼
USART2_SendString(AT_CMD_PW);
for(int i = 0; i < 1000000; i++); // 等待一段時間
while(1)
{
// 接收手機發(fā)送的數(shù)據(jù)
char data = USART2_Receive();
// 處理接收到的數(shù)據(jù),例如發(fā)送回應(yīng)等
// ...
}
}
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; // 復(fù)用推挽輸出
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的參數(shù)
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600; // 波特率為9600
USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 數(shù)據(jù)位長度為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; // 支持收發(fā)模式
USART_Init(USART2, &USART_InitStructure);
// 使能USART2
USART_Cmd(USART2, ENABLE);
}
void USART2_SendChar(char ch)
{
while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET); // 等待發(fā)送緩沖區(qū)為空
USART_SendData(USART2, (uint16_t)ch); // 發(fā)送數(shù)據(jù)
}
void USART2_SendString(char* str)
{
while(*str)
{
USART2_SendChar(*str++);
}
}
char USART2_Receive(void)
{
while (USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == RESET); // 等待接收緩沖區(qū)非空
return (char)USART_ReceiveData(USART2);
}
以上代碼通過USART2串口與HC05模塊進行通信,并發(fā)送AT指令對其進行配置。其中,AT_CMD_MODE
用于將HC05配置為從模式,AT_CMD_PW
用于設(shè)置配對密碼為1234。
代碼設(shè)計思路介紹:
【1】引入頭文件:
#include "stm32f10x.h"
#include "stdio.h"
引入了STM32F10x系列微控制器的相關(guān)頭文件和標(biāo)準(zhǔn)輸入輸出庫的頭文件。
【2】定義宏和函數(shù):
#define AT_CMD_MODE "AT+CMODE=0rn"
#define AT_CMD_PW "AT+PSWD=1234rn"
void USART2_Init(void);
void USART2_SendChar(char ch);
void USART2_SendString(char* str);
char USART2_Receive(void);
定義了用于配置HC05模塊的AT指令,以及用于初始化USART2串口、發(fā)送字符和字符串、接收字符的函數(shù)。
【3】USART2串口初始化函數(shù):
void USART2_Init(void)
該函數(shù)用于初始化USART2串口和相關(guān)引腳。使能了USART2和GPIOA的時鐘,然后配置了USART2的引腳,包括引腳的模式和速度等。接著對USART2進行配置,設(shè)置波特率、數(shù)據(jù)位長度、停止位、奇偶校驗位等參數(shù),并最后使能USART2串口。
【4】發(fā)送字符和字符串函數(shù):
void USART2_SendChar(char ch)
void USART2_SendString(char* str)
這些函數(shù)用于通過USART2串口發(fā)送字符和字符串。對于USART2_SendChar
函數(shù),它會等待發(fā)送緩沖區(qū)為空,然后將字符寫入數(shù)據(jù)寄存器進行發(fā)送。對于USART2_SendString
函數(shù),它會遍歷字符串中的每個字符,并調(diào)用USART2_SendChar
函數(shù)進行發(fā)送。
【5】接收字符函數(shù):
char USART2_Receive(void)
該函數(shù)用于從USART2串口接收一個字符。它會等待接收緩沖區(qū)非空,然后讀取數(shù)據(jù)寄存器的值并返回接收到的字符。此函數(shù)在主循環(huán)中可以用于接收HC05模塊發(fā)送的數(shù)據(jù)。
【6】主函數(shù):
int main(void)
在主函數(shù)中,調(diào)用USART2_Init
函數(shù)初始化USART2串口。然后使用USART2_SendString
函數(shù)依次發(fā)送配置指令AT_CMD_MODE
和AT_CMD_PW
給HC05模塊。發(fā)送完指令后,通過循環(huán)調(diào)用USART2_Receive
函數(shù)接收HC05模塊發(fā)送的數(shù)據(jù)。
五、調(diào)試過程
在項目設(shè)計完成后,進行測試和調(diào)試是非常重要的,以確保系統(tǒng)的正常運行和功能的有效性。
下面是本項目的測試和調(diào)試過程流程:
5.1 硬件測試
- 檢查硬件組裝和連接是否正確,包括主控芯片STM32F103RCT6、傳感器模塊SHT30和BH1750以及藍(lán)牙模塊HC05的連接。
- 使用示波器或多用途測試儀檢測各個模塊的電源供應(yīng)和信號線連接是否正常。
- 測試溫濕度傳感器(SHT30)和光照強度傳感器(BH1750)是否能夠正確采集環(huán)境數(shù)據(jù)。
- 測試蜂鳴器是否能夠發(fā)出合適的聲音提示。
5.2 固件程序測試
- 在STM32開發(fā)環(huán)境中編譯程序,將固件程序燒錄到主控芯片STM32F103RCT6上。
- 使用串口調(diào)試助手等工具,與STM32建立通信連接,檢查數(shù)據(jù)的傳輸和接收是否正常。
- 對溫濕度傳感器和光照強度傳感器進行數(shù)據(jù)采集測試,觀察是否能夠準(zhǔn)確讀取傳感器數(shù)據(jù)。
- 設(shè)置閾值并測試報警功能,確保報警觸發(fā)條件和報警提示的準(zhǔn)確性。
5.3 Android手機APP測試
- 安裝開發(fā)好的Android手機APP到測試設(shè)備上,確保安裝過程順利。
- 打開APP,并與藍(lán)牙模塊HC05進行連接,觀察是否能夠成功建立通信。
- 測試數(shù)據(jù)的傳輸和接收功能,確保從STM32接收到的數(shù)據(jù)能夠在APP界面上正確顯示。
- 設(shè)置閾值并觸發(fā)報警測試,確認(rèn)報警提示(聲音、震動、彈窗等)是否按照設(shè)定的條件正常工作。
5.4 系統(tǒng)整體測試
- 模擬實際環(huán)境,調(diào)整大棚溫濕度和光照強度,觀察系統(tǒng)是否能夠準(zhǔn)確檢測并顯示環(huán)境參數(shù)。
- 調(diào)整報警閾值,觸發(fā)報警條件,驗證報警提示是否按照預(yù)期工作。
- 進行長時間運行測試,確保系統(tǒng)的穩(wěn)定性和可靠性。
六、關(guān)鍵問題討論
6.1 本項目的核心與技術(shù)難點
【1】硬件集成:將主控芯片、傳感器模塊、藍(lán)牙模塊和蜂鳴器等多個硬件模塊進行正確的連接和集成是一個挑戰(zhàn)。需要仔細(xì)設(shè)計電路連接、通信協(xié)議和接口定義,確保各個模塊能夠正常協(xié)同工作。
【2】數(shù)據(jù)處理與算法:在主控芯片的固件程序中,需要對傳感器采集到的數(shù)據(jù)進行處理和分析,判斷是否觸發(fā)報警條件。這可能涉及到數(shù)據(jù)濾波、閾值判定、異常檢測等算法的設(shè)計和實現(xiàn)。
【3】藍(lán)牙通信:與手機APP之間的藍(lán)牙通信是一個難點。需要實現(xiàn)穩(wěn)定可靠的數(shù)據(jù)傳輸和通信協(xié)議,確保數(shù)據(jù)的準(zhǔn)確性和實時性。
6.2 本項目的實用性
【1】實時監(jiān)測和報警功能:該項目能夠?qū)崟r監(jiān)測大棚內(nèi)的溫度、濕度和光照強度,并在超過設(shè)定閥值時觸發(fā)報警。這對于農(nóng)業(yè)生產(chǎn)者來說非常實用,能夠幫助他們及時發(fā)現(xiàn)問題并采取措施,以保證大棚內(nèi)環(huán)境的穩(wěn)定和作物的健康生長。
【2】遠(yuǎn)程監(jiān)控和管理:通過與手機APP的藍(lán)牙通信,用戶可以遠(yuǎn)程監(jiān)控大棚內(nèi)的數(shù)據(jù)并進行管理。他們可以隨時查看溫濕度和光照強度的實時數(shù)據(jù),設(shè)置報警閥值,接收報警通知,并對大棚環(huán)境進行遠(yuǎn)程調(diào)整和控制。
【3】自動化和智能化:該項目利用傳感器和自動化控制技術(shù),實現(xiàn)了對大棚環(huán)境的智能監(jiān)測和控制。這不僅提高了農(nóng)業(yè)生產(chǎn)的效率和質(zhì)量,還減輕了人工管理的負(fù)擔(dān),具有較高的實用性和應(yīng)用價值。
6.3 關(guān)鍵點總結(jié)
【1】傳感器選擇和集成:選擇適合的溫濕度傳感器和光照強度傳感器,并合理集成到硬件設(shè)計中。需要考慮傳感器的精度、響應(yīng)速度以及與主控芯片的通信協(xié)議等因素。
【2】數(shù)據(jù)采集和處理算法:設(shè)計合適的數(shù)據(jù)采集和處理算法,確保從傳感器獲取的數(shù)據(jù)準(zhǔn)確可靠,并能夠根據(jù)設(shè)定的閾值判斷是否觸發(fā)報警條件。
【3】報警機制:設(shè)計報警機制,根據(jù)設(shè)定的閾值和實時采集的數(shù)據(jù)進行比較,當(dāng)達(dá)到報警條件時,觸發(fā)報警提示,如聲音、震動或彈窗等方式。
【4】藍(lán)牙通信:確保藍(lán)牙模塊能夠與主控芯片穩(wěn)定通信,并能夠成功傳輸采集的數(shù)據(jù)到Android手機APP上。需要考慮通信的穩(wěn)定性、數(shù)據(jù)傳輸?shù)乃俾屎桶踩缘纫蛩亍?/p>
【5】Android手機APP設(shè)計:設(shè)計用戶友好的界面,在手機APP上實時顯示大棚內(nèi)的溫濕度和光照強度數(shù)據(jù),并提供設(shè)置界面,允許農(nóng)民設(shè)置報警閾值。同時,實現(xiàn)報警提示的功能,保證報警條件的準(zhǔn)確性和報警方式的有效性。
【6】系統(tǒng)穩(wěn)定性和可靠性:在測試和調(diào)試階段,需要對整個系統(tǒng)進行全面的測試,包括硬件和軟件的各個模塊,以確保系統(tǒng)的穩(wěn)定性和可靠性。同時,考慮到長時間運行的情況,還需進行長時間測試,以驗證系統(tǒng)能夠持續(xù)運行并正常工作。
七、設(shè)計總結(jié)與體會
本項目的目的是設(shè)計實現(xiàn)對農(nóng)業(yè)大棚環(huán)境的智能監(jiān)測和管理,通過傳感器采集數(shù)據(jù)、主控芯片處理和判斷、藍(lán)牙通信與手機APP交互,以及報警蜂鳴器的控制,實現(xiàn)了對溫度、濕度和光照強度等參數(shù)的實時監(jiān)測和報警功能。
在項目開發(fā)過程中,也遇到了一些挑戰(zhàn)和難點,比如:硬件的連接和集成、數(shù)據(jù)處理算法的設(shè)計和實現(xiàn),以及與手機APP之間的藍(lán)牙通信。通過細(xì)致的計劃和分工,最終也是成功地克服了這些困難,得以完成了整個系統(tǒng)的開發(fā)。
在實施過程中,深刻認(rèn)識到模塊化設(shè)計的重要性。通過將系統(tǒng)劃分為多個硬件模塊和軟件模塊,能夠更好地管理和調(diào)試每個模塊,并且在需要時進行模塊的替換和升級,提高了系統(tǒng)的可擴展性和可維護性。
在測試階段,也意識到用戶體驗的重要性。通過與潛在用戶的溝通和反饋,不斷優(yōu)化和改進系統(tǒng)的界面設(shè)計和功能實現(xiàn),力求使用戶能夠輕松使用和管理該系統(tǒng)。這種用戶導(dǎo)向的設(shè)計理念提高了系統(tǒng)的實用性和用戶滿意度。
總的來說,本項目的設(shè)計與實施過程對軟硬件的協(xié)同工作、數(shù)據(jù)處理與算法設(shè)計、用戶體驗等方面有了更深入的理解。通過克服挑戰(zhàn)和不斷優(yōu)化,成功地將智能農(nóng)業(yè)大棚監(jiān)測系統(tǒng)帶入實際應(yīng)用,并為農(nóng)業(yè)生產(chǎn)者提供了一種方便、高效且可靠的解決方案。相信隨著技術(shù)的不斷發(fā)展,智慧農(nóng)業(yè)將在未來發(fā)揮更大的作用,為農(nóng)業(yè)生產(chǎn)帶來更多的創(chuàng)新和改進。