1、開發(fā)環(huán)境
keil5,STM32CubeMX、Altium Designer
2、硬件清單
單片機:STM32F051K8Ux
土壤濕度傳感器:TL - 69
溫度傳感器:DS18B20(數(shù)字傳感器直接輸出數(shù)字信號)
OLED屏幕:OLED12864、
水泵:L9110等;
3、功能設(shè)計
傳感器采集空氣和土壤的溫度以及濕度,將數(shù)據(jù)傳輸給單片機,經(jīng)單片機處理后輸出在OLED顯示屏上。
4、硬件連接
- 將溫度傳感器DS18B20、土壤濕度傳感器YL - 69、水泵L9110、連接到STM32的GPIO引腳上。
- 將OLED屏幕OLED12862連接到STM32的I2C引腳上。
5、功能分析
5.1總體功能
- 使用STM32的GPIO庫和I2C庫來配置和讀取傳感器數(shù)據(jù)。
- 編寫代碼來讀取溫度傳感器DS18B20、濕度傳感器YL - 69的數(shù)據(jù)。
- 根據(jù)傳感器數(shù)據(jù),編寫代碼判斷植物是否需要灌溉,如果需要澆灌,使用GPIO庫來控制水泵L9110的開關(guān)。
- 使用STM32的I2C庫來驅(qū)動oled顯示屏。
- 編寫代碼來實現(xiàn)空氣溫度和土壤濕度數(shù)據(jù)到OLED屏幕上。
5.2傳感器采集數(shù)據(jù)
1. DS18B20溫度傳感器數(shù)據(jù)采集:
? ?- DS18B20是一種數(shù)字溫度傳感器,采用單總線接口進行通信。單片機通過GPIO口與DS18B20進行通信。
? ?- 通信過程中,單片機發(fā)送指令給DS18B20,例如讀取溫度的指令。
? ?- DS18B20將溫度數(shù)據(jù)以序列的形式通過單總線返回給單片機。單片機通過接收和解析這個序列,得到DS18B20傳感器的原始溫度數(shù)據(jù)。
? ?- 單片機可以通過讀取DS18B20的原始溫度數(shù)據(jù),并進行相應(yīng)的計算,得到實際的溫度值。
2. YL69濕度傳感器數(shù)據(jù)采集:
? ?- YL69濕度傳感器是一種模擬濕度傳感器,輸出模擬電壓信號。它通常需要一個模數(shù)轉(zhuǎn)換器(ADC)將模擬信號轉(zhuǎn)換為數(shù)字信號,以便單片機進行處理。
? ?- 單片機通過GPIO口與YL69濕度傳感器進行通信,讀取YL69濕度傳感器的模擬電壓信號。
? ?- 單片機將YL69濕度傳感器的模擬電壓信號輸入到內(nèi)部的ADC模塊中進行轉(zhuǎn)換。
? ?- ADC模塊將模擬電壓信號轉(zhuǎn)換為數(shù)字信號,并將轉(zhuǎn)換后的數(shù)字數(shù)據(jù)傳遞給單片機。
? ?- 單片機可以通過讀取ADC轉(zhuǎn)換后的數(shù)字數(shù)據(jù),并進行相應(yīng)的處理,得到Y(jié)L69濕度傳感器的濕度值。
需要注意的是,具體的數(shù)據(jù)采集方式和通信協(xié)議可能因單片機、傳感器和硬件平臺的不同而有所差異。因此,在實際應(yīng)用中,需要根據(jù)所使用的硬件和軟件平臺的要求,以及傳感器的規(guī)格和接口,進行相應(yīng)的配置和編程。以上是一種可能的實現(xiàn)方式,具體的實現(xiàn)細節(jié)可能會有所不同。
6、代碼編寫
1、GPIO管腳配置
可以在STM32CubeMX中選擇相應(yīng)的引腳,并將其配置為推挽輸出模式,然后生成相應(yīng)的代碼。
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 使能GPIOA和GPIOB的時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
// 配置PA0引腳為推挽輸出
GPIO_InitStructure.GPIO_Pin = PUMP_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
2、配置 I2C
在STM32CubeMX中,可以通過圖形化界面選擇I2C外設(shè)并進行相應(yīng)的配置,然后生成對應(yīng)的代碼。
步驟如下:
1. 打開STM32CubeMX軟件,并創(chuàng)建一個新的工程。
2. 選擇目標(biāo)STM32F051K8Ux微控制器型號。
3. 在"Pinout & Configuration"選項卡中,找到I2C1外設(shè),并配置相關(guān)的引腳。
4. 在"Configuration"選項卡中,找到I2C1外設(shè),并設(shè)置相關(guān)的參數(shù),如時鐘速度、地址等。
5. 確認配置無誤后,點擊"Project"菜單,選擇"Generate Code"生成代碼。
6. 在生成的代碼中,可以找到類似于你提供的`I2C_Configuration`函數(shù)的代碼。
void I2C_Configuration(void)
{
I2C_InitTypeDef I2C_InitStructure;
// 使能I2C1的時鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
// 配置I2C1的引腳
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 配置I2C1的參數(shù)
I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 100000;
I2C_Init(I2C1, &I2C_InitStructure);
// 使能I2C1
I2C_Cmd(I2C1, ENABLE);
}
3、溫度采集函數(shù)
void DS18B20_ReadTemperature(float *temperature)
{
uint8_t buffer[2];
// 發(fā)送讀取溫度命令
I2C_GenerateSTART(I2C1, ENABLE);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
;
I2C_Send7bitAddress(I2C1, DS18B20_ADDRESS, I2C_Direction_Transmitter);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
;
I2C_SendData(I2C1, 0x00);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
;
I2C_GenerateSTOP(I2C1, ENABLE);
// 讀取溫度數(shù)據(jù)
I2C_GenerateSTART(I2C1, ENABLE);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
;
I2C_Send7bitAddress(I2C1, DS18B20_ADDRESS, I2C_Direction_Receiver);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
;
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))
;
buffer[0] = I2C_ReceiveData(I2C1);
I2C_AcknowledgeConfig(I2C1, DISABLE);
I2C_GenerateSTOP(I2C1, ENABLE);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))
;
buffer[1] = I2C_ReceiveData(I2C1);
// 計算溫度值
*temperature = (float)((buffer[1] << 8) | buffer[0]) / 16.0;
}
DS18B20_ReadTemperature函數(shù)從連接到I2C總線的DS18B20溫度傳感器中讀取溫度數(shù)據(jù)。以下是它的工作原理的逐步解釋:
1. 聲明一個數(shù)組 buffer 來存儲2個字節(jié)的溫度數(shù)據(jù)。
2. 通過在I2C總線上生成起始條件并將傳感器選擇為發(fā)送器,發(fā)送讀取溫度的命令。
3. 等待主發(fā)送器模式被選中,然后將溫度寄存器的地址(0x00)發(fā)送給傳感器。
4. 等待字節(jié)傳輸完成,然后生成停止條件來結(jié)束傳輸。
5. 通過在I2C總線上生成起始條件并將傳感器選擇為接收器,發(fā)送讀取溫度數(shù)據(jù)的命令。
6. 等待主接收器模式被選中,然后等待字節(jié)接收完成。
7. 將接收到的字節(jié)存儲在 buffer[0] 中。
8. 禁用應(yīng)答位,表示不再接收更多的字節(jié)。
9. 生成停止條件來結(jié)束傳輸。
10. 等待字節(jié)接收完成,并將其存儲在 buffer[1] 中。
11. 通過將 buffer 中的兩個字節(jié)組合起來并除以16.0來計算溫度值。
12. 將溫度值存儲在由 temperature 指針指向的內(nèi)存位置中。
總體而言,該函數(shù)從DS18B20傳感器中讀取溫度數(shù)據(jù),并計算出攝氏度的溫度值。溫度值然后存儲在由 temperature 指針指向的內(nèi)存位置中,以供進一步使用。
4、濕度采集函數(shù)
void YL69_ReadHumidity(float *humidity)
{
uint8_t buffer[2];
// 發(fā)送讀取濕度命令
I2C_GenerateSTART(I2C1, ENABLE);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
;
I2C_Send7bitAddress(I2C1, YL69_ADDRESS, I2C_Direction_Transmitter);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
;
I2C_SendData(I2C1, 0x00);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
;
I2C_GenerateSTOP(I2C1, ENABLE);
// 讀取濕度數(shù)據(jù)
I2C_GenerateSTART(I2C1, ENABLE);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
;
I2C_Send7bitAddress(I2C1, YL69_ADDRESS, I2C_Direction_Receiver);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
;
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))
;
buffer[0] = I2C_ReceiveData(I2C1);
I2C_AcknowledgeConfig(I2C1, DISABLE);
I2C_GenerateSTOP(I2C1, ENABLE);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))
;
buffer[1] = I2C_ReceiveData(I2C1);
// 計算濕度值
*humidity = (float)((buffer[1] << 8) | buffer[0]) / 1024.0 * 100.0;
}
讀取YL69濕度傳感器的濕度值,并將結(jié)果存儲在 humidity 指針指向的內(nèi)存位置中。
1. 定義一個 buffer 數(shù)組,用于存儲從傳感器讀取的數(shù)據(jù)。
2. 發(fā)送讀取濕度命令:
? ?- 生成起始條件,啟動I2C總線。
? ?- 等待主模式選擇事件。
? ?- 發(fā)送傳感器的I2C地址和傳輸方向(發(fā)送器)。
? ?- 等待主傳輸器模式選擇事件。
? ?- 發(fā)送讀取濕度數(shù)據(jù)的命令(0x00)。
? ?- 等待主字節(jié)傳輸完成事件。
? ?- 生成停止條件,結(jié)束傳輸。
3. 讀取濕度數(shù)據(jù):
? ?- 生成起始條件,啟動I2C總線。
? ?- 等待主模式選擇事件。
? ?- 發(fā)送傳感器的I2C地址和傳輸方向(接收器)。
? ?- 等待主接收器模式選擇事件。
? ?- 等待主字節(jié)接收完成事件。
? ?- 將接收到的字節(jié)存儲在 buffer[0] 中。
? ?- 禁用應(yīng)答位,表示不再接收更多的字節(jié)。
? ?- 生成停止條件,結(jié)束傳輸。
? ?- 等待主字節(jié)接收完成事件。
? ?- 將接收到的字節(jié)存儲在 buffer[1] 中。
4. 計算濕度值:
? ?- 將 buffer[1] 左移8位后與 buffer[0] 進行按位或操作,得到16位的濕度數(shù)據(jù)。
? ?- 將濕度數(shù)據(jù)轉(zhuǎn)換為浮點型,除以1024.0后乘以100.0,得到濕度百分比值。
? ?- 將濕度百分比值存儲在由 humidity 指針指向的內(nèi)存位置中。文章來源:http://www.zghlxwxcb.cn/news/detail-643978.html
總體而言,這段代碼通過I2C總線與YL69濕度傳感器進行通信,發(fā)送讀取濕度命令并讀取濕度數(shù)據(jù)。然后,它將讀取到的濕度數(shù)據(jù)轉(zhuǎn)換為百分比值,并將結(jié)果存儲在由`humidity`指針指向的內(nèi)存位置中。文章來源地址http://www.zghlxwxcb.cn/news/detail-643978.html
7、完整代碼
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_i2c.h"
#include "stdio.h"
#define DS18B20_ADDRESS 0x48
#define YL69_ADDRESS 0x5C
#define PUMP_PIN GPIO_Pin_0
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 使能GPIOA和GPIOB的時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
// 配置PA0引腳為推挽輸出
GPIO_InitStructure.GPIO_Pin = PUMP_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void I2C_Configuration(void)
{
I2C_InitTypeDef I2C_InitStructure;
// 使能I2C1的時鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
// 配置I2C1的引腳
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 配置I2C1的參數(shù)
I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 100000;
I2C_Init(I2C1, &I2C_InitStructure);
// 使能I2C1
I2C_Cmd(I2C1, ENABLE);
}
void DS18B20_ReadTemperature(float *temperature)
{
uint8_t buffer[2];
// 發(fā)送讀取溫度命令
I2C_GenerateSTART(I2C1, ENABLE);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
;
I2C_Send7bitAddress(I2C1, DS18B20_ADDRESS, I2C_Direction_Transmitter);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
;
I2C_SendData(I2C1, 0x00);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
;
I2C_GenerateSTOP(I2C1, ENABLE);
// 讀取溫度數(shù)據(jù)
I2C_GenerateSTART(I2C1, ENABLE);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
;
I2C_Send7bitAddress(I2C1, DS18B20_ADDRESS, I2C_Direction_Receiver);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
;
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))
;
buffer[0] = I2C_ReceiveData(I2C1);
I2C_AcknowledgeConfig(I2C1, DISABLE);
I2C_GenerateSTOP(I2C1, ENABLE);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))
;
buffer[1] = I2C_ReceiveData(I2C1);
// 計算溫度值
*temperature = (float)((buffer[1] << 8) | buffer[0]) / 16.0;
}
void YL69_ReadHumidity(float *humidity)
{
uint8_t buffer[2];
// 發(fā)送讀取濕度命令
I2C_GenerateSTART(I2C1, ENABLE);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
;
I2C_Send7bitAddress(I2C1, YL69_ADDRESS, I2C_Direction_Transmitter);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
;
I2C_SendData(I2C1, 0x00);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
;
I2C_GenerateSTOP(I2C1, ENABLE);
// 讀取濕度數(shù)據(jù)
I2C_GenerateSTART(I2C1, ENABLE);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
;
I2C_Send7bitAddress(I2C1, YL69_ADDRESS, I2C_Direction_Receiver);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
;
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))
;
buffer[0] = I2C_ReceiveData(I2C1);
I2C_AcknowledgeConfig(I2C1, DISABLE);
I2C_GenerateSTOP(I2C1, ENABLE);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))
;
buffer[1] = I2C_ReceiveData(I2C1);
// 計算濕度值
*humidity = (float)((buffer[1] << 8) | buffer[0]) / 1024.0 * 100.0;
}
void ControlPump(float temperature, float humidity)
{
if (temperature > 25.0 && humidity < 50.0) {
// 打開水泵
GPIO_SetBits(GPIOA, PUMP_PIN);
} else {
// 關(guān)閉水泵
GPIO_ResetBits(GPIOA, PUMP_PIN);
}
}
void OLED_WriteString(uint8_t row, uint8_t col, char *str)
{
// 在OLED屏幕上寫入字符串
// ...
}
void OLED_Clear(void)
{
// 清空OLED屏幕
// ...
}
void DisplayData(float temperature, float humidity)
{
char str[16];
// 清空OLED屏幕
OLED_Clear();
// 顯示溫度數(shù)據(jù)
sprintf(str, "Temp: %.2f C", temperature);
OLED_WriteString(0, 0, str);
// 顯示濕度數(shù)據(jù)
sprintf(str, "Humidity: %.2f%%", humidity);
OLED_WriteString(1, 0, str);
}
int main(void)
{
float temperature, humidity;
// 初始化GPIO和I2C
GPIO_Configuration();
I2C_Configuration();
while (1) {
// 讀取溫度數(shù)據(jù)
DS18B20_ReadTemperature(&temperature);
// 讀取濕度數(shù)據(jù)
YL69_ReadHumidity(&humidity);
// 控制水泵
ControlPump(temperature, humidity);
// 在OLED屏幕上顯示數(shù)據(jù)
DisplayData(temperature, humidity);
// 延時一段時間
// ...
}
}
到了這里,關(guān)于基于單片機的家用智能澆灌系統(tǒng)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!