- 打卡等级:常住居民III
- 打卡总天数:137
- 最近打卡:2025-05-01 00:01:04
金牌会员
- 积分
- 1108
|
发表于 2025-3-3 20:19:18
|
显示全部楼层
[code]/*Keil 软件“设置”--- “Editor”,在 “Encoding” 下拉框中选择 “Chinese-GB2312” */
#include <STC8H.h>
#define FLOW_SENSOR_PIN P32 //流量传感器P3.2 INTE0
#define IN_NTC_PIN P10 // 进水 NTCP1.0
#define OUT_NTC_PIN P11 // 出水 NTCP1.1
#define HEATING_CTRL_PIN P33 // PWM 信号控制加热设备的功率
#define UP_KEY_PIN P34 // 按键+
#define DOWN_KEY_PIN P35 // 按键-
#define DIG1_PIN P20 //位选1
#define DIG2_PIN P21 //位选2
unsigned int flow_count = 0; // 水流量脉冲计数
float in_temp = 0.0; // 进水温度
float out_temp = 0.0; // 出水温度
bit heating_flag = 0; // 加热标志 1加热 0停止加热
float set_temp = 40.0; // 预设定出水温度
unsigned int timer0_count = 0; // 定时器 0 计数变量
unsigned int show_set_temp_timer = 0; // 显示设定温度的时间变量
bit show_set_temp_flag = 0; // 显示设定温度标志位 1设定温度 0出水温度
bit flow_detected = 0; // 水流检测标志位 1 检测到水流 0未检测到水流
unsigned int pwm_duty = 0; // PWM 占空比0 - 100加热设备功率调节
unsigned int pwm_period = 100; // PWM 周期,确定 PWM 信号一个周期时长
unsigned int initial_full_heat_timer = 0; // 初始全功率加热计时
bit is_initial_full_heat = 1; //全功率加热标志位 1 加热 0 结束
// 数码管段码表(共阳极)
unsigned char SEG_CODE[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90};
#define SPECIFIC_HEAT_WATER 4200 // 水的比热容(J/(kg·℃))
#define HEATING_POWER 3000 //最高加热功率3000W
void ADC_Init() // ADC 初始化函数
{
ADC_CONTR = 0x80; // 使能 ADC 电源
while (timer0_count < 1); // 延时 1ms等待 ADC 电源稳定
timer0_count = 0; //将定时器 0 计数变量清零
ADC_CONTR |= 0x08; // 启动 ADC 转换 8 分频
}
unsigned int Read_ADC(unsigned char channel) // 读取 ADC 值函数
{
ADC_CONTR &= 0xF0; // 清除通道选择位
ADC_CONTR |= channel; // 设置要转换的通道
ADC_CONTR |= 0x40; // 启动 ADC 转换
while (!(ADC_CONTR & 0x20)); // 等待转换完成
ADC_CONTR &= ~0x20; //清除转换完成标志
return (ADC_RES << 2) | (ADC_RESL & 0x03); // 返回 10 位 ADC 值
}
float ntc_to_temp(unsigned int adc_value) // NTC 温度转换函数
{
// 根据 ADC 值计算对应的电压值,假设参考电压为 5V
float voltage = (float)adc_value * 5.0 / 1023.0;
// 根据电压值计算 NTC 热敏电阻的阻值,假设上拉电阻为 10K
float resistance = (5.0 - voltage) * 10000 / voltage;
// 通过简单的线性关系将电阻值转换为温度值,实际应用中需校准
float temperature = (resistance - 10000) / 38.5;
return temperature;
}
void EX0_Init() // 外部中断 0 初始化函数
{
IT0 = 1; // 设置外部中断 0 为下降沿触发
EX0 = 1; // 使能外部中断 0
EA = 1; // 全局中断使能
}
void EX0_ISR() interrupt 0 // 外部中断 0 服务函数
{
flow_count++; // 水流量脉冲计数加 1
flow_detected = 1; // 水流检测标志位置 1
}
bit Key_Debounce(bit key_pin) // 按键检测函数
{
if (!key_pin) // 检测按键是否按下
{
while (timer0_count < 10); // 消抖延时 10ms
timer0_count = 0; //将定时器0计数变量清零
if (!key_pin) // 再次检测按键是否仍然按下
{
while (!key_pin); // 等待按键释放
return 1; // 按键操作有效,返回 1
}
}
return 0; // 按键操作无效,返回 0
}
unsigned int calculate_pwm_duty() // 计算所需 PWM 占空比函数
{
// 假设水流量传感器每脉冲代表的水体积(L),需根据实际传感器校准
float water_volume_per_pulse = 0.01;
// 计算水流量(kg/s),假设水的密度为 1kg/L
float water_flow_rate = flow_count * water_volume_per_pulse;
// 计算温度差,即设定温度与进水温度的差值
float temp_diff = set_temp - in_temp;
// 计算所需加热功率(W),根据比热容公式计算
float required_power = water_flow_rate * SPECIFIC_HEAT_WATER * temp_diff;
// 计算 PWM 占空比,根据所需功率与设定加热功率的比例计算
unsigned int duty = (unsigned int)((required_power / HEATING_POWER) * 100);
// 确保占空比不超过 100
if (duty > 100)
{
duty = 100;
}
return duty;
}
void Heating_Control() // 加热控制函数
{
if (flow_detected)
{
// 计算设定温度与进水温度的差值
float temp_diff = set_temp - in_temp;
// 假设水流量传感器每脉冲代表的水体积(L),需根据实际传感器校准
float water_volume_per_pulse = 0.01;
// 计算水流量(kg/s),假设水的密度为 1kg/L
float water_flow_rate = flow_count * water_volume_per_pulse;
unsigned int full_heat_time;
// 根据水流量和温差动态调整初始全功率加热时间
if (water_flow_rate > 0.5 && temp_diff > 10) {
// 流量大且温差大,将初始全功率加热时间延长到 3 秒
full_heat_time = 3000;
} else if (water_flow_rate < 0.1 && temp_diff < 5) {
// 流量小且温差小,将初始全功率加热时间缩短到 1 秒
full_heat_time = 1000;
} else {
// 其他情况,保持初始全功率加热时间为 2 秒
full_heat_time = 2000;
}
if (is_initial_full_heat) {
// 处于初始全功率加热阶段,PWM 占空比设为 100%
pwm_duty = 100;
// 初始全功率加热计时加 1
initial_full_heat_timer++;
if (initial_full_heat_timer >= full_heat_time) {
// 达到设定的初始全功率加热时间
// 结束初始全功率加热阶段
is_initial_full_heat = 0;
// 初始全功率加热计时清零
initial_full_heat_timer = 0;
// 根据计算结果设置 PWM 占空比
pwm_duty = calculate_pwm_duty();
}
} else {
// 已结束初始全功率加热阶段,根据计算结果设置 PWM 占空比
pwm_duty = calculate_pwm_duty();
}
// 开启加热标志
heating_flag = 1;
}
else
{
pwm_duty = 0; // 未检测到水流,PWM 占空比设为 0
heating_flag = 0; // 关闭加热标志
is_initial_full_heat = 1; // 下次有水流时重新进入初始全功率加热阶段
initial_full_heat_timer = 0; // 初始全功率加热计时清零
}
}
// 数码管显示函数,在数码管上显示指定的温度值
void Display_Temperature(float temp)
{
// 定义两个变量,用于存储温度值的十位和个位数字
unsigned char digit1, digit2;
// 将温度值转换为整数
int temp_int = (int)temp;
// 提取温度值的十位数字
digit1 = temp_int / 10;
// 提取温度值的个位数字
digit2 = temp_int % 10;
// 显示第一位
// 选中数码管的第一位
DIG1_PIN = 0;
// 取消选中数码管的第二位
DIG2_PIN = 1;
// 将十位数字对应的段码输出到数码管
P0 = SEG_CODE[digit1];
// 延时 5ms,确保数码管显示稳定
while (timer0_count < 5);
// 延时结束后,将定时器 0 计数变量清零,为下一次计时做准备
timer0_count = 0;
// 显示第二位
// 取消选中数码管的第一位
DIG1_PIN = 1;
// 选中数码管的第二位
DIG2_PIN = 0;
// 将个位数字对应的段码输出到数码管
P0 = SEG_CODE[digit2];
// 延时 5ms,确保数码管显示稳定
while (timer0_count < 5);
// 延时结束后,将定时器 0 计数变量清零,为下一次计时做准备
timer0_count = 0;
}
void Timer0_Init() // 定时器 0 初始化函数
{
TMOD &= 0xF0; // 清除定时器 0 模式位,不受之前的影响
TMOD |= 0x01; // 设置定时器 0 为模式 1(16 位定时器)
TH0 = (65536 - 1000) / 256; // 设置定时器 0 的初值,使其定时 1ms
TL0 = (65536 - 1000) % 256;
ET0 = 1; // 使能定时器 0 中断
TR0 = 1; // 启动定时器 0
}
void Timer1_Init() // 定时器 1 初始化函数
{
TMOD &= 0x0F; // 清除定时器 1 模式位,不受之前的影响
TMOD |= 0x10; // 设置定时器 为模式 1(16 位定时器)
TH1 = (65536 - 100) / 256; // 设置定时器 1 的初值,使其定时 100us
TL1 = (65536 - 100) % 256;
ET1 = 1; // 使能定时器 1 中断
TR1 = 1; // 启动定时器 1
}
void main()
{
unsigned int in_adc_value, out_adc_value; //进水和出水的 ADC 值
Timer0_Init(); // 调用定时器 0 初始化函数
Timer1_Init(); //定时器 1 初始化函数,产生 PWM 信号来控制加热设备的功率
ADC_Init(); //ADC 初始化函数
EX0_Init(); //外部中断 0 初始化函数,够响应水流量传感器的脉冲信号
HEATING_CTRL_PIN = 0; //将加热控制引脚置为低电平
while (1)
{
if (flow_count == 0) // 检查水流量脉冲计数是否为 0
{
flow_detected = 0; //将水流检测标志置为 0
}
in_adc_value = Read_ADC(0); //读取进水 NTC的adc值
in_temp = ntc_to_temp(in_adc_value); //进水温度值存入 in_temp 变量中
out_adc_value = Read_ADC(1); //读取出水 NTC的 AD值
out_temp = ntc_to_temp(out_adc_value); //出水温度值存入 out_temp 变量中
if (Key_Debounce(UP_KEY_PIN)) // 检测温度调节按键“+”是否被按下
{
if (set_temp < 50) //当前设定温度小于 50°C
{
set_temp += 1; // 将设定温度加 1°C
show_set_temp_flag = 1; // 显示设定温度的标志位置 1(显示设定温度)
show_set_temp_timer = 0; // 将显示设定温度的计时变量清零,重新开始计时
}
}
if (Key_Debounce(DOWN_KEY_PIN)) // 检测温度调节按键“-”是否被按下
{
if (set_temp > 10) //当前设定温度大于 10°C
{
set_temp -= 1; // 将设定温度减 1°C
show_set_temp_flag = 1; // 显示设定温度的标志位置 1(显示设定温度)
show_set_temp_timer = 0; // 将显示设定温度的计时变量清零,重新开始计时
}
}
Heating_Control(); //调用加热控制函数
if (show_set_temp_flag) // 如果显示设定温度的标志位为 1
{
Display_Temperature(set_temp); //在数码管上显示设定温度
}
else // 如果显示设定温度的标志位为 0
{
Display_Temperature(out_temp); //数码管上显示出水温度
}
while (timer0_count < 10); // 等待定时器 0 计数达到 10,实现 10ms 的延时
timer0_count = 0; //将定时器 0 计数变量清零
}
}
void Timer0_ISR() interrupt 1 // 定时器 0 中断服务函数
{
TH0 = (65536 - 1000) / 256;
TL0 = (65536 - 1000) % 256;
timer0_count++; // 定时器 0 计数变量加 1
if (show_set_temp_flag) // 显示设定温度标志位 1设定温度
{
show_set_temp_timer++; // 显示设定温度的计时变量加 1
if (show_set_temp_timer >= 5000) // 显示设定温度的时间达到 5 秒
{
show_set_temp_flag = 0; // 关闭显示设定温度的标志
show_set_temp_timer = 0; // 显示设定温度的计时变量清零
}
}
}
void Timer1_ISR() interrupt 3 // 定时器 1 中断服务函数,产生 PWM 信号
{
static unsigned int pwm_counter = 0; // 静态变量,用于记录 PWM 信号的计数值
TH1 = (65536 - 100) / 256;
TL1 = (65536 - 100) % 256;
pwm_counter++; // PWM 计数值加 1
if (pwm_counter < pwm_duty)
{
HEATING_CTRL_PIN = 1; // 在占空比范围内,输出高电平
}
else
{
HEATING_CTRL_PIN = 0; // 超出占空比范围,输出低电平
}
if (pwm_counter >= pwm_period) // 达到 PWM 周期,
{
pwm_counter = 0; // PWM 计数值清零,开始下一个周期
}
}
噢 原来是这样啊,会了,插入代码才行啊。 |
|