|
|

楼主 |
发表于 2025-9-30 20:07:15
|
显示全部楼层
本帖最后由 jf201006 于 2025-9-30 20:22 编辑
以下程序,带有调试的部分没有删除,请自行检查。
这是最小功能版,加减温度、故障检测及蜂鸣、休眠、软关机。
没有温度补偿及更换不同发热头(手柄)后的温度校准。
半桶水,注释已经很详细了,不答疑哈。
- #include <avr/io.h>
- #include <avr/interrupt.h>
- #include <util/delay.h>
- #include <math.h>
- // 数码管段选引脚定义 (共阳极,低电平有效)
- #define SEG_A PB6 // 数码管A段
- #define SEG_B PD0 // 数码管B段
- #define SEG_C PD2 // 数码管C段
- #define SEG_D PD4 // 数码管D段
- #define SEG_E PD5 // 数码管E段
- #define SEG_F PB7 // 数码管F段
- #define SEG_G PD1 // 数码管G段
- #define SEG_DP PD3 // 数码管小数点
- // 数码管位选引脚定义 (共阳极,低电平有效)
- #define DIGIT_1 PC1 // 第一位数字(百位)
- #define DIGIT_2 PC4 // 第二位数字(十位)
- #define DIGIT_3 PC5 // 第三位数字(个位)
- // 按键引脚定义 (上拉输入,低电平表示按下)
- #define KEY_DEC PB3 // K1 - 减温度
- #define KEY_FUNC PB4 // K2 - 功能/快速设置
- #define KEY_INC PB5 // K3 - 加温度
- #define KEY_RST PC2 // S1 - 恢复出厂设置
- // 其他引脚定义
- #define VIB_SENSOR PB0 // 振动传感器输入(高电平有效)
- #define ZERO_CROSS PD6 // 交流过零检测输入
- #define HEATER_CTL PB1 // 加热控制输出(高电平有效)
- #define BUZZER PC0 // 蜂鸣器输出(低电平有效)
- // ADC通道定义
- #define TEMP_ADC 7 // ADC7 - 温度传感器输入
- // 默认参数设置
- #define DEFAULT_TEMP 280 // 默认温度280°C
- #define MIN_TEMP 150 // 最低温度150°C
- #define MAX_TEMP 500 // 最高温度500°C
- #define SLEEP_TEMP 200 // 休眠温度200°C
- // 温度与ADC采样值对应关系(两点校准)
- #define TEMP1 200 // 温度点1
- #define ADC1_MV 530 // 温度点1对应的mV值
- #define TEMP2 350 // 温度点2
- #define ADC2_MV 975 // 温度点2对应的mV值
- // 时间常数定义(ms)
- #define DEBOUNCE_TIME 20 // 按键去抖时间
- #define LONG_PRESS_TIME 500 // 长按时间阈值
- #define DISP_UPDATE_TIME 5 // 显示更新间隔
- #define SLEEP_TIME 600000 // 休眠触发时间(10分钟)
- #define SHUTDOWN_TIME 1800000 // 关机触发时间(30分钟)
- #define ERROR_BEEP_TIME 10000 // 错误提示间隔(10秒)
- #define ZERO_CROSS_DEBOUNCE 500 // 过零检测去抖时间(us)
- // 时间常数(基于10ms过零周期的整数倍)
- #define TEMP_UPDATE_TIME 200 // 温度采样间隔200ms(20×10ms)
- #define PID_UPDATE_TIME 200 // PID计算间隔=采样间隔(同步)
- #define HEAT_SUB_CYCLE 20 // 加热小周期(20个半波=200ms)
- #define HEAT_FULL_CYCLE 100 // 加热大周期(100个半波=1秒)
- // 全局变量:记录当前小周期内已加热的半波数
- volatile uint8_t current_sub_cycle_count = 0;
- volatile uint8_t heat_sub_cycles = 0; // 每个小周期需加热的半波数
- // 过零控制参数
- #define MAX_HEAT_CYCLES 20 // 最大加热周期数(100个半波=1秒)现在用20半波
- #define MIN_HEAT_CYCLES 0 // 最小加热周期数
- // 加热故障检测参数
- #define HEATING_FAULT_TIME 40000 // 加热故障检测时间(40秒)
- #define HEATING_FAULT_DELTA 80 // 加热故障温度差(80°C)
- // 数码管显示字符编码 (共阳极, 低电平有效)
- // 段位顺序:DP G F E D C B A (bit7 ~ bit0)
- const uint8_t seg_pattern[] = {
- // 0 1 2 3 4 5 6 7 8 9
- 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90,
- // E - ' ' S H
- 0x86, 0xBF, 0xFF, 0x92, 0x89
- };
- // 全局变量定义
- volatile uint16_t set_temp = DEFAULT_TEMP; // 设定温度
- volatile uint16_t actual_temp = 0; // 实际温度
- volatile uint16_t befor_sleep_temp = 0; // 进入休眠前的温度
- volatile uint8_t display_value[3] = {0}; // 显示数值缓存
- volatile uint8_t digit_pos = 0; // 当前显示位
- volatile uint8_t heating = 0; // 加热状态(1:加热中)
- volatile uint8_t in_settings = 0; // 设置模式标志
- volatile uint8_t quick_set_index = 0; // 快速设置索引
- volatile uint32_t last_activity_time = 0; // 最后活动时间
- volatile uint32_t sleep_start_time = 0; // 进入休眠时间
- volatile uint8_t sleep_mode = 0; // 休眠模式标志
- volatile uint8_t shutdown_mode = 0; // 关机模式标志
- volatile uint8_t error_state = 0; // 错误状态(0:正常)
- volatile uint32_t error_beep_time = 0; // 错误提示时间
- volatile uint8_t blink_state = 0; // 闪烁状态
- volatile uint32_t last_blink_time = 0; // 最后闪烁时间
- // 加热故障检测变量
- volatile uint32_t heating_fault_start_time = 0; // 开始检测加热故障的时间
- volatile uint8_t heating_fault_detected = 0; // 加热故障检测标志
- // 过零控制变量
- volatile uint8_t zero_cross_detected = 0; // 过零检测标志
- volatile uint32_t last_zero_cross_time = 0; // 最后过零时间
- volatile uint8_t heat_cycles = 0; // 当前加热周期数
- volatile uint8_t required_heat_cycles = 0; // 需要加热的周期数
- // 均匀分布算法变量
- volatile int16_t heat_accumulator = 0; // 加热累加器
- // 快速设置温度值
- const uint16_t quick_set_temps[] = {250, 330, 380};
- // PID控制参数(根据实际调整)
- float Kp = 4.0; // 比例系数 - 提高响应速度 5.0
- float Ki = 0.05; // 积分系数 - 减小稳态误差 0.05
- float Kd = 2.0; // 微分系数 - 抑制超调 2.0
- float integral = 0; // 积分项
- float last_error = 0; // 上一次误差值
- uint32_t last_pid_time = 0; // 上次PID计算时间
- // 按键长按处理变量
- volatile uint8_t key_long_press_active = 0; // 长按激活标志
- volatile uint32_t key_long_press_time = 0; // 长按计时
- volatile uint8_t key_long_press_id = 0; // 长按按键ID
- // 函数声明
- void init_io(void); // IO初始化
- void init_adc(void); // ADC初始化
- void init_timers(void); // 定时器初始化
- void init_ext_int(void); // 外部中断初始化(过零检测)
- void update_display(void); // 更新显示
- void read_temp(void); // 读取温度
- void check_buttons(void); // 检查按键
- void heater_control(void); // 加热控制(过零触发)
- void check_sleep(void); // 检查休眠状态
- void handle_errors(void); // 处理错误状态
- void beep(uint16_t duration, uint16_t frequency); // 蜂鸣控制(时间,频率)
- uint16_t read_adc(uint8_t channel); // 读取ADC的 MV值
- uint16_t mv_to_temp(uint16_t mv); // 将MV值转换为温度值
- void calculate_pid(void); // PID计算
- uint32_t millis(void); // 获取当前时间(ms)
- uint32_t micros(void); // 获取当前时间(us)
- void set_digit(uint8_t digit, uint8_t value, uint8_t dp); // 设置数码管显示
- void handle_long_press(void); // 处理长按按键
- void check_heating_fault(void); // 检查加热故障
- int main(void) {
- // 初始化系统
- init_io(); // IO初始化
- init_adc(); // ADC初始化
- init_timers(); // 定时器初始化
- init_ext_int(); // 外部中断初始化(过零检测)
-
- sei(); // 启用全局中断
-
- // 初始化时间戳
- last_activity_time = millis();
- last_pid_time = millis();
- befor_sleep_temp = DEFAULT_TEMP;
-
- // 主循环
- while(1) {
- check_buttons(); // 检查按键输入
- read_temp(); // 读取温度传感器
- calculate_pid(); // 计算PID输出
- heater_control(); // 加热控制
- check_sleep(); // 检查休眠状态
- handle_errors(); // 处理错误状态
- check_heating_fault(); // 检查加热故障
- update_display(); // 更新数码管显示
-
- _delay_ms(5); // 短延时,降低CPU占用
- }
- }
- // IO初始化函数
- void init_io(void) {
- // 设置数码管段选引脚为输出
- DDRB |= (1 << SEG_A) | (1 << SEG_F) | (1 << HEATER_CTL);
- DDRD |= (1 << SEG_B) | (1 << SEG_C) | (1 << SEG_D) |
- (1 << SEG_E) | (1 << SEG_G) | (1 << SEG_DP);
-
- // 设置数码管位选引脚为输出
- DDRC |= (1 << DIGIT_1) | (1 << DIGIT_2) | (1 << DIGIT_3) | (1 << BUZZER);
-
- // 设置按键引脚为输入,启用上拉电阻
- DDRB &= ~((1 << KEY_DEC) | (1 << KEY_FUNC) | (1 << KEY_INC));
- PORTB |= (1 << KEY_DEC) | (1 << KEY_FUNC) | (1 << KEY_INC);
-
- DDRC &= ~(1 << KEY_RST);
- PORTC |= (1 << KEY_RST);
-
- // 设置振动传感器引脚为输入,启用上拉电阻
- DDRB &= ~(1 << VIB_SENSOR);
- PORTB |= (1 << VIB_SENSOR);
-
- // 设置过零检测引脚为输入
- DDRD &= ~(1 << ZERO_CROSS);
- PORTD |= (1 << ZERO_CROSS); // 启用上拉电阻
-
- // 初始化加热控制引脚(关闭状态)
- PORTB &= ~(1 << HEATER_CTL);
-
- // 初始化蜂鸣器引脚(关闭状态)
- PORTC |= (1 << BUZZER);
-
- // 初始化显示 - 关闭所有数码管
- PORTC &= ~((1 << DIGIT_1) | (1 << DIGIT_2) | (1 << DIGIT_3));
- }
- // ADC初始化函数
- void init_adc(void) {
- // 使用外部AREF作为参考电压,选择ADC7通道,右对齐模式
- ADMUX = (0 << REFS1) | (0 << REFS0) | (0 << ADLAR) | (TEMP_ADC & 0x0F);
-
- // 使能ADC,预分频128(8MHz/128=62.5kHz)
- ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
-
- // 第一次转换丢弃,确保ADC稳定
- ADCSRA |= (1 << ADSC);
- while(ADCSRA & (1 << ADSC));
- }
- // 定时器初始化函数
- void init_timers(void) {
- // 定时器0 用于数码管扫描(CTC模式)
- // 8MHz/64=125kHz,125kHz/100=1.25kHz(0.8ms中断)
- TCCR0A = (1 << WGM01); // CTC模式
- TCCR0B = (1 << CS01) | (1 << CS00); // 64分频
- OCR0A = 100; // 比较匹配值 100计数 = 0.8ms
- TIMSK0 = (1 << OCIE0A); // 启用比较匹配中断
-
- // 定时器1 用于时间计数(1ms分辨率)
- // 8MHz/64=125kHz,125kHz/125=1kHz(1ms中断)
- TCCR1A = 0;
- TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10); // CTC模式,64分频
- OCR1A = 125; // 比较匹配值 125计数 = 1ms
- TIMSK1 = (1 << OCIE1A); // 启用比较匹配中断
- }
- // 外部中断初始化(过零检测)
- void init_ext_int(void) {
- // 使用PCINT22(PD6)用于过零检测
- PCICR |= (1 << PCIE2); // 启用PCINT2组中断(PD0-PD7)
- PCMSK2 |= (1 << PCINT22); // 启用PD6的引脚变化中断
- }
- // 读取ADC值并转换为mV
- uint16_t read_adc(uint8_t channel) {
- // 选择通道,保持参考电压设置不变
- ADMUX = (0 << REFS1) | (0 << REFS0) | (0 << ADLAR) | (channel & 0x0F);
-
- // 开始转换
- ADCSRA |= (1 << ADSC);
-
- // 等待转换完成
- while (ADCSRA & (1 << ADSC));
-
- // 返回10位ADC值转换的mV值
- // 右对齐时,ADC值 = ADCL(低8位) + (ADCH << 8)(高2位)
- return ADC; // ADC寄存器自动拼接ADCL和ADCH(右对齐)
- }
- // 将mV值转换为温度值(线性插值)
- uint16_t mv_to_temp(uint16_t mv) {
- // 已知两点: (ADC1_MV, TEMP1) 和 (ADC2_MV, TEMP2)
- // 线性插值公式: temp = TEMP1 + (mv - ADC1_MV) * (TEMP2-TEMP1)/(ADC2_MV-ADC1_MV)
- uint32_t delta_temp = TEMP2 - TEMP1;
- uint32_t delta_mv = ADC2_MV - ADC1_MV;
- uint16_t temp;
- // 温度低于校准点范围时,线性外推
- if (mv < ADC1_MV) {
- temp = TEMP1 - (uint16_t)(((ADC1_MV - mv) * delta_temp) / delta_mv);
- }
- // 温度高于校准点范围时,线性外推
- else {
- temp = TEMP1 + (uint16_t)(((mv - ADC1_MV) * delta_temp) / delta_mv);
- }
- // 温度范围限制
- if (temp < 0) return 0; // 超过最低显示范围,显示000°C
- if (temp > 999) return 999; // 超过最高显示范围,显示999°C
-
- return temp;
- }
- // 读取温度传感器值
- void read_temp(void) {
- static uint32_t last_temp_read = 0;
- uint32_t current_time = millis();
-
- // 定时读取温度(200ms一次)
- if (current_time - last_temp_read >= TEMP_UPDATE_TIME) {
- last_temp_read = current_time;
-
- // 读取温度传感器的mV值
- uint16_t adc_value = read_adc(TEMP_ADC);
-
- // 计算电压(mV):参考电压2500mV,10位分辨率
- uint32_t voltage = (adc_value * 2500UL) / 1024;
-
- // 检查热耦故障(超过2.2V)
- if(voltage > 2200) {
- error_state = 1; // 1表示热耦故障
- return;
- }
-
- // 转换为温度值
- actual_temp = mv_to_temp(voltage);
- // 调试:如果需要显示电压值,可以取消下面的注释
- // actual_temp = voltage / 10; // 显示电压的前三位数字
- // 温度更新后立即触发PID计算(同步)
- calculate_pid();
- }
- }
- // 检查加热故障
- void check_heating_fault(void) {
- // 错误或关机状态不检测
- if (error_state || shutdown_mode) return;
-
- uint32_t current_time = millis();
-
- // 计算当前温度与设定温度的差值
- int16_t temp_difference = abs(set_temp - actual_temp);
-
- // 温差大于阈值时开始计时
- if (temp_difference > HEATING_FAULT_DELTA) {
- if (heating_fault_start_time == 0) {
- // 第一次检测到温差大于80度,记录开始时间
- heating_fault_start_time = current_time;
- } else {
- // 检查是否持续超过故障检测时间是否持续了40秒
- if (current_time - heating_fault_start_time > HEATING_FAULT_TIME) {
- // 持续40秒温差仍然大于80度,触发加热故障报警
- error_state = 2; // 2表示加热故障
- heating_fault_detected = 1;
- }
- }
- } else {
- // 温差正常(小于80度),重置计时器
- heating_fault_start_time = 0;
- heating_fault_detected = 0;
- }
- }
- // PID控制计算
- void calculate_pid(void) {
- // 错误或关机状态,停止加热
- if (error_state || shutdown_mode) {
- integral = 0;
- last_error = 0; //上一次误差值
- required_heat_cycles = 0;
- return;
- }
-
- // 计算误差
- float error = set_temp - actual_temp;
-
- // 实际温度高于设定温度,停止加热并重置积分
- if (error < 0) {
- required_heat_cycles = 0;
- integral = 0; // 重置积分项,防止积分饱和
- last_error = error;
- return;
- }
-
- // 温差较大时全功率加热,启动时的强加热阶段
- if (error > 100) {
- required_heat_cycles = MAX_HEAT_CYCLES;
- integral = 0;
- last_error = error;
- return;
- }
-
- // 积分项计算(仅误差为正时累加,防止积分饱和)
- if (error > 0) {
- integral += error;
- // 限制积分范围
- if (integral > 500) integral = 500;
- if (integral < -500) integral = -500;
- } else {
- integral = 0; // 当误差为负时重置积分项
- }
- /*
- // 微分项 - 使用实际温度的变化率而不是误差变化
- // 这样可以避免在设定点变化时产生大的微分冲击
- static float last_actual_temp = 0;
- float derivative = (actual_temp - last_actual_temp);
- last_actual_temp = actual_temp;
- */
- // 微分项计算(误差变化率)
- float derivative = (error - last_error);
- last_error = error;
- derivative = -derivative; // 反转符号,抑制超调
-
- // PID输出计算
- float p_term = Kp * error;
- float i_term = Ki * integral;
- float d_term = Kd * derivative;
- float output = p_term + i_term + d_term;
-
- // 限制输出范围
- if (output < 0) output = 0;
- if (output > 100) output = 100;
-
- required_heat_cycles = (uint8_t)output;
- // 计算当前小周期(20半波)的加热数:按比例分配到20个半波中
- // heat_sub_cycles = (required_heat_cycles * HEAT_SUB_CYCLE) / HEAT_FULL_CYCLE;
- required_heat_cycles = (required_heat_cycles * HEAT_SUB_CYCLE) / HEAT_FULL_CYCLE;
- }
- // 加热控制(过零触发)
- void heater_control(void) {
- // 错误或关机状态,停止加热
- if (error_state || shutdown_mode) {
- PORTB &= ~(1 << HEATER_CTL);
- heating = 0;
- return;
- }
-
- // 休眠模式下维持休眠温度
- if (sleep_mode && set_temp != SLEEP_TEMP) {
- set_temp = SLEEP_TEMP;
- }
-
- // 更新加热状,根据实际加热周期数确定
- heating = (required_heat_cycles > 0);
- // 过热保护:实际温度高于设定温度时强制停止加热
- if (actual_temp > set_temp ) {
- required_heat_cycles = MIN_HEAT_CYCLES;
- heating = 0;
- integral = 0; // 重置积分项
- }
-
- // 停止加热时重置故障检测计时器
- if (!heating) {
- heating_fault_start_time = 0; // 停止加热时重置故障检测计时器
- }
- }
- // 处理按键长按
- void handle_long_press(void) {
- if (!key_long_press_active) return;
-
- uint32_t current_time = millis();
-
- // 长按每150ms触发一次
- if (current_time - key_long_press_time > 150) {
- key_long_press_time = current_time;
-
- // 根据不同按键处理
- switch(key_long_press_id) {
- case 0: // K1 - 快速减
- if (set_temp > MIN_TEMP) set_temp--;
- in_settings = 1;
- break;
- case 2: // K3 - 快速加
- if (set_temp < MAX_TEMP) set_temp++;
- in_settings = 1;
- break;
- default: // 其他按键取消长按
- key_long_press_active = 0;
- break;
- }
-
- // 更新活动时间
- last_activity_time = current_time;
- }
- }
- // 检查按键状态
- void check_buttons(void) {
- static uint8_t last_key_state[4] = {1, 1, 1, 1}; // 初始状态(未按下)
- static uint32_t key_press_time[4] = {0, 0, 0, 0}; // 按键按下时间
- uint8_t key_state[4]; // 当前按键状态
-
- handle_long_press(); // 处理长按
-
- // 读取按键状态(1表示按下)
- key_state[0] = (PINB & (1 << KEY_DEC)) ? 0 : 1; // K1 - 减
- key_state[1] = (PINB & (1 << KEY_FUNC)) ? 0 : 1; // K2 - 功能
- key_state[2] = (PINB & (1 << KEY_INC)) ? 0 : 1; // K3 - 加
- key_state[3] = (PINC & (1 << KEY_RST)) ? 0 : 1; // S1 - 复位
-
- // 处理每个按键
- for (uint8_t i = 0; i < 4; i++) {
- // 按键按下(上升沿)
- if (key_state[i] && !last_key_state[i]) {
- key_press_time[i] = millis(); // 记录按下时间
-
- // 唤醒休眠
- if (sleep_mode) {
- sleep_mode = 0;
- set_temp = befor_sleep_temp; // 恢复休眠前温度
- beep(100, 1000); // 提示音
- }
-
- // 更新活动时间
- last_activity_time = millis();
- }
-
- // 按键释放(下降沿)
- if (!key_state[i] && last_key_state[i]) {
- uint32_t press_duration = millis() - key_press_time[i];
-
- // 去抖处理
- if (press_duration > DEBOUNCE_TIME) {
- // 短按处理
- if (press_duration < LONG_PRESS_TIME) {
- switch(i) {
- case 0: // K1 - 减温度
- if (set_temp > MIN_TEMP) set_temp--;
- in_settings = 1;
- break;
- case 1: // K2 - 功能切换
- quick_set_index = (quick_set_index + 1) % 3;
- set_temp = quick_set_temps[quick_set_index];
- in_settings = 1;
- break;
- case 2: // K3 - 加温度
- if (set_temp < MAX_TEMP) set_temp++;
- in_settings = 1;
- break;
- case 3: // S1 - 恢复默认
- set_temp = DEFAULT_TEMP;
- befor_sleep_temp = set_temp;
- break;
- }
- last_activity_time = millis();
- } else { // 长按时,标记长按激活
- key_long_press_active = 1;
- key_long_press_id = i;
- key_long_press_time = millis();
- }
- }
-
- // 释放当前长按的按键
- // (只有当这个按键是当前长按的按键时才取消)
- if (i == key_long_press_id) {
- key_long_press_active = 0;
- }
- }
-
- // 持续按下检测(用于长按触发)
- if (key_state[i] && last_key_state[i]) {
- uint32_t press_duration = millis() - key_press_time[i];
- // 如果按键按下时间超过长按时间,并且还没有激活长按,则激活长按
- if (press_duration > LONG_PRESS_TIME && !key_long_press_active) {
- key_long_press_active = 1;
- key_long_press_id = i;
- key_long_press_time = millis();
- }
- }
-
- last_key_state[i] = key_state[i]; // 更新按键状态
- }
-
- // 设置模式1秒后自动退出
- if (in_settings && (millis() - last_activity_time > 1000)) {
- in_settings = 0;
- befor_sleep_temp = set_temp; // 保存设置
- }
- }
- // 检查休眠和关机状态
- void check_sleep(void) {
- uint32_t current_time = millis();
-
- // 检测振动传感器(唤醒功能)
- static uint8_t last_vib_state = 1;
- uint8_t vib_state = (PINB & (1 << VIB_SENSOR)) ? 0 : 1;
-
- if (vib_state && !last_vib_state) { // 检测到振动
- last_activity_time = current_time;
-
- // 唤醒休眠
- if (sleep_mode) {
- sleep_mode = 0;
- set_temp = befor_sleep_temp; // 恢复温度设置
- beep(100, 1000); // 提示音
- }
- }
- last_vib_state = vib_state;
-
- // 检查进入休眠
- if (!sleep_mode && !shutdown_mode && !error_state) {
- if (current_time - last_activity_time > SLEEP_TIME) {
- sleep_mode = 1;
- sleep_start_time = current_time;
- befor_sleep_temp = set_temp; // 保存当前温度
- set_temp = SLEEP_TEMP; // 切换到休眠温度
- }
- }
-
- // 检查进入关机
- if (sleep_mode && !shutdown_mode && !error_state) {
- if (current_time - sleep_start_time > SHUTDOWN_TIME) {
- shutdown_mode = 1;
- }
- }
- }
- // 错误状态处理
- void handle_errors(void) {
- if (!error_state) return;
-
- uint32_t current_time = millis();
-
- // 定时蜂鸣提,10秒
- if (current_time - error_beep_time > ERROR_BEEP_TIME) {
- error_beep_time = current_time;
- beep(600, 1500); // 错误提示音
- }
-
- // 错误状态下停止加热
- required_heat_cycles = 0;
- heating = 0;
- PORTB &= ~(1 << HEATER_CTL);
- }
- // 蜂鸣器控制
- void beep(uint16_t duration, uint16_t frequency) {
- if (frequency == 0) return; // 避免除零错误
-
- // 计算周期和半周期
- uint32_t period_us = 1000000UL / frequency;
- uint32_t half_period_us = period_us / 2;
-
- uint32_t start_time = micros();
- uint32_t end_time = start_time + (uint32_t)duration * 1000UL; // 总时长(us)
- uint8_t buzzer_state = 0; // 蜂鸣器状态:0为关,1为开
- uint32_t last_toggle_time = start_time;
-
- // 生成指定频率的方波
- while (micros() < end_time) {
- uint32_t current_time = micros();
- // 到达翻转时间时切换蜂鸣器状态
- if (current_time - last_toggle_time >= half_period_us) {
- if (buzzer_state) {
- PORTC |= (1 << BUZZER); // 蜂鸣器关
- } else {
- PORTC &= ~(1 << BUZZER); // 蜂鸣器开
- }
- buzzer_state = !buzzer_state;
- last_toggle_time = current_time;
- }
- }
-
- // 确保蜂鸣器最终关闭
- PORTC |= (1 << BUZZER);
- }
- // 设置数码管显示
- void set_digit(uint8_t digit, uint8_t value, uint8_t dp) {
- // 关闭所有位选
- PORTC &= ~((1 << DIGIT_1) | (1 << DIGIT_2) | (1 << DIGIT_3));
-
- // 获取段选码
- uint8_t pattern = seg_pattern[value];
-
- // 设置段选信号(低电平有效)
- if(!(pattern & 0x01)) PORTB &= ~(1 << SEG_A); else PORTB |= (1 << SEG_A);
- if(!(pattern & 0x02)) PORTD &= ~(1 << SEG_B); else PORTD |= (1 << SEG_B);
- if(!(pattern & 0x04)) PORTD &= ~(1 << SEG_C); else PORTD |= (1 << SEG_C);
- if(!(pattern & 0x08)) PORTD &= ~(1 << SEG_D); else PORTD |= (1 << SEG_D);
- if(!(pattern & 0x10)) PORTD &= ~(1 << SEG_E); else PORTD |= (1 << SEG_E);
- if(!(pattern & 0x20)) PORTB &= ~(1 << SEG_F); else PORTB |= (1 << SEG_F);
- if(!(pattern & 0x40)) PORTD &= ~(1 << SEG_G); else PORTD |= (1 << SEG_G);
-
- // 控制小数点
- if (dp) {
- PORTD &= ~(1 << SEG_DP); // 点亮小数点
- } else {
- PORTD |= (1 << SEG_DP); // 关闭小数点
- }
-
- // 开启当前位选
- switch(digit) {
- case 0: PORTC |= (1 << DIGIT_1); break;
- case 1: PORTC |= (1 << DIGIT_2); break;
- case 2: PORTC |= (1 << DIGIT_3); break;
- }
- }
- // 更新数码管显示
- void update_display(void) {
- static uint32_t last_display_update = 0;
- static uint32_t last_blink_update = 0;
- static uint32_t last_temp_update = 0;
- uint32_t current_time = millis();
-
- // 显示温度值更新频率(每秒2-3次)
- if (current_time - last_temp_update >= 400) { // 400ms = 2.5次/秒
- last_temp_update = current_time;
- // 确定显示温度(设置模式显示设定值,否则显示实际值)
- uint16_t display_temp = in_settings ? set_temp : actual_temp;
- // 分解各位数字
- display_value[0] = display_temp / 100; // 百位
- display_value[1] = (display_temp / 10) % 10; // 十位
- display_value[2] = display_temp % 10; // 个位
- }
- // 显示更新频率控制(减少闪烁)
- if (current_time - last_display_update < DISP_UPDATE_TIME) {
- return;
- }
- last_display_update = current_time;
-
- // 错误状态显示
- if (error_state) {
- if (digit_pos == 0) {
- // 显示"S"(传感器故障)或"H"(加热故障)
- set_digit(0, (error_state == 1) ? 13 : 14, 0);
- } else if (digit_pos == 1) {
- set_digit(1, 11, 0); // 显示"-"
- } else {
- set_digit(2, 10, 0); // 显示"E"
- }
- digit_pos = (digit_pos + 1) % 3;
- return;
- }
-
- // 关机模式关闭显示
- if (shutdown_mode) { // 关闭所有显示
- PORTC &= ~((1 << DIGIT_1) | (1 << DIGIT_2) | (1 << DIGIT_3));
- return;
- }
-
- // 休眠模式闪烁控制
- if (sleep_mode) {
- static uint32_t last_blink_update = 0;
- if (current_time - last_blink_update > 500) { // 500ms闪烁周期
- last_blink_update = current_time;
- blink_state = !blink_state;
- }
- if (!blink_state) { // 闪烁关闭阶段
- PORTC &= ~((1 << DIGIT_1) | (1 << DIGIT_2) | (1 << DIGIT_3));
- return;
- }
- }
-
- // 正常显示(个位小数点表示加热状态)
- uint8_t dp = (digit_pos == 2 && heating) ? 1 : 0;
- set_digit(digit_pos, display_value[digit_pos], dp); // 显示当前位
- digit_pos = (digit_pos + 1) % 3; // 切换到下一位
- }
- // 过零检测中断服务程序
- ISR(PCINT2_vect) {
- // 检查PD6引脚状态变化(过零检测)
- static uint8_t last_pd6_state = 0;
- uint8_t current_pd6_state = PIND & (1 << ZERO_CROSS);
-
- // 仅处理状态变化的情况
- if (current_pd6_state == last_pd6_state) return;
- last_pd6_state = current_pd6_state;
-
- uint32_t current_time = micros();
- // 过零检测去抖(避免高频干扰)
- if (current_time - last_zero_cross_time < ZERO_CROSS_DEBOUNCE) return;
- last_zero_cross_time = current_time;
- // 如果要求加热周期数为0,直接返回
- if (required_heat_cycles == 0) {
- heat_accumulator = 0; // 重置累加器
- return;
- }
-
- // 均匀分布算法控制加热
- // 累加器算法:每次过零时累加所需加热功率
- heat_accumulator += required_heat_cycles;
- // 当累加器达到或超过20时,触发加热并减去20
- if (heat_accumulator >= 20) {
- heat_accumulator -= 20;
- // 触发加热(输出200us脉冲)
- PORTB |= (1 << HEATER_CTL);
- _delay_us(200); // 触发脉冲宽度
- PORTB &= ~(1 << HEATER_CTL);
- }
- /* // 小周期计数逻辑(20个半波=200ms,与采样/PID周期对齐)
- current_sub_cycle_count++;
- if (current_sub_cycle_count >= HEAT_SUB_CYCLE) {
- current_sub_cycle_count = 0; // 小周期结束,重置计数
- }
- // 加热控制逻辑(基于小周期内的分配)
- if (error_state || shutdown_mode || sleep_mode) {
- // 异常状态下禁止加热
- PORTB &= ~(1 << HEATER_CTL);
- heat_accumulator = 0;
- return;
- }
- // 当需要加热时,在小周期内的前N个半波触发加热
- if (current_sub_cycle_count < heat_sub_cycles) {
- PORTB |= (1 << HEATER_CTL); // 触发加热
- _delay_us(200); // 保持触发信号(根据继电器特性调整)
- PORTB &= ~(1 << HEATER_CTL); // 关闭加热触发
- } else {
- PORTB &= ~(1 << HEATER_CTL); // 本半波不加热
- }
- */
- }
- // 定时器0中断服务程序 - 数码管扫描
- ISR(TIMER0_COMPA_vect) {
- update_display(); // 定时刷新显示
- }
- // 定时器1中断服务程序 - 时间计数
- volatile uint32_t timer1_millis = 0;
- volatile uint32_t timer1_micros = 0;
- ISR(TIMER1_COMPA_vect) {
- timer1_millis++; // 毫秒计数
- timer1_micros += 1000; // 微秒计数
- }
- // 获取当前时间(ms)
- uint32_t millis(void) {
- uint32_t m;
- cli(); // 关中断防止计数被修改
- m = timer1_millis;
- sei(); // 开中断
- return m;
- }
- // 获取当前时间(us)
- uint32_t micros(void) {
- uint32_t m;
- cli(); // 关中断防止计数被修改
- m = timer1_micros;
- sei(); // 开中断
- return m;
- }
复制代码 谢谢观赏!
双节同辉,家和国盛!
祝各位坛友及数码之家的全体工作人员双节快乐!
|
打赏
-
查看全部打赏
|