標(biāo)題:
為什么C語言程序while里第一和第二個if語句仿真時會跳過?
[打印本頁]
作者:
fzzz321
時間:
2023-5-13 13:53
標(biāo)題:
為什么C語言程序while里第一和第二個if語句仿真時會跳過?
求大神指導(dǎo)!
紅外程序單獨使用正常,如果加入一些現(xiàn)實及定時程序后就不正常,然后仿真單步,發(fā)現(xiàn)適中不進入while循環(huán)里的下面兩個語句,求大神指點!
if(IR_Flag) //如果有紅外數(shù)據(jù)傳入并接收完成
{
IR_decode(); //調(diào)用紅外解碼函數(shù)(用于得到鍵值)
IR_Flag=0; //清除紅外數(shù)據(jù)接收完成標(biāo)志位
}
if(IR_KEY) //如果紅外解析成功,認(rèn)定按鍵按下
{
IR_control(); //調(diào)用紅外控制函數(shù)(用戶控制LED燈)
}
源碼如下:
/*********************************************/
/* timer */
/* 創(chuàng)建者 :jeremy.zhu */
/* 創(chuàng)建時間:2023/04/29 */
/*********************************************/
#include "STC8.H"
#include "TM1637.H"
#include "intrins.h"
#define u8 uint8_t
#define u16 uint16_t
#define u32 uint32_t
typedef unsigned char uint8_t;
typedef unsigned int uint16_t;
typedef unsigned long uint32_t;
/************************端口/引腳定義區(qū)域************************/
sbit RED=P1^2; //RGB指示燈1
sbit GREEN=P1^3; //RGB指示燈2
sbit BLUE=P1^4; //RGB指示燈3
sbit time_hr = P3^0; //按鍵1,時間設(shè)置:小時+
sbit time_min = P3^1; //按鍵2,時間設(shè)置:分鐘+
sbit on_off = P3^2; //按鍵3,開關(guān)
sbit mode_set = P3^3; //按鍵4,功能選擇
sbit plasma = P3^4;
sbit ozone = P3^5;
//----------------------------------------------------------------
sbit KEY=P1^7; //用戶按鍵
/************************用戶自定義數(shù)據(jù)區(qū)域***********************/
bit IR_KEY=0; //紅外按鍵按下標(biāo)志
bit IR_Flag=0; //紅外數(shù)據(jù)接收完成標(biāo)志位
u8 IR_time=0; //下降沿之間的時間計數(shù)值
u8 IR_code[4]; //用戶碼+用戶碼+數(shù)據(jù)碼+數(shù)據(jù)反碼
u8 IR_data[33]; //引導(dǎo)碼+32個位數(shù)據(jù)各自占用的時間
u8 mode=0; //mode為工作模式0,1 分別表示停止模式和運行模式
u8 hour=0,minute=0,second=0,time_count=0; //真實計時的時,分,秒,10ms計數(shù)器
u8 show[6]={0,0,0,0,0,0}; //TM1637四位數(shù)碼管顯示數(shù)組:小時的十位和個位,分鐘的十位和個位,最后兩個為小時和分鐘。
u16 uiKeyTimeCnt1; //按鍵1計數(shù)
u16 uiKeyTimeCnt2; //按鍵2計數(shù)
u16 uiKeyTimeCnt3; //按鍵3計數(shù)
u16 uiKeyTimeCnt4; //按鍵4計數(shù)
bit ShortTouchFlag1=0; //按鍵1短按按鍵有效標(biāo)志
bit ShortTouchFlag2=0; //按鍵2短按按鍵有效標(biāo)志
bit ShortTouchFlag3=0; //按鍵3短按按鍵有效標(biāo)志
bit ShortTouchFlag4=0; //按鍵4短按按鍵有效標(biāo)志
//bit delay_OnOff=0; //延時上電和延時斷電選擇位,開機檢查Key3設(shè)置此位,0表示延時斷電,1表示延時上電。
bit flag_1s=1; //秒任務(wù)標(biāo)志位
bit flag_500ms=1; //半秒標(biāo)志位
bit stat_500ms=0; //半秒狀態(tài)位,控制時間冒號閃爍
/**************************函數(shù)聲明區(qū)域***************************/
void delay(u16 Count); //延時函數(shù)聲明
void Time0_init(void); //定時計數(shù)器0初始化函數(shù)
void Int0_init(void); //外部中斷0初始化函數(shù)
void IR_decode(void); //紅外解碼函數(shù)(用于得到鍵值)
void IR_control(void); //紅外控制函數(shù)(用戶控制LED燈)
void Key_scan(void);
void Key_process(void);
/***************************主函數(shù)區(qū)域****************************/
void main(void)
{
//STC8G/H系列單片機除P3.0和P3.1外,所有I/O上電均為高阻輸入狀態(tài)
//所以大家必須要先配置I/O模式再去用引腳
P1M0|=0x1C; //P1.2至1.4引腳為推挽輸出模式
P1M1&=0xE3; //P1.2至1.4引腳為推挽輸出模式
P1M0&=0x7F; //P1.7引腳為準(zhǔn)雙向模式
P1M1&=0x7F; //P1.7引腳為準(zhǔn)雙向模式
P3M1=0x00; //將P3口設(shè)置為推挽輸出
P3M0=0xFF;
BLUE=RED=GREEN=1; //上電后三個LED都保持熄滅狀態(tài)
Time0_init(); //定時計數(shù)器0初始化函數(shù)
Int0_init(); //外部中斷0初始化函數(shù)
TM1637_display(0,0,0,0,1); //上電后默認(rèn)顯示00:00
// delay(100); //等待配置穩(wěn)定
while(1)
{
if(IR_Flag) //如果有紅外數(shù)據(jù)傳入并接收完成
{
IR_decode(); //調(diào)用紅外解碼函數(shù)(用于得到鍵值)
IR_Flag=0; //清除紅外數(shù)據(jù)接收完成標(biāo)志位
}
if(IR_KEY) //如果紅外解析成功,認(rèn)定按鍵按下
{
IR_control(); //調(diào)用紅外控制函數(shù)(用戶控制LED燈)
}
Key_process(); //調(diào)用按鍵處理函數(shù)
if(flag_500ms==1) //每500毫秒進行一次顯示處理,主要是為了實現(xiàn)時間冒號的閃爍
{
flag_500ms=0; //清除半秒標(biāo)志位
stat_500ms=~stat_500ms; //時間冒號每秒亮滅一次
if(mode==1) //只在啟動定時的狀態(tài)下刷新顯示時間
{
if(second>0) //以下為將實際計時的時間轉(zhuǎn)換為數(shù)碼管顯示的時間。比如定時還剩20秒時,數(shù)碼管實際顯示的是00:01。
show[5]=minute+1;
else
show[5]=minute;
if(show[5]==60)
{
show[5]=0;
show[4]=hour+1;
}
else
show[4]=hour;
show[0]=show[4]/10%10; //顯示的小時十位數(shù)
show[1]=show[4]%10; //顯示的小時個位數(shù)
show[2]=show[5]/10%10; //顯示的分鐘十位數(shù)
show[3]=show[5]%10; //顯示的分鐘個位數(shù)
TM1637_display(show[0],show[1],show[2],show[3],stat_500ms); //顯示時間,冒號位是0還是1由stat_500ms確定,每半秒變化一次。
}
if(mode==1&&flag_1s==1) //以下為定時狀態(tài)下更新計時時間,當(dāng)秒任務(wù)標(biāo)志位為1時進行倒計時
{
flag_1s=0; //清除秒任務(wù)標(biāo)志位
if(second>0) //如果秒大于0,則減1秒
{
second--;
}
else if(minute>0) //如果秒等于0,則從分鐘借位,分鐘減1,秒變?yōu)?9
{
minute--;
second=59;
}
else if(hour>0) //如果秒和分鐘都為0,則從小時借位,小時減1,分鐘和秒都為59
{
hour--;
minute=59;
second=59;
}
else //如果時分秒都為0
{
mode=0; //倒計時結(jié)束,進入停止?fàn)顟B(tài)
// relay=delay_OnOff; //依據(jù)開機時設(shè)置的延時斷電或延時上電,設(shè)置計時完成后的繼電器狀態(tài)。如果設(shè)置的是延時斷電,計時到后繼電器驅(qū)動為0。
TM1637_display(0,0,0,0,1); //計時到后時間顯示00:00,時間冒號不閃爍
}
}
}
}
}
/****************************************************************/
//延時函數(shù)delay(),有形參Count無返回值
/****************************************************************/
void delay(u16 Count)
{
while(Count--)
{
_nop_();
}
}
void Time0_init(void)//初始化函數(shù)
{
AUXR=0x80; //定時器0設(shè)為1T模式,和定時器1設(shè)為12T
TMOD = 0x00; //設(shè)置定時器0,定時器1為模式0-16位自動重載
TL0 = 0xFE; //設(shè)置定時器0初值
TH0 = 0xF3; //定時278us
TL1 = 0x00; //設(shè)置定時器1初值
TH1 = 0xDC; //定時10ms
TF0 = 0; //清除TF0標(biāo)志
TF1 = 0; //清除TF1標(biāo)志
TR0 = 1; //定時器0開始計時
TR1 = 1; //定時器1開始計時
ET0 = 1; //開定時器0中斷
ET1 = 1; //開定時器1中斷
}
void Int0_init(void)
{
IT0=1; //配置外部中斷0信號觸發(fā)方式為邊沿觸發(fā)(下降沿有效)
EX0=1; //使能INT0中斷
EA = 1; //開總中斷
}
/****************************************************************/
//紅外解碼函數(shù)IR_decode(),用于得到鍵值,無形參,無返回值
/****************************************************************/
void IR_decode(void)
{
u8 i,j,k;
//變量i控制循環(huán)次數(shù),用于最終得到4個字節(jié)數(shù)據(jù)(2個用戶碼+2個數(shù)據(jù)碼)
//變量j控制循環(huán)次數(shù),通過循環(huán)和時長判斷把8個時間間隔分析為“0碼”
//和“1碼”,然后最終通過按位或運算及右移運算得到紅外數(shù)據(jù),變量k用
//于控制IR_data[]數(shù)組的下標(biāo)變化。
u8 Timer_Value,IR_Value;
//變量Timer_Value用于從IR_data[]數(shù)組中取出“時間間隔”數(shù)據(jù)
//變量IR_Value用于存放最終的紅外數(shù)據(jù)
k=1; //先讓變量k等于1,因為k為0時取出的將會是“引導(dǎo)碼的時間間隔”
for(i=0;i<4;i++) //外層循環(huán)4次為了得到4個數(shù)據(jù)字節(jié)
{
for(j=0;j<=7;j++) //內(nèi)層循環(huán)8次為了拼合8個數(shù)據(jù)位為1個字節(jié)
{
Timer_Value=IR_data[k]; //取出相應(yīng)紅外位的“時間間隔”數(shù)據(jù)
if(Timer_Value>7) //若“時間間隔”比7大那肯定是“1碼”反之為“0碼”
IR_Value|=0x80; //通過按位或運算高位填1
if(j<7) //若數(shù)據(jù)沒有拼合完8次
IR_Value>>=1; //通過右移運算“騰出”位置準(zhǔn)備下一位判定
k++; //下標(biāo)變量自增
}
IR_code
=IR_Value; //得到紅外數(shù)據(jù)后放回IR_code[]數(shù)組
IR_Value=0; //清零IR_Value變量
}
IR_KEY=1; //紅外按鍵按下標(biāo)志位置1,提示系統(tǒng)有按鍵按下
}
/****************************************************************/
//紅外控制函數(shù)IR_control(),用戶控制LED燈,無形參,無返回值
/****************************************************************/
void IR_control(void)
{
switch(IR_code[2])//只需要判斷數(shù)據(jù)碼即可
//IR_code[0]是用戶碼第1字節(jié),IR_code[1]是用戶碼第2字節(jié)
//IR_code[3]是數(shù)據(jù)碼字節(jié),IR_code[4]是取反后的數(shù)據(jù)碼字節(jié)
{
case 0x0C:{RED=0;GREEN=BLUE=1;ShortTouchFlag2=1;};break;
//若按下遙控板的“1”則紅燈亮起
case 0x18:{GREEN=0;RED=BLUE=1;ShortTouchFlag1=1;};break;
//若按下遙控板的“2”則綠燈亮起
case 0x5E:{BLUE=0;RED=GREEN=1;ShortTouchFlag3=1;};break;
//若按下遙控板的“3”則藍燈亮起
// case 0x08:{BLUE=RED=GREEN=0;};break;
//若按下遙控板的“4”則全部亮起,發(fā)白光
// default:{BLUE=RED=GREEN=1;};break;
//若按下遙控板的其它鍵則RGB全部熄滅
}
IR_KEY=0;//遙控控制完成,清零該標(biāo)志位
}
/****************************************************************/
//外部中斷0中斷服務(wù)函數(shù)INT0_ISR(),無形參,無返回值
/****************************************************************/
void INT0_ISR() interrupt 0
{
static u8 IR_bit; //變量IR_bit用于指示紅外數(shù)據(jù)的位數(shù)
static bit Start_Flag; //位變量Start_Flag用于指示是否開始處理
if(Start_Flag)
{
if(IR_time<70&&IR_time>32) //判斷引導(dǎo)碼(9ms+4.5ms)
//IR_time大約要溢出32次(9ms/0.278ms)到70次(可以大于(9+4.5)/0.278)
IR_bit=0; //清除位數(shù)變量,確保當(dāng)前IR_bit為0,表示引導(dǎo)碼
IR_data[IR_bit]=IR_time; //存儲相應(yīng)位時間寬度
IR_time=0; //清零時間寬度計數(shù)值
IR_bit++; //位數(shù)變量自增
if(IR_bit==33) //如果達到了33位(引導(dǎo)碼+32個數(shù)據(jù)位)
{
IR_Flag=1; //紅外數(shù)據(jù)接收完成標(biāo)志位置1
IR_bit=0; //位數(shù)變量清零
}
}
else //外部中斷0檢測到下降沿,即將開始引導(dǎo)碼
{
IR_time=0; //清零時間計數(shù)值
Start_Flag=1; //紅外數(shù)據(jù)產(chǎn)生第一次下降沿,意味著數(shù)據(jù)即將開始
}
}
/****************************************************************/
//定時計數(shù)器0中斷服務(wù)函數(shù)TIMER0_ISR(),無形參,無返回值
/****************************************************************/
void TIMER0_ISR() interrupt 1
{
IR_time++;
/*每過0.278ms則T0溢出一次,就是想要用溢出次數(shù)去衡量兩個下降沿之間
的時間長短:前導(dǎo)碼9ms+4.5ms,則IR_time大約要溢出32次(9ms/0.278ms)
到70次(可以大于(9+4.5)/0.278)。如果是“0碼”,則周期是1.125ms,則
IR_time大約要溢出4次(1.125ms/0.278ms),如果是“1碼”,周期是2.25ms,
則IR_time大約要溢出8次(2.25ms/0.278ms)。這樣就可以區(qū)分不同的紅外位
含義了.*/
}
void time1(void) interrupt 3 //T1中斷服務(wù),每10ms響應(yīng)一次
{
time_count++; //計數(shù)加1
Key_scan(); //每10ms掃描一次按鍵狀態(tài)
if(time_count==50) //每500ms時設(shè)置一次半秒標(biāo)志位
flag_500ms=1;
if(time_count==100) //每1秒設(shè)置一次半秒標(biāo)志位和秒任務(wù)標(biāo)志位
{
time_count=0;
flag_500ms=1;
flag_1s=1;
}
}
/********************************************************************/
/********************************************************************/
/********************************************************************/
/******************************
函數(shù)說明:按鍵短按長按檢測
******************************/
void Key_scan(void) //在中斷里調(diào)用,每10ms檢查一次按鍵狀態(tài)
{
if(time_hr==0) //如果按鍵1按下
{
uiKeyTimeCnt1++; //累加按鍵計時
}
if(time_hr==1) //當(dāng)按鍵松開(也可能是抖動彈開)
{
if(uiKeyTimeCnt1>2&&uiKeyTimeCnt1<=200) //只有大于20mS,且小于2秒,才判為短按
{
uiKeyTimeCnt1=0; //清零按鍵計時
ShortTouchFlag1=1; //短按標(biāo)志位置1
}
}
if(time_min==0) //如果按鍵2按下
{
uiKeyTimeCnt2++; //累加按鍵計時
}
if(time_min==1) //當(dāng)按鍵松開(也可能是抖動彈開)
{
if(uiKeyTimeCnt2>2&&uiKeyTimeCnt2<=200) //只有大于20mS,且小于2秒,才判為短按
{
uiKeyTimeCnt2=0; //清零按鍵計時
ShortTouchFlag2=1; //短按標(biāo)志位置1
}
}
if(on_off==0) //如果按鍵2按下
{
uiKeyTimeCnt3++; //累加按鍵計時
}
if(on_off==1) //當(dāng)按鍵松開(也可能是抖動彈開)
{
if(uiKeyTimeCnt3>2&&uiKeyTimeCnt3<=200) //只有大于20mS,且小于2秒,才判為短按
{
uiKeyTimeCnt3=0; //清零按鍵計時
ShortTouchFlag3=1; //短按標(biāo)志位置1
}
}
if(mode_set==0) //如果按鍵2按下
{
uiKeyTimeCnt4++; //累加按鍵計時
}
if(mode_set==1) //當(dāng)按鍵松開(也可能是抖動彈開)
{
if(uiKeyTimeCnt4>2&&uiKeyTimeCnt4<=200) //只有大于20mS,且小于2秒,才判為短按
{
uiKeyTimeCnt4=0; //清零按鍵計時
ShortTouchFlag4=1; //短按標(biāo)志位置1
}
}
}
/******************************
函數(shù)說明:按鍵處理
******************************/
void Key_process(void)
{
if(ShortTouchFlag2 == 1) //當(dāng)按鍵1短按標(biāo)志位為1時進行按鍵1短按處理
{
ShortTouchFlag2=0; //清除短按標(biāo)志位
minute++; //短按按鍵1的效果:分鐘加1
if(minute==60) //如果設(shè)置分鐘達到60分
minute=0; //將分鐘清零
if(second>0) //以下將實際計時的小時和分鐘轉(zhuǎn)換為數(shù)碼管顯示的小時和分鐘。比如計時還有00:00:20秒時,數(shù)碼管顯示的是00:01。
show[5]=minute+1; //只要秒不為零,則顯示出來的分鐘應(yīng)該比實際計時的分鐘加1
else
show[5]=minute; //只有秒為零時,顯示的分鐘才和計時的分鐘一致
if(show[5]==60) //如果顯示的分鐘為60分,則顯示的小時比實際計時的小時+1。
{
show[5]=0;
show[4]=hour+1;
}
else
show[4]=hour; //如果顯示的分鐘比實際的加1后還不到60分鐘,則顯示的小時和計時的小時一致。
show[0]=show[4]/10%10; //顯示的小時十位數(shù)
show[1]=show[4]%10; //顯示的小時個位數(shù)
show[2]=show[5]/10%10; //顯示的分鐘十位數(shù)
show[3]=show[5]%10; //顯示的分鐘個位數(shù)
TM1637_display(show[0],show[1],show[2],show[3],1); //顯示定時時間。在按鍵調(diào)時狀態(tài)下,時間的冒號固定顯示不閃爍。
}
if(ShortTouchFlag1==1) //當(dāng)按鍵1長按標(biāo)志位為1時進行按鍵1長按處理
{
ShortTouchFlag1=0; //清除長按標(biāo)志位
hour++; //按鍵1長按的效果:小時加1
if(hour==100) //如果設(shè)定的小時到100了
hour=0; //小時清零。定時時間最高只能設(shè)定99小時59分鐘。
if(second>0) //以下將實際計時的小時和分鐘轉(zhuǎn)換為數(shù)碼管顯示的小時和分鐘,同上。
show[5]=minute+1;
else
show[5]=minute;
if(show[5]==60)
{
show[5]=0;
show[4]=hour+1;
}
else
show[4]=hour;
show[0]=show[4]/10%10; //顯示的小時十位數(shù)
show[1]=show[4]%10; //顯示的小時個位數(shù)
show[2]=show[5]/10%10; //顯示的分鐘十位數(shù)
show[3]=show[5]%10; //顯示的分鐘個位數(shù)
TM1637_display(show[0],show[1],show[2],show[3],1); //顯示定時時間。在按鍵調(diào)時狀態(tài)下,時間的冒號固定顯示不閃爍。
}
if(ShortTouchFlag3==1) //按鍵2短按處理,在停止?fàn)顟B(tài)下短按為啟動運行
{
ShortTouchFlag3=0; //清除短按標(biāo)志位
if(mode==0&&(minute>0||hour>0)) //只在停止?fàn)顟B(tài)下且設(shè)定了有效的定時時間,才能響應(yīng)短按
{
mode=1; //短按的效果:啟動定時
// relay=~delay_OnOff; //開始定時后,根據(jù)開機時設(shè)定的延時斷電或延時上電,繼電器進行相應(yīng)動作。如設(shè)定的是延時斷電(delay_OnOff為0),啟動后繼電器應(yīng)該先通電動作。
}
}
}
作者:
wulin
時間:
2023-5-13 15:59
始終不能進入if(IR_Flag) 和 if(IR_KEY) 當(dāng)然是這兩個判斷條件不能滿足,要在紅外解碼函數(shù)和外部中斷0函數(shù)中找原因。
作者:
huaruolong
時間:
2023-5-13 16:31
你在程序中找IR_Flag,發(fā)現(xiàn)他受 if(Start_Flag)
{
if(IR_time<70&&IR_time>32) //判斷引導(dǎo)碼(9ms+4.5ms)
//IR_time大約要溢出32次(9ms/0.278ms)到70次(可以大于(9+4.5)/0.278)
IR_bit=0; //清除位數(shù)變量,確保當(dāng)前IR_bit為0,表示引導(dǎo)碼
IR_data[IR_bit]=IR_time; //存儲相應(yīng)位時間寬度
IR_time=0; //清零時間寬度計數(shù)值
IR_bit++; //位數(shù)變量自增
if(IR_bit==33) //如果達到了33位(引導(dǎo)碼+32個數(shù)據(jù)位)
{
IR_Flag=1; //紅外數(shù)據(jù)接收完成標(biāo)志位置1
IR_bit=0; //位數(shù)變量清零
}
}控制,這個語句有2個條件,1,Start_Flag必須等于1, 2。IR_bit==33,那你繼續(xù)向下追蹤,看這兩個條件怎樣才能成立。
作者:
sgq657785
時間:
2023-5-13 21:06
劃線處加IR_FLAG=1;
IMG_20230513_210538.jpg
(182.87 KB, 下載次數(shù): 65)
下載附件
2023-5-13 21:06 上傳
作者:
Hephaestus
時間:
2023-5-13 21:49
既然都用上仿真了,IR_Flag和IR_KEY的值會看不到?
作者:
fzzz321
時間:
2023-5-17 16:04
謝謝各位,問題是P3.0和P3.1口的問題,已經(jīng)改掉,仿真的時候這個口會有問題!
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1