本文是關(guān)于51單片機(jī)中斷系統(tǒng)的擴(kuò)展實(shí)驗(yàn)。
一、 擴(kuò)展實(shí)驗(yàn)一:使用外部中斷0控制蜂鳴器,外部中斷1控制直流電機(jī)
外部中斷擴(kuò)展實(shí)驗(yàn)一實(shí)現(xiàn)的功能:使用外部中斷0控制蜂鳴器發(fā)聲/不發(fā)聲,外部中斷1控制直流電機(jī)轉(zhuǎn)動/停止。
由蜂鳴器的內(nèi)容可以知道,蜂鳴器分為有源蜂鳴器和無源蜂鳴器;蜂鳴器有兩個管腳,要使蜂鳴器發(fā)聲,需要有電流通過蜂鳴器,即管腳一端接正極,管腳另一端接負(fù)極。有源蜂鳴器只需給一定的電壓即可發(fā)聲,無源蜂鳴器需要一定頻率的脈沖才可發(fā)聲。這里設(shè)計了兩種蜂鳴器,都由外部中斷0控制。
直流電機(jī)的驅(qū)動方式與蜂鳴器類似。
proteus中硬件設(shè)計如下,為顯示蜂鳴器的發(fā)聲,這里使用了一個LED顯示發(fā)聲與否。蜂鳴器的一端連接到電源,另一端經(jīng)過ULN2003芯片連接P1.5口,當(dāng)P1.5=0時蜂鳴器發(fā)聲;直流電機(jī)的一端連接到電源,另一端經(jīng)過ULN2003連接到P1.0口,當(dāng)P1.0=0時電機(jī)轉(zhuǎn)動。為體現(xiàn)中斷,使用獨(dú)立按鍵模塊連接到P3.2和P3.3口,當(dāng)按鍵按下,蜂鳴器發(fā)聲或電機(jī)轉(zhuǎn)動。

軟件設(shè)計如下:
/*
實(shí)現(xiàn)功能:外部中斷0控制蜂鳴器發(fā)聲,外部中斷1控制直流電機(jī)轉(zhuǎn)動
- 與外部中斷0和外部中斷1有關(guān)的有兩個寄存器IE和TCON,
- IE是中斷允許控制寄存器,TCON是中斷請求標(biāo)志寄存器。
- IE中包括了
- 總中斷允許位(EA)
- 外部中斷0/1允許位(EX0/EX1)
- 定時器0/1允許位(ET0/ET1)
- 串口中斷允許位(ES);
- TCON中的低四位是外部中斷允許和觸發(fā)方式控制位,包括了
- IT0/IT1是外部中斷0/1觸發(fā)方式控制位,0表示低電平觸發(fā),1表示下降沿觸發(fā);
- IE0/IE1是外部中斷0/1請求標(biāo)志位
[2023-12-19] zoya
*/
#include "reg52.h"
#include "typedef.h"
#include "Delay.h"
sbit BEEP = P1^5;
sbit MOTOR = P1^0;
sbit CTR_INT0 = P3^2;
sbit CTR_INT1 = P3^3;
/*************************************************************************
* 函數(shù)名: IntInit
* 函數(shù)功能: 外部中斷0/1初始化,設(shè)置中斷觸發(fā)方式為邊沿觸發(fā)
* 輸入: void
* 輸出: void
**************************************************************************/
void IntInit()
{
// 1. 設(shè)置中斷觸發(fā)方式
IT0=1;
IT1=1;
// 2. 打開外部中斷0/1
EX0=1;
EX1=1;
// 3. 打開總中斷
EA=1;
}
void main()
{
MOTOR=0;
BEEP=0;
IntInit();
while(1);
}
/*************************************************************************
* 函數(shù)名: Int0
* 函數(shù)功能: 外部中斷0中斷服務(wù)函數(shù),
* 控制蜂鳴器發(fā)聲
* 輸入: void
* 輸出: void
**************************************************************************/
void Int0() interrupt 0
{
delayms(10); // 按鍵延時消抖
if(0 == CTR_INT0){
BEEP = ~BEEP;
}
}
/*************************************************************************
* 函數(shù)名: Int1
* 函數(shù)功能: 外部中斷1中斷服務(wù)函數(shù),
* 控制直流電機(jī)轉(zhuǎn)動
* 輸入: void
* 輸出: void
**************************************************************************/
void Int1() interrupt 2
{
delayms(10); // 按鍵延時消抖
if(0 == CTR_INT1)
{
MOTOR=~MOTOR;
}
}
仿真結(jié)果:

二、擴(kuò)展實(shí)驗(yàn)二:修改定時器初值,設(shè)定3秒鐘的定時時間讓LED模塊閃爍
如何計算定時器初值?
以使用12MHz的晶振頻率計算。如果使用的是12MHz晶振,單片機(jī)內(nèi)部的時鐘頻率為12分頻即12/12MHz=1MHz;那么對應(yīng)的機(jī)器周期為1/1MHz=1us。即使用12MHz晶振的機(jī)器周期為1us。
如果要定時1ms,需要計數(shù)1ms/1us=1000個,定時器使用方式1工作,那么初值為
= 0xFC18。即初值THx=0xfc,TLx=0x18。
如果要定時1s,可以通過初值設(shè)置定時1ms,當(dāng)定時結(jié)束重新賦初值,并設(shè)定一個全局變量累計定時1ms的次數(shù),當(dāng)該全局變量累計1000次時表示定時1s。
如果要設(shè)定3s時間,可以通過初值設(shè)定定時3ms,其它同定時1ms。定時3ms需要計數(shù)3ms/1us=3000,定時器使用方式1工作,初值為
= 62536 = 0xF448,即初值THx=0xF4,TLx=0x48。
該實(shí)驗(yàn)在前面使用示例的基礎(chǔ)上更改計數(shù)初值即可實(shí)現(xiàn)定時3s實(shí)現(xiàn)LED模塊的閃爍。proteus中設(shè)計LED模塊如下,定時器模塊在單片機(jī)內(nèi)部。

軟件設(shè)計如下:
/*
實(shí)現(xiàn)功能:定時器0定時3s實(shí)現(xiàn)LED模塊亮滅
- 與定時/計數(shù)器工作有關(guān)的寄存器有IE、TCON、TMOD、THx、TLx
- IE是中斷允許控制寄存器,TCON是中斷請求標(biāo)志寄存器,TMOD是定時/計數(shù)器工作方式寄存器
- THx和TLx是計數(shù)初值賦值寄存器。
- IE中包括了
- 總中斷允許位(EA)
- 外部中斷0/1允許位(EX0/EX1)
- 定時器0/1允許位(ET0/ET1)
- 串口中斷允許位(ES);
- TCON中的高四位用于控制定時/計數(shù)器的啟動和中斷申請,包括TR0/1、TF0/1
- TR0/TR1是T0/T1運(yùn)行控制位,TR0=1時開始工作,TR0=0時停止工作,TR1與TR0類似;
- TF0/TF1是T0/T1溢出中斷請求標(biāo)志位,溢出時由硬件自動置位,CPU響應(yīng)中斷后由硬件自動清0
可隨時查詢該位狀態(tài),也可軟件置1或清0.
- TMOD高四位控制T1,低四位控制T0,高四位和低四位分別為有GATE、C/T、M1M0
- GATE是門控位,
- GATE=0表示不受外部中斷信號影響,僅TR0/TR1控制定時/計數(shù)器工作,
- GATE=1表示受外部中斷信號影響,即TR0/TR1+INT0控制定時/計數(shù)器工作
- C/T是定時/計數(shù)器模式選擇位,C/T=0為定時模式,C/T=1為計數(shù)模式;
- M1M0是工作方式設(shè)置位,有四種方式:00 01 10 11
[2023-12-20] zoya
*/
#include "reg52.h"
#include "typedef.h"
#include "Delay.h"
#define GPIO_LED P2
/*************************************************************************
* 函數(shù)名: Timer0Init
* 函數(shù)功能: 定時器0初始化,工作方式1定時3ms,僅TR0啟動或停止計數(shù)
* 輸入: void
* 輸出: void
**************************************************************************/
void Timer0Init()
{
// 1. 設(shè)置工作方式1,僅TR0控制
TMOD |= 0x01;
// 2. 設(shè)置定時3ms的初值,0xf448
TH0 = 0xf4;
TL0 = 0x48;
// 3. 打開中斷允許位
EA = 1;
ET0 = 1;
// 4. 置位TR0,開始計數(shù)
TR0 = 1;
}
void main()
{
Timer0Init();
while(1);
}
/*************************************************************************
* 函數(shù)名: Timer0
* 函數(shù)功能: 定時器0中斷服務(wù)函數(shù),定時3s控制LED模塊亮滅
* 輸入: void
* 輸出: void
**************************************************************************/
void Timer0() interrupt 1
{
static u16 i;
// 重新賦初值
TH0 = 0xf4;
TL0 = 0x48;
i++;
if(1000 == i)
{
i=0;
GPIO_LED = ~GPIO_LED;
}
}
仿真結(jié)果:

三、擴(kuò)展實(shí)驗(yàn)三:使用定時器1和數(shù)碼管設(shè)計一個數(shù)字時鐘
定時器的設(shè)置參考擴(kuò)展實(shí)驗(yàn)二。
數(shù)字時鐘采用24小時制,顯示使用“00-00-00”格式。
這里數(shù)碼管使用一個八位一體的共陰極數(shù)碼管,使用芯片74HC138控制數(shù)碼管的位選,使用芯片74HC245控制數(shù)碼管的段選;P0口控制74HC245的輸入,P2.2 ~ P2.4控制74HC138的輸入。proteus設(shè)計如下:

軟件設(shè)計如下:
/*
實(shí)現(xiàn)功能:定時器1和數(shù)碼管設(shè)計一個數(shù)字時鐘
- 與定時/計數(shù)器工作有關(guān)的寄存器有IE、TCON、TMOD、THx、TLx
- IE是中斷允許控制寄存器,TCON是中斷請求標(biāo)志寄存器,TMOD是定時/計數(shù)器工作方式寄存器
- THx和TLx是計數(shù)初值賦值寄存器。
- IE中包括了
- 總中斷允許位(EA)
- 外部中斷0/1允許位(EX0/EX1)
- 定時器0/1允許位(ET0/ET1)
- 串口中斷允許位(ES);
- TCON中的高四位用于控制定時/計數(shù)器的啟動和中斷申請,包括TR0/1、TF0/1
- TR0/TR1是T0/T1運(yùn)行控制位,TR0=1時開始工作,TR0=0時停止工作,TR1與TR0類似;
- TF0/TF1是T0/T1溢出中斷請求標(biāo)志位,溢出時由硬件自動置位,CPU響應(yīng)中斷后由硬件自動清0
可隨時查詢該位狀態(tài),也可軟件置1或清0.
- TMOD高四位控制T1,低四位控制T0,高四位和低四位分別為有GATE、C/T、M1M0
- GATE是門控位,
- GATE=0表示不受外部中斷信號影響,僅TR0/TR1控制定時/計數(shù)器工作,
- GATE=1表示受外部中斷信號影響,即TR0/TR1+INT0控制定時/計數(shù)器工作
- C/T是定時/計數(shù)器模式選擇位,C/T=0為定時模式,C/T=1為計數(shù)模式;
- M1M0是工作方式設(shè)置位,有四種方式:00 01 10 11
使用一個八位一體的共陰極數(shù)碼管顯示時間,74HC138芯片控制數(shù)碼管的位選,74HC245控制數(shù)碼管的段選。
[2023-12-20] zoya
*/
#include "reg52.h"
#include "typedef.h"
#include "Delay.h"
#define GPIO_DISPLAY P0
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
// 共陰極數(shù)碼管的碼表,0-9以及:
u8 code smg[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x67, 0x40};
static u16 h, m, s;
/*************************************************************************
* 函數(shù)名: Timer0Init
* 函數(shù)功能: 定時器0初始化,工作方式1定時3ms,僅TR0啟動或停止計數(shù)
* 輸入: void
* 輸出: void
**************************************************************************/
void Timer1Init()
{
// 1. 設(shè)置工作方式1,僅TR0控制
TMOD |= 0x10;
// 2. 設(shè)置定時1ms的初值,0xFC18
TH1 = 0xFC;
TL1 = 0x18;
// 3. 打開中斷允許位
EA = 1;
ET1 = 1;
// 4. 置位TR1,開始計數(shù)
TR1 = 1;
}
void DigDisplay()
{
LSA=0; LSB=0; LSC=0; GPIO_DISPLAY = smg[h/10];
delayms(1);
LSA=1; LSB=0; LSC=0; GPIO_DISPLAY = smg[h%10];
delayms(1);
LSA=0; LSB=1; LSC=0; GPIO_DISPLAY = smg[10];
delayms(1);
LSA=1; LSB=1; LSC=0; GPIO_DISPLAY = smg[m/10];
delayms(1);
LSA=0; LSB=0; LSC=1; GPIO_DISPLAY = smg[m%10];
delayms(1);
LSA=1; LSB=0; LSC=1; GPIO_DISPLAY = smg[10];
delayms(1);
LSA=0; LSB=1; LSC=1; GPIO_DISPLAY = smg[s/10];
delayms(1);
LSA=1; LSB=1; LSC=1; GPIO_DISPLAY = smg[s%10];
delayms(1);
}
void main()
{
GPIO_DISPLAY = 0x00;
Timer1Init();
while(1)
{
DigDisplay();
}
}
/*************************************************************************
* 函數(shù)名: Timer1
* 函數(shù)功能: 定時器1中斷服務(wù)函數(shù),控制數(shù)碼管顯示
* 輸入: void
* 輸出: void
**************************************************************************/
void Timer1() interrupt 3
{
static u16 j;
// 重新賦初值
TH1 = 0xFC;
TL1 = 0x18;
j++;
if(1000 == j)
{
j=0;
s++;
if(60 == s)
{
s=0; m++;
if(60 == m)
{
m=0; h++;
if(24 == h)
{
h=0;
}
}
}
}
}
仿真結(jié)果:
