<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                【85.1 寄存器配置的本質。】 單片機內部可供我們選擇的資源非常豐富,有定時器,有串口,有外部中斷,等等。這些豐富的資源,就像你進入一家超市,你只需選擇你所需要的東西就可以了,所以配置寄存器的關鍵在于選擇,所謂選擇就是往寄存器里面做填空題,單片機系統內部再根據你的“選擇清單”,去啟動對應的資源。那么我們怎么知道某個型號的單片機內部有哪些資源呢?看該型號“單片機的說明書”呀,“單片機的說明書”就是我們通常所說的“芯片的datasheet”,或者說是“芯片的數據手冊”,這些資料單片機廠家會提供的。 跟單片機打交道,其實跟人打交道沒什么區別,你要讓單片機按照你的“意愿”走,你首先要把你的“意愿”表達清楚,這個“意愿”就是信息,信息要具備準確性和唯一性,不能模凌兩可。比如,現在要讓單片機“每1ms產生一次中斷”,你想想你可能需要給單片機提供哪些信息? (1)51單片機有2個定時器,一個是0號定時器,一個是1號定時器,我們要面臨“二選一”的選擇,本例子中用的是“0號定時器”。 (2)0號定時器內部又有4種工作方式:方式0,方式1,方式2,方式3,本例子中用的是“方式1”。 (3)定時器到底多長時間中斷一次,這就涉及到填充與中斷時間有關的寄存器的數值,該數值是跟時間成比例關系,本例子中配置的是1ms中斷,就要填充對應的數值。 (4)默認狀態下,定時器是不會被開啟的,如果要開啟,這里就是涉及到定時器的“開關”,本例子要開啟此開關。 (5)定時器時間到了就要產生中斷,中斷也有“總開關”和“定時器的局部開關”,這兩個開關都必須同時打開,中斷才會有效。 要配置定時器“每1ms產生一次中斷”,大概就上述這些信息,根據這些信息提示,下面開始講解一下寄存器的具體內容。 【85.2 定時器/計數器的模式控制寄存器TMOD。】 寄存器TMOD是一個8位的特殊變量,里面每一位都代表了不同的功能選擇。根據芯片的說明書,TMOD的8位從左到右依次對應從D7到D0(左高位,右低位),定義如下: GATE C/T M1 M0 GATE C/T M1 M0 仔細觀察,發現左4位與右4位是對稱的,分別都是“GATE,C/T , M1 , M0”,左4位控制的是“定時器1”,右4位控制的是“定時器0”,因為本例子用的是“定時器0”,因此“定時器1”的左4位都設置為0的默認數值,我們只需重點關注右4位的“定時器0”即可。 GATE:定時器是否受“其它外部開關”的影響的標志位。定時器的開啟或者停止,受到兩個開關的影響,第一個開關是“自身原配開關”,第二個開關是“其它外部開關”。GATE取1代表定時器受“其它外部開關”的影響,取0代表定時器不受“其它外部開關”的影響。本例子中,定時器只受到“自身原配開關”的影響,而不受到“其它外部開關”的影響,因此,GATE取0。 C/T:定時器有兩種模式,該位取1代表“計數器模式”,取0代表“定時器模式”。本例子是“定時器模式”,因此,C/T取0。 M1與M0:工作方式的選擇。M1與M0這兩位的01搭配,可以有4種組合(00,01,10,11),每一種組合就代表一種工作方式。本例子選用“方式1”,因此M1與M0取“01”的組合。 綜上所述,TMOD的配置代碼是:TMOD=0x01; 【85.3 決定時間長度的寄存器TH0與TL0。】 TH0與TL0,T代表定時器英文單詞TIME的T,H代表高位,L代表低位,0代表定時器0。 TH0是一個8位寬度的寄存器,TL0也是一個8位寬度的寄存器,兩者合并起來成為一個整體,實際上就是一個16位寬度的寄存器,TH0是高8位,TL0是低8位,它們合并后的數值范圍是:0到65535。該16位寄存器取值越大,定時中斷一次的時間反倒越小,為什么?TH0與TL0的初始值,就像一個水桶里裝的水。如果這個桶是空桶(取值為0),“雨水”想把這個桶“滴滿溢出”所需要的時間就很大。如果里面已經裝了大半的水(取值為大于32767),“雨水”想把這個桶“滴滿溢出”所需要的時間就很小。這里的關鍵詞“滴滿溢出”的“滴”與“滿溢出”,“滴”的速度是由單片機晶振決定的,而“滿溢出”一次就代表產生一次中斷,執行完中斷函數在即將返回主函數之前,我們重新裝入特定容量的水(重裝初值),為下一次的“滴滿溢出”做準備,依次循環,從而連續不斷地產生間歇的定時中斷。 配置中斷時間的大小是需要經驗的,因為,每次定時中斷的時間太長,就意味著時間的可分度太粗,而如果每次定時中斷的時間太短,則會產生很頻繁的中斷,勢必會影響主函數main()的執行效率,而且累記中斷次數的時間誤差也會增大。因此,配置中斷時間是需要經驗的,根據經驗,定時中斷取1ms一次,是幾乎所有單片機項目的最佳選擇,按我的理解,“1ms定時中斷一次”已經是單片機界公認的一種“標配”。 要配置1ms定時中斷,TH0與TL0如何取值?剛才提到一個形象的例子“桶,滴,滿溢出”。TH0與TL0的最大取值范圍是65535,可以理解成為最大65535“滴”,如果超過65535“滴”(比如加1“滴”后變成65536“滴”)就會“滿溢出”,從而產生一次中斷(65536是中斷發生的臨界值)。而“滴一次的時間”就剛好是單片機執行“一次單指令的時間”,“一次單指令的時間”等于12個晶振周期,比如12MHz的晶振,晶振周期是(1/12000000)秒,而“一次單指令的時間”就等于12乘以(1/12000000)秒,等于0.000001秒,也就是1us。1us“滴”一次,要產生1ms的時間就需要“滴”1000次。“滿溢出”的前提條件是“桶里”一共需要裝入65536滴才溢出,因此,在12MHz的晶振下要產生1ms的定時中斷,TH0與TL0的初值應該是64536(65536減去1000等于64536),而64536變成十六進制0xfc17,再分解到高8位TH0為0xfc,低8位TL0為0x17。 剛才的例子是假如晶振在12MHz的情況下所計算出來的結果,而本教程所用的晶振是11.0592MHz,根據11.0592MHz產生1ms的定時中斷,TH0與TL0應該取值多少?根據剛才的計算方式: 初值=\[溢出值\]-(\[0.001秒\]/(\[晶振周期的12個\]\*(\[1秒\]/\[晶振頻率\]))) 初值=65536-(0.001/(12\*(1/11059200))) 初值=65536-922 (注:922是921.6的四舍五入) 初值=64614 初值=0xfc66 初值TH0=0xfc 初值TL0=0x66 【85.4 中斷的總開關EA與局部開關ET0。】 EA:中斷的總開關。寬度是1位的位變量。此開關如果取0,就會強行屏蔽所有的中斷,因此,只要用到中斷,此開關必須取1。 ET0:專門針對定時器0中斷的局部開關。寬度是1位的位變量。此開關如果取0,則會屏蔽定時器0的中斷,如果取1則允許定時器0中斷。如果要定時器0能產生中斷,那么總開關EA與ET0必須同時都打開(都取1),兩者缺一不可。 【85.5 定時器0的“自身原配開關”TR0。】 TR0:定時器的“自身原配開關”。寬度是1位的位變量。很多初學者會把EA,ET0,TR0三者搞不清。定時器可以工作在“查詢標志位”和“中斷”這兩種狀態,也就是說在沒有中斷的情況下定時器也可以單獨使用的。TR0是定時器0自身的發動引擎,要不要把這個發動引擎所產生的能量傳輸到中斷的渠道,則取決于中斷開關EA和ET0。TR0是源頭開關,EA是中斷總渠道開關,ET0是中斷分支渠道的定時器0開關。TR0取1表示啟動定時器0,取0表示關閉定時器0。 【85.6 定時器0的中斷函數的書寫格式。】 void 函數名() interrupt 1 { ...中斷程序內容; ...此處省去若干代碼 ...中斷程序內容; ...最后面的代碼,要記得重裝TH0與TL0的初值; } 函數名可以隨便取,只要不是編譯器已經征用的關鍵字。這里的1是定時器0的中斷號。不同的中斷號代表不同類型的中斷,至于哪類中斷對應哪個中斷號,大家可以查找相關書籍和資料。本節用的定時器0處于工作方式1的情況下,在即將退出中斷之前,需要重裝TH0與TL0的初始值。 【85.7 寄存器的名字來源。】 前面講的寄存器都有固定的名字,而且這些名字都是唯一的,拼寫的時候少一個字母或者多一個字母,C編譯器都會報錯不讓你通過,因此問題來了,初學者剛接觸一款單片機的時候,如何知道某個寄存器它特定的唯一的名字?有兩個來源。 第一個來源,可以打開C編譯器的某個頭文件(.h格式)查看這些寄存器的名字。比如51單片機可以查看REG52.H這個頭文件。如何打開REG52.H這個文件?在Keil源代碼編輯器界面下,選中上面REG52.H這幾個字符,在右鍵彈出的菜單下點擊Open ducument“REG52.H”即可。 第二個來源是直接參考一些現成的范例程序,這些范例程序網上很多,有的是原廠提供的,有的是熱心網友的分享,有的是技術書籍或者學習板開發板廠家提供的。 【85.8 如何快速配置寄存器。】 建議一邊閱讀芯片的數據手冊,一邊參考一些現成的范例程序,這些范例程序網上很多,有的是原廠提供的,有的是熱心網友的分享,有的是技術書籍或者學習板開發板廠家提供的。 【85.9 練習例程。】 現在編寫一個定時中斷程序,讓兩個LED燈閃爍,一個是在主函數里用累計主循環次數的方式實現(P0.0控制),另一個是在定時中斷函數里用累計定時中斷次數的方式實現(P0.1控制)。這兩個閃爍的LED燈,一個在main函數,一個是在中斷函數,兩路任務互不干涉獨立運行,并行處理的“雛形”略顯出來。 ![](https://img.kancloud.cn/0f/49/0f49cc4e7b34f0e8c13dd7e514906c88_214x279.png) 圖85.9.1 灌入式驅動8個LED \#include "REG52.H" \#define CYCLE\_SUM 5000 //主循環的次數 \#define INTERRUPT\_SUM 500 //中斷的次數 sbit P0\_0=P0^0; //在主循環里的LED燈 sbit P0\_1=P0^1; //在定時中斷里的LED燈 unsigned char Gu8CycleStep=0; unsigned long Gu32CycleCnt=0; //累計主循環的計數器 unsigned char Gu8InterruptStep=0; unsigned long Gu32InterruptCnt=0; //累計定時中斷次數的計數器 void main() { TMOD=0x01; //設置定時器0為工作方式1 TH0=0xfc; //產生1ms中斷的TH0初始值 TL0=0x66; //產生1ms中斷的TL0初始值 EA=1; //開總中斷 ET0=1; //允許定時0的中斷 TR0=1; //啟動定時0的中斷 while(1) //主循環 { switch(Gu8CycleStep) { case 0: Gu32CycleCnt++; if(Gu32CycleCnt>=CYCLE\_SUM) { Gu32CycleCnt=0; P0\_0=0; //主循環的LED燈亮。 Gu8CycleStep=1; } break; case 1: Gu32CycleCnt++; if(Gu32CycleCnt>=CYCLE\_SUM) { Gu32CycleCnt=0; P0\_0=1; //主循環的LED燈滅。 Gu8CycleStep=0; } break; } } } void T0\_time() interrupt 1 //定時器0的中斷函數,每1ms單片機自動執行一次此函數 { switch(Gu8InterruptStep) { case 0: Gu32InterruptCnt++; //累計中斷次數的次數 if(Gu32InterruptCnt>=INTERRUPT\_SUM) //次數達到設定值就跳到下一步驟 { Gu32InterruptCnt=0; //及時清零計數器,為下一步驟的新一輪計數準備 P0\_1=0; //定時中斷的LED燈亮。 Gu8InterruptStep=1; //跳到下一步驟 } break; case 1: Gu32InterruptCnt++; //累計中斷次數的次數 if(Gu32InterruptCnt>=INTERRUPT\_SUM) //次數達到設定值就返回上一步驟 { Gu32InterruptCnt=0; //及時清零計數器,為返回上一步驟的新一輪計數準備 P0\_1=1; //定時中斷的LED燈滅。 Gu8InterruptStep=0; //返回到上一個步驟 } break; } TH0=0xfc; //重裝初值,不能忘。 TL0=0x66; //重裝初值,不能忘。 }
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看