久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

標題: 51單片機入門經驗分享4-定時器的使用 [打印本頁]

作者: dabing89    時間: 2018-10-13 08:48
標題: 51單片機入門經驗分享4-定時器的使用
本帖最后由 dabing89 于 2018-10-14 18:56 編輯

                                                    定時器的使用 ---20181013


好,繼續更新這個帖子,前邊我們點亮了流水燈,然而定時是用DELAY實現的,實際上在實際的項目中,DELAY基本上不會用,如果一個程序中,主循環有大量的DELAY出現,那么就不合理了,所以必須要用定時器 ,保證程序的實時性,這一貼,我們寫一個程序,用定時器0來實現LED間隔500MS閃爍的效果   ,代碼如下:   
  1. /*******************************************************************
  2. * 文件名  LED0 500MS閃爍
  3. * 描述:        點亮LED---用定時器的辦法
  4. * 2018-09-19 調試通過
  5. * 功能  入門模板
  6. * 作者: 大核桃
  7. * 版本號:V1.00(2018.09.19)
  8. ********************************************************************/
  9. #include "config.h"
  10. #include "intrins.h"


  11. /*******************************************************************
  12. * 文件名 變量重新定義區域
  13. * 描述:        
  14. * 功 能
  15. * 作者:大核桃
  16. * 版本號:V1.00(2018.09.17)
  17. ********************************************************************/

  18. typedef unsigned char uint8;//無符號字符型
  19. typedef unsigned int  uint16;//無符號整型
  20. typedef unsigned long uint32;//無符號長整型


  21. /*******************************************************************
  22. * 文件名:位重新定義區域 函數前置聲明
  23. * 描述:        
  24. * 功 能
  25. * 作者:大核桃
  26. * 版本號:V1.00(2018.09.17)
  27. ********************************************************************/
  28. void Delay500ms();                //@11.0592MHz
  29. void MCU_Port_Init(void);
  30. void Bsp_Tim0_Init(void);

  31. sbit LED0 = P1^0;
  32. sbit LED1 = P1^1;
  33. sbit LED2 = P1^2;
  34. sbit LED3 = P1^3;
  35. sbit LED4 = P1^4;
  36. sbit LED5 = P3^2;
  37. sbit LED6 = P0^0;
  38. sbit LED7 = P0^1;

  39. bit flag500ms = 0;//500ms定時標志位


  40. /*******************************************************************
  41. * 文件名 main函數入口
  42. * 描述:        
  43. * 功 能
  44. * 作者:大核桃
  45. * 版本號:V1.00(2018.09.17)
  46. ********************************************************************/
  47. void main(void)
  48. {
  49.         MCU_Port_Init();//端口模式初始化函數
  50.         Bsp_Tim0_Init();//定時器0初始化函數


  51.         while(1)
  52.         {           
  53.                 if(flag500ms)
  54.                 {
  55.                         P2 = 0XFE;//1111_1110;
  56.                 }
  57.                 else
  58.                 {
  59.                    P2 = 0XFF;//1111_1111;        
  60.                 }

  61.         }
  62. }

  63. /*******************************************************************
  64. * 文件名:void MCU_Port_Init(void)
  65. * 描述:        MCU端口上電初始化函數
  66. * 功 能
  67. * 作者:大核桃
  68. * 版本號:V1.00(2018.09.17)
  69. ********************************************************************/
  70. void MCU_Port_Init(void)
  71. {
  72.         //第0 和1位配置推完輸出模式,大電流
  73.         P0M1 = 0XFC; //        1111_1100
  74.         P0M0 = 0X03; // 0000_0011

  75.         //第01234位配置推完輸出模式,大電流,567配置高阻輸入,用于ADC
  76.         P1M1 = 0XE0; //1110_0000        
  77.         P1M0 = 0X1F; //0001_1111

  78.         //P2配置位準雙向口
  79.         P2M1 = 0X00; //0000_0000        
  80.         P2M0 = 0X00; //0000_0000

  81.         P2 = 0XFF;//P2口初始化為1

  82.         //P5配置位準雙向口
  83.         P5M1 = 0X00; //0000_0000        
  84.         P5M0 = 0X00; //0000_0000

  85.         P5 = 0XFF;//P5口初始化為1

  86.         //P3 23467推完輸出
  87.         P3M1 = 0X00; //0000_0000        
  88.         P3M0 = 0XFC; //1101_1100

  89.         P3 = 0X23;  //0010_0011


  90.         //上電IO默認是0
  91.         LED0 = 1;//輸出1
  92.         LED1 = 0;
  93.         LED2 = 0;
  94.         LED3 = 0;
  95.         LED4 = 0;
  96.         LED5 = 0;
  97.         LED6 = 0;
  98.         LED7 = 0;//
  99.                
  100. }

  101. /*******************************************************************
  102. * 文件名:void Bsp_Tim0_Init(void)
  103. * 描述:        定時器0初始化函數
  104. * 功 能
  105. * 作者:大核桃
  106. * 版本號:V1.00(2018.09.19)
  107. ********************************************************************/
  108. void Bsp_Tim0_Init(void)                //1000微秒@11.0592MHz
  109. {
  110.         AUXR |= 0x80;                //定時器時鐘1T模式
  111.         TMOD &= 0xF0;                //設置定時器模式
  112.         TMOD |= 0X01;      
  113.         TH0 = 0xD4;                    //設置定時初值
  114.         TL0 = 0xCD;                    //設置定時初值
  115.         TR0 = 1;                    //定時器0開始計時
  116.         ET0 = 1;            //使能定時器0的中斷
  117.         EA = 1;             //打開總中斷
  118. }

  119. /*******************************************************************
  120. * 文件名:TIM0_IRQ_Handler
  121. * 描  述:中斷服務函數        
  122. * 功  能 中斷服務標號 INT0 ET0 INT1 ET1 UART1 ADC LVD TIME2
  123. * 優先級:                      0            1    2         3          4           5   6    12
  124. * 版本號:V1.00(2018.09.19)
  125. ********************************************************************/
  126. void TIM0_IRQ_Handler(void) interrupt 1
  127. {
  128.     static uint16 tmr500ms = 0;

  129.         TH0 = 0xD4;                    //設置定時初值
  130.         TL0 = 0xCD;                    //設置定時初值

  131.         tmr500ms++;
  132.         if(tmr500ms >= 500)
  133.         {
  134.                 tmr500ms = 0;

  135.                 flag500ms = !flag500ms;        //500MS閃爍
  136.         }
  137.         
  138.                
  139. }
復制代碼


因為在實際使用中,定時器和中斷都是在一起配合使用,所以這兒我們就不分開,但是要說的是,定時器是硬件,是單片機內部存在的一個模塊,而中斷僅僅是一種處理問題的機制,上面這個d代碼看著不多,但是消息量很大,我們一點一點解剖,理解了定時器的的原理,等你上手STM32的時候,定時器原理可以直接不看,直接拿來用就好了。
    先從STC89C52RC的開始說起,我們知道,STC89C52RC是標準51內核,在標準51的體系下,12個時鐘周期是一個機器周期,啥意思呢?比如你的外部晶振是11.0592MHZ,那么11059200的倒數,也就是周期了,這個倒數叫做時鐘周期,也叫震蕩周期,算一下時間,1/11059200 = 0.0904US,這就是STC89C52的時鐘周期,那么51單片機就規定,12個這樣的時鐘周期為一個機器周期,所以在乘以12,那么一個機器周期的數值是1.085US,注意這是在11.0592MHZ下,如果是在12MHZ下,那么一個機器周期就是1US,這就是定時器的時間基準。我們再來看下,如果我們用STC89C52來做一個500MS的定時器該怎么做呢?配置如下即可實現:
  1. /*******************************************************************
  2. * 文件名:void Bsp_Tim0_Init(void)
  3. * 描述:        定時器0初始化函數
  4. * 功 能
  5. * 作者:大核桃
  6. * 版本號:V1.00(2018.09.19)
  7. ********************************************************************/
  8. void Bsp_Tim0_Init(void)                //1000微秒@11.0592MHz
  9. {
  10.         TMOD &= 0xF0;                //設置定時器模式
  11.         TMOD |= 0X01;      
  12.         TH0 = 0xFC;                    //設置定時初值
  13.         TL0 = 0x66;                    //設置定時初值
  14.         TR0 = 1;                    //定時器0開始計時
  15.         ET0 = 1;            //使能定時器0的中斷
  16.         EA = 1;             //打開總中斷

  17. }

  18. /*******************************************************************
  19. * 文件名:TIM0_IRQ_Handler
  20. * 描  述:中斷服務函數        
  21. * 功  能 中斷服務標號 INT0 ET0 INT1 ET1 UART1 ADC LVD TIME2
  22. * 優先級:                      0            1    2         3          4           5   6    12
  23. * 版本號:V1.00(2018.09.19)
  24. ********************************************************************/
  25. void TIM0_IRQ_Handler(void) interrupt 1
  26. {
  27.     static uint16 tmr500ms = 0;

  28.         TH0 = 0xFC;                    //設置定時初值
  29.         TL0 = 0x66;                    //設置定時初值

  30.         tmr500ms++;
  31.         if(tmr500ms >= 500)
  32.         {
  33.                 tmr500ms = 0;

  34.                 flag500ms = !flag500ms;        //500MS閃爍
  35.         }
  36.         
  37.                
  38. }
復制代碼



還是來解釋下,首先定時器的配置步驟是這樣的:
1.先設置TMOD這個寄存器,選擇定時器0的模式寄存器,配置定時器0為16位不可重裝載模式

2.設置定時器的定時初值,高八位和低八位
3.打開定時器的運行標志位,因為TCON是一個可位尋址的寄存器,所以直接TR0 = 1;就好。
4.使能定時器0的中斷ET0
5.打開總中斷EA
OK,這樣就配置好了寄存器,定時器也可以工作了,然而我們了解定時器是怎么運行的了嗎?沒有!!!很多人不知道為啥是這個數值,而且定時器的的初值還有好幾種寫法,如果有人用了不一樣的而寫法,你一定要知道是等價的寫法。


  關于初值的計算
   我們知道定時器0是一個16位的定時器,最大計數65536(0-65535)分為高八位和低八位,TH0存儲的是高八位的數據,TL0存儲的是低八位的數據,0XFC是一個16進制數值,換算10進制是252,0X66是102,我們知道低八位最大計數到255,TH0就變成1,然后進位,清零,又開始從0計數,那么我們可以算算這個初值是多少?252*256 +102 = 64614,而64614的16進制表示形式就是0XFC66,這樣我們就搞清楚定時器的計時原理了,如下所示,初值代碼可以改寫成這樣:
  1. TH0 = (65535 - 921) / 256;                    //設置定時初值
  2.         TL0 = (65535 - 921) % 256;                    //設置定時初值
復制代碼
也就是說,我們讓單片機從64614開始計數,到65535溢出,總共計數921個,而我們又知道1個機器周期是1.085US,那么921個機器周期是多少呢?921*1.085 = 1000US,正好是1MS的定時,我們在程序中讓其溢出500次,那么不就是500MS了嗎?就是這樣來的,原理一定要搞清楚。不管什么STM32,64,128都是這樣的原理{:lol:}。關于中斷使用的時候,打開使能就好了,EA是總中斷使能位,如果這個不打開,ET0單獨打開是沒用的,這才是一把手。
   關于STC15W系列的定時器
好了,既然我們搞清楚了,STC89C52的定時器的原理了,我們來看下,STC15W的定時器配置,因為我們都是定時1MS,那么,為啥初值不一樣呢?我們來算下STC15W的這個初值對應的10進制數值是多少?是54477,好陌生的數字,怎么來的呢?65536-54477 = 11059,也就是說在STC15W的內核下,我們只要計數11059個,就可以達到1MS的定時,我們知道,STC15W是單周期的時鐘,也就是說我們不12分頻,我們直接就是一個時鐘周期就是一個機器周期,(1/11059200)*11059 = 1ms,明白了吧?所以,本節的程序代碼,也可以這樣寫,是一樣的作用的。
  1. /*******************************************************************
  2. * 文件名:void Bsp_Tim0_Init(void)
  3. * 描述:        定時器0初始化函數
  4. * 功 能
  5. * 作者:大核桃
  6. * 版本號:V1.00(2018.09.19)
  7. ********************************************************************/
  8. void Bsp_Tim0_Init(void)                //1000微秒@11.0592MHz
  9. {
  10.         AUXR |= 0x80;                //定時器時鐘1T模式
  11.         TMOD &= 0xF0;                //設置定時器模式
  12.         TMOD |= 0X01;      
  13. //        TH0 = 0xD4;                    //設置定時初值
  14. //        TL0 = 0xCD;                    //設置定時初值
  15.         TH0 = (65535 - 11059) / 256;//設置定時初值
  16.         TL0 = (65535 - 11059) % 256;//設置定時初值
  17.         TR0 = 1;                    //定時器0開始計時
  18.         ET0 = 1;            //使能定時器0的中斷
  19.         EA = 1;             //打開總中斷

  20. }
復制代碼




關于在單片機中大量存在的& |運算的詳細說明
    其實這個,不太想說,但無奈上網看到好多初學者根本不知道& |的作用,還是詳細的說明下比較好,以定時器0的配置為例。
    AUXR |= 0x80; AUXR是一個輔助寄存器,這不需要多說,|= 0x80有什么講究呢?|(或),是讓某一位置1的意思,讓那一位置一呢?很明顯,讓是1的那一位置一,0X80不就是最高位是1嗎?那就是讓最高位置一好了,有人說,這有啥用呢?本來不就是1嗎?人家還有后半句,而其他位保持不變,其他位?啥位?等于0的那些對吧?也就是低7位不變了。這樣操作有啥好處呢?我們知道ET0 = 1;TR0 = 1;之所以可以這樣操作,是因為他們可以被位尋址,可以進行單獨的位操作,而AUXR是不可以進行位尋址的,因此一次操作必須操作8個位,你想想看,AUXR這個寄存器的功能如下圖:

   你能保證直接讓AUXR = 0X80,不對其他位造成影響嗎?現在大家的編程還比較簡單,只有一個定時器,要是用到3個,4個定時器呢?這樣不就互相干擾了嗎?扯淡么?所以 & |的重要性也就凸現出來了。
   再來看后面這2句,很明顯TMOD是不可以位尋址的,按照我們剛才的分析,|是讓某一位置一,那么&,自然就是讓某一位清零了,來看下0XF0,二進制是1111_0000,也就是低4位置0,高4位不要管,因為&是乘法運算啊,只要都是1,那么就是1,很明顯讓低4位清零,下一句是0000_0001,讓最低為置一啊,對吧,要注意,這里的2句是連續操作的,不是單獨的的操作,什么意思?前者的運算結果,又給了后者,所以我們總體來看這2句代碼,先讓低四位清零,高四位不變,然后將這個結果進行或運算,讓最低位置一,而高7位都不變,因為任何數|還是任何數啊,對吧,這就達到了一個互不干擾的目的,這樣的代碼在STM32上好多好多的,都是起到一個互不干擾的作用。這樣的做法可以確保定時器0和定時器1是獨立的,如果我們不這樣做,你看看是工作在啥模式?除了定時器配置在16位不可重裝模式在,定時器1被配置在了16位自動重裝定時器,我們沒有使用定時器1,萬一出錯怎么辦?這就不好了。
  

關于自動重裝載和不可自動重裝模式
  其實,沒啥太大的區別,如果是自動重裝,那么在中斷服務函數中,TH0 TL0就不需要去再去重新賦值了,直接刪掉就好,如果不是自動重裝,則必須要加。還差點忘了一個事,你怎么確定你的定時是500MS呢?答案不能靠眼睛看把,看看示波器觀察的結果,嗯,是對的。如下圖,1S 1HZ的方波信號

好了,今天就到這里吧,代碼上傳 004 定時器的使用.rar (30.68 KB, 下載次數: 92)







作者: 哈哈我哈哈    時間: 2018-10-14 14:51
我不明白為啥這么好的分享瀏覽量這么低呢,樓主加油
作者: dabing89    時間: 2018-10-14 15:28
哈哈我哈哈 發表于 2018-10-14 14:51
我不明白為啥這么好的分享瀏覽量這么低呢,樓主加油

謝謝支持
作者: djz_1688    時間: 2018-10-26 09:53
樓主厲害
作者: qq76832893    時間: 2018-10-27 16:29
感謝分享,正在學習單片機,
作者: XMJ.    時間: 2018-10-27 22:41
感謝分享
作者: vectorxu    時間: 2018-10-29 14:15

感謝分享,正在學習單片機,
作者: y352715553    時間: 2018-10-29 22:45
真的好實用,正好解決了我的疑惑,力贊!!!!!
作者: enchidianzi    時間: 2018-11-2 06:55
挺不錯的資料
作者: 打雜的    時間: 2018-11-15 18:25
咋沒有專門寫匯編語言的內容?
作者: 紫色的云    時間: 2018-11-20 08:49
謝謝樓主的分享,很詳細的講解
作者: jake-119001234    時間: 2018-11-20 11:33
好東東,下載學習下!!1
作者: 陳臣塵    時間: 2018-11-21 01:22
樓主,我有個地方不懂,從第二次溢出開始,進入中斷后tmr500ms不是都會重新賦值為零嗎,這樣子不是不會大于或等于500嗎,那怎么執行if函數
作者: dabing89    時間: 2018-11-21 15:40
陳臣塵 發表于 2018-11-21 01:22
樓主,我有個地方不懂,從第二次溢出開始,進入中斷后tmr500ms不是都會重新賦值為零嗎,這樣子不是不會大于 ...

void TIM0_IRQ_Handler(void) interrupt 1
{
    static uint16 tmr500ms = 0;

        TH0 = 0xFC;                    //設置定時初值
        TL0 = 0x66;                    //設置定時初值

        tmr500ms++;//這個你應該沒有看到
作者: 時光倒影    時間: 2018-12-13 11:39
謝謝樓主分享
作者: cjh060594766    時間: 2018-12-24 14:33
學習 學習
作者: 2019keil    時間: 2019-1-23 11:46
感謝分享
作者: dianzifashaoyou    時間: 2019-3-23 21:42
謝謝分享好好學習。
作者: duan子    時間: 2019-4-14 14:46
謝謝分享好好學習

作者: qiaohw519    時間: 2019-4-14 16:34
這個文章真是太接地氣了,基本上把定時掰開了講清楚了
說的非常好,初學者都能夠看懂,
受益良多
作者: he992790757    時間: 2019-6-15 14:24
感謝分享!!!
作者: yfpc2006    時間: 2019-7-28 18:23
很適合初學者,或者這方面理解不清的朋友!
講的非常好,樓主加油~~~~~
作者: 小黑屋525    時間: 2019-7-28 18:37
這是真的好貼,加油!
作者: mengbook    時間: 2019-8-15 08:31
樓主 是怎么自學的
作者: baiwj2004    時間: 2020-2-11 07:21


感謝分享,正在學習單片機,
作者: sklx24503    時間: 2020-6-16 15:12
謝謝樓主的分享,很詳細的講解
作者: shineben    時間: 2020-9-2 16:36
樓主,還有后續經驗分享嗎??
作者: maozj    時間: 2020-9-15 22:38
講解的很清楚,謝謝!
作者: seethrufxl    時間: 2021-1-12 16:38
樓主高手,謝謝了!
作者: 51mcu學習    時間: 2021-1-23 20:14
感謝分享,正在學習單片機!
作者: 山外天驚天外山    時間: 2021-2-10 20:52
http://m.zg4o1577.cn/bbs/dpj-202537-1.html
作者: lsh04    時間: 2021-3-2 08:50
感謝分享,正在學習單片機
作者: lsg0280    時間: 2021-7-9 17:57
溫習定時器的使用,多看看有啟發。
作者: andygo    時間: 2022-3-7 09:43
對初學者很友發,值得多看幾次
作者: mcuhui    時間: 2022-4-9 18:53
這樣的C教材還是第一次拜讀,比那些所謂名校的教材更加通俗易懂
作者: yaofuming    時間: 2022-5-1 20:34
別的不服,就服樓主。&、|、TH0、TL0講得非常非常清楚!
作者: 人生涅槃    時間: 2022-6-22 17:28
謝謝樓主我會來學習的
作者: zzzzz8840    時間: 2022-10-19 10:44
就是定時器搞不懂,這文章太好了,萬分感謝!
作者: wyl138    時間: 2022-10-31 20:19
聽君一席話,勝讀十年書,拜謝!
作者: Olivialivia    時間: 2022-12-29 16:44
說實話,這是我看過講定時器講的最清楚的了,點贊
作者: 51老鷹    時間: 2023-2-1 10:09
終于知道為什么要這樣了,感謝樓主。
作者: chengchun    時間: 2023-3-26 16:40
寫得太好了,剛接觸51單片機,簡單的點亮LED和花樣流水燈都會了,開始學習更深的知識,謝謝
作者: Q__Q    時間: 2023-5-13 15:01
謝謝樓主 這篇我看懂了來龍去脈了 終于對定時器明白了一些 收藏學習




歡迎光臨 (http://m.zg4o1577.cn/bbs/) Powered by Discuz! X3.1
主站蜘蛛池模板: 日韩av在线中文字幕 | 中文字幕一区二区三区不卡在线 | 91精品久久久久久久久久入口 | www.黄色网| 激情欧美一区二区三区中文字幕 | 天天综合操| 日本一区二区三区在线观看 | 国产精品美女久久久久久免费 | 欧美激情精品久久久久久变态 | 一级欧美| 久久久成人网 | 自拍视频精品 | 免费在线播放黄色 | 久久综合国产 | 国产精品久久久久久吹潮日韩动画 | 精品一区二区三区四区在线 | 一级黄片一级毛片 | 欧美一区二区二区 | 久久久久久久久99 | 欧美综合在线观看 | 精品欧美激情在线观看 | 午夜寂寞影院列表 | 看av电影 | 免费欧美| 精品一区二区电影 | 成人av在线播放 | 三级在线免费 | 国产精品视频一区二区三区 | 成人影| 色播av| 久久com| 国产精品色 | 影音先锋中文字幕在线观看 | 亚洲高清在线播放 | aaa在线观看 | 日韩久久精品 | 国产精品久久久久久婷婷天堂 | 欧美美女爱爱视频 | 精品视频久久久久久 | 亚洲一区二区三区视频在线 | 日日天天 |