本帖最后由 hxdby 于 2022-2-16 19:07 编辑
最近在调试中遇到一个非常诡异的问题!虽然我解决了,但是到现在我都不知道具体原因是啥, 特分享出来,与大家探讨。
做了一个简单的可以通过按键调整时间控制继电器打开关闭的单片机板子,带数码管显示,全部功能程序代码都已经完成,昨天板子我开了一夜做测试,今天早上起来突然发现一个键突然失灵了,不能切换分秒显示了,我以为是按键坏了,结果不是。
先解释板子的工作逻辑:1,板子带一路继电器,可以通过按键设置分和秒来设置继电器打开和关闭的时间
2,继电器打开时间设置函数是RELAY_SET_ON(), 继电器关闭时间设置函数是RELAY_SET_OFF(); 这两个函数实现功能和代码都一样,只是变量名不同
3,设置时间可以通过数码管显示,
4,总共三个按键,SW1, SW2, SW3。SW1是增加,SW2是减小。SW3是分和秒设置切换按键。简单说就是,如果设置分钟,按一下SW1,分钟增加1,按一下SW2,分钟减小1,如果要设置秒钟,则按一下SW3,切换到秒钟设置,然后在通过SW1/SW2来增减。
先上部分程序(不重要的单片机代码就不贴出来,只贴重要的):
//全局变量
uint8_t relay_on_cnt =0; //打开时间设置中的分秒切换变量,通过SW3设置
uint8_t relay_off_cnt =0; //关闭时间设置中的分秒切换变量,通过SW3设置
uint8_t RELAY_min_set_ON =0 //继电器打开时间设置中的分钟变量
uint8_t RELAY_sec_set_ON = 0 //继电器打开时间设置中的秒钟变量
uint8_t RELAY_min_set_OFF =0 //继电器关闭时间设置中的分钟变量
uint8_t RELAY_sec_set_OFF = 0 //继电器关闭时间设置中的分钟变量
uint8_t key_number3 =0; //触发的按键编号,当SW3按下时,按键扫描KEY_SCAN()函数返回不同的key_number3键值
uint8_t key_number =0; //触发的按键编号,当SW1 或SW2按下时,key_number返回不同的键值
//函数原型
void RELAY_SET_ON(); //设置继电器打开时间
void RELAY_SET_OFF(); //设置继电器关闭时间
void KEY_SCAN() ; //按键扫描
void DISPLAY_MIN_SEC_SET(); //数码管显示设置的分秒参数
//主函数
int main (void)
{
while(1)
{
RELAY_SET_ON();
RELAY_SET_OFF();
KEY_SCAN() ;
}
}
// 函数定义
void RELAY_SET_ON(); //设置继电器打开时间
{
switch (key_number3) //SW3按下
{
case 1: //SW3短按,relay_on_cnt计数器在0和1之间循环自加
relay_on_cnt ++;
if (relay_on_cnt >1)
{
relay_on_cnt=0;
}
key_number3=0;
break;
case 2:
relay_on_cnt --; //SW3长按超过1s,relay_on_cnt计数器在0和1之间循环连续自减,实现连击功能
if (relay_on_cnt>1)
{
relay_on_cnt=1;
}
key_number3=0;
break;
default:; break;
}
/*以上的代码主要是通过按下SW3来切换分钟和秒钟的设置,如果 relay_on_cnt=0,则进入分钟设置界面。如果 relay_on_cnt=1,则进入秒钟设置界面,这段代码和RELAY_SET_OFF();中完全一样,但是这里没问题,RELAY_SET_OFF();会出现问题*/
if (relay_on_cnt==0) //继电器打开分钟设置
{
switch (key_number) //根据返回到键值进行分钟的加减操作
{
case 1: // SW1 触发,开始减操作
RELAY_min_set_ON --;
if (RELAY_min_set_ON >99)
{
RELAY_min_set_ON =99;
}
key_number=0;
break;
case 2: //SW2触发,开始加操作
RELAY_min_set_ON ++;
if (RELAY_min_set_ON >99)
{
RELAY_min_set_ON =0;
}
key_number=0;
break;
default: ; break;
}
}
if (relay_on_cnt==1) //秒设置
{
switch (key_number)
{
case 1: // SW1 触发,开始减操作
RELAY_sec_set_ON --;
if (RELAY_sec_set_ON >99)
{
RELAY_sec_set_ON =99;
}
key_number=0;
break;
case 2: //SW2触发,开始加操作
RELAY_sec_set_ON ++;
if (RELAY_sec_set_ON >99)
{
RELAY_sec_set_ON =0;
}
key_number=0;
break;
default: ; break;
}
}
DISPLAY_MIN_SEC_SET(); // 设置第参数在数码管即时显示
}
//函数定义
void RELAY_SET_OFF(); //设置继电器关闭时间,该函数代码与上述RELAY_SET_ON()中完全相同,只是变量名不同. 所以不再一一注释
{
switch (key_number3)
{
case 1:
relay_off_cnt ++;
if (relay_off_cnt >1)
{
relay_off_cnt=0;
}
key_number3=0;
break;
case 2:
relay_off_cnt --;
if (relay_off_cnt>1)
{
relay_off_cnt=1;
}
key_number3=0;
break;
default:; break;
}
//上述红色部分代码出了问题!!出问题后,检查了这部分代码,和RELAY_SET_ON();中的完全一样,后来复制了RELAY_SET_ON();中的这部分代码到这里,改了变量名,问题就解决了!觉得很诡异,如果是这部分代码出问题,那么在一开始就应该有问题,而我的板子是跑了一夜之后出问题的,而且是100%必现,我仔细检查了代码,完全一样,手动修改某些变量,也不行。非得从RELAY_SET_ON();中复制才可以,why?????
if (relay_off_cnt==0)
{
switch (key_number)
{
case 1: // SW1 触发,开始减操作
RELAY_min_set_OFF --;
if (RELAY_min_set_OFF >99)
{
RELAY_min_set_OFF =99;
}
key_number=0;
break;
case 2: //SW2触发,开始加操作
RELAY_min_set_OFF ++;
if (RELAY_min_set_OFF >99)
{
RELAY_min_set_OFF =0;
}
key_number=0;
break;
default: ; break;
}
}
if (relay_off_cnt==1) //秒调整
{
switch (key_number)
{
case 1: // SW1 触发,开始减操作
RELAY_sec_set_OFF --;
if (RELAY_sec_set_OFF >99)
{
RELAY_sec_set_OFF =99;
}
key_number=0;
break;
case 2: //SW2触发,开始加操作
RELAY_sec_set_OFF ++;
if (RELAY_sec_set_OFF >99)
{
RELAY_sec_set_OFF =0;
}
key_number=0;
break;
default: ; break;
}
}
DISPLAY_MIN_SEC_SET();
}
现在的问题是,板子跑了一夜之后,继电器关闭时间设置突然不显示了,数码管全黑。而继电器打开设置界面是正常显示的。我关闭板子电源,重新开机,继电器关闭时间设置界面可以显示,但是只要一按SW3按键切换分秒设置,就没显示了,而且这个问题是100%必现。
我怀疑是RELAY_SET_OFF(); 中的程序出了问题,所以和RELAY_SET_ON(); 对比了一下,发现完全一样,除了变量名不同,其他没有任何区别。而且这个问题不是一直出现的,是板子开始是好的,我开机一夜,跑了一夜后突然变成这样的。如果是程序问题,应该从一开就会有问题。
我百思不得其解,因为如果是RELAY_SET_OFF();程序问题,那RELAY_SET_ON();一定会出现问题,因为这两个函数中的代码逻辑完全相同,只是变量名不同,这套代码也用了好几月了,没出过问题。但现在的问题是,两个完全一样的函数,继电器打开时间设置显示没有任何问题,而且问题只出在按下SW3按键的时候。
于是我开始研究SW3这一段代码,也就是上述RELAY_SET_OFF();中红色部分,我对比了几百次,和RELAY_SET_ON();完全一样,因为本身也没有多少代码。我突发奇想,把RELAY_SET_ON();中对应部分代码复制过来,然后改掉变量名,然后烧录测试,板子居然好了!
我实在不理解为啥会这样?非得复制才行?我觉得不可理解,究竟是啥原因,有没有高人可以深入解释下,感谢!
|