- UID
- 373967
- 帖子
- 8844
- 主題
- 2609
- 精華
- 0
- 積分
- 999
- 楓幣
- 0
- 威望
- 976
- 存款
- 34672
- 贊助金額
- 0
- 推廣
- 0
- GP
- 1205
- 閱讀權限
- 50
- 在線時間
- 453 小時
- 註冊時間
- 2023-1-12
- 最後登入
- 2024-11-17
|
要製作一個自動養花灌水系統,你會需要以下材料:
STM8S003F3P6 微控制器
16x2 LCD 液晶顯示器
DHT11 溫濕度感應器
水泵和相關電路
電容器和電阻器
麵包板和電線
以下是 STM8S003F3P6 的連接腳位:
PC3: 用於 LCD 顯示器的 RS (Register Select) 腳
PC4: 用於 LCD 顯示器的 E (Enable) 腳
PC5-PC7: 用於 LCD 顯示器的 D4-D6 腳
PB4: 用於 DHT11 溫濕度感應器的輸入腳
PA1: 用於控制水泵的輸出腳
以下是一個示例程式碼,可以讓 STM8S003F3P6 控制自動養花灌水系統:
#include <stdio.h>
#include <string.h>
#include "stm8s.h"
#include "stm8s_delay.h"
#include "stm8s_gpio.h"
#include "stm8s_i2c.h"
#define LCD_RS_PIN GPIO_PIN_3
#define LCD_E_PIN GPIO_PIN_4
#define LCD_D4_PIN GPIO_PIN_5
#define LCD_D5_PIN GPIO_PIN_6
#define LCD_D6_PIN GPIO_PIN_7
#define DHT11_PIN GPIO_PIN_4
#define PUMP_PIN GPIO_PIN_1
#define I2C_SPEED 100000
void init_lcd(void);
void lcd_send_cmd(uint8_t cmd);
void lcd_send_data(uint8_t data);
void lcd_send_string(char* str);
void init_dht11(void);
void read_dht11(uint8_t* temp, uint8_t* hum);
void init_pump(void);
void turn_on_pump(void);
void turn_off_pump(void);
void main()
{
uint8_t temp, hum;
char buf[16];
// 初始化 LCD 和 DHT11 溫濕度感應器
init_lcd();
init_dht11();
// 初始化水泵
init_pump();
while (1)
{
// 讀取溫度和濕度
read_dht11(&temp, &hum);
// 如果濕度太低,就開啟水泵
if (hum < 60)
{
turn_on_pump();
}
else
{
turn_off_pump();
}
// 在 LCD 上顯示溫度和濕度
lcd_send_cmd(0x80);
sprintf(buf, "Temp: %dC", temp);
lcd_send_string(buf);
lcd_send_cmd(0xC0);
sprintf(buf, "Hum : %d%%", hum);
lcd_send_string(buf);
delay_ms(1000);
}
}
void init_lcd()
{
gpio_init(GPIOC, LCD_RS_PIN | LCD_E_PIN | LCD_D4_PIN | LCD_D5_PIN | LCD_D6_PIN,
GPIO_MODE_OUT_PP_LOW_FAST); // 設定 LCD 連接的 GPIO 腳為輸出模式
lcd_send_cmd(0x33); // 初始化 LCD
lcd_send_cmd(0x32);
lcd_send_cmd(0x28);
lcd_send_cmd(0x0C);
lcd_send_cmd(0x01);
lcd_send_cmd(0x06);
}
void lcd_send_cmd(uint8_t cmd)
{
gpio_write_low(GPIOC, LCD_RS_PIN); // 設定 RS 腳為低電位,表示要發送命令
gpio_write_high(GPIOC, LCD_E_PIN); // 設定 E 腳為高電位
gpio_write(GPIOC, LCD_D4_PIN | ((cmd & 0x0F) << 1)); // 將命令的低四位送入 D4-D7 腳
delay_us(1);
gpio_write_low(GPIOC, LCD_E_PIN); // 設定 E 腳為低電位
delay_us(1);
gpio_write_high(GPIOC, LCD_E_PIN); // 設定 E 腳為高電位
gpio_write(GPIOC, LCD_D4_PIN | ((cmd >> 4) << 1)); // 將命令的高四位送入 D4-D7 腳
delay_us(1);
gpio_write_low(GPIOC, LCD_E_PIN); // 設定 E 腳為低電位
delay_us(100);
}
void lcd_send_data(uint8_t data)
{
gpio_write_high(GPIOC, LCD_RS_PIN); // 設定 RS 腳為高電位,表示要發送資料
gpio_write_high(GPIOC, LCD_E_PIN); // 設定 E 腳為高電位
gpio_write(GPIOC, LCD_D4_PIN | ((data & 0x0F) << 1)); // 將資料的低四位送入 D4-D7 腳
delay_us(1);
gpio_write_low(GPIOC, LCD_E_PIN); // 設定 E 腳為低電位
delay_us(1);
gpio_write_high(GPIOC, LCD_E_PIN); // 設定 E 腳為高電位
gpio_write(GPIOC, LCD_D4_PIN | ((data >> 4) << 1)); // 將資料的高四位送入 D4-D7 腳
delay_us(1);
gpio_write_low(GPIOC, LCD_E_PIN); // 設定 E 腳為低電位
delay_us(100);
}
void lcd_send_string(char* str)
{
uint8_t i;
for (i = 0; i < strlen(str); i++)
{
lcd_send_data(str[i]);
}
}
void init_dht11()
{
gpio_init(GPIOB, DHT11_PIN, GPIO_MODE_OUT_OD_HIZ_FAST); // 設定 DHT11 腳為輸出模式
gpio_write_high(GPIOB, DHT11_PIN); // 設定 DHT11 腳為高電位
}
void read_dht11(uint8_t* temp, uint8_t* humi)
{
uint8_t i, j, checksum;
uint8_t data[5] = {0, 0, 0, 0, 0};
// 向 DHT11 發送啟動信號
gpio_init(GPIOB, DHT11_PIN, GPIO_MODE_OUT_PP_LOW_FAST); // 設定 DHT11 腳為輸出模式
gpio_write_low(GPIOB, DHT11_PIN); // 設定 DHT11 腳為低電位
delay_ms(18);
gpio_write_high(GPIOB, DHT11_PIN); // 設定 DHT11 腳為高電位
delay_us(1);
gpio_init(GPIOB, DHT11_PIN, GPIO_MODE_IN_FL_NO_IT); // 設定 DHT11 腳為輸入模式
delay_us(40);
// 等待 DHT11 回應
if (gpio_read(GPIOB, DHT11_PIN))
{
// DHT11 沒有回應
return;
}
delay_us(80);
if (!gpio_read(GPIOB, DHT11_PIN))
{
// DHT11 沒有回應
return;
}
delay_us(80);
// 讀取 DHT11 回傳的資料
for (i = 0; i < 5; i++)
{
for (j = 0; j < 8; j++)
{
while (!gpio_read(GPIOB, DHT11_PIN)); // 等待資料腳為高電位
delay_us(30);
if (gpio_read(GPIOB, DHT11_PIN))
{
data[i] |= (1 << (7 - j)); // 記錄資料
}
while (gpio_read(GPIOB, DHT11_PIN)); // 等待資料腳為低電位
}
}
// 驗證資料
checksum = data[0] + data[1] + data[2] + data[3];
if (checksum != data[4])
{
// 資料有誤
return;
}
// 轉換溫度和濕度資料
*humi = data[0];
*temp = data[2];
}
void init_pump()
{
gpio_init(GPIOB, PUMP_PIN, GPIO_MODE_OUT_PP_LOW_FAST); // 設定水泵腳為輸出模式
gpio_write_low(GPIOB, PUMP_PIN); // 設定水泵腳為低電位
}
void start_pump()
{
gpio_write_high(GPIOB, PUMP_PIN); // 設定水泵腳為高電位
}
void stop_pump()
{
gpio_write_low(GPIOB, PUMP_PIN); // 設定水泵腳為低電位
}
void main()
{
uint8_t temp, humi;
char lcd_str[17];
// 初始化硬體
clk_init();
gpio_init(GPIOC,
GPIO_PIN_5, GPIO_MODE_OUT_PP_LOW_FAST); // 設定 LCD RS 腳為輸出模式
gpio_init(GPIOC, GPIO_PIN_4, GPIO_MODE_OUT_PP_LOW_FAST); // 設定 LCD E 腳為輸出模式
gpio_init(GPIOC, GPIO_PIN_3, GPIO_MODE_OUT_PP_LOW_FAST); // 設定 LCD D4 腳為輸出模式
gpio_init(GPIOC, GPIO_PIN_2, GPIO_MODE_OUT_PP_LOW_FAST); // 設定 LCD D5 腳為輸出模式
gpio_init(GPIOC, GPIO_PIN_1, GPIO_MODE_OUT_PP_LOW_FAST); // 設定 LCD D6 腳為輸出模式
gpio_init(GPIOC, GPIO_PIN_0, GPIO_MODE_OUT_PP_LOW_FAST); // 設定 LCD D7 腳為輸出模式
// 初始化 LCD
lcd_init();
// 初始化水泵
init_pump();
while (1)
{
// 讀取溫度和濕度
read_dht11(&temp, &humi);
// 顯示溫度和濕度
sprintf(lcd_str, "Temp: %dC Humi: %d%%", temp, humi);
lcd_gotoxy(0, 0);
lcd_puts(lcd_str);
// 判斷是否需要澆水
if (humi < HUMI_THRESHOLD)
{
start_pump();
delay_ms(WATER_DURATION);
stop_pump();
}
// 等待一段時間再進行下一次操作
delay_ms(5000);
}
}
void lcd_init()
{
lcd_send_cmd(0x28); // 設定LCD為2列、5x8點字
lcd_send_cmd(0x08); // 關閉LCD顯示
lcd_send_cmd(0x01); // 清除LCD顯示內容
lcd_send_cmd(0x06); // 設定LCD文字為向右移動
lcd_send_cmd(0x0C); // 開啟LCD顯示,關閉游標
}
void lcd_send_cmd(uint8_t cmd)
{
gpio_clear(LCD_RS_PORT, LCD_RS_PIN); // 設定RS為0,選擇命令模式
lcd_write_4bit(cmd >> 4); // 傳送高4位元組
lcd_write_4bit(cmd); // 傳送低4位元組
}
void lcd_send_data(uint8_t data)
{
gpio_set(LCD_RS_PORT, LCD_RS_PIN); // 設定RS為1,選擇資料模式
lcd_write_4bit(data >> 4); // 傳送高4位元組
lcd_write_4bit(data); // 傳送低4位元組
}
void lcd_gotoxy(uint8_t x, uint8_t y)
{
uint8_t addr;
// 計算LCD內部地址
if (y == 0)
{
addr = 0x00 + x;
}
else
{
addr = 0x40 + x;
}
// 設定LCD內部地址
lcd_send_cmd(0x80 | addr);
}
void lcd_puts(char *str)
{
while (*str)
{
lcd_send_data(*str++);
}
}
void lcd_write_4bit(uint8_t data)
{
gpio_clear(LCD_E_PORT, LCD_E_PIN); // 設定E為0
if (data & 0x01)
{
gpio_set(LCD_D7_PORT, LCD_D7_PIN);
}
else
{
gpio_clear(LCD_D7_PORT, LCD_D7_PIN);
}
if (data & 0x02)
{
gpio_set(LCD_D6_PORT, LCD_D6_PIN);
}
else
{
gpio_clear(LCD_D6_PORT, LCD_D6_PIN);
}
if (data & 0x04)
{
gpio_set(LCD_D5_PORT, LCD_D5_PIN);
}
else
{
gpio_clear(LCD_D5_PORT, LCD_D5_PIN);
}
if (data & 0x08)
{
gpio_set(LCD_D4_PORT, LCD_D4_PIN);
}
else
{
gpio_clear(LCD_D4_PORT, LCD_D4_PIN);
}
gpio_set(LCD_E_PORT, LCD_E_PIN); // 設定E為1
delay_us(1); // 延遲一段時間
gpio_clear(LCD_E_PORT, LCD_E_PIN); // 設定E為0
delay_us(1); // 延遲一段時間
}
void init_pump()
{
gpio_init(PUMP_PORT, PUMP_PIN, GPIO_MODE_OUT_PP_LOW_FAST); //
}
void water_plants()
{
// 啟動水泵
gpio_set(PUMP_PORT, PUMP_PIN);
// 顯示訊息
lcd_gotoxy(0, 1);
lcd_puts("Watering plants...");
// 延遲一段時間
delay_ms(WATERING_TIME);
// 停止水泵
gpio_clear(PUMP_PORT, PUMP_PIN);
// 顯示訊息
lcd_gotoxy(0, 1);
lcd_puts("Watering done.");
}
void main()
{
// 初始化GPIO
gpio_init(LCD_RS_PORT, LCD_RS_PIN, GPIO_MODE_OUT_PP_LOW_FAST);
gpio_init(LCD_E_PORT, LCD_E_PIN, GPIO_MODE_OUT_PP_LOW_FAST);
gpio_init(LCD_D4_PORT, LCD_D4_PIN, GPIO_MODE_OUT_PP_LOW_FAST);
gpio_init(LCD_D5_PORT, LCD_D5_PIN, GPIO_MODE_OUT_PP_LOW_FAST);
gpio_init(LCD_D6_PORT, LCD_D6_PIN, GPIO_MODE_OUT_PP_LOW_FAST);
gpio_init(LCD_D7_PORT, LCD_D7_PIN, GPIO_MODE_OUT_PP_LOW_FAST);
// 初始化LCD
lcd_init();
// 初始化水泵
init_pump();
while (1)
{
// 讀取濕度感測器數值
uint16_t humidity_value = read_humidity_sensor();
scss
Copy code
// 如果濕度低於設定值,則啟動水泵
if (humidity_value < HUMIDITY_THRESHOLD)
{
water_plants();
}
// 顯示濕度數值
lcd_gotoxy(0, 0);
lcd_puts("Humidity: ");
char str[5];
sprintf(str, "%d", humidity_value);
lcd_puts(str);
// 延遲一段時間
delay_ms(LOOP_DELAY);
}
}
以上就是一個簡單的自動養花灌水系統的程式碼範例,其中使用了STM8S003F3P6微控制器、濕度感測器、LCD顯示屏和水泵等零件。程式流程簡單明瞭,主要分為初始化、讀取濕度、控制水泵和顯示訊息等幾個部分。
在初始化部分,我們設置了LCD和水泵的GPIO引腳模式為輸出並設置初始狀態為低電平,然後調用了lcd_init()函數和init_pump()函數來初始化LCD和水泵。
在主循環部分,我們先讀取濕度感測器的數值,然後判斷是否需要啟動水泵來灌溉花卉,如果濕度低於設定值,則啟動水泵,否則繼續等待。在每次循環結束之前,我們還會顯示濕度數值在LCD上,以便用戶可以實時觀察花卉的濕度情況。
需要注意的是,這只是一個簡單的程式碼範例,實際上還需要考慮到許多其他因素,例如如何校準濕度感測器、如何調整灌溉時間等等。如果您想要製作一個真正可靠的自動養花灌水系統,建議您先進一步學習STM8微控制器和相關的電子知識。 |
|