我在做一个基于51单片机温度传感器的设计,是当测定温度超过设定温度时候,会进入报警模式,但是现在的问题是,进入报警模式蜂鸣器能够正常报警,但是从报警模式退出以后,蜂鸣器持续鸣响,只有摁下任意摁键以后才停止鸣响。以下是我的代码:
#include <reg51.h>
#include <intrins.h>
#define LED P0 // 数码管段码接口
sbit DQ = P3^7; // DS18B20数据线
sbit BEEP = P1^3; // 蜂鸣器报警
sbit ALARM_LED = P2^1; // 灯光报警LED
sbit SHCP = P2^3; // 74HC595移位时钟
sbit STCP = P2^2; // 74HC595锁存时钟
sbit DS = P2^4; // 74HC595数据线
/*========== 步进电机引脚 ==========*/
sbit IN1 = P1^4;
sbit IN2 = P1^5;
sbit IN3 = P1^6;
sbit IN4 = P1^7;
/*========== 按键引脚 ==========*/
sbit KEY1 = P1^0; // 设置模式-调低温度 / 手动-正转
sbit KEY2 = P1^1; // 设置模式-调高温度 / 手动-反转
sbit KEY3 = P1^2; // 进入/退出设置模式
/*========== 数码管段码 ==========*/
unsigned char code dofly_DuanMa[] =
{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff};
unsigned char code dofly_WeiMa[] =
{0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
/*========== 变量区域(新增蜂鸣器控制变量) ==========*/
int temperature = 0;
int set_temperature = 300; // 30.0℃(放大10倍存储,0.5℃对应数值+5)
bit set_mode = 0; // 0=正常模式 1=设置模式
bit alarm_flag = 0;
bit direction = 0; // 0=正转 1=反转
bit motor_manual = 0; // 是否处于手动控制电机模式
unsigned char phase_index = 0;
unsigned char key3_cnt = 0; // KEY3消抖计数
unsigned char key1_cnt = 0; // KEY1消抖计数
unsigned char key2_cnt = 0; // KEY2消抖计数
unsigned char code phase_table[8] =
{0x08,0x0C,0x04,0x06,0x02,0x03,0x01,0x09};
// 新增蜂鸣器控制变量
unsigned int beep_counter = 0; // 蜂鸣器计时计数器
unsigned char beep_interval = 50; // 鸣叫间隔(初始50ms)
#define MIN_BEEP_INTERVAL 5 // 最小间隔(5ms)
#define MAX_BEEP_INTERVAL 50 // 最大间隔(50ms)
unsigned char temp_diff = 0; // 实际温度与设定温度差值(℃)
/*========== 延时函数 ==========*/
void DelayUs2x(unsigned char t){ while(--t); }
void delay_ms(unsigned int ms){ unsigned int i,j;for(i=ms;i>0;i--) for(j=114;j>0;j--);}
/*========== DS18B20 ==========*/
bit Init_DS18B20(void){
bit dat;
DQ = 1; DelayUs2x(5);
DQ = 0; DelayUs2x(200); DelayUs2x(200);
DQ = 1; DelayUs2x(50);
dat = DQ; DelayUs2x(25);
return dat;
}
void WriteOneChar(unsigned char dat){
unsigned char i;
for(i=8;i>0;i--){
DQ = 0; DQ = dat & 0x01;
DelayUs2x(25);
DQ = 1; dat >>= 1;
}
DelayUs2x(25);
}
unsigned char ReadOneChar(void){
unsigned char i,dat=0;
for(i=8;i>0;i--){
DQ = 0; dat >>= 1; DQ = 1;
if(DQ) dat |= 0x80;
DelayUs2x(25);
}
return dat;
}
int ReadTemperature(void){
unsigned char a,b;
int t;
Init_DS18B20(); WriteOneChar(0xCC); WriteOneChar(0x44); delay_ms(10);
Init_DS18B20(); WriteOneChar(0xCC); WriteOneChar(0xBE);
a = ReadOneChar(); b = ReadOneChar();
t = b; t <<= 8; t = t | a;
return (int)(t * 0.625); // 放大10倍,精确到0.1℃
}
/*========== 步进电机驱动 ==========*/
void step_motor_drive(void){
IN1 = (phase_table[phase_index]&0x08)?1:0;
IN2 = (phase_table[phase_index]&0x04)?1:0;
IN3 = (phase_table[phase_index]&0x02)?1:0;
IN4 = (phase_table[phase_index]&0x01)?1:0;
if(direction == 0){
phase_index++;
if(phase_index>=8) phase_index=0;
}
else{
if(phase_index==0) phase_index=7;
else phase_index--;
}
}
/*========== 74HC595 显示函数 ==========*/
void HC595_send(unsigned char dat){
unsigned char i;
for(i=0;i<8;i++){
SHCP=0; DS=dat&0x80; dat<<=1; SHCP=1;
}
STCP=0; _nop_(); STCP=1;
}
void DisplayTemperature(void){
unsigned char temp_buf[4];
int temp_val = set_mode ? set_temperature : temperature;
temp_buf[0] = temp_val/1000; // 千位(温度通常0-99℃,此处用于消隐)
temp_buf[1] = (temp_val%1000)/100; // 百位(十位温度)
temp_buf[2] = (temp_val%100)/10; // 十位(个位温度)
temp_buf[3] = temp_val%10; // 个位(小数位)
// 显示千位(消隐)
LED = (temp_buf[0]==0)? dofly_DuanMa[16]:dofly_DuanMa[temp_buf[0]];
HC595_send(dofly_WeiMa[7]); delay_ms(1); HC595_send(0);
// 显示百位(十位温度)
LED = dofly_DuanMa[temp_buf[1]];
HC595_send(dofly_WeiMa[6]); delay_ms(1); HC595_send(0);
// 显示十位(个位温度,带小数点)
LED = dofly_DuanMa[temp_buf[2]]&0x7F;
HC595_send(dofly_WeiMa[5]); delay_ms(1); HC595_send(0);
// 显示个位(小数位)
LED = dofly_DuanMa[temp_buf[3]];
HC595_send(dofly_WeiMa[4]); delay_ms(1); HC595_send(0);
// 显示℃符号
LED = dofly_DuanMa[12];
HC595_send(dofly_WeiMa[3]); delay_ms(1); HC595_send(0);
}
/*========== 按键处理(核心修改部分) ==========*/
void key_scan(void){
// KEY3:短按进入/退出设置模式(消抖处理)
if(KEY3 == 0){
key3_cnt++;
if(key3_cnt >= 20){ // 约400ms消抖
set_mode = ~set_mode; // 切换设置模式
BEEP = 1; // 进入/退出设置模式时立即关闭蜂鸣器
beep_counter = 0; // 重置蜂鸣器计数器
key3_cnt = 0;
}
}
else key3_cnt = 0;
// 设置模式:按键1调低温度(步长0.5℃),按键2调高温度(步长0.5℃)
if(set_mode == 1){
motor_manual = 0; // 设置模式下禁用手动电机
IN1 = IN2 = IN3 = IN4 = 0; // 停止电机
// KEY1:调低温度(最小10.0℃,防止过低)
if(KEY1 == 0){
key1_cnt++;
if(key1_cnt >= 50){ // 长按约1s触发(防误触)
if(set_temperature >= 100){ // 10.0℃下限
set_temperature -= 5; // 0.5℃步长(对应数值-5)
}
key1_cnt = 0;
}
}
else key1_cnt = 0;
// KEY2:调高温度(最大99.5℃,防止过高)
if(KEY2 == 0){
key2_cnt++;
if(key2_cnt >= 50){ // 长按约1s触发(防误触)
if(set_temperature <= 995){ // 99.5℃上限
set_temperature += 5; // 0.5℃步长(对应数值+5)
}
key2_cnt = 0;
}
}
else key2_cnt = 0;
}
// 正常模式:保持原手动电机控制逻辑
else{
static unsigned int k1=0,k2=0;
// KEY1 长按 → 正转
if(KEY1==0){
k1++;
if(k1 > 10){
direction = 0; // 正转
motor_manual = 1; // 开启手动电机模式
}
}else k1 = 0;
// KEY2 长按 → 反转
if(KEY2==0){
k2++;
if(k2 > 10){
direction = 1; // 反转
motor_manual = 1; // 开启手动电机模式
}
}else k2 = 0;
// 都松开 → 关闭手动模式,停止电机
if(KEY1==1 && KEY2==1){
motor_manual = 0;
IN1 = IN2 = IN3 = IN4 = 0;
}
}
}
/*========== 蜂鸣器控制(与前序代码一致,核心修改) ==========*/
void beep_control_fixed(void) {
// 触发条件:正常模式+实际温度>设定温度
if(set_mode == 0 && temperature > set_temperature) {
alarm_flag = 1;
// 计算实际温度差值(℃,因温度放大10倍存储,需除以10)
temp_diff = (temperature - set_temperature) / 10;
if(temp_diff < 1) temp_diff = 1; // 最小差值1℃,避免间隔为0
// 温度越高,鸣叫间隔越小(50ms~5ms)
beep_interval = MAX_BEEP_INTERVAL - (temp_diff * 2);
if(beep_interval < MIN_BEEP_INTERVAL) {
beep_interval = MIN_BEEP_INTERVAL;
}
// 蜂鸣器脉冲控制(鸣叫=beep_interval ms,停止=beep_interval ms)
beep_counter++;
if(beep_counter <= beep_interval) {
BEEP = 0; // 低电平鸣叫(根据硬件调整,若不响则改为1)
ALARM_LED = 0; // LED同步亮
} else if(beep_counter <= beep_interval * 2) {
BEEP = 1; // 高电平停止
ALARM_LED = 1; // LED同步灭
} else {
beep_counter = 0; // 重置计数器
}
} else {
// 未触发条件:关闭蜂鸣器和LED
alarm_flag = 0;
BEEP = 1;
ALARM_LED = 1;
beep_counter = 0;
}
}
/*========== 主程序(修改报警逻辑为新蜂鸣器控制) ==========*/
void main(void){
unsigned char temp_count = 0;
// 初始化:蜂鸣器和LED默认关闭
BEEP = 1;
ALARM_LED = 1;
IN1 = IN2 = IN3 = IN4 = 0;
while(1){
key_scan(); // 按键扫描(含设置模式逻辑)
// 1秒更新一次温度
if(++temp_count >= 50){
temp_count = 0;
temperature = ReadTemperature(); // 读取温度(100ms一次,50次=5秒?此处保留原逻辑,可按需调整为100次=10秒)
}
beep_control_fixed(); // 调用新蜂鸣器控制函数(替代原Alarm_Process)
// 无报警时才允许手动控制电机
if(!alarm_flag && !set_mode){ // 设置模式下禁用手动电机
if(motor_manual){
step_motor_drive(); // 手动转动
}
else{
IN1 = IN2 = IN3 = IN4 = 0; // 松开按键 → 停止
}
} else if(alarm_flag && !set_mode) {
// 报警时自动控制电机正转
direction = 0;
step_motor_drive();
}
DisplayTemperature();// 显示温度(设置模式显示设定值,正常模式显示实测值)
delay_ms(20);
}
}
请帮我看看什么问题。谢谢大家