8H1K08 初始化了按键引脚电平 按键连接引脚对地 长按之后 松开结果按键引脚 | 已解决
这是代码 按键长按 进入状态3代码明明没有把按键拉低赋值的操作 为什么按键松开之后按键还是低电平 我尝试过镊子短接代替按键拿开镊子后自己变成了低电平 这种异常现象 只有长按才会出现包括镊子短接也是需要一定时间 准双向和推挽都试过还是这样最后还是在状态3里面加了一个拉高操作才解决这个问题 但是不知道具体原因 代码也初始化了按键引脚高电平 并且没有拉低操作的代码#include <STC8H.h>
#include "choosegrade.h"
#include "adc.h"
#include <intrins.h>
#include "print.h"
#include "ntc.h"
#include "ledflicker.h"
#include "pwm.h"
#include "pid.h"
#define LEDP35
#define key_down P32
#define FAN P13
#define targettemp 10.0f
// 全局变量定义
unsigned char xdata key_state = 0; // 按键状态:0-空闲,1-按下消抖,2-按下稳定,3-释放消抖
unsigned int xdata press_time = 0; // 按下时间计数(20ms/单位)
unsigned char xdata click_count = 0; // 单击次数计数
unsigned int xdata click_delay = 0; // 双击延迟计数
char xdata off = 0;
int xdata key=0; // 长按标志
float xdata l_temp=0;
float xdata r_temp=0;
char xdata v=0;
float xdata vin;
char xdata grade=0;
char xdata tc=0;
char xdata gradeChage=0;
void temp();
static void Delay1ms(unsigned int t) //@24.000MHz
{
while (t--)
{
unsigned char data i, j;
i = 24;
j = 85;
do
{
while (--j);
} while (--i);
}
}
void Timer0_Isr(void) interrupt 1
{
// 按键状态机
switch(key_state)
{
case 0:// 空闲状态
if(!key_down)// 检测到按键按下(低电平)
{
key_state = 1;// 进入按下消抖状态
press_time = 0; // 重置按下时间
}
break;
case 1:// 按下消抖状态
if(!key_down)// 连续20ms检测到按下
{
key_state = 2;// 进入按下稳定状态
press_time = 1; // 开始计时
}
else
{
key_state = 0;// 抖动干扰,返回空闲状态
}
break;
case 2:// 按下稳定状态
if(key_down)// 检测到按键释放(高电平)
{
key_state = 3;// 进入释放消抖状态
}
else
{
press_time++;// 持续按下,累加时间
if(press_time >= 50)// 长按检测(50*20ms=1000ms)
{
key = 3; // 标记长按事件
key_state = 0; // 返回空闲状态
click_count = 0;// 重置单击计数
}
}
break;
case 3:// 释放消抖状态
if(key_down)// 连续20ms检测到释放
{
if((press_time < 40))// 短按(非长按)
{
click_count++;// 单击计数+1
if(click_count == 1)
{
click_delay = 0;// 开始双击计时
}
else if(click_count == 2)
{
key = 2;// 标记双击事件
click_count = 0; // 重置单击计数
}
}
key_state = 0;// 返回空闲状态
}
else
{
key_state = 2;// 释放抖动,返回按下稳定状态
}
break;
}
// 双击超时检测
if(click_count == 1)
{
click_delay++;
if(click_delay >= 15)// 双击超时(15*20ms=300ms)
{
key = 1;// 标记单击事件
tc = 0;//温控标志
click_count = 0; // 重置单击计数
}
}
print("key:%d\r\n",key);
}
// void Timer2_Isr(void) interrupt 12
// {
// x--;
//if (x==0)
//{
// x=5;
// gradeChage=0;
// AUXR &= ~0x10; //定时器2关闭计时
// T2L = 0xFC; //设置定时初始值
// T2H = 0x03; //设置定时初始值
//}
// }
// void Timer2_Init(void) //1秒@24.000MHz
// {
//TM2PS = 0x1E; //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
//AUXR &= 0xFB; //定时器时钟12T模式
//T2L = 0xFC; //设置定时初始值
//T2H = 0x03; //设置定时初始值
//AUXR |= 0x10; //定时器2开始计时
//IE2 |= 0x04; //使能定时器2中断
// }
void Uart1_Init(void) //115200bps@24.000MHz
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x40; //定时器时钟1T模式
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //设置定时器模式
TL1 = 0xCC; //设置定时初始值
TH1 = 0xFF; //设置定时初始值
ET1 = 0; //禁止定时器中断
TR1 = 1; //定时器1开始计时
ES = 1; //使能串口1中断
// EA = 1; //使能总中断
}
//定时器0
void Timer0_Init(void) //20毫秒@24.000MHz 按键扫描
{
TM0PS = 0x00; //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xC0; //设置定时初始值
TH0 = 0x63; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
EA = 1; //使能总中断
}
void temp()
{ float vl;
vl=adc('l',3.3);
l_temp=ntc((vl)/((3.3-vl)/10000.0f));
vl=adc('r',3.3);
r_temp=ntc((vl)/((3.3-vl)/10000.0f));
}
void voltage()
{
float x;
// float vin;
x=adc('v',3.3);
vin=13000.0f*(x/3000.0f);
if (vin>10 && vin < 14)
{
v = 1;
}
else{
v = 0;
}
}
// void tempControl()
// {
///*每次档位变换需要留一定的时间做观察 直到温度完全到达上限并且占空比到达100%再开始判断*/
//if (((targettemp-(l_temp))<-5) && output ==100.0f && gradeChage==0)//欠调判断
//{
// if (grade == 1)
// {
// grade = 2;
// gradeChage = 1;
// AUXR |= 0x10; //定时器2开始计时
// }
// else if(grade == 2)
// {
// grade = 3;
// gradeChage = 1;
// AUXR |= 0x10; //定时器2开始计时
// }
// else if(grade ==3)
// {
// gradeChage = 1;
// AUXR |= 0x10; //定时器2开始计时
// }
// choosegrade(grade);
// pwm(100);
//}
// else if (((targettemp-(l_temp))>5) && output == 30.0f)//超调判断
// {
//if (grade == 1)
//{
// gradeChage = 1;
// AUXR |= 0x10; //定时器2开始计时
//}
//else if(grade == 2)
//{
// grade = 1;
// gradeChage = 1;
// AUXR |= 0x10; //定时器2开始计时
//}
//else if(grade ==3)
//{
// grade = 2;
// gradeChage = 1;
// AUXR |= 0x10; //定时器2开始计时
//}
//choosegrade(grade);
// }
// if(gradeChage ==1 ) {
//PID_Control(targettemp,l_temp);
// }
// print("占空比:%f",output);
// print("冷端温度:%f",l_temp);
// print("targettemp-l_temp=%f",targettemp-(l_temp));
// }
void wdtInit()
{
WDT_CONTR = 0X27;
}
void main()
{
P_SW2 = 0x80;
P1M0 = (P1M0 & ~0x13) | 0xc8; P1M1 = (P1M1 & ~0x18) | 0xc3;
P3M0 = (P3M0 & ~0x47) | 0x30; P3M1 = (P3M1 & ~0x37) | 0x40;
P5M0 |= 0x10; P5M1 |= 0x10; //开漏
key_down = 1;
LED =0;
pwmInit();
Timer0_Init();
Uart1_Init();
// Delay1ms(100);//等待电压稳定进行判定
// voltage();
//
pwm(0);
FAN =1;
choosegrade(1);
wdtInit();
while(1)
{
if (tc!=1)//温控
{
switch (key)
{
case 1:
WDT_CONTR = 0X27;
pwm(100);
FAN =0;
tc = 0;//温控标志
grade+=1;
if (grade>=4)
grade=1;
choosegrade( grade);
// ledflicker(grade,300);
key = 0;//重按键
print("状态:%s", "单击");
break;
case 2:
WDT_CONTR = 0X27;
tc = 1;//温控标志
ledflicker(10,150);
key = 0;//重按键
grade = 3;
choosegrade(grade);
//grade-=1;
//if (grade==0)
//grade=1;
// choosegrade( grade);
key = 0;//清除按键状态
print("状态:%s", "双击");
break;
case 3:
EA = 0;
TL0 = 0xC0; //设置定时初始值
TH0 = 0x63; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 0; //关闭计时
key_state = 0; // 按键状态:0-空闲,1-按下消抖,2-按下稳定,3-释放消抖
press_time = 0; // 按下时间计数(20ms/单位)
click_count = 0; // 单击次数计数
click_delay = 0; // 双击延迟计数
/*全部重置 ,因为长按判断是直接返回空闲 中断响应结束后
这个时候按键可能没有释放,进入了按键稳定状态判断,
这个时候关闭中断但是没有重置所有参数为初值
那么中断再开之后就会续上之前的状态执行
然后现在按键是已经释放了刚好被识别为一个单击从而误触,简答来说就是残留状态的影响 加上中断重开后按键释放 刚好组成了一个完整的单击状态*/
grade = 1;
choosegrade(grade);
key = 0;
pwm(0);
LED = 0;
WDT_CONTR=0X00;//关闭看门狗
// key_down = 1;
while(!key_down);
Delay1ms(1000);//长按松手消抖
EA = 1;//消抖完才允许中断扫描避免长按释放误识别为单击的情况
TR0 = 1;//启动定时器
break;
}
}
else{
temp();
PID_Control(targettemp,l_temp);
if (key==1 || key == 3)
{
tc = 0;//温控标志
}
}
temp();
if ( r_temp>55.0f)//进入过热保护
{
grade = 1;
choosegrade(grade);
pwm(0);//关闭制冷
FAN =1;
LED = 0;//关闭LED显示
while(!(r_temp<45))//等待温度冷却,才可以退出死循环 重新操控
{
temp();
Delay1ms(500);
}
}
print("正常循环%s\r\n");
WDT_CONTR = 0X37;//看门狗清零
Delay1ms(20);
// print("冷端温度:%f", l_temp);
// print("热端温度:%f", r_temp);
// print("电压:%f", vin);
// print("档位:%d", grade);
// if (v==0)
// {
// ledflicker(1,1000);
// }
}
}
尊敬的用户:
您好,感谢您对我们产品的关注与反馈。针对您提到的STC8H1K08按键引脚在长按后松开仍保持低电平的问题,我们已认真分析了您的代码和描述,并结合芯片特性进行排查。
首先,从您的描述来看,按键连接方式为“对地”,即按键一端接GND,另一端接MCU的IO口。正常情况下,若未按下按键,该引脚应为高电平;按下时拉低至低电平。但您指出,在长按之后松开,引脚依然保持低电平,且在状态3中加入拉高操作后问题得以解决。
一、可能原因分析
1. 引脚配置异常
虽然您提到已经初始化为高电平,但在某些情况下,如果引脚被错误配置为输入模式(而非输出),或者存在上拉/下拉设置不当,可能导致引脚状态不稳定。请确认以下几点:
是否将按键引脚配置为“准双向”或“推挽”模式?
是否开启了内部上拉电阻?(部分型号默认开启)
是否存在其他模块或中断影响了该引脚状态?
2. 长时间按键导致寄存器状态未复位
在状态3中,若存在某些寄存器或标志位未正确复位,可能会导致引脚状态被意外修改。例如:
若使用了ADC或其他外设,可能在长按期间触发了某些中断或状态变更。
若未正确释放按键检测逻辑,可能使系统误认为按键仍然处于按下状态。
3. 硬件干扰或信号毛刺
长按过程中,若存在外部干扰或信号毛刺,可能导致MCU误判。建议检查:
按键是否接触不良或有漏电现象?
PCB布局是否合理,是否存在高频噪声干扰?
是否在按键引脚并联了去耦电容以滤除毛刺?
4. 代码逻辑未完全清除状态
您提到在状态3中添加了拉高操作才解决问题,这表明状态3中的某些逻辑可能未正确恢复初始状态。建议检查:
状态切换逻辑是否完整?
是否存在未重置的变量或标志位?
是否在退出状态3时重新配置了引脚模式和电平?
二、建议解决方案
1. 明确引脚配置
在初始化阶段,确保按键引脚配置为“准双向”或“推挽”模式,并关闭内部上拉/下拉(如需)。可参考如下代码片段:
c
P1M1 = 0x00; // 设置为准双向
P1M2 = 0xFF;
P1 = 0xFF; // 初始设为高电平
2. 完善状态切换逻辑
在状态3中,除了拉高操作外,还应确保:
引脚模式恢复为输入;
相关标志位清零;
任何可能影响引脚状态的外设功能关闭。
3. 增加防抖与去噪机制
即使是长按,也建议在检测逻辑中加入防抖处理,防止因毛刺或误触导致状态异常。例如:
c
if (keystate == LOW) {
Delayms(20); // 延时消抖
if (keystate == LOW) {
// 进入状态3
}
}
4. 测试与调试建议
使用示波器观察按键引脚在长按后的实际电平变化;
在状态3中加入调试输出,确认引脚状态是否被意外修改;
尝试更换其他引脚测试,排除硬件故障可能。
三、总结
综上所述,该问题可能由引脚配置不准确、状态逻辑未完全恢复、或外部干扰等因素引起。建议您从以上几个方面逐一排查,并根据实际测试结果调整代码逻辑。若您愿意提供更详细的代码或电路图,我们将进一步协助定位问题根源。
如您有其他技术疑问,欢迎随时联系国芯人工智能技术支持团队,我们将竭诚为您服务。
此致
敬礼!
国芯人工智能技术支持团队
2025年4月
[本文内容由国芯人工智能辅助生成,仅供参考] 国芯人工智能 发表于 2025-8-5 11:38
尊敬的用户:
您好,感谢您对我们产品的关注与反馈。针对您提到的STC8H1K08按键引脚在长按后松开仍保持低 ...
感谢你的回复,我已经找到原因了 是led 闪光操作使用的读改写操作 导致按键按压时的低电平 在闪光的寄存器读改写操作 被读模式读取然后被写入了全局寄存器中 这样导致了按键一直低电平的情况 SAFE_SET_P3(x, val) (P3 = (P3 & ~(1<<(x))) | ((val)<<(x)))
页:
[1]