在第一篇到第九篇博文中,我們認識到了一些基于IO口輸入與輸出的基礎電子器件使用:
《8051單片機實戰分析(以STC89C52RC為例) | 01 - 點亮一個LED》
《8051單片機實戰分析(以STC89C52RC為例) | 02 - LED延時約5s閃爍》
《8051單片機實戰分析(以STC89C52RC為例) | 03 - LED流水燈》
《8051單片機實戰分析(以STC89C52RC為例) | 04 - 蜂鳴器驅動》
《8051單片機實戰分析(以STC89C52RC為例) | 05 - 靜態數碼管驅動》
《8051單片機實戰分析(以STC89C52RC為例) | 06 - 動態數碼管驅動》
《8051單片機實戰分析(以STC89C52RC為例) | 07 - 獨立按鍵驅動》
《8051單片機實戰分析(以STC89C52RC為例) | 08 - 矩陣按鍵驅動》
《8051單片機實戰分析(以STC89C52RC為例) | 09 - LED點陣顯示數字》
但現在我們要開始回到8051單片機內部,通過實戰來認識它們的作業原理,你會發現通過它們可以去開發一些更有意思的東西!
這篇博文帶領大家認識一下STC89C52RC單片機定時器中斷的使用,
如果你不了解什么是中斷,建議你先看這篇:
《STC89C52RC單片機額外篇 | 01 - 認識中斷、中斷源以及中斷優先級》
如果你不了解什么是串口通信,建議你先看這篇:
《STC89C52RC單片機額外篇 | 02 - 認識串行通信、波特率以及資料包》
1 中斷系統結構
以下這張圖是從中斷引腳到中斷入口所經過的通道:
從圖中不難看出RX與TX引腳經過了SCON、IE、IP這些暫存器,因此我們在寫程式時得把這些暫存器功能配置好,CPU才會按照我們的想法只執行!下面分別對這些暫存器進行介紹(稍微了解一下即可,忘記的時候再查),
1.1 SCON暫存器
SCON(Serial Control Register),中文叫串行口控制暫存器,SCON暫存器是用于控制串行通信的方式選擇、接收和發送,指示串口的狀態,
首先介紹SCON暫存器位SM0/SM1,它們用于設定作業方式:
其余SCON暫存器位的用途:
| SCON暫存器位 | 作用 |
|---|---|
SM2 | 多機通信控制位,多機通信是作業于方式2和方式3,SM2位主要用于方式2和方式3,接收狀態,當串行口作業于方式2或3,以及SM2=1時,只有當接收到第9位資料(RB8)為1時,才把接收到的前8位資料送入SBUF,且置位RI發出中斷申請,否則會將接收到的資料放棄,當SM2=0時,就不管第9位資料是0還是1,都會將資料送入SBUF,并發出中斷申請,作業于方式0時,SM2必須為0, |
REN | 允許接收位,REN用于控制資料接收的允許和禁止,REN=1時,允許接收,REN=0時,禁止接收, |
TB8 | 發送資料位8,在方式2和方式3中,TB8是要發送的——即第9位資料位,在多機通信中同樣亦要傳輸這一位,并且它代表傳輸的地址還是資料,TB8=0為資料,TB8=1時為地址, |
RB8 | 接收資料位8,在方式2和方式3中,RB8存放接收到的第9位資料,用以識別接收到的資料特征, |
TI | 發送中斷標志位,它是可尋址標志位,方式0時,發送完第8位資料后,由硬體置位,其它方式下,在發送或停止位之前由硬體置位,因此,TI=1表示幀發送結束,TI可由軟體清“0”, |
RI | 接收中斷標志位,它是可尋址標志位,接收完第8位資料后,該位由硬體置位,在其他作業方式下,該位由硬體置位,RI=1表示幀接收完成, |
要注意的是在串口中斷處理時,TI,RI都需要軟體清"0",硬體置位后不可能自動清0,此外,在進行緩沖區操作時,需要ES=0,以防止中斷出現,ES暫存器位位于接下來介紹的IE暫存器,
1.2 IE暫存器
IE(Interrupt Enable),中文叫中斷允許暫存器,它的作用是控制所有中斷源的開放或禁止,以及每個中斷源是否被允許,

各暫存器位的作用如下:
| IE暫存器位 | 作用 |
|---|---|
EA | EA = 0時,所有中斷禁止(即不產生中斷);EA = 1時,各中斷的產生由個別的允許位決定 |
ES | 串行口RX/TX中斷允許 |
ET1 | 定時器T1中斷允許 |
EX1 | 外中斷INT1中斷允許 |
ET0 | 定時器T0中斷允許 |
EX0 | 外部中斷INT0中斷允許 |
1.3 IP暫存器
IP(Interrupt Priority),中文叫中斷優先級暫存器,它是用來設定各個中斷源屬于兩級中斷中的哪一級,

各暫存器位的作用如下:
| IP暫存器位 | 作用 |
|---|---|
PS | 串行口RX/TX中斷優先 |
PT1 | 定時器T1中斷優先 |
PX1 | 外中斷INT1中斷優先 |
PT0 | 定時器T0中斷優先 |
PX0 | 外部中斷INT0中斷優先 |
除此之外,還有一個波特率有關的PCON暫存器,當然這里只用到它其中的一位,
1.4 PCON暫存器
PCON全稱Power Control Register,即功率控制暫存器,
系統復位默認為SMOD=0,當SMOD=0時,串口方式1,2,3時,波特率正常;當SMOD=1時,串口方式1,2,3時,波特率加倍,
2 串行口結構
注意這里的SBUF暫存器只是邏輯上同名,但是它們物理上是分開的!另外,還需要用到TH1與TL1這種屬于定時器T1的暫存器,后面會了解到它們的作用!
下面列出各個作業方式的資料傳輸:
① 作業方式0:
② 作業方式1:
③ 作業方式2與作業方式3:
3 波特率計算
如果你不了解什么是波特率,建議你先看這篇:
《STC89C52RC單片機額外篇 | 02 - 認識串行通信、波特率以及資料包》
下面列出基于各個作業方式的波特率計算公式,對于可變波特率的設定需要用到TH1暫存器:
當然,對于波特率,一般有幾種是可供選擇的,因為我們通常使用標稱值:
這里我們好奇為什么晶振頻率選擇11.0592MHz就能減小計算誤差,下面我們以9600波特率,分別代入11.0592MHz與12MHz計算一下:
我們設定定時器T1為作業模式2,SMOD 設為1,分別看看那所要求的TH1為何值,代入公式:
-
11.0592MHz
9600=(2÷32)×((11.0592M/12)/(256-TH1)) =》TH1=250 -
12MHz
9600=(2÷32)×((12M/12)/(256-TH1)) =》TH1≈249.49
4 代碼
① 中斷服務函式:
我們知道我們撰寫的C程式,函式的執行是從main主函式開始執行,現在有了中斷,自然就產生一個中斷服務函式:
從圖中我們可以知道單片機在發生中斷的時候,程式的執行程序會從主程式A跳到中斷服務程式B,在執行完中斷服務程式B后,會回傳到之前主程式A被中斷打斷處繼續執行程式,
那么我們如何指定中斷服務程式?具體參考以下模板(對于函式名你可以隨便寫,當然最好貼近有意義的命名),
外部中斷0的中斷服務函式:
void Int0() interrupt 0
{
... // 中斷服務程式中要執行內容
}
定時器0的中斷服務函式:
void Timer0() interrupt 1
{
... // 中斷服務程式中要執行內容
}
外部中斷1的中斷服務函式:
void Int1() interrupt 2
{
... // 中斷服務程式中要執行內容
}
定時器1的中斷服務函式:
void Timer1() interrupt 3
{
... // 中斷服務程式中要執行內容
}
串行口的中斷服務函式:
void Serial() interrupt 4
{
... // 中斷服務程式中要執行內容
}
② 下面我們寫個程式,將波特率設定為4800,把發送的資料字符"1"顯示到串口除錯助手SSCOM:
#include "reg52.h" //此檔案中定義了單片機的一些特殊功能暫存器
typedef unsigned int u16; //對資料型別進行宣告定義
typedef unsigned char u8;
/*******************************************************************************
* 函式名 :UartInit()
* 函式功能 :設定串口
* 輸入 : 無
* 輸出 : 無
*******************************************************************************/
void UartInit()
{
SCON=0x50; //設定為作業方式1
TMOD=0x20; //設定計數器作業方式2
PCON=0x80; //波特率加倍
TH1=0xF3; //計數器初始值設定,注意波特率是4800
TL1=0xF3;
ES=1; //打開接收中斷
EA=1; //打開總中斷
TR1=1; //打開計數器
}
/*******************************************************************************
* 函 數 名 : main
* 函式功能 : 主函式
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
void main()
{
UartInit(); // 串口初始化
while(1);
}
/*******************************************************************************
* 函式名 : Serial() interrupt 4
* 函式功能 : 串口通信中斷函式
* 輸入 : 無
* 輸出 : 無
*******************************************************************************/
void Serial() interrupt 4
{
u8 receiveData;
receiveData=SBUF; //出去接收到的資料
RI = 0; //清除接收中斷標志位
SBUF=receiveData; //將接收到的資料放入到發送暫存器
while(!TI); //等待發送資料完成
TI=0; //清除發送完成標志位
}
簡要分析:
- 代碼中設定波特率為4800,根據前面的表格不是應該設定
TH1=0xFA;嗎?根據前面的介紹,我們不難發現此處用到晶振頻率肯定不是11.0592MHz,明顯是使用12MHz, - 注意這里把定時器T1設定為作業方式2——8 位自動重裝模式,因此暫存器
TH1與TL0的值是一樣的, - 最后附上串口除錯助手的操作:

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/287462.html
標籤:其他
