OK6410 裸機中斷最簡單代碼
中斷,我認為在初學(xué)單片機開發(fā)的時候是一個比較麻煩的事情,所有想把這個東西弄懂,結(jié)果在網(wǎng)上找了遍,都沒有找到可以用的代碼!為什么呢?因為懂的人,覺得沒有必要,不懂的人反正是不懂,就像我一樣。在論壇上http://bbs.witech.com.cn/thread-3809-1-1.html ,我覺得那個裸機視頻很好,至少我在視頻的幫助下,很快可以完成點燈了,那種興奮是非常好的,但想走入中斷,那就是一個很麻煩的事。高手們寫的代碼,太長太多,像我只是知道一點點的,是看不懂太多代碼的,至于官方的代碼,更是難懂,因為太多太復(fù)雜,對于初學(xué)者不利,容易打退堂鼓。(……好像說了太多廢話了,其實我想說的是,初學(xué)這東西,還是要有點韌性好)
如果想在OK6410開發(fā)板上學(xué)著寫一個裸機程序,那本文是非常適合你的,我會讓你知道寫中斷的一切我知道,而你也同樣需要的知識。如果您是高手,請莫見笑,并煩請指教。
本文將使用最簡代碼來完成定時器0的中斷,每秒中斷一次,并輪流顯示開發(fā)板上的四個小LED燈。
程序兩個部分,一部分是啟動代碼(匯編),另一部分是中斷C程序。
節(jié)選啟動復(fù)位代碼:
- ;允許中斷
- ENABLE_IRQ
- MRSR0,CPSR;將CPSR保存至R0寄存器中
- BICR0,R0,#0x80;R0=R0&~0x80,清除中斷位
- MSRCPSR_c,R0;將R0寫回CPSR狀態(tài)寄存器
- MOVPC,LR;返回到調(diào)用代碼
- ResetInit
- LDRR14,=0x50100000;初始化一下棧指針
- BLENABLE_IRQ;打開中斷允許位
- BMain;跳入MAIN程序
上面的代碼就是一個簡單的啟動代碼,當(dāng)然來包括中斷向量配置這些,這些請查看上傳的工程文件。
如果需要完成中斷,那么一定得打開中斷允許位,不然,任意中斷都是不會產(chǎn)生的,這是我摸索過程中的一個問題。這個問題很難嗎?不是,而是因為沒有人告訴你這么做,后來我在周立功出的ARM基礎(chǔ)書上看到的??傊?,要完成一個中斷的產(chǎn)生,需要具備三個條件:(1)初始化了中斷源,(2)配置了中斷向量允許位,(3)狀態(tài)寄存器的標志位請零。上述代碼完成了第三個條件,下面,我通過代碼來完成中斷源的初始化工作。下面給出一張周立功給出的一張圖:
如果您因為中斷不能進入,請檢查是否滿足前面的三個條件,也對應(yīng)于本圖的三個環(huán)。
當(dāng)我發(fā)現(xiàn)中斷不進入的時候,也看到過此圖,但并沒有理解,只到我調(diào)度的時候,在AXD下查看CPU寄存器的時候,發(fā)現(xiàn)I與F的標志,將手對修改了I標志,結(jié)果中斷程序的斷點進入了,至此明白了這個圖。有時候一個圖在這里,如果你沒有理解這個圖,或者理解這圖背后的原理,是很難明白繪圖者的真正函義。圖對于理解了的,很容易記憶,而且有用,對于其它人而言,也容易理解,但有時候理解并不能把握真實的函義,所以需要學(xué)習(xí),將圖的理解,并最終成為自己的記憶。
下面代碼通過設(shè)置寄存器來完成配置工作。在這里的代碼,如果你手上沒有芯片文檔,那基本上是看不懂的天書。因為我是菜鳥,所以我覺得我的問題可能是一些初學(xué)者的問題。比如,下面的代碼為什么是這樣寫的,這樣寫的依據(jù)是從哪里來的?你告訴我去參考文檔,我知道了這個配置的原理,但我還是無法融匯貫通啊?我當(dāng)時看文檔的時候總是問自己這些問題。為什么呢?因為文檔太長太多,而且是英文的,我手里的S3C6410文檔就有1371頁,是不是我寫LED就只看GPIO部分了呢?的確是這樣,但你想寫中斷了,是不是只看定時器單節(jié)就可以了,這里回答肯定不是這樣的,你需要查看中斷相關(guān)節(jié),可能還要查看前面幾節(jié)關(guān)于CPU的特性介紹,中斷功能的介紹等信息,這也意味著,走入中斷,表示你對這個CPU也有所了解了,通過對中斷的理解,也表明你可以做更多有意義的事情了??次臋n,看資料是必須的,遇到問題再去看資料的時候,會得到一些靈感。
- //初始化定時器0,重動重載計數(shù)值
- //這里為什么是這樣的順序,為什么這么寫,請參考S3C6410芯片文檔
- voidtimer_init(void)
- {
- rTINT_CSTAT|=1<<0;//開timer0中斷,允許timer0中斷發(fā)生
- rVIC0INTENABLE|=1<<23;//開timer0的使能(相當(dāng)于關(guān)掉mask)
- rTCFG0&=~0xFF;//清除預(yù)分頻因子位
- rTCFG0|=0x42;//設(shè)置分頻因子(66分頻),定時器時鐘頻率為1Mhz
- rTCFG1&=~0x11;//設(shè)置DividerMUX0為零1分頻
- rTCNTB0=1000000;//設(shè)初值(1s)
- rTCON|=1<<1;//開ManualUpdate(UpdateTCNTB0,TCMPB0)設(shè)置初值后要更新TCNTB
- rTCON|=1<<3;//AutoReloadon自動重裝開啟
- rTCON|=1<<0;//timer0open;
- rTCON&=~(1<<1);//不再UpdateTCNTB0,TCMPB0
- }
關(guān)于定時器初值的計算,我說一下我的理解。
MHz是兆赫茲,表示一秒內(nèi)振蕩的資料,這表示1MHz = 每秒震蕩1000 000次,反過來,如果你需要一秒的定時,你需要計數(shù)1000,000次,也就是要求頻率為1MHz,那如何配置頻率為1MHz呢?參考手冊上有這個參數(shù):
Timer input clock Frequency = PCLK / ( {prescaler value + 1} ) / {divider value}
這樣如果需要一秒的時間一次中斷,在沒有配置PPL(可以配置CPU的倍頻的東西)的情況下,CPU的頻率為FOSC的頻率,即66MHz,在分頻為66,預(yù)分頻為0,那么需要設(shè)置計數(shù)值為1000,000,這樣就可以產(chǎn)生每秒一次的中斷了。
中斷初始化完成之后,主程序可以進入死循環(huán),等待中斷的來臨……
在等待之前,我們需要正確設(shè)置中斷向量,進入C語言代碼的中斷程序,再正確返回到程序的原為位置。中進入中斷向量之前,CPU進入中斷狀態(tài),使用中斷狀態(tài)下的特殊寄存器,通過寄存器仍然使用中斷之前模式的,為了防止破壞中斷之前的代碼,需要備份這些寄存器,之后,將中斷函數(shù)的返回地址設(shè)置好后,就可以進入實際中斷處理函數(shù)了。中斷處理函數(shù)返回后,需要恢復(fù)寄存器現(xiàn)場,并通過將PC設(shè)置為中斷前的地址,以使主程序斷續(xù)。
- IRQHandler
- STMFDSP!,{r0-r3,r12,lr};保存現(xiàn)場
- ldrlr,=int_return;設(shè)置中斷異常處理程序返回地址到下面的位置
- BIRQ_Exception;直接進入到中斷函數(shù)處理
- int_return
- LDMFDSP!,{r0-r3,r12,lr};恢復(fù)現(xiàn)場
- SUBSPC,LR,#4;返回進入中斷前的代碼
下面給出簡單的中斷跑馬燈代碼:
- inti=0;
- //IRQ異常中斷
- voidIRQ_Exception()
- {
- i%=4;
- //打開一個燈,并閉另外一個燈
- rGPMDAT=~(1<
- //清除定時器中斷狀態(tài)位
- while((rTINT_CSTAT&0x20))rTINT_CSTAT|=(1<<5);
- }
好了,中斷程序就這樣介紹完了,這里還有如何設(shè)置啟動代碼,寄存器如果定義等相關(guān)內(nèi)容,可以參考由上面給出的飛凌論壇的《裸機教學(xué)視頻第一季》。如果出了第二季,我就不會這么走的如此艱辛了。
程序下載地址:http://download.csdn.net/source/3567988
評論