新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 單片機的延時與中斷問題及解決方法

單片機的延時與中斷問題及解決方法

作者: 時間:2016-11-19 來源:網(wǎng)絡(luò) 收藏
延時與中斷出錯,是單片機新手在單片機開發(fā)應(yīng)用過程中,經(jīng)常會遇到的問題,本文匯總整理了包含了MCS-51系列單片機、MSP430單片機、C51單片機、8051F的單片機、avr單片機、STC89C52、PIC單片機…..在內(nèi)的各種單片機常見的延時與中斷問題及解決方法,希望對單片機新手們,有所幫助!

一、單片機延時問題20問

1、單片機延時程序的延時時間怎么算的?
答:如果用循環(huán)語句實現(xiàn)的循環(huán),沒法計算,但是可以通過軟件仿真看到具體時間,但是一般精精確延時是沒法用循環(huán)語句實現(xiàn)的。
如果想精確延時,一般需要用到定時器,延時時間與晶振有關(guān)系,單片機系統(tǒng)一般常選用11.059 2 MHz、12 MHz或6 MHz晶振。第一種更容易產(chǎn)生各種標(biāo)準(zhǔn)的波特率,后兩種的一個機器周期分別為1 μs和2 μs,便于精確延時。本程序中假設(shè)使用頻率為12 MHz的晶振。最長的延時時間可達(dá)216=65 536 μs。若定時器工作在方式2,則可實現(xiàn)極短時間的精確延時;如使用其他定時方式,則要考慮重裝定時初值的時間(重裝定時器初值占用2個機器周期)。

2、求個單片機89S51 12M晶振 用定時器延時10分鐘,控制1個燈就可以
答:可以設(shè)50ms中斷一次,定時初值,TH0=0x3c、TL0=0xb0。中斷20次為1S,10分鐘的話,需中斷12000次。計12000次后,給一IO口一個低電平(如功率不夠,可再加擴展),就可控制燈了。

而且還要看你用什么語言計算了,匯編延時準(zhǔn)確,知道單片機工作周期和循環(huán)次數(shù)即可算出,但不具有可移植性,在不同種類單片機中,匯編不通用。用c的話,由于各種軟件執(zhí)行效率不一樣,不會太準(zhǔn),通常用定時器做延時或做一個不準(zhǔn)確的延時,延時短的話,在c中使用匯編的nop做延時


3、51單片機C語言for循環(huán)延時程序時間計算 ,設(shè)晶振12MHz,即一個機器周期是1us。
for(i=0,i<100;i++)
for(j=0,j<100;j++)
我覺得時間是100*100*1us=10ms,怎么會是100ms
答:
不可能的,是不是你的編譯有錯的啊
我改的晶振12M,在KEIL 4.0 里面編譯的,為你得出的結(jié)果最大也就是40ms,這是軟件的原因,
不可能出現(xiàn)100ms那么大的差距,是你的軟件的原因。
不信你實際編寫一個秒鐘,利用原理計算編寫一個燒進單片機和利用軟件測試的秒程序燒進單片機,你會發(fā)現(xiàn)原理計算的程序是正確的



4 、51單片機c語言 _nop_()是一個空指令?短時間延時的?空幾個機器周期?
答:這個_nop_()等效與匯編里面的,NOP指令,也就是空一個機器周期,如果是傳統(tǒng)51單片機的話,等于空12個時鐘周期

5、51單片機 延時500ms 用機器周期疊加怎么算?
答:DELAY:
MOV R7,#4
D2:MOV R6,#250
D1:MOV R5,#250
DJNZ R5,$
DJNZ R6,D1
DJNZ R7,D2
RET
假設(shè)晶振為12MHz
剛延時時間為:
250*250*4*2=500MS

6、51單片機C語言程序中延時函數(shù)delay的原理是什么?
現(xiàn)在找到兩個函數(shù)
第一:
void delay(void)
{ unsigned int i,j;
for(i=0;i<500;i++)
{ for(j=0;j<121;j++)
{;}
}
}

第二:
void delay(unsigned int k)
{ unsigned int i,j;
for(i=0;i{ for(j=0;j<121;j++)
{;}
}
}
現(xiàn)有幾個疑問:
(1):延時函數(shù)的原理?
(2):兩個for循環(huán)的作用?
(3):i、j的取值有什么規(guī)律和依據(jù)?是不是和單片機接的晶振頻率有關(guān)?所能延時的最小單位時間是怎么計算的?
延時時間怎么計算啊!假如用的是AT89C51RC+11.0592M的晶振呢?
答:
1:原理:僅僅執(zhí)行一些,沒有實質(zhì)性影響的所謂“無意義指令”,比如做比大小啊,做某個int的自加運算啊之類的
2:兩重for的作用:簡單的說,就像高中數(shù)學(xué)中的“乘法原理”一樣,這樣可以很輕易的迅速增加上述“無意義指令”的數(shù)目
3:關(guān)于取值大小:這個如果是在C下變成,這個值不僅僅與晶振、單片機本身運算速度有關(guān),而且還與C的編譯器有關(guān),所以說,這個值雖說是可以精確計算的,但大多數(shù)情況下,程序員用的都是“經(jīng)驗值”——當(dāng)然,如果用匯編編程,情況就不一樣了,因為每一條指令所使用的機器周期是一定的,你當(dāng)然可以根據(jù)所有指令使用的總時間,精確的算出具體延時的總時間

綜合你的的問題,我給你一點建議,就是剛學(xué)單片機的時候,還是一定要老老實實的從匯編編程學(xué)起——這樣,在你以后接觸到C之后,你才能明白,這中間實際上經(jīng)歷了一個什么樣的過程,只有這樣你才能真正理解單片機。當(dāng)然,等最終你完全拿下一種單片機之后,盡量使用C編程,無疑是歷史所肯定的。

7、51單片機,晶振為6M,求一個10ms的延時程序
答:延時有很多種方法,有一種是讓單片機去做無聊的循環(huán),還有一種是用定時器。
第一種的算法是:
晶振的周期T1=1/f; 這里f=6MHz 所以T1=1/6 us;(微秒)
單片機花12個T1去執(zhí)行一個指令,
所以一個機器周期等于12個晶振周期,
T2=12*T1=2us
10ms=1000 0us
所以你要得到10ms的延時就要想辦法讓機器去做5000條“無聊的指令”
所以
DEL: MOV R5,#05H
F1: MOV R6,#05H
F2: MOV R7,#32H
F3: DJNZ R7,F3
DJNZ R6,F2
DJNZ R5,F1
RET
這種方法是用于對時間要求不高的地方,我說的是其思想,程序中可能有錯的地方
用定時器的方法我不太會就不誤人了 (補充一下就是這個是用匯編寫的,你在主程序中用ACALL DEL調(diào)用就延時了。


8、今天我用單片機做“眨眼的LED”實驗時,程序運行,每次只令燈亮或滅都沒問題,但是一開延時不能出現(xiàn)期盼的燈亮燈滅的現(xiàn)象,這是怎么回事?
實驗的硬件條件是:STC89C52,編譯環(huán)境:keil 3。

下面是我寫的程序,請教高手?。?!


#include // 文件包含處理
#define uchar unsigned char //宏定義,方便以后程序的書寫
#define uint unsigned int
sbit P1_0 = P1 ^ 0; //位變量定義
void Delay(uint t)
{
uchar i;
while(--t)
{
for(i = 0; i < 125; i++) //延時1MS,在這里我們用的晶振是是12M,根據(jù)機器周期的計算,我們
{;} //可算得本次循環(huán)延時約1MS
}
}
void main(void)
{
while(1)
{
P1_0 = 0; //點亮LED燈
Delay(1000); //應(yīng)單片執(zhí)行程序的時間很快,所以必須延時,要不看不到實驗現(xiàn)象
P1_0 = 1; //熄滅LED燈
}

補充提問:我是讓P1.0先低然后延時之后再高,即燈先亮再滅,然后開始循環(huán)的

答:應(yīng)該這樣寫
while(1)
{
P1_0 = 0; //點亮LED燈
Delay(1000); //應(yīng)單片執(zhí)行程序的時間很快,所以必須延時,要不看不到實驗現(xiàn)象
P1_0 = 1; //熄滅LED燈
Delay(1000);
補充問題:問題恰恰就錯在這了,循環(huán)完一遍之后燈由滅到亮根本沒有時間延時,即第一次循環(huán)中燈還沒來的機滅呢,就進入到第二輪循環(huán)中的亮了,所以原因就在這,這錯誤太低級了,以后引以為鑒吧

9、單片機延時函數(shù)的問題
void delay(uchar i)
{
uchar j;
while(i--)
{
for(j=125;j>0;j--)
;
}
}
這個函數(shù)中的i,j的大小有嗎?

答:這個函數(shù)中j的大小和你定義的數(shù)據(jù)類型有關(guān),因為你定義的為無符號字符型,為單字節(jié)數(shù)據(jù),所以最大為255。.
如果你需要增大,可以改變j的數(shù)據(jù)類型定義,如unsigned int (2字節(jié))可以到65535;無符號長整形unsigned long(4字節(jié)) 可以到4294967295。 而上面所所256是-1,而你定義的是無符號字符型。

10、請教一個AVR單片機延時的問題
外部晶振用的是8MHz,延時1微秒的程序如下:
void delay_us(unsigned int delay_counter)//延時1us
{
do
{
delay_counter--;
}
while(delay_counter>1);
}
請問,為什么能延時1微秒啊?

答:8MHZ表示單片機的運行周期為1/8us,也就是0.125us執(zhí)行一步
你使用的是軟件延時
那么包括程序的提取,執(zhí)行等都要花費時間
比如,你提取這個函數(shù)可能花去一步,那現(xiàn)在就使用了0.125us啦
接著你執(zhí)行這個函數(shù),在單片機內(nèi)部,運算是通過寄存器的移來移去實現(xiàn)的
這都需要時間,可能你看到的就一句counter--這個指令,可能會花費好幾個時鐘周期來實現(xiàn)
舉個例子:
c=a+b,只有一句,但實際上花費的時間并不短
mov a,#data1;//數(shù)據(jù)data1放入a寄存器
mov b,#data2;//數(shù)據(jù)data2放入b寄存器
add a,b;//寄存器a的值與b相加,結(jié)果放入a
mov c,a;//將a的值放入c
這樣才是單片機內(nèi)部真正執(zhí)行的指令,這需要花費至少4個時鐘周期,而不是1個
至于晶體管級的我就不解釋了,你得好好學(xué)習(xí)匯編才能理解單片機的運作。

至于這個函數(shù)為什么能延時1ms,這個是靠經(jīng)驗來判斷的,最直接的方法就是用示波器看,以上均為推論。

本文引用地址:http://m.butianyuan.cn/article/201611/318542.htm

11、PIC單片機的延時問題 晶振4Mhz:
void delay()
{
unsigned int d=1000;
while(--d){;}
}
此函數(shù)在4M晶體下產(chǎn)生10003us的延時,也就是10MS。
問題:我剛算了一下他應(yīng)該執(zhí)行了999條指令,1條單周期的指令也才1US,那就是999us,為什么會有10ms的延時?
1:for(x=100;--x;){;} : 2: for(x=0;x<100;x++){;} 2句話相同
第一句:X的值范圍是不是 1~99?為什么?
第二句:X的范圍是不是0~99?為什么?這么算的。我知道符號在前在后的區(qū)別。2句話應(yīng)該是不一樣的才對??!
答:
問題1:“我剛算了一下他應(yīng)該執(zhí)行了999條指令”因為你算錯了。延時時間是由產(chǎn)生的匯編代碼所決定的,C語言語句只是個假象,千萬不要以為C語言一行就是一條指令!此處由于涉及到雙字節(jié)減法,因此會有額外的判斷,編譯結(jié)果每次循環(huán)耗費幾十個周期毫不奇怪。

問題2:前一句x從100開始遞減,遞減至1時退出循環(huán)。后一句x從0開始遞增,遞增到100時退出循環(huán)。所謂“2句話”相同僅僅是指這兩個循環(huán)體的循環(huán)次數(shù)相同。實際上兩個循環(huán)的執(zhí)行過程是完全不同的,所消耗時間也有可能不同。

12、stc單片機的延時問題 ,STC10F08XE單片機,晶振22.1184M
void delay(unsigned long uldata)
{
unsigned int j = 0;
unsigned int g = 0;
for (j=0;j<5;j++)
{
for (g=0;g{
_nop_();
_nop_();
_nop_();
}
}
}
當(dāng)uldata=1時延時多少秒?
請給出具體算法…………
答:用keil轉(zhuǎn)換成匯編語句,然后對照指令表計算就行了

13、我想用單片機連接不斷地向電腦發(fā)數(shù),如下:
while (1)
{
send_char(9);
delay(n);
}
如每發(fā)送一個數(shù),應(yīng)延時多少微妙好呢?即一般最短能延時多少微米呢?如延時太長的話,那發(fā)送很多數(shù)據(jù)不就用很長時間嗎?

答:不做太多的串口處理分析,只順著你的問題和你的方法說說:
先考慮下串口的速率 假設(shè)9600,那么發(fā)送一個字符要多久?
(9600bit/S) / 10bit(一個字符1+8+1) = 960字符/秒 約 1ms/byte
也就是說你如果在1ms內(nèi)發(fā)送超過一個字符就沒意義了,硬件速度達(dá)不到。
while(1)
{
send_char(9);
delay(n);
}
這個循環(huán)是執(zhí)行周期也就十幾微秒+delay()的延遲,所以任何小于1040微秒的延遲對串口硬件來說沒意義,上一個還沒處理完,下一個就來了根本執(zhí)行不了嘛。
如果你send_char()里面有while(!TI);TI = 0;這樣的語句或有串口中斷TI的處理的話,那么實際上你的delay()已經(jīng)在發(fā)送函數(shù)里了,while(!TI);這部就是延遲等待嗎?那根本不需要主函數(shù)去延遲了,直接發(fā)就行了。

14、一個單片機延時子程序的問題,在延時子程序那里,一直搞不明白,給r7和r6賦予0,然后下面的djnz r7,delayloop不就一直循環(huán)了,那還怎么接下去的程序?

org 0000h
ljmp start
org 0030h
start: mov a,#0feh
mov r5,#8
output: mov p1,a
rl a
call delay
djnz r5,output
ljmp start
delay: mov r6,#0
mov r7,#0
delayloop:djnz r7,delayloop
djnz r6,delayloop
ret
end

答: 你的延時程序不是因為值為0,而是跳轉(zhuǎn)位置不對,改為如下:
delay: mov r6,#0
delayloop:mov r7,#0
:djnz r7,$
djnz r6,delayloop
ret
R7,R6初值為0,但是當(dāng)DJNZ執(zhí)行時,這條指令是先減1再判斷,所以0-1=255,判斷的話也不為0,仍然循環(huán)256次。

0-1=255的解釋:
0000 0000
- 0000 0001
-------------------------
1111


15、我想提兩個單片機延時與按鍵的問題
1:如果一個程序中延時和按鍵,如果延時子程序比較長(假如2秒),怎樣確保按鍵能夠得到及時響應(yīng)(假如PC正在執(zhí)行延時子程序,正在這時候有按鍵輸入,不是響應(yīng)不了)——,,,前提是不能用定時器定時掃描,和中斷來做,因為定時器和中斷我另有其他用途
2:單片機沒有串口。怎樣才能使得他與24C02進行通信(24C02是具有2K內(nèi)存的EEPROM)
答:
首先明確一點你說單片機沒有串口,應(yīng)該是指沒有I2C口吧。
1 在延時程序里面加入按鍵的檢測
2 用IO口模擬I2C時序讀寫

16、51單片機延時小程序,求高手解釋什么意思?
delay200ms:
mov r2,#82
l0:mov r1,#116
l1:mov r0,#9
djnz r0,$
djnz r1,l1
djnz r2,l0
ret
答:以下是每條指令的時間,T為一個機器周期
delay200ms:
mov r2,#82;1T
l0:mov r1,#116;1T
l1:mov r0,#9;1T
djnz r0,$;2T
djnz r1,l1;2T
djnz r2,l0;2T
ret;2T
以上共三層循環(huán),忽略部分指令,最簡單算法是:
2*9*116*82=171216
不忽略指令是:
1+(1+(1+2*9+2)*116+2)*82+2=200001
因此延時時間大約為200ms


17、于51單片機延遲時間的問題
uchar i;i--;
uint i;i--;
這兩條語句在12M晶振下運行時間分別是多少??
答:一個時鐘周期,2us,共4us

18、周期為6MHZ的單片機延時10秒的子程序的怎么編?
答:/
* 名稱 : Delay()
* 功能 : 延時,延時時間為 10ms * del。這是通過軟件延時,有一定誤差。
* 輸入 : del
* 輸出 : 無
*/
void Delay(uint del)
{
uint i,j;
for(i=0; ifor(j=0; j<1827; j++) //這個是通過軟件仿真得出的數(shù)
;
}
這個是晶振為12mhz的單片機延時10ms的程序,你只要在這個基礎(chǔ)上減小一倍就行了,當(dāng)然至于具體值還是要調(diào)試下的。


19、片機的有些程序需要調(diào)用延時程序,如何能合理的安排循環(huán)次數(shù)以及空操作的個數(shù)?
答:用匯編的話就根據(jù)你的當(dāng)前晶振頻率去推算你的指令周期,然后結(jié)合你需要延遲的時間,編寫延遲程序,用C的話還是要看最后生成的匯編碼是什么樣的了。最簡單的方法就是寫好程序以后再編譯器里軟仿真看時間。贊同2| 評論(1)

20、單片機延時程序問題
延時程序 void delay(uint dt)
{
uchar bt;
for(;dt;dt--);
for(bt=0;bt<255;bt++);
}
編譯時有警告C:DOCUMENTS AND SETTINGSADMINISTRATOR桌面字 310 點陣LED顯示.C(46): warning C235: parameter 1: different types
為什么?求大俠指點
答:某個函數(shù)傳參類型與聲明類型不符。
另外你這個for(;dt;dt--);沒有起到外層循環(huán)的作用……

二、單片機中斷問題30例

1、單片機外中斷INT0為下降沿觸發(fā),當(dāng)中斷被觸發(fā)后cpu執(zhí)行中斷程序,若本次中斷的程序還未執(zhí)行完INT0又來了一個相同的下降沿中斷信號怎么辦?cpu會怎么處理?若是定時器中斷呢?串口中斷呢?求解釋
答:再來一個INT0信號不會執(zhí)行。相同的優(yōu)先級不會打斷正在執(zhí)行的中斷。
一. 如果是高優(yōu)先級的中斷來了,會打斷低優(yōu)先級的正在執(zhí)行的中斷而執(zhí)行高優(yōu)先級的中斷。
51單片機的默認(rèn)(此時的IP寄存器不做設(shè)置)中斷優(yōu)先級為:
外部中斷0 > 定時/計數(shù)器0 > 外部中斷1 > 定時/計數(shù)器1 > 串行中斷;
當(dāng)同時有幾種中斷到達(dá)時,高優(yōu)先級中斷會先得到服務(wù)。
例如:當(dāng)計數(shù)器0中斷和外部中斷1(優(yōu)先級 計數(shù)器0中斷>外部中斷1)同時到達(dá)時,會進入計時器0的中斷服務(wù)函數(shù);但是在外部中斷1的中斷服務(wù)函數(shù)正在服務(wù)的情況下,這時候任何中斷都是打斷不了它的,包括邏輯優(yōu)先級比它高的外部中斷0計數(shù)器0中斷。
51單片機的中斷優(yōu)先級控制寄存器IP可以把默認(rèn)的中斷優(yōu)先級設(shè)置為高或低級,
例如默認(rèn)是外部中斷0 > 定時/計數(shù)器0 > 外部中斷1 > 定時/計數(shù)器1 > 串行中斷;
現(xiàn)在設(shè)為定時1 和串行中斷為高優(yōu)先級 其它為低 ,那么中斷0執(zhí)行時會被定時器1 或串行中斷打斷,如果設(shè)定的兩個高優(yōu)先級定時/計數(shù)器1 和串行中斷同時響應(yīng),會再自然排隊,先執(zhí)行定時1中斷再執(zhí)行串行中斷。

2、單片機中斷問題,中斷3為什么不執(zhí)行,整個程序有什么不對的地方呢?
#include
#define uint unsigned int
#define uchar unsigned char
sbit p1_0=P1^0;
sbit p1_1=P1^1;
sbit p1_2=P1^2;
sbit p1_3=P1^3;
sbit p1_4=P1^4;
sbit p1_5=P1^5;

uchar PWM_T1 = 0;
uchar PWM_T2 = 0;
uint i,m;
void delay(uint z)
{
for(i=z;i>0;i--)
for(m=0;m<110;m++);
}
void PWM_value_left(int pwm_set)
{
PWM_T1=pwm_set;
}
void PWM_value_right(int pwm_set)
{
PWM_T2=pwm_set;
}
void main(void)
{
bit flag = 1;
uint n;
TMOD=0x22;
TH0=241;
TH1=241;
TL0=241;
TL1=241;
TR0=1;
TR1=1;
ET0=1;
ET1=1;
EA=1;
P1=0xf0;
delay(20);
PWM_value_left(7);
PWM_value_right(10);
delay(100);
PWM_value_left(8);
PWM_value_right(9);
delay(100);
PWM_value_left(9);
PWM_value_right(8);
delay(100);
PWM_value_left(10);
PWM_value_right(7);
}
timer0() interrupt 1 using 2
{
static uint t ;
t++;
if(t==10)
{
t=0;
p1_0=1;
p1_1=0;
}
if(PWM_T1==t)
P1=P1&0xfc;
}
timer1() interrupt 3
{
static uint t1 ;
t1++;
if(t1==10)
{
t1=0;
p1_2=1;
p1_3=0;
}
if(PWM_T2==t1)
P1=P1&0xf3;
}

答:沒有主循環(huán),
沒有等到中斷3
程序運行一次就跑飛了?。?!

void main(void)
{
//...你的程序
//在這里加 死循環(huán),等待中斷
while(1)
{
;
}
}
而且,中斷響應(yīng)函數(shù)里必須要清中斷標(biāo)志位(你的沒有)!

3、各位大俠幫我看一下我寫的51單片機C程序中斷有沒有問題,執(zhí)行中斷后不能繼續(xù)執(zhí)行主程序,注:P3.2口一直接
注:P3.2口一直接地,程序如下:
#include
sbit dula=P2^6;
sbit wela=P2^7;
sbit d0=P1^0;
sbit d1=P1^1;
sbit d2=P1^2;
sbit d3=P1^3;
sbit d4=P1^4;
sbit d5=P1^5;
sbit d6=P1^6;
sbit d7=P1^7;
#define uchar unsigned char
#define uint unsigned int
uchar num;
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
void delay(uint z);
void main()
{
EA=1;
EX0=1;
IT0=0;
wela=1;
P0=0xc0;
wela=0;
while(1)
{

for(num=0;num<16;num++)
{
dula=1;
P0=table[num];
dula=0;
delay(1000);
}
}
}
void delay(uint z)
{
uint a,b;
for(a=z;a>0;a--)
for(b=110;b>0;b--);
}
void exter0() interrupt 0
{
uint c;
for(c=0;c<25000;c++);
d0=0;
for(c=0;c<25000;c++);
d0=1;
for(c=0;c<25000;c++);
d1=0;
for(c=0;c<25000;c++);
d1=1;
for(c=0;c<25000;c++);
d2=0;
for(c=0;c<25000;c++);
d2=1;
for(c=0;c<25000;c++);
d3=0;
for(c=0;c<25000;c++);
d3=1;
for(c=0;c<25000;c++);
d4=0;
for(c=0;c<25000;c++);
d4=1;
for(c=0;c<25000;c++);
d5=0;
for(c=0;c<25000;c++);
d5=1;
for(c=0;c<25000;c++);
d6=0;
for(c=0;c<25000;c++);
d6=1;
for(c=0;c<25000;c++);
d7=0;
for(c=0;c<25000;c++);
d7=1;

}
答:
IT0=0;//低電平觸發(fā),只要單片機監(jiān)測到是低電平,就觸發(fā)中斷
你P3.2一直接地,一直是低電平,那中斷就不斷的執(zhí)行,當(dāng)然回不到主程序中了。
改成IT0=1;//下降沿觸發(fā),單片機監(jiān)測到高電平到電平跳變,就觸發(fā)中斷
就算P3.2一直接地,也只觸發(fā)一次,中斷執(zhí)行完了,就回到主程序中了。

4、我的單片機這個程序為什么不能完全執(zhí)行整個程序誰能告訴我!就是沒法執(zhí)行3次亮暗的!
2010-10-20 21:40 提問者:3865203bin3 | 懸賞分:10
ORG 0000H
AG:MOV A,#11111110B
AG1:RL A
MOV P0,A
ACALL DELAY
DJNZ R0,AG1
ACALL DELAY
MOV A,#11111111B
MOV P1,A
ACALL DELAY
MOV P0,#00000000B
ACALL DELAY
MOV P0,#11111111B
ACALL DELAY
MOV P0,#00000000B
ACALL DELAY
MOV P0,#11111111B
ACALL DELAY
SJMP AG
DELAY:MOV R3,#10
D3:MOV R2,#200
D1:MOV R1,#250
D2JNZ R1,D2
DJNZ R2,D1
DJNZ R3,D3
RET
END

我是想執(zhí)行完流水燈亮.就然后執(zhí)行全亮全暗3次 !可是就是不會跳到全亮全暗3次~~

答:
R0沒有賦初值!另外建議不要使用前2B個地址,因為51中斷矢量就在這個空間里。建議從0030H開始。以下程序在keil4中仿真成功。
ORG 0000H
AJMP AG
ORG 0030H
AG:MOV A,#11111110B
MOV R0,#8
AG1:RL A
MOV P0,A
ACALL DELAY
DJNZ R0,AG1
ACALL DELAY
MOV A,#11111111B
MOV P1,A
ACALL DELAY
MOV P0,#00000000B
ACALL DELAY
MOV P0,#11111111B
ACALL DELAY
MOV P0,#00000000B
ACALL DELAY
MOV P0,#11111111B
ACALL DELAY
SJMP AG
DELAY:MOV R3,#10
D3:MOV R2,#200
D1:MOV R1,#250
D2JNZ R1,D2
DJNZ R2,D1
DJNZ R3,D3
RET
END

5、STC89C52通過兩個外部中斷P3.2和P3.3,來控制P1.0和P1.1的數(shù)碼管亮和滅,一定keil C
說明:通過外部中斷0,P1.0的數(shù)碼管亮,中斷結(jié)束后,數(shù)碼管滅;再由外部中斷1,P1.1的數(shù)碼管亮,次中斷結(jié)束后,數(shù)碼管滅;簡言之就是一個中斷只控制一個數(shù)碼管,中斷之間在功能上沒有必然的聯(lián)系,編程環(huán)境keil C51。P1.0和P1.1口上接的都是普通LED小燈,數(shù)碼管=LED小燈。

以下是我編的程序,就是一個中斷控制一個數(shù)碼管,但是當(dāng)有兩個中斷時,我就抓瞎了
#include
sbit D1=P1^0;
void main()
{
D1=1;
EA=1;
EX0=1;
}
void exter() interrupt 0
{
D1=0;
}
求高手幫我改改程序,改成兩個中斷的那種,功能要求都寫在上面了~3Q,我會去keil里面模擬的~~o()^))o

答:
/*模塊低電平有效、外部中斷0、1為低電平出發(fā)*/
#include "reg52.h"
void delay( char i)
{
unsigned char t;
while(i--)
{
for(t=0;t<108;t++);
}
}
void INT0_ROUTING() interrupt 0//外部中斷0子程序
{
P0=0xfe;//LED0點亮
while((P3|0xfb)==0xff);//等待外部中斷0口(P3^2松開)
delay(10);//延時去抖動
P0=0xff;//LED0熄滅
}
void INT0_ROUTING() interrupt 2
{
P0=0xfd;//LED1點亮
while((P3|0xf7)==0xff);//等待外部中斷1口(P3^3松開)
delay(10);//延時去抖動
P0=0xff;//LED1熄滅
}

void main()
{
EA=1;//中斷總開關(guān)
EX0=1;//外部中斷0開
EX1=1;//外部中斷1開
/*默認(rèn)低電平觸發(fā)*/
while(1);//死循環(huán) 防止跑飛
}

6、單片機中斷問題,下面這段程序不知道為什么只進一次中斷,就沒有反應(yīng)了呢?

#include // 包含51單片機寄存器定義的頭文件
#define uint unsigned int
sbit key1=P1^4;
sbit key2=P1^5;

void delay1ms(uint i)
{
uchar j;
while(i--)
{
for(j=0;j<125;j++) //1ms基準(zhǔn)延時程序
{
;
}
}
}
void init()
{
EA=1; //開總中斷
ES=1; //開串口中斷
TMOD= 0x21; //定時器1定時方式2,定時器1工作于8位自動重載模式, 用于產(chǎn)生波特率
SCON = 0x50; // 設(shè)定串行口工作方式1 允許接收
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TH1= 0xfd; //11.0592M 波特率9600
TL1= 0xfd;
PCON =0x00; // 波特率不倍增
TR1= 1; //啟動定時器T1
TR0=1; //啟動定時器T0
ET0=1; //打開T0中斷
}
void key()
{
if(key2==0)
P0=0x3f;
delay1ms(5000);
P0=0xf3;
}
void mainxh()
{
while(1)
{
key();
P0=0x32;
}
}
void keybreak()
{
P0=0xf1;
delay1ms(5000);
P0=0x1f;
mainxh();
}
void main(void)
{
init();
mainxh();
}
void Time0(void) interrupt 1
{
TH0=(65536-50000)/256; //定時器T0的高8位重新賦初值
TL0=(65536-50000)%256; //定時器T0的高8位重新賦初值
if(key1==0)
keybreak();
}

這個程序上電后P0口顯示0x32;按下key2顯示0x3f;key1用于中斷,每20ms檢測是否有按下key1鍵,有的話,P0口顯示0xf1。

答 :
ORG 0000H AJMP MAIN ORG 0001H LJMP INT_0 ORG 30H MAIN:MOV SP,#8FH MOV P0,#0FFH MOV P3,#0FFH SETB IT0 SETB EA SETB EX0 LJMP START START: MOV A,#10000000B LOOP: MOV P0,A RLC A LCALL DELAY LCALL DELAY LJMP LOOP LJMP START;
這句是多余的 根本不會執(zhí)行 INT_0: PUSH ACC ;
由于p中1斷中1A被設(shè)為10所以5中7斷返回后對A移位沒有意義,o A一e直為10 ,并不d是只能中斷一1次 .
還有,不清楚key1是什么中斷,貌似是鍵盤掃描吧,
while(1)
{
key();
P0=0x32;
}
都進入死循環(huán)了,所以跳不出來,就一次中斷了。

7、新手學(xué)習(xí)avr單片機ATmage 128 遇到問題,中斷程序被忽略問題,找不到原因。
avr studio 4 軟件仿真時,編譯通過了,單在編譯信息欄卻看到中斷程序被忽略。在軟件仿真時也發(fā)現(xiàn)中斷程序沒有執(zhí)行。不知道問題出在哪里,我用的是avr studio 4 ATmage 128 單片機.

程序如下

#include
#include
void main() //用的是TC0 溢出中斷,來控制八位LED 一秒閃爍
{
PORTE = 0xFF; //LED 關(guān) 端口高電平位關(guān)
DDRE = 0xFF;
MCUCR |=(1<sei(); //開啟全局中斷
TIMSK|=(1<TCNT0 =155; //定時器賦初值
TCCR0 |= (1 << CS01); //8分頻
while (1);

}

volatile unsigned int j =0;
#pragma interrupt_handler timer0_ovf_isr:17
void timer0_ovf_isr(void)
{
TCNT0 = 156; //設(shè)初值
j++;
if(j <= 5000) //中斷5000次后 執(zhí)行LED 電平翻轉(zhuǎn)
PORTE ^= 0xFF; //LED 電平翻轉(zhuǎn)

}


../lesson2.c:18: warning: ignoring #pragma interrupt_handler timer0_ovf_isr

上面是寫的程序。還有編譯信息欄里的話。

答:
不是,你那句#pragma interrupt_handler timer0_ovf_isr:17是ICCAVR編譯軟件中寫中斷的方式,而看你的頭文件#include 和#include 應(yīng)該是用avr studio裝GCCavr編譯軟件的寫法,你加上把中斷成
SIGNAL(SIG_OVERFLOW0)
{
TCNT0 = 156; //設(shè)初值
j++;
if(j <= 5000) //中斷5000次后 執(zhí)行LED 電平翻轉(zhuǎn)
PORTE ^= 0xFF; //LED 電平翻轉(zhuǎn)

}
看看,記住,這是GCCAVR 編譯軟件的寫法

8新學(xué)的C51單片機,編了個電平觸發(fā)式中斷程序,不知道為什么和跳變沿的一樣了,諸位幫忙看看.
#include
#define uchar unsigned char
#define uint unsigned int
sbit d1=P1^0;
sbit dula=P2^6;
sbit wela=P2^7;
void delay(uint z);
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
void main()
{
EA=1;
EX0=1;
IT0=0;
while(1)
{ d1=1;
dula=1;
P0=table[1];
dula=0;
P0=0xff;
wela=1;
P0=0xfe;
wela=0;
delay(500);

dula=1;
P0=table[2];
dula=0;
P0=0xff;
wela=1;
P0=0xfd;
wela=0;
delay(500);

dula=1;
P0=table[3];
dula=0;
P0=0xff;
wela=1;
P0=0xfb;
wela=0;
delay(500);

dula=1;
P0=table[4];
dula=0;
P0=0xff;
wela=1;
P0=0xf7;
wela=0;
delay(500);

dula=1;
P0=table[5];
dula=0;
P0=0xff;
wela=1;
P0=0xef;
wela=0;
delay(500);

dula=1;
P0=table[6];
dula=0;
P0=0xff;
wela=1;
P0=0xdf;
wela=0;
delay(500);


}
}
void delay(uint z)
{
uint x,y;
for(x=100;x>0;x--)
for(y=z;y>0;y--);
}
void enter() interrupt 0
{
d1=0;
}

答: 你這個程序中設(shè)置IT0=0,說明是低電平觸發(fā),所以只要P3^2口一直是低電平那么主程序停止,所以發(fā)光二極管點亮,如果P3^2口變?yōu)楦唠娖?,主程序繼續(xù),發(fā)光二極管熄滅。另一種情況是當(dāng)IT0=1的時候是負(fù)跳變觸發(fā),就是當(dāng)P3^2口檢測到一個又高電平到低電平的跳變后,觸發(fā)中斷,在中斷函數(shù)中點亮燈,立即出中斷,執(zhí)行到d1=1時熄燈??吹降默F(xiàn)象就是燈閃一下,直到又檢測到一個負(fù)跳變,燈又閃一下。兩種觸發(fā)方式的現(xiàn)象是不一樣的,如果你硬件沒問題的話。你可以把中斷函數(shù)寫成d1=!d1試試。

9、在C51單片機中,中斷服務(wù)程序怎么撤銷中斷引腳上的低電平?
我用的是,第一個單片機輸出低電平到第二個單片機的P3^2,第二個單片機是電平觸發(fā)方式中斷
低電平觸發(fā)方式:要求低電平保持到CPU實際響應(yīng)為止,為了避勉CPU再次響應(yīng)中斷,在中斷服務(wù)程序中應(yīng)該撤除中斷引腳上的低電平。請問,怎么撤銷?在中斷服務(wù)程序中怎么寫? 直接寫P3^2=1;行嗎?
答:
第一個單片機的程序,是誰來編寫? 如果也是樓主,那就好辦了。
第二個單片機完成了中斷的功能,在退出之前,可以向第一個單片機回送一個脈沖;
第一個單片機收到這個脈沖,就應(yīng)該撤消送到第二個單片機的中斷申請信號。
----
另外,如果能算出來完成中斷的時間,第一個單片機送來的申請信號,就不要超過這個時間,應(yīng)該及時、自動的撤消申請信號。
第一個單片機送來的申請信號,也不可過短,應(yīng)該能讓對方檢測到。

10、程序如下,我想要得到的效果是1秒左邊的電動機轉(zhuǎn)動,同時黃燈亮,1秒右邊轉(zhuǎn)動,藍(lán)燈亮,以此循環(huán)下去,但是這個程序用上去后,左邊轉(zhuǎn)》右邊轉(zhuǎn)》左邊轉(zhuǎn)》之后就一直是左邊了,不切換了,誰能幫我解決下問題,感激不盡!!
#include
sbit m=P2^0;
sbit b=P2^6;
sbit y=P2^7;
unsigned char count;
void main()
{
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TR0=1;
ET0=1;
EA=1;
count=0;
m=!0;
b=!1;
y=!0;
while(1)
{
if(TF0==1)
{
count++;
if(count==20)
{
m=0;
b=1;
y=0;
}
if(count==40)
{
m=!0;
b=!1;
y=!0;
}
TF0=0;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
}
}
}


答案
#include
sbit m=P2^0;
sbit b=P2^6;
sbit y=P2^7;
unsigned char count;
void main()
{
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TR0=1;
count=0;
m=!0;
b=!1;
y=!0;
while(1) {
if(TF0==1) {
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TF0=0;
count++;
if(count==20) {
m=0; b=1; y=0;
}
if(count==40) {
count=0; //加上這句.
m=!0; b=!1; y=!0;
}
}
}
}!
用T0定時50ms,溢出20次,溢出40次,分別代表了具體的時間。 溢出40次之后,應(yīng)該從頭開始統(tǒng)計溢出次數(shù),所以,此處應(yīng)該有count=0;。 樓主原來的程序,缺少count=0;,那么它就會繼續(xù)增加,直到65536,才自動回到0。 這樣,時間,就難以控制了。

11、求助關(guān)于51單片機外部中斷的問題,小弟最近在學(xué)單片機,剛做了一個鍵盤掃描程序。發(fā)現(xiàn)如果外部中斷為電平觸發(fā),程序能正常運行。但如果改為邊沿觸發(fā),在將鍵值送給顯示重開中斷指令為EX0=1后,中斷竟然還會被觸發(fā)一次,這之后,再按鍵就不能觸發(fā)中斷了。如果將中斷程序中關(guān)中斷語句去掉,按鍵能被掃描,但引起中斷的次數(shù)不好說了。請大俠們看看哪出問題了。謝謝

uchar keynum,//定義全局變量按鍵時的鍵值
dpnum,//顯示值
time1,//延時計數(shù)值
topen,//延時計數(shù)控制
keyin;//外部中斷0向主程序傳遞有中斷標(biāo)識,有鍵按下
keydeal;//按鍵程序調(diào)用標(biāo)志

uchar keytable[4][4]={7,8,9,/,4,5,6,*,1,2,3,-,c,0,=,+};//按實際鍵盤編值
uchar keyboard();//鍵盤掃描程序,負(fù)責(zé)鍵值掃描,判斷鍵釋放由主函數(shù)完成
void display(uchar,uchar);// 顯示子程序,
sbit keysign=P3^2;//P3.2為中斷0入口,此定義用于程序判斷是否真有鍵按下及鍵是否釋放
void main()
{uchar keybiao,keybiao1;//有鍵按下標(biāo)志,鍵放開標(biāo)志
IE=0x89;//開總中斷,外部中斷0,定時器中斷1
IT0=1;//中斷觸發(fā)方式
PT1=1;//中斷優(yōu)先級
TMOD=0x90;//定時器1工作方式1
TH1=(65536-5000)/256;//定時器初值高8位(定時5ms)
TL1=(65536-5000)%256;
TR1=1;//開始計時
P2=0xf0;//給鍵盤列高電平,行低電平
keydeal=0x00;//讓鍵處理初值為0,既未處理
while(1)
{if(keyin==1) //可能有鍵按下
{
if(time1>=2)//已延時10ms;計數(shù)2次,
{if(keysign==0&&keydeal==0)
{keynum=keyboard();
keybiao=1;
keydeal=1;
topen=0;//關(guān)延時計數(shù)
}//判斷是否真有鍵按下,調(diào)用鍵盤掃描程序
else if(keybiao==0&&time1>=2&&keybiao1==0)
{EX0=1;
keyin=0;
topen=0;
}//如果沒鍵按下,重開外部中斷0,中斷標(biāo)志清0
}
if(keybiao==1&&keysign!=0)
{keybiao=0;
time1=0;
keybiao1=1;//為防止前一次time1的影響而設(shè)的標(biāo)志
topen=1;
}

if(keybiao1==1&&time1>=2)
{keybiao1=0;
topen=0;
EX0=1;
keyin=0;//重開外部中斷0,中斷標(biāo)志清0
keydeal=0;//重開鍵未處理,讓程序可調(diào)用處理程序
dpnum=keynum;//將鍵值傳給顯示
}
}
}
}
void display(uchar x,uchar i)//中斷控制顯示,顯示一直持續(xù)到下次中斷到

uchar keyboard()
{uchar con1,con2,i,j;
con1=P2|0x0f;//只保留P2口高四位,便于switch
switch(con1)//通過cp可得到列為0的位
{case 0x7f:j=3;break;//j為列值
case 0xbf:j=2;break;
case 0xdf:j=1;break;
case 0xef:j=0;break;
}
for(i=0;i<=3;i++)
{P2=_crol_(0xfe,i);//依次給行賦0
con2=P2|0x0f;// 只保留P2口高四位,便于比較
if(con2!=0xff) break;
}
P2=0xf0;//給鍵盤列高電平,行低電平
return(keytable[i][j]);

}

void T1_time()interrupt 3
{TH1=(65536-5000)/256;//定時器初值高8位(定時5ms)
TL1=(65536-5000)%256;
time1++;
if(topen!=1) time1=0;//如果延時標(biāo)志不為1,不開始計時
display(dpnum,5);
}
void int0()interrupt 0
{EX0=1;
keyin=1;//向主程序傳遞鍵按下
topen=1;//10ms延時計數(shù)開始
}
由于字?jǐn)?shù)有限,有部分程序給刪了,顯示等部分程序應(yīng)該沒問題,我在其它地方能正常運行。

答:
不需要每次在進入中斷程序后開一次中斷;EX0=1可以去掉。
實際上,外部中斷工作在邊沿觸發(fā)方式的時候,第一次電平跳變觸發(fā)后進入中斷程序,然后硬件自動清除IE0中斷標(biāo)志位。但是在執(zhí)行中斷程序的過程中,如果中斷引腳再次檢測到電平跳變(負(fù)到高),那么IE0會被再次置1 。如果在退出中斷程序之前沒及時清0,那么就會再次引發(fā)一次中斷。
而按鍵的過程,不包括按下和松開時的電平抖動,至少會產(chǎn)生兩次電平跳轉(zhuǎn)。
因此,只需在你中斷程序里適當(dāng)加一點延遲,再將EX=1, 改成IE0=0 。

12、我用的單片機是8051F的單片機,在程序中我用了兩個中斷。一個是定時計數(shù)器2產(chǎn)生的中斷100MS一次的數(shù)據(jù)采集。另一個是向上位機發(fā)送采集來的數(shù)據(jù),使用的串口來實現(xiàn)的,用的單片機的UART來實現(xiàn)。也是一個中斷。這兩個中斷在一起工作時需要注意些什么?我的中斷程序出了一些問題。
(就是默認(rèn)情況下,UART的中斷級別更高,但是有的時候UART的中斷不能及時響應(yīng),這是為甚?)
答:
之前和你做的一樣就兩個中斷 UART0加一個定時器 我用的是C8051F040
你向上位機發(fā)送數(shù)據(jù)使用UART0時 要確認(rèn)定時器工作完畢
T2定時中斷后 你加一個完成標(biāo)志如T2FLAG
if(T2FLAG==1) 將采集的數(shù)據(jù)放入 UART0的SBUF0 是UART0工作
你100ms的中斷時間 C8051這么快速的單片機怎么都該發(fā)送完成了吧。

13、MSP430單片機中斷嵌套,如何跳出中斷?
當(dāng)進行A中斷時,來了一個B中斷,我想讓B中斷程序執(zhí)行完后不繼續(xù)
執(zhí)行A中斷而跳出整個中斷,去執(zhí)行主程序,請問這個怎么設(shè)置呢?
答:
中斷的時候會把SR狀態(tài)跟中斷下來要執(zhí)行語句的地址放進堆棧中,實現(xiàn)處理完中斷以后cpu要執(zhí)行的語句,注意是地址先進,SR后進,出棧時SR先出,地址后出,當(dāng)然了在中斷里面可以嵌套中斷的,對可屏蔽中斷來說,主要是CPU響應(yīng)中斷以后,GIE會自動復(fù)位,所以不能對可屏蔽中斷進行嵌套,如果在中斷中要嵌套可屏蔽中斷的話可以開GIE,但要注意的是如果此時正在響應(yīng)的中斷標(biāo)志還是置位的情況下會反復(fù)進入此中斷,就像死循環(huán)一樣,這時會引起堆棧的溢出,而在響應(yīng)可屏蔽中斷時,不可屏蔽中斷不受此影響,因為他不受GIE的影響,只受自己單獨的使能位影響。在堆棧中的操作原理類似。

14、MSP430單片機有幾個需要軟件清除的中斷標(biāo)志?如何清除?
(1)清除各個端口的外中斷用:PxIFG,相應(yīng)的位置0即可;
(2)清除Timer中斷用:TAIFG,TBIFG,相應(yīng)的位置0即可;
答:
MSP430的16個外中斷比如軟件清除Flag,在進入外中斷后,首先要做的就是把相應(yīng)的PxIFG清0;
而定時器Timer中斷是自動清除Flag;
還有在中斷嵌套的時候會用到,在進入中斷后,MCU會自動把全局中斷位GIE清零,這樣在進入本中斷后就不會再相應(yīng)其他中斷,若要進行中斷嵌套,必須在進入中斷后把GIE再置1.

15、MCS-51系列單片機的有幾個中斷源?各中斷標(biāo)志是如何產(chǎn)生的?如何清除各中斷標(biāo)志?
答:
標(biāo)準(zhǔn)51有5個中斷向量(不算復(fù)位),分別是外部中斷0,定時器0,外部中斷1,定時器1,串行口;總共有6個中斷標(biāo)志,串行口的發(fā)送和接受共享一個中斷向量。
各個終端標(biāo)志產(chǎn)生情況如下:
外部中斷可以設(shè)置邊沿觸發(fā)或者電平觸發(fā),邊沿觸發(fā)進入中斷程序后硬件自動清中斷標(biāo)志,電平觸發(fā)需要軟件清標(biāo)志位;
定時器T0,T1計數(shù)溢出產(chǎn)生中斷,進入中斷程序硬件自動清標(biāo)志位;
串行口發(fā)送完成或者接收到數(shù)據(jù)就觸發(fā)中斷,由于是兩個中斷標(biāo)志共享一個中斷向量,所以需要在中斷程序里由軟件判斷是發(fā)送中斷還是接受中斷,并且只能由軟件清標(biāo)志位;

以上是標(biāo)準(zhǔn)51的中斷系統(tǒng),52由于多了一個T2定時器(T2定時器跟T0,T1功能相差很大,T2要強大很多),因此多了一個中斷向量2個中斷標(biāo)志(溢出中斷和T2外部中斷),T2中斷標(biāo)志必須由軟件清除標(biāo)志位
中斷使能位于IE寄存器
各中斷標(biāo)志位于相應(yīng)的模塊控制寄存器里面
模塊 位地位 位名稱 說明
T1 TCON.7 TF1 T1溢出標(biāo)志
T0 TCON.5 TF0 T0溢出標(biāo)志
T2 T2CON.7 TF2 T2溢出中斷標(biāo)志
T2CON.6 EXF2 T2外部中斷標(biāo)志
外部中斷1 TCON.3 IE1 外部中斷1標(biāo)志
外部中斷0 TCON.1 IE0 外部中斷0標(biāo)志
串行口 SCON.1 TI 發(fā)送中斷標(biāo)志
SCON.0 RI 接受中斷標(biāo)志

16、MCS51單片機的匯編語言的中斷服務(wù)程序最多有幾個?
答:一般而言有5個對:2個外中斷 ,2個定時器中斷, 1個串口中斷。
但是單片機的中斷服務(wù)資源是根據(jù)硬件的結(jié)構(gòu)設(shè)計,會有不同的數(shù)量和類型的中斷服務(wù),,,因此中斷并不是對語言來講的,而是對于硬件資源來講的。比如52有6個中斷。
基于語言編譯器來講,我就舉例個人感覺最好的開發(fā)51大系列的開發(fā)環(huán)境Keil,其編譯器最多支持32個中斷服務(wù),,,,因此中斷對編譯來說,是一個“模擬”的概念。

17、單片機中斷改變頻率,為什么幾個輸出頻率無法改變? 程序如下?
#include
#define uchar unsigned char
#define uint unsigned int
uchar T,t1;
unsigned char data table[5] = {486,236,151,111,86} ;
sbit CLK=P2^3 ;
sbit EN=P2^0 ;
void init();
void main()
{
init();
}
void init()
{
EN=1;
T=0;
TMOD=0x01;
EA=1;
TR0=1;
ET0=1;
t1=table[T];
TH0=(65536-t1)/256;
TL0=(65536-t1)%256;
}
void timer0() interrupt 1
{
TMOD=0x01;
EA=1;
TR0=1;
ET0=1;
t1=table[T];
TH0=(65536-t1)/256;
TL0=(65536-t1)%256;
CLK=~CLK;
}
答:
T你只付了0值,怎么會變化頻率呢?你在主函數(shù)里加個T的賦值語句就行了,例如:while(T){T--;delay1s();}

18、單片機中斷程序的書寫步驟?
答:
標(biāo)準(zhǔn)形式:
void 函數(shù)名(void)interrupt n using m
{函數(shù)體語句}
n ----中斷編號
m-----要使用工作寄存器組號

19、我想知道單片機的蜂鳴器音樂程序中斷是如何響應(yīng)的?從main主程序中如何到中斷程序?具體步驟是啥?謝謝!
#include
sbit speaker = P1^5;
unsigned char timer0h, timer0l, time;
//--------------------------------------
//單片機晶振采用11.0592MHz
// 頻率-半周期數(shù)據(jù)表 高八位 本軟件共保存了四個八度的28個頻率數(shù)據(jù)
code unsigned char FREQH[] = {
0xF2, 0xF3, 0xF5, 0xF5, 0xF6, 0xF7, 0xF8, //低音1234567
0xF9, 0xF9, 0xFA, 0xFA, 0xFB, 0xFB, 0xFC, 0xFC,//1,2,3,4,5,6,7,i
0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFE, //高音 234567
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF}; //超高音 1234567
// 頻率-半周期數(shù)據(jù)表 低八位
code unsigned char FREQL[] = {
0x42, 0xC1, 0x17, 0xB6, 0xD0, 0xD1, 0xB6, //低音1234567
0x21, 0xE1, 0x8C, 0xD8, 0x68, 0xE9, 0x5B, 0x8F, //1,2,3,4,5,6,7,i
0xEE, 0x44, 0x6B, 0xB4, 0xF4, 0x2D, //高音 234567
0x47, 0x77, 0xA2, 0xB6, 0xDA, 0xFA, 0x16}; //超高音 1234567
//--------------------------------------
//世上只有媽媽好數(shù)據(jù)表 要想演奏不同的樂曲, 只需要修改這個數(shù)據(jù)表
code unsigned char sszymmh[] = {5,1,1,5,1,1,6,1,2,5,1,2,1,2,2,7,1,4,5,1,1,5,1,1,6,1,2,5,1,2,2,2,2,1,2,4,
5,1,1,5,1,1,5,2,2,3,2,2,1,2,2,7,1,2
};
//--------------------------------------
void t0int() interrupt 1 //T0中斷程序,控制發(fā)音的音調(diào)
{
TR0 = 0; //先關(guān)閉T0
speaker = !speaker; //輸出方波, 發(fā)音
TH0 = timer0h; //下次的中斷時間, 這個時間, 控制音調(diào)高低
TL0 = timer0l;
TR0 = 1; //啟動T0
}
//--------------------------------------
void delay(unsigned char t) //延時程序,控制發(fā)音的時間長度
{
unsigned char t1;
unsigned long t2;
for(t1 = 0; t1 < t; t1++) //雙重循環(huán), 共延時t個半拍
for(t2 = 0; t2 < 8000; t2++); //延時期間, 可進入T0中斷去發(fā)音
TR0 = 0; //關(guān)閉T0, 停止發(fā)音
}
//--------------------------------------
void song() //演奏一個音符
{
TH0 = timer0h; //控制音調(diào)
TL0 = timer0l;
TR0 = 1; //啟動T0, 由T0輸出方波去發(fā)音
delay(time); //控制時間長度
}
//--------------------------------------
void main(void)
{
unsigned char k, i;
TMOD = 1; //置T0定時工作方式1
ET0 = 1; //開T0中斷 IE=0x82;
EA = 1; //開CPU中斷
while(1) {
i = 0;
time = 1;
while(time) {
k = sszymmh[i] + 7 * sszymmh[i + 1] - 1;
//第i個是音符, 第i+1個是第幾個八度
timer0h = FREQH[k]; //從數(shù)據(jù)表中讀出頻率數(shù)值
timer0l = FREQL[k]; //實際上, 是定時的時間長度
time = ssz
ymmh[i + 2]; //讀出時間長度數(shù)值
i += 3;
song(); //發(fā)出一個音符
}
}
}
答:
你看main()函數(shù)就行了,首先進行k、i的定義,然后是定義中斷的類型(程序中用的是定時器中斷),這個定時器有點特殊,它的作用是定義頻率的,頻率間隔小則聲調(diào)高,反之聲調(diào)低。這個頻率就是時間的倒數(shù)唄,所以TH的值越大,聲調(diào)越高;TL的值越小,聲調(diào)越低。接著往下走,while(1) 就是等待中斷的意思,這個程序中的定時器中斷沒有設(shè)置初值,所以中斷幾乎沒有等待,時時觸發(fā)(要是有等待時間,音樂不就連不上了么)。綜上:這個定時器中斷完成兩個任務(wù):1、使單片機時時觸發(fā)(等待時間幾乎為0);2、控制了音符的演奏頻率。
再往下 while(time) 的循環(huán)就是為演奏的音符賦值的操作了。

20、單片機中斷該什么時候進如?
答:
中斷看是外部中斷、定時器還是串行口中斷了。
如果是外部中斷,就是p3.2、p3.3檢測到這兩個口電平變化時(假設(shè)這兩個口接上按鍵,那么當(dāng)按鍵按下時表明產(chǎn)生中斷),然后跳到中斷程序執(zhí)行。
如果是定時器中斷的話,有個中斷標(biāo)志位TFx(x表示0或者1),比如說你設(shè)置一個1S的定時器程序,你以50ms為基準(zhǔn),20次產(chǎn)生1s的時間,然后當(dāng)50ms一過,標(biāo)志位就產(chǎn)生變化,進入定時器中斷程序執(zhí)行!
串行口中斷也是一樣有一個標(biāo)志位,接受或者發(fā)送數(shù)據(jù)滿了以后,標(biāo)志位就發(fā)生變化,然后進入中斷執(zhí)行!

21、PIC單片機AD中斷什么時候開啟,對AD中斷應(yīng)該怎樣理解。
答:
AD模數(shù)轉(zhuǎn)換,是把模擬電壓數(shù)值采樣進來,然后轉(zhuǎn)換成數(shù)字信號。這一采樣和轉(zhuǎn)換是需要時間的。并不是一開AD就能讀到數(shù)字信號數(shù)據(jù)。
一般來說其時間都只有幾微秒到幾百微秒(根據(jù)設(shè)置不同而定)。如果單片機沒有其他工作的時候,可以用循環(huán)等待的方式等AD轉(zhuǎn)換結(jié)束(轉(zhuǎn)換結(jié)束后DONE位會被置位)。但如果你的單片機還有其他工作,那就沒必要在等待它上面花費時間??梢蚤_AD操作后,繼續(xù)執(zhí)行其他程序。而轉(zhuǎn)換結(jié)束后,AD中斷可以暫時斷開現(xiàn)有炒作,而把AD數(shù)據(jù)讀進來。這就是AD中斷的作用。

2251單片機的五個中斷分別在什么時候(什么情況)執(zhí)行里面的程序!
答:
外部中斷0 :P3.2口有低電平(IT0=0)/ 下降沿(IT0=1)。
外部中斷1 :P3.3口有低電平(IT1=0)/ 下降沿(IT1=1)。
定時器0中斷:當(dāng)定時器0計數(shù)到FFFF溢出時
定時器1中斷:當(dāng)定時器1計數(shù)到FFFF溢出時
串口中斷:串口接收到一幀?;虬l(fā)送完一幀數(shù)據(jù)都會產(chǎn)生中斷。
你網(wǎng)上找一下TCON和SCON。什么條件讓中斷標(biāo)志位的值改變。 那么就會進入中斷服務(wù)程序去。

23、51單片機,如果中斷函數(shù)比較長,執(zhí)行到一半又觸發(fā)了這個中斷,程序會停止從頭執(zhí)行,還是執(zhí)行結(jié)束后響應(yīng)中
答:
51單片機中,中斷分高低兩個優(yōu)先級,高優(yōu)先級的中斷能打斷低優(yōu)先級的中斷。
但同級中斷是不能打斷同級中斷的!無論該中斷函數(shù)有多長,在執(zhí)行到一半這個中斷又發(fā)生了,還是要等到該中斷函數(shù)執(zhí)行完畢,并再執(zhí)行了一條主程序指令后才會再次進入該中斷。
不過,若樓主恰好在這個低優(yōu)先級中斷服務(wù)程序中修改了該中斷為高優(yōu)先級,那么如果該中斷函數(shù)比較長,執(zhí)行到一半又觸發(fā)了這個中斷,則該中斷函數(shù)就會被重新從頭開始執(zhí)行(中斷嵌套)。這是因為除串口中斷以外的其他中斷,在 CPU 響應(yīng)該中斷,程序轉(zhuǎn)入該中斷函數(shù)前就已經(jīng)將該中斷的中斷標(biāo)志清零了。
另外,51的串口中斷比較特別,因為需要軟件清除串口中斷標(biāo)志,所以只要在未清串口中斷標(biāo)志前,是不會發(fā)生上述這樣的中斷嵌套的。

24、求51單片機程序,兩個計數(shù)器,主要是中斷函數(shù)的函數(shù)名以及初始化設(shè)置
答:
void into_into() interrupt 1 定時器0中斷入口函數(shù)
{
。。。。中斷服務(wù)程序。。。。
TH0=0;//
TL0=0;// 重新給T0賜值
}
void into_into() interrupt 3 定時器1中斷入口函數(shù)
{
。。。。中斷服務(wù)程序。。。。
TH1=0;//
TL1=0;// 重新給T1賜值
}
void to_to()
{
TMOD=0x11; //頂時器T0和T1工作方式1
TH0=0;//
TL0=0;// T0賜初值
TH1=0;//
TL1=0// T1賜初值
TR0=1;// 開始記數(shù)
ET0=1;// 允許T0中斷
TR1=1;// 開始記數(shù)
ET1=1;// 允許T1中斷
EA=1; // 打開總中斷
}
void main()
{
INIT_T0(); //定時器中斷初始化
while(1)
{
...........
}

25、請教一個單片機中斷的問題:比如來了一個脈沖,開始中斷,但中斷里的程序執(zhí)行到一半時,又來了一個脈沖,請問這時中斷里的程序是從頭開始呢還是繼續(xù)呢?
我的意思是程序就一個中斷A,來了一個脈沖,A執(zhí)行,A執(zhí)行到一半時,又來了一個脈沖,通知A執(zhí)行。這時A是從頭執(zhí)行還是先不理會呢?
答:
需要具體情況具體分析,因為不同的單片機在中斷機制上有細(xì)微的差別,需要查他的資料。
一般來說,一個中斷源請求中斷,對CPU來說,是一次性的做了一個“中斷掛號”。假如當(dāng)時因條件不滿足(例如CPU正在“關(guān)中斷”,即沒有打開“中斷允許”),而沒有響應(yīng)中斷,則掛號信息還在,這樣,將來一旦打開了中斷允許,仍然會響應(yīng),只是晚了一點而已。
而中斷響應(yīng)以后,必須有辦法把這個“中斷掛號”消除掉。有的CPU的功能是:只要響應(yīng)了這個中斷,掛號就自動消除了。也有的CPU不能自動清除掛號,必須在中斷服務(wù)程序中編入“清除中斷掛號”的操作,否則,一旦打開了中斷允許,它又會重復(fù)發(fā)生中斷。

現(xiàn)在的大多數(shù)單片機里,中斷控制器和CPU是在同一個芯片中,它可以做到自動消除中斷掛號。而過去許多種CPU,所配用的中斷控制器是另外一個芯片,自然就無法自動消除了。

也有的CPU中有另外一種“不掛號”的中斷請求。它必須由外界(發(fā)出中斷請求的那個設(shè)備)來保持一直不停申請,等到響應(yīng)中斷的時候,再設(shè)法(例如,在中斷服務(wù)程序中發(fā)出一個輸出信號)通知那個設(shè)備撤銷申請。

大多數(shù)的CPU中,一旦響應(yīng)中斷進入了服務(wù)程序,就把“中斷允許”關(guān)掉了。故此時如果又有下一個中斷請求來了,不能立即響應(yīng),只能掛一個號,等以后“開中斷”時才能再響應(yīng)。如果程序員希望能夠“嵌套中斷”(即在一次中斷服務(wù)程序的執(zhí)行中途又進入了另一個中斷服務(wù)程序),就需要在服務(wù)程序內(nèi)編入“開中斷”的操作。

“嵌套中斷”原則上允許“自己嵌套自己”,也就是說,一次中斷服務(wù)程序的執(zhí)行中途又被打斷并進入了和自己一樣的中斷服務(wù)程序,并從頭到尾執(zhí)行一遍,結(jié)束后返回到先前打斷的那一點,并繼續(xù)執(zhí)行后半截服務(wù)程序。這種情況會產(chǎn)生什么效果,是需要程序員自己考慮的。

也有的CPU具有“優(yōu)先次序”機制,可以在某一級的中斷服務(wù)程序里禁止優(yōu)先級不比自己高的其他中斷來打斷自己。同時,也提供給程序員有“放棄優(yōu)先權(quán)”以及“修改優(yōu)先級”的靈活性。
而被優(yōu)先機制暫時“屏蔽”的那些較低優(yōu)先級的中斷申請,同樣掛號仍在,以后高優(yōu)先級的中斷結(jié)束以后,還能響應(yīng)。

不過需要注意,大多數(shù)的CPU中,“中斷掛號”是只能掛一個的。也就是說,在前一次的中斷申請所掛的號還沒有被清除以前,又來了下一個中斷申請,那么,第二個掛號是掛不上的。

不過某些處理器中,中斷掛號可能分成幾個層次:CPU里面是一層,外圍針對各個具體的設(shè)備,還有另外一級“預(yù)備掛號”,那就比較復(fù)雜了。

另外多說幾句:上面已經(jīng)說,程序員可以自己決定你的中斷服務(wù)程序允許還是不允許“嵌套”。

如果不允許,您可以采用關(guān)中斷的辦法,或者利用優(yōu)先機制,來屏蔽同一中斷源的第二個中斷請求。
這樣,第二個中斷就不會被響應(yīng)。但它仍可以掛上一個號(只要它發(fā)生在上一個中斷掛號已經(jīng)被清除掉以后的時間)。然后,中斷服務(wù)程序結(jié)束時,一般都會開中斷并釋放優(yōu)先級屏蔽。然后,第二個中斷請求就會被響應(yīng),于是再一次執(zhí)行中斷服務(wù)程序。

如果允許“嵌套”,那就會如我上面所說:
一次中斷服務(wù)程序的執(zhí)行中途又被打斷并進入了和自己一樣的中斷服務(wù)程序,并從頭到尾執(zhí)行一遍,結(jié)束后返回到先前打斷的那一點,并繼續(xù)執(zhí)行后半截服務(wù)程序。

26、我用51單片機定時/計數(shù)器1計數(shù)為什么不計數(shù)?想讓它記數(shù)產(chǎn)生中斷讓蜂鳴器響。
sbit fengming=P1^6;
void main()
{
TMOD=0x50;
EA=1;
ET1=1;
TH1=0xff;//來一次中斷記一次數(shù)
TL1=0xff;
TR1=1;
}
void time1(void) interrupt 3
{
fengming=0;
}

答:
不知道是你在網(wǎng)頁上打錯了,還是怎么回事。
void time1(void) interrupt 3-------》void timer1(void) interrupt 3

主程序最后,要加個死循環(huán):while(1){};

還有,你在這用了方式1,這個方式在你進中斷后,TH1和TL1會變成0000H。你不對他重新賦值,你要等FFFFH次計數(shù),才會進中斷。


27MCS-51 單片機定時器/計數(shù)器1的中斷入口地址是: 一共有四個A. 0003H B. 000BH C. 0013H D. 001BH,到底是是哪一個?
答:答案是D.1BH
因為:
外中斷0——03h
定時器0——0bh
外中斷1——13h
定時器1——1bh
串口———23h
請背熟

28、我看很多程序都是主程序進入while(1),就死在while(1)里了,然后等待外中斷。那么現(xiàn)在的問題是我想讓它進入外中斷完事后,跳過while(1),執(zhí)行下邊的程序,該怎么辦?
while里邊用break嗎?不知道好使不好使,還有標(biāo)志位我看是硬件自動清零,查詢標(biāo)志應(yīng)該不能用吧,那該怎么辦呢?
答:
結(jié)束while(1)語句最好的方法就是使用break來跳出死循環(huán),關(guān)鍵就是選擇合適的flag(標(biāo)志位),如果說中斷標(biāo)志位是硬件自動清零的話,那么樓主不妨在中斷服務(wù)子程序中自己加入一個標(biāo)志位:如果用匯編語言的話,PSW中的F0位就可以很好的使用;如果用C的話,就可以隨便定義一個位變量,如bit a=0;。也就是說,樓主需要在程序中定義一個位變量a,在中斷服務(wù)子程序中將a置1,退出中斷后查詢a是否為1,例如:if(a) {a=0;break;}這樣就跳出了while語句了。
比方說,如果樓主想寫一個等待按鍵按下中斷的程序,就可以用while(!a);而不用while(1)語句了。

29、我用外部中斷1,中斷一次顯示下一個數(shù),數(shù)碼管顯示沒問題。但是我用P3-3口用導(dǎo)線連接,接觸一次地線,松開一次,這時候數(shù)碼管顯示會亂跳,有時候加兩次數(shù),有時候加好多次數(shù),反正就是不穩(wěn)定。假如p3-3口通過按鍵接地的話,按一次按鍵一般情況會加一次數(shù),但有時候也是不穩(wěn)定,可能中斷好幾次。
程序如下:
#include
#define uint unsigned int
#define uchar unsigned char
uchar code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
uchar times;
uchar i=0;
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=112;y>0;y--);
}

void main()
{

EA=1;
EX1=1;
IT1=1;
while(1)
{
P1=table[i];
P2=0x00;
}
}


void into() interrupt 2
{ delay(1000);
i++;
if(i==10) i=1;

}

答:
是抖動的問題。
應(yīng)該采取消抖措施,硬件、軟件方法皆可。
----
樓主在中斷函數(shù)中,延時,時間看來很是不短!
但是延時后,并沒有檢測按鍵是否還在按下,這就不能算是軟件消抖。

30、 (1) 為什么單片機有兩個外部中斷0允許位?有什么作用?
(2)在51內(nèi)核單片機中,當(dāng)允許響應(yīng)外部中斷0的中斷請求時,其特殊功能寄存器ie中的位必須為1 es exo ea et0?

答:
(1)兩個中斷是因為一般的單片機有兩個中斷源,可以實現(xiàn)兩級中斷嵌套,在實現(xiàn)復(fù)雜功能上兩級中斷嵌套很有用。

(2)
EA--總中斷允許位,必須為1
ES--串行中斷允許位,不必開,為0
EX0--外部中斷0允許位,應(yīng)為1
ET0--定時計數(shù)溢出中斷允許位,不必開,為0



關(guān)鍵詞: 單片機延時中斷問

評論


技術(shù)專區(qū)

關(guān)閉