?? 專欄簡介:本專欄記錄了從零學習單片機的過程,其中包括51單片機和STM32單片機兩部分;建議先學習51單片機,其是STM32等高級單片機的基礎(chǔ);這樣再學習STM32時才能融會貫通。
?? 專欄適用人群 :適用于想要從零基礎(chǔ)開始學習入門單片機,且有一定C語言基礎(chǔ)的的童鞋。
??專欄目標:實現(xiàn)從零基礎(chǔ)入門51單片機和STM32單片機,力求在玩好單片機的同時,能夠了解一些計算機的基本概念,了解電路及其元器件的基本理論等。?? 專欄主要內(nèi)容: 主要學習51單片機的功能、各個模塊、單片機的外設(shè)、驅(qū)動等,最終玩好單片機和單片機的外設(shè),全程手敲代碼,實現(xiàn)我們所要實現(xiàn)的功能。
?? 專欄說明 :如果文章知識點有錯誤的地方,歡迎大家隨時在文章下面評論,我會第一時間改正。讓我們一起學習,一起進步。
??專欄主頁:http://t.csdn.cn/HCD8v
本學習過程參考:https://space.bilibili.com/383400717
單片機安裝軟件、各種資料以及源碼的路徑:
https://pan.baidu.com/s/1vDTN2o8ffvczzNQGfyjHng
提取碼:gdzf
本節(jié)主要介紹學習定時器的相關(guān)功能,包括定時器簡介、定時器原理、計數(shù)器、時鐘、中斷系統(tǒng)等基礎(chǔ)知識;并利用兩個小實驗來進行練習,分別是使用定時器實現(xiàn)按鍵控制流水燈模式以及使用定時器實現(xiàn)定時器時鐘。
一、定時器介紹和本節(jié)目標
1.1 定時器簡介和定時器原理
1.1.1 定時器簡介
STC89C52的定時器資源,如下圖所示,具體的可以 參考手冊:\51單片機入門教程資料\課件及程序源碼\相關(guān)資料\STC89C52.pdf 第七章 定時器/計數(shù)器
1.1.2 定時器原理
下面會學習什么是中斷系統(tǒng)。
定時器的工作模式如下:
本文我們只學習模式1:16位定時器/計數(shù)器;其是最常用的;其他幾個模式基本不怎么常用。
模式1的框圖如下圖所示:
可以將其分為三部分,時鐘部分,計數(shù)器部分和中斷部分,如下圖所示:
1.1.2.1 計數(shù)器
計數(shù)器是如何進行計數(shù)的呢?上圖中我們可以看到計數(shù)器部分有TL0和TH0,每個都存放8字節(jié)數(shù)據(jù),總共可以存的數(shù)字為從0-65535;由左邊的時鐘給TL0和TL1提供脈沖,每提供一個脈沖,這16為計數(shù)器里面的值就會加1;當值加到最大值65535時,下一個脈沖再過來,就會造成計數(shù)器的溢出,溢出時計數(shù)器就會給到一個標志位給TF0,收到標志位,TF0就會給中斷系統(tǒng)一個中斷信號申請中斷;
圖中的TR0是控制定時器是否啟動;
1.1.2.2 時鐘
從圖中可以看出,時鐘的來源有兩個,一個是SYSclk,即系統(tǒng)時鐘;另一個是T0Pin,T0Pin是單片機外部的接口;如下圖所示
在關(guān)鍵圖中可以看出,14引腳的位置就是T0Pin;
所以時鐘既可以由系統(tǒng)時鐘(SYSclk)來提供,也可以通過外部引腳來提供;當由外部引腳來提供時鐘的時候,我們的定時器就是一個計數(shù)器;因為外部來一個脈沖計數(shù)器就加一,所以就相當于一個脈沖計數(shù)器;計數(shù)器名字的來源也是來于此。
當然最常用的還是由系統(tǒng)時鐘來提供脈沖。系統(tǒng)時鐘也是晶振周期。晶振在開發(fā)部上的位置如下圖所示:
本開發(fā)板上的晶振為12MHz,所以該開發(fā)板上的系統(tǒng)時鐘也就是12MHz。
系統(tǒng)時鐘輸入的12MHz;12T模式會將輸入的12MHz的系統(tǒng)時鐘12分頻,分頻后輸出的頻率就是1MHz;所以定時器的周期就是1微秒(Hz代表每秒周期震動1次, 60Hz代表每秒周期震動60次 1MHZ=1000000HZ。所以1MHz為一秒震動一百萬次)。即在圖中畫的紅色線路(C/T=0)的情況下,定時器的計數(shù)單元每隔一微秒就計數(shù)一次。
我們本節(jié)定時器時鐘的選擇配置為:分頻模式選擇12分頻,然后選擇C/T=0,即定時器功能(當C/T=1時,是連接下面,即計數(shù)器功能); 所以整體流程為:系統(tǒng)時鐘(SYSclk)->12分頻(12T模式)->定時器模式(C/T=0),如下圖所示:
1.1.2.3 中斷系統(tǒng)
中斷系統(tǒng)也是51單片機一個很重要的知識點,本節(jié)的定時器需要中斷系統(tǒng),后面要學習到的串口也需要中斷系統(tǒng);i/o口也需要中斷系統(tǒng),等等,許多設(shè)備都需要中斷系統(tǒng)。所以中斷系統(tǒng)會和許多外設(shè)打交道。
中斷系統(tǒng)的介紹如下圖所示(參考\51單片機入門教程資料\課件及程序源碼\相關(guān)資料\STC89C52.pdf 第6章 中斷系統(tǒng)
)
總結(jié)幾個重點:
1、中斷是可以使CPU擁有對外界緊急事件的實時處理能力
2、高優(yōu)先級的中斷可以打斷中優(yōu)先級的中斷
中斷的處理流程
中斷的處理流程如下圖所示:
當主程序正在運行時,如果突然來了一個中斷請求,則CPU會響應(yīng)中斷請求
,進而去處理中斷處理程序,當中斷處理程序執(zhí)行完之后,再返回主程序
執(zhí)行主程序的任務(wù)。
中斷資源
中斷資源也是和單片機的型號關(guān)聯(lián)在一起的,即不同種類的單片機可能擁有不同的中斷資源,例如中斷源個數(shù)不同,優(yōu)先級個數(shù)不同等。
下圖是STC89C5的中斷資源:
1.1.2.4 定時器和中斷系統(tǒng)
定時器和中斷系統(tǒng)具體的關(guān)系圖如下圖所示(以傳統(tǒng)51單片機為例):
整體的流程如下圖紅線部分所示:,由時鐘到定時器再到中斷系統(tǒng);關(guān)于整個流程的具體代碼實現(xiàn)下面會學習;
1.1.2.5 定時器相關(guān)寄存器
前面我們學過,單片機通過配置寄存器來控制內(nèi)部線路的連接。通過內(nèi)部線路的不同連接方式來實現(xiàn)不同的功能。
下圖列出了和定時器有關(guān)的寄存器已經(jīng)和中斷有關(guān)的寄存器:
寄存器具體由什么作用呢?
前面我們講到的具體模式的配置,也就是上圖中的各個開關(guān),具體撥到哪個位置上, 就是由寄存器來控制的。如下圖所示:
具體的介紹請參考手冊(\51單片機入門教程資料\課件及程序源碼\相關(guān)資料\STC89C52.pdf 第7.1.1節(jié)
)
視頻介紹請參考(https://www.bilibili.com/video/BV1Mb411e7re/?p=17&spm_id_from=pageDriver&vd_source=e2638d12685eef84cda913d9d67be0a9的第48分鐘后)
總結(jié)如下:
1、寄存器是連接軟硬件的媒介
2、在單片機中寄存器就是一段特殊的RAM存儲器一方面,寄存器可以存儲和讀取數(shù)據(jù),另一方面,每一個寄存器背后都連接了一根導線,控制著電路的連接方式
3、寄存器相當于一個復雜機器的“操作按鈕
所以只要我們在程序中將相應(yīng)的寄存器配置好,單片機的電路就會按照我們審定的模式去工作。
1.2 本節(jié)目標
目標1:按鍵控制LED流水燈模式
流水燈的效果在前面學習LED燈的時候已經(jīng)演示過了,本節(jié)要做的就是通過定時器,將按鍵和流水燈結(jié)合在一起;效果還是流水燈的效果。
目標2:使用定時器實現(xiàn)時鐘
二、按鍵控制LED流水燈模式
代碼路徑:51單片機入門教程資料\課件及程序源碼\程序源碼\KeilProject\7-1 按鍵控制LED流水燈模式
代碼的編寫過程,請參考https://www.bilibili.com/video/BV1Mb411e7re/?p=18&spm_id_from=pageDriver&vd_source=e2638d12685eef84cda913d9d67be0a9
具體代碼:
#include <REGX52.H>
#include "Timer0.h"
#include "Key.h"
#include <INTRINS.H>
unsigned char KeyNum,LEDMode;
void main()
{
P2=0xFE;
Timer0Init();
while(1)
{
KeyNum=Key(); //獲取獨立按鍵鍵碼
if(KeyNum) //如果按鍵按下
{
if(KeyNum==1) //如果K1按鍵按下
{
LEDMode++; //模式切換
if(LEDMode>=2)LEDMode=0;
}
}
}
}
//定時器中斷函數(shù)
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x18; //設(shè)置定時初值
TH0 = 0xFC; //設(shè)置定時初值
T0Count++; //T0Count計次,對中斷頻率進行分頻
if(T0Count>=500)//分頻500次,500ms
{
T0Count=0;
if(LEDMode==0) //模式判斷
P2=_crol_(P2,1); //LED輸出
if(LEDMode==1)
P2=_cror_(P2,1);
}
}
其中,Timer0.c如下:
#include <REGX52.H>
/**
* @brief 定時器0初始化,1毫秒@12.000MHz
* @param 無
* @retval 無
*/
void Timer0Init(void)
{
TMOD &= 0xF0; //設(shè)置定時器模式
TMOD |= 0x01; //設(shè)置定時器模式
TL0 = 0x18; //設(shè)置定時初值
TH0 = 0xFC; //設(shè)置定時初值
TF0 = 0; //清除TF0標志
TR0 = 1; //定時器0開始計時
ET0=1;
EA=1;
PT0=0;
}
/*定時器中斷函數(shù)模板
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x18; //設(shè)置定時初值
TH0 = 0xFC; //設(shè)置定時初值
T0Count++;
if(T0Count>=1000)
{
T0Count=0;
}
}
*/
Key.c的內(nèi)容如下:
#include <REGX52.H>
#include "Delay.h"
/**
* @brief 獲取獨立按鍵鍵碼
* @param 無
* @retval 按下按鍵的鍵碼,范圍:0~4,無按鍵按下時返回值為0
*/
unsigned char Key()
{
unsigned char KeyNumber=0;
if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;}
if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;}
if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}
if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}
return KeyNumber;
}
代碼解釋,這里主要解釋一下Timer0.c
里的Timer0Init函數(shù),
/**
* @brief 定時器0初始化,1毫秒@12.000MHz
* @param 無
* @retval 無
*/
void Timer0Init(void)
{
TMOD &= 0xF0; //設(shè)置定時器模式
TMOD |= 0x01; //設(shè)置定時器模式
TL0 = 0x18; //設(shè)置定時初值
TH0 = 0xFC; //設(shè)置定時初值
TF0 = 0; //清除TF0標志
TR0 = 1; //定時器0開始計時
ET0=1;
EA=1;
PT0=0;
}
首先是配置定時器模式TMOD:TMOD &= 0xF0
表示將TMOD的低四位清零,高四位保持不變;TMOD |= 0x01
表示將TMOD的最低位置1,其他位不變;
這兩步操作,其實跟TMOD=0x01;
效果是一樣的,好處是防止同時操作多個寄存器時串位的情況,能夠在實現(xiàn)配置高四位的同時,不影響低四位。TL0 = 0x18; TH0 = 0xFC;
表示設(shè)置定時初值,TL0為低位,TH0為高位。
TF0=0
清除TF0標志;TR0 = 1;
如上圖中,當TR0為1時,與門的輸出結(jié)果就全取決于TR0下面那部分了。
ET0=1
,打開ET0的開關(guān);EA=1
,打開EA的開關(guān);PT0=0
,設(shè)置為低優(yōu)先級。
其實對定時器的設(shè)置不一定要我們手敲代碼,簡單方法是利用STC-ISP軟件里的功能生成,步驟如下:
假設(shè)我們要設(shè)置一個1ms的定時器:
按照下圖進行配置,點擊生成C代碼即可生成一個1ms的定時器代碼,
但是AUXR是相對于最新版本的,我們的單片機并不需要,直接刪掉就行??梢园l(fā)現(xiàn),跟我們自己上面寫的代碼是一致的。但是少了中斷的配置,我們將中斷的配置加上即可。
配置中斷:ET0=1
,打開ET0的開關(guān);EA=1
,打開EA的開關(guān);PT0=0
,設(shè)置為低優(yōu)先級。
所以后面我們在寫定時器的代碼時,直接用STC-ISP軟件里生成代碼,然后在后面加上以上配置中斷的代碼即可
。
前面講了定時器的配置,那定時器達到定時時間后,需要觸發(fā)中斷,轉(zhuǎn)而去執(zhí)行中斷處理程序,中斷處理程序如下所示,其中在函數(shù)名定義后面加上 interrupt 1
,就表示這是中斷處理程序,當定時器達到時間后,就會自動觸發(fā)中斷去執(zhí)行該中斷處理程序。
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x18; //設(shè)置定時初值
TH0 = 0xFC; //設(shè)置定時初值
T0Count++; //T0Count計次,對中斷頻率進行分頻
if(T0Count>=500)//分頻500次,500ms
{
T0Count=0;
if(LEDMode==0) //模式判斷
P2=_crol_(P2,1); //LED輸出
if(LEDMode==1)
P2=_cror_(P2,1);
}
}
每次執(zhí)行中斷處理程序,都要給TL0和TH0賦初值,具體設(shè)置為多少,參考上面STC-ISP生成的代碼里的值即可。T0Count
用來控制時間,比如我們想要達到0.5秒間隔再去處理某件事,但是定時器每次觸發(fā)的頻率是1ms,所以就定義T0Count
,每次觸發(fā)中斷處理函數(shù),T0Count
就加1,代表過了1ms了,當T0Count
加到500時,就表示過了500ms,也就是0.5s了。
再后面的代碼(中斷控制函數(shù)里的代碼)就是控制獨立按鍵了。_crol_
和_cror_
函數(shù)包含在INTRINS.H
函數(shù)庫中,含義分別是循環(huán)左移和循環(huán)右移
執(zhí)行完中斷處理函數(shù)后,繼續(xù)執(zhí)行主程序的代碼。
最終的效果就是目標1了,即用按鍵控制流水燈模式。
三、定時器時鐘
代碼路徑:51單片機入門教程資料\課件及程序源碼\程序源碼\KeilProject\7-2 定時器時鐘
文章來源:http://www.zghlxwxcb.cn/news/detail-722936.html
具體代碼:文章來源地址http://www.zghlxwxcb.cn/news/detail-722936.html
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "Timer0.h"
unsigned char Sec=55,Min=59,Hour=23;
void main()
{
LCD_Init();
Timer0Init();
LCD_ShowString(1,1,"Clock:"); //上電顯示靜態(tài)字符串
LCD_ShowString(2,1," : :");
while(1)
{
LCD_ShowNum(2,1,Hour,2); //顯示時分秒
LCD_ShowNum(2,4,Min,2);
LCD_ShowNum(2,7,Sec,2);
}
}
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x18; //設(shè)置定時初值
TH0 = 0xFC; //設(shè)置定時初值
T0Count++;
if(T0Count>=1000) //定時器分頻,1s
{
T0Count=0;
Sec++; //1秒到,Sec自增
if(Sec>=60)
{
Sec=0; //60秒到,Sec清0,Min自增
Min++;
if(Min>=60)
{
Min=0; //60分鐘到,Min清0,Hour自增
Hour++;
if(Hour>=24)
{
Hour=0; //24小時到,Hour清0
}
}
}
}
}
到了這里,關(guān)于51單片機(七)定時器的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!