<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 單片機(jī)學(xué)習(xí)之六:基本I/O口試驗(yàn)二:跑馬燈

          單片機(jī)學(xué)習(xí)之六:基本I/O口試驗(yàn)二:跑馬燈

          作者: 時(shí)間:2016-09-18 來源:網(wǎng)絡(luò) 收藏

            一、試驗(yàn)現(xiàn)象:

          本文引用地址:http://www.ex-cimer.com/article/201609/297082.htm

            二極管從右至左依次發(fā)光。

            二、試驗(yàn)?zāi)康模?/strong>

            l 掌握寄存器A,Rn的使用方法

            l 掌握左移指令

            l 掌握延時(shí)程序的編寫

            三、任務(wù)分析:

            電路圖同試驗(yàn)1,有了上一個(gè)試驗(yàn)的基礎(chǔ),這個(gè)程序?qū)ξ覀兙蜎]有什么難度啦。我們可以這樣作:

            首先:mov p0,#ofeh(讓最右邊的燈亮),然后經(jīng)過一段延時(shí),再:mov p1,#ofdh,這樣依次賦值,直到:mov p0,#07fh(最左面的燈亮)。然后用ajmp指令返回,讓燈光再重新開始循環(huán)。

            這樣固然可以,但是程序不夠簡(jiǎn)單明了,我們要寫8個(gè)mov語(yǔ)句。設(shè)想一下,假如有幾十個(gè)燈,那寫起來不是麻煩死啦?

            好在有一條左移指令rl a,它的作用是把累加器a中的數(shù)循環(huán)左移。

            順便說一下累加器a,它是中的最常用的寄存器,大部分單操作數(shù)的指令都以a作為操作對(duì)象(例如rl a);也有很多雙操作數(shù)指令的一個(gè)操作數(shù)取自a(例如mov a,#00h);還有加、減、乘、除等算數(shù)指令的運(yùn)算結(jié)果也經(jīng)常保留在a中,或者ab寄存器對(duì)中。

            所以我們的程序就可以這樣來實(shí)現(xiàn)啦:首先給a賦值,再輸出到p0;然后延時(shí);接下來把a(bǔ)中的數(shù)進(jìn)行左移。然后重復(fù)上面的過程就可以啦。

            四、試驗(yàn)程序

            org 0000h

            start: clr p1.5

            mov a,#0feh ;給a賦立即數(shù),執(zhí)行之后,a中的數(shù)據(jù)是11111110

            loop: mov p0,a ;把a(bǔ)中的數(shù)據(jù)傳輸?shù)絧0

            lcall delay ;(1)

            rl a ;(2)

            ajmp loop ;返回標(biāo)號(hào)為loop的指令

            delay: mov r6,#02h ;(3)

            del1: mov r5,#0ffh ;(4)

            del2: djnz r5,del2 ;(5)

            djnz r6,del1 ;(6)

            ret ;(7)

            end

            注釋:

            1、這是一個(gè)子程序調(diào)用指令。在程序設(shè)計(jì)中,常常把具有一定功能的公用程序編成子程序,以便讓主程序調(diào)用。

            該指令的執(zhí)行過程是這樣的:當(dāng)執(zhí)行l(wèi)call指令后,程序就轉(zhuǎn)到lcall后面標(biāo)號(hào)delay指定的程序處往下執(zhí)行,當(dāng)執(zhí)行遇到ret指令時(shí),就返回lcall指令下面的一條指令,即rl a指令。

            從上面的分析,我們可以知道:標(biāo)號(hào)為delay的程序應(yīng)該是一段延時(shí)程序,那么它到底延時(shí)了多長(zhǎng)時(shí)間呢?我們一會(huì)給大家講解這個(gè)時(shí)間的計(jì)算方法,先往下看吧。

            同樣,子程序調(diào)用也有兩條指令:acall和lcall。兩者的區(qū)別是:acall指令調(diào)用的子程序起始地址必須和acall后面的第一條指令在同一個(gè)2k區(qū)域的程序存儲(chǔ)器內(nèi);而lcall指令可以調(diào)用存放在程序存儲(chǔ)器中64K字節(jié)范圍內(nèi)的任何地方的子程序。簡(jiǎn)單的說就是acall調(diào)用的范圍小,而lcall的范圍大。如果你拿不準(zhǔn)的話,就用lcall吧。

            2、這條指令的功能是:把累加器a中的內(nèi)容向左移動(dòng)一位,最高位的內(nèi)容A7被移動(dòng)到最低位A0,圖示如下:

            

           

            3、現(xiàn)在我們來分析delay子程序的延時(shí)時(shí)間:

            我們先看(3)(4)(5)(6)(7)這樣幾個(gè)語(yǔ)句:

            (3)的意思是給r6賦值02h。r6是什么?我們好像以前沒有說過。大家先知道它也是一個(gè)8位的寄存器就行啦,關(guān)于它的內(nèi)容,我們下面在介紹。

            (4)的意思和(3)類似,不再贅述。

            (5)應(yīng)用了djnz指令,這個(gè)指令的意思是:減1不為0轉(zhuǎn)移。因此語(yǔ)句(6)的意思是:把r5中間存的內(nèi)容減去1,如果不是0,就繼續(xù)執(zhí)行該條語(yǔ)句,否則,執(zhí)行下面的語(yǔ)句。

            (6)根據(jù)上面的分析我們知道:(6)的意思是:把r6中的內(nèi)容減1,如果不是0,就返回標(biāo)號(hào)為del1的程序,重新給r5賦值0ffh,然后在對(duì)r5進(jìn)行減1運(yùn)算。

            從分析可見,如果延時(shí)程序執(zhí)行完,djnz指令總的執(zhí)行次數(shù)是:02h×0ffh,即2×255=510次。

            可見,如果我們知道執(zhí)行一次djnz指令的時(shí)間,我們就可以算出這個(gè)程序的延時(shí)時(shí)間了。那么執(zhí)行一次djnz指令需要多少時(shí)間呢?

            的指令執(zhí)行起來所花費(fèi)的時(shí)間是不一樣的,有的指令執(zhí)行時(shí)間短,只需要1個(gè)機(jī)器周期,而有的指令執(zhí)行時(shí)間長(zhǎng),需要4個(gè)機(jī)器周期。Djnz指令的執(zhí)行時(shí)間是2個(gè)機(jī)器周期。

            每一個(gè)機(jī)器周期又是多長(zhǎng)呢?從相關(guān)教材上,我們知道1個(gè)機(jī)器周期是振蕩周期的12倍。

            而振蕩周期T=1/振蕩頻率=1/12MHZ

            所以延時(shí)程序的總的延時(shí)時(shí)間是:2×255×2×12×(1/12MHZ)=1ms

            好啦,現(xiàn)在把上面的程序下載到單片機(jī)中,你看到了什么?

            怎么回事,所有的燈都亮啦!

            當(dāng)然啦,因?yàn)槲覀兊难訒r(shí)太短啦,只有1ms,所以我們的眼睛根本分辨不出來。我們現(xiàn)在把延時(shí)增加為100ms,程序修改如下:

            org 0000h

            start: clr p1.5

            mov a,#0feh

            loop: mov p0,a

            lcall delay

            rl a

            ajmp loop

            delay: mov r7,#100 ;把1ms延時(shí)子程序執(zhí)行100次

            del1: mov r6,#02h

            del2: mov r5,#0ffh

            del3: djnz r5,del3

            djnz r6,del2

            djnz r7,del1

            ret

            end

            現(xiàn)在再看看,一切正常啦,ok!

            4、現(xiàn)在來看看寄存器R的問題

            單片機(jī)的存儲(chǔ)器結(jié)構(gòu)和常見的微型計(jì)算機(jī)的配置方式不同,把程序存儲(chǔ)器和數(shù)據(jù)存儲(chǔ)器分開。程序存儲(chǔ)器用來存放程序,數(shù)據(jù)存儲(chǔ)器用來存放程序運(yùn)行需要的常數(shù)和變量。

            單片機(jī)的數(shù)據(jù)存儲(chǔ)器分為內(nèi)部存儲(chǔ)器和外部存儲(chǔ)器,用mov訪問內(nèi)部數(shù)據(jù)存儲(chǔ)器,用movx訪問外部數(shù)據(jù)存儲(chǔ)器。

            內(nèi)部數(shù)據(jù)存儲(chǔ)器是最靈活的地址空間,一共有256字節(jié)。這256個(gè)字節(jié)被分為兩組:00h~7fh的低128字節(jié)是內(nèi)部RAM區(qū);80h~ffh的高128字節(jié)為特殊功能寄存器區(qū)。其中低128字節(jié)的地址分配如下圖所示:

            

           

            從圖上可見,低128字節(jié)中,從00h~1fh共32個(gè)字節(jié)是四個(gè)通用的工作寄存器區(qū),每一個(gè)區(qū)有8個(gè)工作寄存器,編號(hào)均為從R0~R7。

            大家可能會(huì)問,既然四個(gè)工作寄存器組的名字都叫R0~R7,那么,上面的程序中間用的寄存器到底是哪個(gè)呢?

            當(dāng)前程序使用的工作寄存器區(qū)是有程序狀態(tài)字PSW決定的。

            那么PSW又在哪里呢?

            剛才我們說到80h~ffh的高128字節(jié)是特殊功能寄存器區(qū),PSW就在這個(gè)區(qū)里面。這個(gè)區(qū)域還有很多別的特殊功能寄存器,大家可以參考相關(guān)資料。

            PSW是一個(gè)8位的寄存器,它各位的說明如下:

            

           

            其中,決定選擇哪個(gè)寄存器區(qū)的是RS1和RS0這兩位,為00時(shí),選擇0區(qū);01時(shí)選擇1區(qū);10時(shí)選擇2區(qū);11時(shí)選擇3區(qū)。

            大家可能會(huì)問,程序中間并沒有給這個(gè)寄存器賦值,那么它到底選擇哪個(gè)區(qū)域呢?

            由于單片機(jī)被復(fù)位后,所有的寄存器請(qǐng)零,所以在本程序中,缺省的使用的是0區(qū)的寄存器組。

            5、課后練習(xí)

            (1)、學(xué)習(xí)該試驗(yàn)中出現(xiàn)的理論知識(shí),包括程序存儲(chǔ)器,數(shù)據(jù)存儲(chǔ)器的地址分配,和相關(guān)指令。

            (2)、編寫一個(gè)程序,讓二極管從左至右發(fā)光,延遲時(shí)間是1s,即1000ms。注意,可不是把上面程序中的mov r7,#100,改成mov r7,#1000,那么簡(jiǎn)單哦。



          關(guān)鍵詞: 單片機(jī) 跑馬燈

          評(píng)論


          相關(guān)推薦

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

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();