新手剛起步,有點搞不懂定時器中斷函數(shù)的運行時刻,我想把超聲波測量的距離放在數(shù)碼管中顯示,于是在中斷函數(shù)中加入了掃描數(shù)碼管函數(shù),但是在實際運行中出現(xiàn)了數(shù)值跳動緩慢,大概15s才跳動一下,而且我的小車輪子轉(zhuǎn)速也會出現(xiàn)大概15s會停一下(測試過如果不把掃描數(shù)碼管放在定時器中斷函數(shù)就不會有這種情況)于是我又想我寫在主函數(shù)中,但是多次嘗試,發(fā)現(xiàn)寫在主函數(shù)中雖然數(shù)字跳動很快,但是無論我怎么寫都只顯示最后數(shù)碼管第三位,我想要的是顯示三位數(shù)。以下是我正在改寫的代碼
單片機源程序如下:
#include <reg52.h>//51頭文件
#include <intrins.h> //包含nop等系統(tǒng)函數(shù)
#include <config.h>//配置文件
sbit RX = P2^0;//ECHO超聲波模塊回響端
sbit TX = P2^1;//TRIG超聲波模塊觸發(fā)端
sbit DU =P2^6;
sbit WE =P2^7;
unsigned int timer=0;
unsigned char posit=0;
unsigned char const discode[] ={ 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F,0x6F,0x40,0x00}; //數(shù)碼管段選碼
unsigned char const positon[3]={ 0xfe,0xfd,0xfb}; //數(shù)碼管位選碼
unsigned char disbuff[4 ] ={ 0,0,0,0,};
unsigned char pwm_left_val = 210;//左電機占空比值 取值范圍0-170,0最快
unsigned char pwm_right_val = 210;//右電機占空比值取值范圍0-170 ,0最快
unsigned char pwm_t;//周期
unsigned int time = 0;//傳輸時間
unsigned long S = 0;//距離
bit flag = 0;//超出測量范圍標志位
/*掃描數(shù)碼管*/
void Display1(void) //掃描數(shù)碼管
{
DU = 0; //關(guān)閉段 選
P0=(discode[disbuff[0]])|0x80; //或上0x80是為了添加小數(shù)點
DU = 1; //開啟段選,段選值送過去了
DU = 0; //關(guān)閉段選
WE = 0; //關(guān)閉位選
P0=positon[0];
WE=1;
WE=0;
}
void Display2(void) //掃描數(shù)碼管
{
DU = 0; //關(guān)閉段 選
P0=discode[disbuff[1]];
DU = 1; //開啟段選,段選值送過去了
DU = 0; //關(guān)閉段選
WE = 0; //關(guān)閉位選
P0=positon[1];
WE=1;
WE=0;
}
void Display3(void) //掃描數(shù)碼管
{
DU = 0; //關(guān)閉段 選
P0=discode[disbuff[2]];
DU = 1; //開啟段選,段選值送過去了
DU = 0; //關(guān)閉段選
WE = 0; //關(guān)閉位選
P0=positon[2];
WE=1;
WE=0;
}
void delay(unsigned int z)//毫秒級延時
{
unsigned int x,y;
for(x = z; x > 0; x--)
for(y = 114; y > 0 ; y--);
}
void Delay10us(unsigned char i) //10us延時函數(shù) 啟動超聲波模塊時使用
{
unsigned char j;
do{
j = 10;
do{
_nop_();
}while(--j);
}while(--i);
}
/*小車前進*/
void forward()
{
left_motor_go; //左電機前進
right_motor_go; //右電機前進
}
/*小車左轉(zhuǎn)*/
void left_run()
{
left_motor_stops; //左電機停止
right_motor_go; //右電機前進
}
/*小車右轉(zhuǎn)*/
void right_run()
{
right_motor_stops;//右電機停止
left_motor_go; //左電機前進
}
/*PWM控制使能 小車原地左轉(zhuǎn)*/
void left_rapidly()
{
left_motor_back;
right_motor_go;
}
/*小車后退*/
void backward()
{
left_motor_back; //左電機后退
right_motor_back; //右電機后退
}
/*小車停止*/
void stop()
{
right_motor_stops;//右電機停止
left_motor_stops; //左電機停止
}
void StartModule() //啟動超聲波模塊
{
TX=1; //啟動一次模塊
Delay10us(2);
TX=0;
}
/*定時器1中斷輸出PWM信號*/
void timer1() interrupt 3
{
//Display(); //如果把掃描數(shù)碼管函數(shù)加在這里,就會導(dǎo)致數(shù)碼管數(shù)字15s以上才跳動一次,另外小車輪子也同時停止轉(zhuǎn)動
pwm_t++;//周期計時加
if(pwm_t == 255)
{
// StartModule(); //啟動模塊測距
pwm_t = EN1 = EN2 = 0;
}
if(pwm_left_val == pwm_t)//左電機占空比
EN1 = 1;
if(pwm_right_val == pwm_t)//右電機占空比
EN2 = 1;
}
/*啟動函數(shù)*/
void start()
{
beep = 0; //使能有源蜂鳴器
delay(200);//200毫秒延時
beep = 1; //關(guān)閉有源蜂鳴器
}
/*電機加速函數(shù)*/
void keying_s2()
{
if(key_s2 == 0)// 實時檢測S2按鍵是否被按下
{
delay(5); //軟件消抖
if(key_s2 == 0)//再檢測S2是否被按下
{
while(!key_s2);//松手檢測
if(pwm_right_val >= 0 && pwm_left_val >= 0 )
{
pwm_left_val--;
pwm_right_val--;
}
}
}
}
/*電機減速函數(shù)*/
void keying_s3()
{
if(key_s3 == 0)// 實時檢測S2按鍵是否被按下
{
delay(5); //軟件消抖
if(key_s3 == 0)//再檢測S2是否被按下
{
while(!key_s2);//松手檢測
if(pwm_right_val < 255 && pwm_left_val < 255 )
{
pwm_left_val++;
pwm_right_val++;
}
}
}
}
/*定時器0中斷*/
void timer0() interrupt 1 //T0中斷用來計數(shù)器溢出,超過測距范圍
{
flag=1; //中斷溢出標志
}
/*計算超聲波所測距離并顯示*/
void Conut()
{
time=TH0*256+TL0;
TH0=0;
TL0=0;
S=(float)(time*1.085)*0.017;
if((S>=700)||flag==1) //超出測量范圍
{
flag=0;
disbuff[0]=10;
disbuff[1]=10; //“-”
disbuff[2]=10; //“-”
}
else
{
disbuff[0]=S/100;
disbuff[1]=S%100/10;
disbuff[2]=S%10;
}
}
//尋跡
void tracking()
{
//為0 沒有識別到黑線 為1識別到黑線
if(left_led1 == 1 && right_led1 == 1)//左右尋跡探頭識別到黑線
{
forward();//前進
}
else
{
if(left_led1 == 1 && right_led1 == 0)//小車右邊出線,左轉(zhuǎn)修正
{
left_run();//左轉(zhuǎn)
}
if(left_led1 == 0 && right_led1 == 1)//小車左邊出線,右轉(zhuǎn)修正
{
right_run();//右轉(zhuǎn)
}
if(left_led1 == 0 && right_led1 == 0)//左右尋跡探頭都沒識別到黑線
{
backward();//后退
}
}
}
/*超聲波避障*/
void Avoid()
{
if(S < 400)//設(shè)置避障距離(單位毫米),掉頭距離
{
// beep = 0;//使能蜂鳴器
stop();//停車
delay(100);//停車時間
left_rapidly();//原地左轉(zhuǎn)
delay(180);//左右角度,數(shù)值越大轉(zhuǎn)向角度越大
do{
left_rapidly();//原地左轉(zhuǎn)
delay(10);//轉(zhuǎn)向角度
stop(); //停車
delay(1);//停車時間
}while(left_led1 == 0 || right_led1 == 0); //回到黑線上則退出,否則繼續(xù)原地轉(zhuǎn)向?qū)ふ液诰
// beep = 1;//關(guān)閉蜂鳴器 //測試太吵了,暫時關(guān)掉
}
}
void main()
{
unsigned int i;
keying_s2();
keying_s3();
start();//等待按鍵按下啟動
delay(1000);//延時1秒
TMOD |= 0x20;//定時器1工作模式2,8位自動重裝。用于產(chǎn)生PWM
TMOD |= 0x01;//定時器0工作模塊1,16位定時模式。T0用測ECH0脈沖長度
TH1 = 220; //
TL1 = 220; //100HZ T1 小車機械周期為1.85微秒
TH0 = 0;
TL0 = 0;//T0,16位定時計數(shù)用于記錄ECHO高電平時間
ET1 = 1;//允許T1中斷
ET0 = 1;//允許T0中斷
TR1 = 1;//啟動定時器1
EA = 1;//啟動總中斷
StartModule(); //啟動模塊測距
while(1)
{
StartModule(); //啟動模塊測距
while(!RX); //當RX(ECHO信號回響)為零時等待
TR0=1; //開啟計數(shù) ,此時ECHO信號回響為1
while(RX); //當RX為1計數(shù)并等待
TR0=0; //關(guān)閉計數(shù) ,此時ECHO信號恢復(fù)為0
Conut(); //計算距離
Avoid(); //避障
//之前我也考慮過在這里添加三個Display()函數(shù),就不用循環(huán)掃描了,寫成三個函數(shù),分別對應(yīng)數(shù)碼管的三個位,但是基本前兩位看不清,只能看清楚第三位,我知道這是因為延時的原因,但是這里的延時確實不好調(diào)整。
for(i=0; i<1800; i++) //超聲波每次測距間隔不低于65ms
tracking(); //尋跡
}
}
我個人的思想是那個T1中斷函數(shù)很慢才啟動一次,測試我發(fā)現(xiàn)其實超聲波模塊的測距是很頻繁的,所以我覺得disbuffer數(shù)組中的數(shù)是經(jīng)常在調(diào)整的,知識因為掃描數(shù)碼管函數(shù)啟動一次很慢,所以才導(dǎo)致要花費15s才能有變換。但是我又想不通T1那個函數(shù)不可能15s才進入一次啊,因為pwm在每個周期都要靠那里使能占空比,所以請教一下大佬,這是什么原因?如果順帶能告訴我如何優(yōu)化,更是感激不盡!
|