/*
STC8G1K08水位控制系統
時鐘頻率: 11.0592MHz
編譯環境: Keil C51
*/
#include "STC8G.H"
#include <intrins.h>
#include <stdio.h>
// 引腳定義
sbit ON_KEY = P1^5; // P1.5 開機按鍵
sbit OFF_KEY = P1^6; // P1.6 停止按鍵
sbit RST_KEY = P1^7; // P1.7 復位按鍵
sbit H1_out = P3^2; // 輸出1
sbit H2_out = P3^3; // 輸出2
sbit H3_out = P3^4; // 輸出3
sbit PUMP_out = P3^5; // 水泵輸出
sbit ALARM_out = P3^6; // 報警輸出
sbit LED_jiare = P3^7; // 加熱LED
sbit LED_queshui = P1^3; // 缺水LED
sbit LED_jiashui = P1^4; // 加水LED
sbit LED_stop = P5^4; // 停止LED
sbit LED_yunxin = P5^5; // 運行LED
// 系統狀態
bit system_running = 0; // 系統運行標志
bit adc_running = 0; // ADC采集標志
bit pump_running = 0; // 水泵運行標志
bit alarm_state = 0; // 報警狀態
bit level_state[3] = {0}; // 水位狀態: 0=無水位, 1=有水位
unsigned int adc_value[3]; // ADC采樣值
unsigned int adc_filter[3]; // ADC濾波后值
unsigned char adc_count = 0;// ADC采樣計數
bit send_serial = 0; // 串口發送標志
unsigned int adc_threshold = 1000; // 水位閾值
//int threshold_str; //添加
// 函數聲明
void delay_ms(unsigned int ms);
void GPIO_Init(void);
void Timer0_Init(void);
void Timer1_Init(void);
void ADC_Init(void);
void UART1_Init(void);
void UART1_SendByte(unsigned char dat);
void UART1_SendString(char *str);
unsigned int ADC_Read(unsigned char channel);
void ADC_Start(void);
void System_Control(void);
void Key_Scan(void);
void Output_Control(void);
void UART1_SendADCData(void);
void System_Reset(void);
void All_Output_Low(void);
// 延時函數
void delay_ms(unsigned int ms) {
unsigned int i, j;
for(i = 0; i < ms; i++)
for(j = 0; j < 114; j++);
}
// 初始化所有輸出為低電平
void All_Output_Low(void) {
H1_out = 0;
H2_out = 0;
H3_out = 0;
PUMP_out = 0;
ALARM_out = 0;
LED_jiare = 0;
LED_queshui = 0;
LED_jiashui = 0;
LED_yunxin = 0;
}
// GPIO初始化
void GPIO_Init(void) {
// 按鍵引腳設為高阻輸入
P1M0 &= ~0xE0; // P1.5, P1.6, P1.7
P1M1 |= 0xE0;
// LED引腳設為推挽輸出
P1M0 |= 0x18; // P1.3, P1.4
P1M1 &= ~0x18;
P3M0 |= 0xFC; // P3.2-P3.7
P3M1 &= ~0xFC;
P5M0 |= 0x30; // P5.4, P5.5
P5M1 &= ~0x30;
// ADC引腳設為高阻輸入
P1M0 &= ~0x07; // P1.0, P1.1, P1.2 (ADC0~ADC2)
P1M1 |= 0x07;
// 上電初始狀態
LED_stop = 1; // 停止LED亮
All_Output_Low(); // 其他輸出全低
// 內部上拉
P1 |= 0xE0; // 按鍵上拉
}
// 系統復位
void System_Reset(void) {
system_running = 0;
adc_running = 0;
pump_running = 0;
alarm_state = 0;
// 重置水位狀態
level_state[0] = 0;
level_state[1] = 0;
level_state[2] = 0;
// 復位ADC值
adc_value[0] = 0;
adc_value[1] = 0;
adc_value[2] = 0;
adc_filter[0] = 0;
adc_filter[1] = 0;
adc_filter[2] = 0;
// 輸出控制
LED_stop = 1;
All_Output_Low();
// 發送復位信息
UART1_SendString("System Reset\r\n");
}
// 定時器0初始化(用于按鍵掃描)
void Timer0_Init(void) {
AUXR &= 0x7F; // 定時器時鐘12T模式
TMOD &= 0xF0; // 設置定時器模式
TMOD |= 0x01; // 定時器0模式1
TL0 = 0x00; // 設置定時初值
TH0 = 0xDC; // 11.0592MHz, 10ms中斷
TR0 = 1; // 定時器0開始計時
ET0 = 1; // 使能定時器0中斷
EA = 1; // 開總中斷
}
// 定時器1初始化(用于系統控制)
void Timer1_Init(void) {
AUXR &= 0xBF; // 定時器時鐘12T模式
TMOD &= 0x0F; // 設置定時器模式
TMOD |= 0x10; // 定時器1模式1
TL1 = 0x00; // 設置定時初值
TH1 = 0xDC; // 11.0592MHz, 10ms
TR1 = 1; // 定時器1開始計時
ET1 = 1; // 使能定時器1中斷
}
// ADC初始化
void ADC_Init(void) {
ADCCFG = 0x2F; // 設置ADC時鐘為系統時鐘/16,右對齊
ADC_CONTR = 0x80; // 打開ADC電源
delay_ms(1); // 延時等待ADC穩定
}
// 串口1初始化
void UART1_Init(void) {
// 使用定時器2作為波特率發生器
AUXR &= 0xFB; // 定時器2時鐘為Fosc/12, 即12T
T2L = 0xE0; // 設定定時初值
T2H = 0xFE; // 11.0592MHz, 9600波特率
AUXR |= 0x10; // 定時器2開始計時
S1CON &= ~0x40; // 串口1選擇定時器2為波特率發生器
S1CON |= 0x40; // 允許串口1接收
P_SW1 &= 0x3F; // 串口1切換到P3.0/P3.1
// 設置P3.0和P3.1為推挽輸出
P3M0 |= 0x03;
P3M1 &= ~0x03;
}
// 串口1發送一個字節
void UART1_SendByte(unsigned char dat) {
S1BUF = dat;
while((S1CON & 0x02) == 0); // 等待發送完成
S1CON &= ~0x02; // 清除發送完成標志
}
// 串口1發送字符串
void UART1_SendString(char *str) {
while(*str != '\0') {
UART1_SendByte(*str++);
}
}
// ADC采集
unsigned int ADC_Read(unsigned char channel) {
ADC_CONTR &= 0xF8; // 清除通道選擇
ADC_CONTR |= (channel & 0x07); // 選擇ADC通道
ADC_CONTR |= 0x40; // 啟動ADC轉換
_nop_(); _nop_(); _nop_(); _nop_(); // 等待轉換完成
while(!(ADC_CONTR & 0x20)); // 等待轉換完成
ADC_CONTR &= ~0x20; // 清除轉換完成標志
return (ADC_RES << 8) | ADC_RESL; // 返回12位ADC值
}
// 啟動ADC采集
void ADC_Start(void) {
static unsigned char adc_channel = 0;
unsigned int adc_val;
if(!adc_running) return;
// 采集當前通道
adc_val = ADC_Read(adc_channel);
// 一階低通濾波
adc_filter[adc_channel] = (adc_filter[adc_channel] * 7 + adc_val) / 8;
adc_value[adc_channel] = adc_filter[adc_channel];
// 檢測水位
if(adc_value[adc_channel] > adc_threshold) {
level_state[adc_channel] = 1; // 有水位
} else {
level_state[adc_channel] = 0; // 無水
}
adc_channel++;
if(adc_channel >= 3) {
adc_channel = 0;
adc_count++;
if(adc_count >= 5) { // 采集5輪后發送數據
adc_count = 0;
send_serial = 1; // 設置發送標志
}
}
}
// 按鍵掃描
void Key_Scan(void) {
static bit on_key_pressed = 0;
static bit off_key_pressed = 0;
static bit rst_key_pressed = 0;
static unsigned int on_key_time = 0;
static unsigned int off_key_time = 0;
static unsigned int rst_key_time = 0;
// 開機按鍵檢測
if(!ON_KEY) {
if(!on_key_pressed) {
on_key_pressed = 1;
on_key_time = 0;
} else {
on_key_time++;
if(on_key_time >= 5) { // 50ms去抖
if(on_key_time == 5) { // 首次按下
system_running = 1; // 系統啟動
adc_running = 1; // 啟動ADC采集
LED_stop = 0; // 關閉停止LED
LED_yunxin = 1; // 打開運行LED
// 初始狀態:無水位
ALARM_out = 1; // 報警
LED_queshui = 1; // 缺水指示燈
UART1_SendString("System Started\r\n");
}
}
}
} else {
on_key_pressed = 0;
}
// 停止按鍵檢測
if(!OFF_KEY) {
if(!off_key_pressed) {
off_key_pressed = 1;
off_key_time = 0;
} else {
off_key_time++;
if(off_key_time >= 5) { // 50ms去抖
if(off_key_time == 5) { // 首次按下
LED_stop = 1; // 停止LED亮
All_Output_Low(); // 其他輸出全低
UART1_SendString("System Stopped\r\n");
}
}
}
} else {
off_key_pressed = 0;
}
// 復位按鍵檢測
if(!RST_KEY) {
if(!rst_key_pressed) {
rst_key_pressed = 1;
rst_key_time = 0;
} else {
rst_key_time++;
if(rst_key_time >= 5) { // 50ms去抖
if(rst_key_time == 5) { // 首次按下
System_Reset(); // 系統復位
}
}
}
} else {
rst_key_pressed = 0;
}
}
// 輸出控制邏輯
void Output_Control(void) {
if(!system_running) return;
// 檢查所有水位狀態
if(level_state[0] == 0 && level_state[1] == 0 && level_state[2] == 0) {
// 情況2:所有ADC都沒有檢測到水位
H1_out = 0;
H2_out = 0;
H3_out = 0;
PUMP_out = 0;
LED_jiare = 0;
LED_queshui = 1; // 缺水指示燈亮
LED_jiashui = 0;
ALARM_out = 1; // 報警
}
else if(level_state[0] == 1 && level_state[1] == 0 && level_state[2] == 0) {
// 情況3:只有ADC0檢測到水位
ALARM_out = 0; // 關閉報警
PUMP_out = 1; // 開啟水泵
H1_out = 0;
H2_out = 0;
H3_out = 0;
LED_jiare = 0;
LED_queshui = 0;
LED_jiashui = 1; // 加水指示燈
}
else if(level_state[0] == 1 && level_state[1] == 1) {
// 情況4:ADC0和ADC1檢測到水位
ALARM_out = 0; // 關閉報警
PUMP_out = 1; // 開啟水泵
H1_out = 1; // 輸出高電平
H2_out = 1;
H3_out = 1;
LED_jiare = 1; // 加熱指示燈
LED_queshui = 0;
LED_jiashui = 0;
}
else if(level_state[0] == 1 && level_state[1] == 1 && level_state[2] == 1) {
// 情況5:所有ADC都檢測到水位
ALARM_out = 0; // 關閉報警
PUMP_out = 0; // 關閉水泵
H1_out = 1; // 輸出高電平
H2_out = 1;
H3_out = 1;
LED_jiare = 1; // 加熱指示燈
LED_queshui = 0;
LED_jiashui = 0;
}
else {
// 其他組合狀態
// 可以添加其他邏輯或保持當前狀態
}
}
// 串口發送ADC數據
void UART1_SendADCData(void) {
char buffer[80];
if(!send_serial) return;
// 格式化發送數據
sprintf(buffer, "ADC0:%04u(%s) ADC1:%04u(%s) ADC2:%04u(%s) | OUT:H1=%d H2=%d H3=%d PUMP=%d ALARM=%d\r\n",
adc_value[0], level_state[0] ? "H" : "L",
adc_value[1], level_state[1] ? "H" : "L",
adc_value[2], level_state[2] ? "H" : "L",
H1_out, H2_out, H3_out, PUMP_out, ALARM_out);
UART1_SendString(buffer);
send_serial = 0; // 清除發送標志
}
// 定時器0中斷服務函數(按鍵掃描)
void Timer0_ISR() interrupt 1 {
TL0 = 0x00; // 重裝定時器初值
TH0 = 0xDC;
Key_Scan(); // 掃描按鍵
}
// 定時器1中斷服務函數(主控制)
void Timer1_ISR() interrupt 3 {
static unsigned char timer_count = 0;
TL1 = 0x00; // 重裝定時器初值
TH1 = 0xDC;
timer_count++;
// 20ms任務
if(timer_count % 2 == 0) {
if(system_running) {
ADC_Start(); // 啟動ADC采集
}
}
// 50ms任務
if(timer_count % 5 == 0) {
if(system_running) {
Output_Control(); // 輸出控制
}
}
// 100ms任務
if(timer_count % 10 == 0) {
UART1_SendADCData(); // 串口發送數據
}
// 500ms任務
if(timer_count % 50 == 0) {
if(system_running) {
LED_yunxin = !LED_yunxin; // 運行LED閃爍
}
}
if(timer_count >= 100) { // 1秒周期
timer_count = 0;
}
}
// 主函數
void main(void) {
// 系統初始化
GPIO_Init();
Timer0_Init();
Timer1_Init();
ADC_Init();
UART1_Init();
delay_ms(100); // 延時穩定
// 初始狀態
system_running = 0;
adc_running = 0;
LED_stop = 1; // 停止LED亮
All_Output_Low(); // 其他輸出全低
// 發送啟動信息
UART1_SendString("Water Level Control System Started\r\n");
UART1_SendString("Threshold: ");
// 發送閾值
char threshold_str[10];
sprintf(threshold_str, "%d\r\n", adc_threshold);
UART1_SendString(threshold_str);
// 主循環
while(1) {
// 系統監控
if(!system_running) {
LED_stop = 1; // 確保停止LED亮
}
// 空閑時進入低功耗模式
PCON |= 0x01; // 進入IDLE模式
_nop_();
_nop_();
}
}
|