/*
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_();
}
}
|