一、外部中断
1.1简介
内核与外设之间的主要交互方式有两种:轮询和中断。轮询的方式貌似公平,但实际工作效率很低,且不能及时响应紧急事件;中断系统使得内核具备了应对突发事件的能力。 在执行CPU在当前程序中,由于系统中急需处理,CPU暂停正在执行的程序,转而执行另一个特殊程序来处理紧急情况。CPU自动返回原暂停程序继续执行。由于外部原因,该程序在执行过程中中中断,称为中断。 中断服务函数:中断内核响应后执行的相应处理程序。 中断向量:中断服务程序的入口地址。每个中断源对应一个固定的入口地址。当内核响应中断请求时,将暂停当前程序执行,然后跳转到入口地址执行代码。 五个中断请求源: 外部中断0:INT0 中断号:0 定时/计数器0:TF0 中断号:1 外部中断1: INT1 中断号:2 定时/计数器1: TF1 中断号:3 串口中断: RI/TI 中断号:4
1.2硬件设计
中断系统结构: EA :允许位整体中断;EA=1允许中断。 ES :串行中断允许位(只能用于串行口通信);ES=1允许中断。 ET1 :T1中断允许位;ET1=1允许中断。 EX1 :INT1中断允许位;EX1=1允许中断。 ET0 :T0中断允许位;ET0=1允许中断。 EX0 :INT0中断允许位;EX0=1允许中断。 一般来说,有两个中断处理函数,一个是中断初始化函数,另一个是中断服务函数。初始化函数是一种普通函数,但中断服务函数有特殊的格式要求: <1>中断函数没有回值,无参数。 <2>函数名后面有一个关键字interrupt,说明这是中断服务函数。 <3>在关键字interrupt后面跟上中断号,说明这个中断服务函数是为那个中断服务的。 中断服务函数的格式为: void 函数名() interrupt 中断号 {…… ……}
1.2.硬件设计过程
1.3代码设计
例如: 定义一个Working() 函数,使L指示灯不断闪烁。P32引脚定义为外部中断功能,按钮S在中断响应函数中,按钮会产生外部中断触发信号,LED8闪光熄灭。 从原理图可以看出,S1按键由P40控制,使用杜邦线P40和外部中断0,即P32相连。 中断初始化函数按上图写出,中断打开;
代码:
/***** STC15单片机开发系统演示程序 定义一个working() 函数,使L指示灯闪烁。将P32引脚定义为外部中断功能, 按键S在中断响应函数中,按钮会产生外部中断触发信号,LED8闪光熄灭。 硬件:按键S1对应的P4.0用线连接P3.2 MCU:STC15W4K56S4 ,
晶体频率:22.1184MHz ****/ #include <stc15.h> #include <intrins.h> void Delay(unsigned char t) //@22.1184MHz延时1ms { while(t) { unsigned char i, j; _nop_(); _nop_(); i = 22; j = 128; do { while (--j); } while (--i); t--; } } void HC138_Y(unsigned char n) ///138译码器控制端口 { switch(n) { 1: //数码管---位码--控制输出Y1 P0 = ((P0&0xF8)|0x04); break; case 2: //数码管---断码--控制输出Y2 P0 = ((P0&0xF8)|0x02); break; case 3: //LED灯--控制输出Y3--控制输出Y3 P0 = ((P0&0xF8)|0x06); break; case 4: //ULN2003--电机--继电器--控制输出Y4 P0 = ((P0&0xF8)|0x01); break; } } void working(void) { HC138_Y(3); P2 = 0x01; P0 &= 0xF8; Delay(100); HC138_Y(3); P2 = 0x00; P0 &= 0xF8; Delay(100); } void Init_INT0(void) //打开外部中断0 { IT0 = 1; //设置为电平触发 EX0 = 1; //打开中断允许控制位 EA = 1; //打开总中断 } void INT0() interrupt 0 //P3.2端口对应的是外部中断0 { HC138_Y(3); P2 = 0x80; P0 &= 0xF8; Delay(100); HC138_Y(3); P2 = 0x00; P0 &= 0xF8; Delay100(); } void main() { P0M1=0;P0M0=0; P1M1=0;P1M0=0; P2M1=0;P2M0=0; P3M1=0;P3M0=0; Init_INT0(); //中断初始化 while(1) { working(); } }
二、定时器
实验用开发板型号:STC15W4K56S4
2.1基础简介
定时器/计数器T0由特殊功能寄存器TH0,TL0构成;定时器/计数器T1由特殊功能寄存器TH1,TL1构成。
2.1.1定时器/计数器工作方式寄存器TMOD
8位分为两组,高4位控制T1,低4位控制 T0,不能位寻址。 TMOD 各位的功能如下: (1)GATE:门控位 GATE=0,定时器/计数器是否计数,仅由控制位 TRx(x=0,1)来控制。 GATE-1,定时器/计数器是否计数,要由外中断号脚(IT0 或 IT1)上的电平与运行控制 位 TRx 两个条件共同控制。 (2)M1、MO:工作方式选择位 MI、MO 的4种编码,对应于 4种工作方式的选择,如下表所示。
(3)C/T:计数器模式和定时器模式选择位 C/T = 0,为定时器工作模式,对系统时钟 12 分频后的内部脉冲进行计数。 C/T = 1,为计数器工作模式,计数器对外部输入引脚 T0(p3.4)或T1(P3.5)的外部脉冲(负跳变)计数
2.1.2定时器/计数器工作方式寄存器TCON
TCON的字节地址为88H,可以位寻址,位地址为88H-8FH TCON的低4位功能与外部中断有关,TCON 寄存器中与中断系统有关的各标志位的功能如下: (1)TF1:片内定时器/计数器 T1 的溢出中断请求标志位。 当启动 T1计数后,定时器/计数器T1 从初值开始加 1计数,当计数溢出时,由硬件自动置 TE1 为1,向CPU 申请中断。CPU 响应TF1 中断时,TF1标志由硬件自动清零,TF1 也可由软件清零。 (2)TF0:片内定时器/计数器T0 的溢出中断请求标志位,功能与TF1 相同。 (3)IE1:外部中断请求1的中断请求标志位。 (4)IE0:外部中断请求0的中断请求标志位。 (5)IT1:选择外部中断请求1为跳沿触发方式还是电平触发方式。 IT1 = 0,为电平触发方式,加到引脚 INT1上的外部中断请求输入信号为低电平有效,并把IE1置“1”。转向中断服务程序时,则由硬件自动把 IE1 清零。 IT1 = 1,为跳沿触发方式,加到 脚 INT1上的外部中断请求输入信号电平从高到低的负跳沿 有效,并把 IE1 置“1”。转向中断服务程序时,则由硬件自动把 IE1 清零。 (6)IT0:选择外部中断请求。为跳沿触发方式还是电平触发方式,与IT1类似。 (7)TR1、TR0 :计数运行控制位 TR1 位(或TR0 位)= 1,启动定时器/计数器计数的必要条件。 TR1位(或TR0 位)= 0,停止定时器/计数器计数。 该位可由软件置 1 或清零。
2.2硬件设计
时间设置: 定时时间计算: <1>定时时间t,单位us 例如定时5ms, t = 50000,计算出X,X = 19456 = 0x4c00,将初值写入TH0和TL0寄存器即可,即:TH0 = 0x4c;TL0 = 0x00; <2>定时时间t,单位us TH0 = (65535-t)/256; TL0 = (65535-t)%256; //比如当晶振频率为11.0592M的晶振。 则每秒可产生机器周期为11.0592/12=0.9216M的机器周期,也就是921600个机器周期。50ms等于0.05秒,所以需要921600*0.05=46080个机器周期;定时器在方式1工作,为16位,最大值为65536,所以需设初值为65536-46080=19456;转为16进制为(4c00),所以高位TH0=0x4c; TL0=0x00;
2.3代码设计
利用15单片机的定时/计数器T0的模式1实现间隔定时,每隔1秒L8指示灯闪烁一下, 也就是点亮0.5秒,熄灭0.5秒。
/***** STC15单片机开发系统演示程序 利用15单片机的定时/计数器T0的模式1实现间隔定时, 每隔1秒L8指示灯闪烁一下, 也就是点亮0.5秒,熄灭0.5秒。 MCU:STC15W4K56S4 ,晶体频率:22.1184MHz ****/
#include <stc15.h>
#include <intrins.h>
int count = 0;
void Delay(unsigned char t) //@22.1184MHz延时1ms
{
while(t)
{
unsigned char i, j;
_nop_();
_nop_();
i = 22;
j = 128;
do
{
while (--j);
} while (--i);
t--;
}
}
void HC138_Y(unsigned char n) //138译码器控制使能端口
{
switch(n)
{
case 1: //数码管---位码--控制输出Y1
P0 = ((P0&0xF8)|0x04);
break;
case 2: //数码管---断码--控制输出Y2
P0 = ((P0&0xF8)|0x02);
break;
case 3: //LED灯--控制输出Y3--控制输出Y3
P0 = ((P0&0xF8)|0x06);
break;
case 4: //ULN2003--电机--继电器--控制输出Y4
P0 = ((P0&0xF8)|0x01);
break;
}
}
void Init_Timer0(void) //打开外部中断0
{
TMOD = 0x01;//TMOD寄存器,选择工作模式
TH0 = (65535-50000)/256;//时间计算50ms
TL0 = (65535-50000)%256;
ET0 = 1;//打开定时器中断
EA = 1;//因为是选用定时器是T0,所以源允许处ET0要允许,才能往后执行
TR0 = 1;//启动定时器T0,此时开始定时计数
}
void INT0() interrupt 1 //打开定时器T0,中断号为1
{
TH0 = (65535-50000)/256;//时间计算
TL0 = (65535-50000)%256;
count++;
if(count == 10) //每次计数50ms,经过10次计数,500ms
{
HC138_Y(3);
P2 = 0x80;
P0 &= 0xF8;
Delay(100);
HC138_Y(3);
P2 = 0x00;
P0 &= 0xF8;
Delay(100);
count = 0; //标志位清0
}
}
void main()
{
P0M1=0;P0M0=0;
P1M1=0;P1M0=0;
P2M1=0;P2M0=0;
P3M1=0;P3M0=0;
Init_Timer0(); //打开中断
while(1)
{
}
}