一、外部中断
实验用开发板型号:STC15W4K56S4
1.1简介
内核与外设之间的主要交互方式有两种:轮询和中断。轮询的方式貌似公平,但实际工作效率很低,且不能及时响应紧急事件;中断系统使得内核具备了应对突发事件的能力。 在执行CPU当前程序时,由于系统中出现了某种急需处理的情况,CPU暂停正在执行的程序,转而去执行另外一段特殊程序来处理出现的紧急事务,处理结束后,CPU自动返回到原来暂停的程序中去继续执行。这种程序在执行过程中由于外界的原因而被中间打断的情况,称为中断。 中断服务函数:内核响应中断后执行的相应处理程序。 中断向量:中断服务程序的入口地址。每个中断源都对应一个固定的入口地址。当内核响应中断请求时,就会暂停当前的程序执行,然后跳转到该入口地址执行代码。 5个中断请求源: 外部中断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硬件设计流程
1.3代码设计
例如: 定义一个Working() 函数,使L1指示灯不断闪烁。将P32引脚定义成外部中断功能,按键S1按键就会产生外部中断触发信号,在中断响应函数中,LED8闪亮一下熄灭。 由原理图可知,S1按键由P40控制,使用杜邦线将P40和外部中断0也就是P32相连。 根据上图写出中断初始化函数,打开中断;
代码:
#include <stc15.h>
#include <intrins.h>
void Delay(unsigned char t)
{
while(t)
{
unsigned char i, j;
_nop_();
_nop_();
i = 22;
j = 128;
do
{
while (--j);
} while (--i);
t--;
}
}
void HC138_Y(unsigned char n)
{
switch(n)
{
case 1:
P0 = ((P0&0xF8)|0x04);
break;
case 2:
P0 = ((P0&0xF8)|0x02);
break;
case 3:
P0 = ((P0&0xF8)|0x06);
break;
case 4:
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)
{
IT0 = 1;
EX0 = 1;
EA = 1;
}
void INT0() interrupt 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秒。
#include <stc15.h>
#include <intrins.h>
int count = 0;
void Delay(unsigned char t)
{
while(t)
{
unsigned char i, j;
_nop_();
_nop_();
i = 22;
j = 128;
do
{
while (--j);
} while (--i);
t--;
}
}
void HC138_Y(unsigned char n)
{
switch(n)
{
case 1:
P0 = ((P0&0xF8)|0x04);
break;
case 2:
P0 = ((P0&0xF8)|0x02);
break;
case 3:
P0 = ((P0&0xF8)|0x06);
break;
case 4:
P0 = ((P0&0xF8)|0x01);
break;
}
}
void Init_Timer0(void)
{
TMOD = 0x01;
TH0 = (65535-50000)/256;
TL0 = (65535-50000)%256;
ET0 = 1;
EA = 1;
TR0 = 1;
}
void INT0() interrupt 1
{
TH0 = (65535-50000)/256;
TL0 = (65535-50000)%256;
count++;
if(count == 10)
{
HC138_Y(3);
P2 = 0x80;
P0 &= 0xF8;
Delay(100);
HC138_Y(3);
P2 = 0x00;
P0 &= 0xF8;
Delay(100);
count = 0;
}
}
void main()
{
P0M1=0;P0M0=0;
P1M1=0;P1M0=0;
P2M1=0;P2M0=0;
P3M1=0;P3M0=0;
Init_Timer0();
while(1)
{
}
}
|