本帖最后由 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();中對應部分代碼復制過來,然后改掉變量名,然后燒錄測試,板子居然好了!
我實在不理解為啥會這樣?非得復制才行?我覺得不可理解,究竟是啥原因,有沒有高人可以深入解釋下,感謝!
|