位 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|
名称 | TF1 | TR1 | TF0 | TR0 | IE1 | IT1 | IE0 | IT0 |
位 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|
名称 | EA | – | – | ES | ET1 | EX1 | ET0 | EX0 |
EA:总允许
ES:串行口
ET:定时器
EX:外部中断
写1,表示允许
位 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|
名称 | – | – | – | PS | PT1 | PX1 | PT0 | PX0 |
写1,表示高优先级中断
高优先级中断可打断低优先级中断,同级不可打断
出现多个同级中断的查询次序:INT0>>T0>>INT1>>T1>>Serial
一个中断源的中断请求被响应,必须满足以下必要条件:
a. 中断请求标志=1
b. 中断允许位=1
c. EA=1
d. 无同级或更高级的中断正在被执行
当遇到下列三种情况之一时,中断响应被封锁:
a. CPU正在处理同级或更高优先级的中断
b. 所查询的机器周期不是当前正在执行指令的最后一个机器周期
c. 正在执行的指令是RETI或是访问IE或IP的指令
大于3个机器周期,小于8个机器周期
中断服务函数的一般形式
void 函数名(void) interrupt n using m
n:中断号
m:工作寄存器区选择(如果不选using项,中断函数中的所有工作寄存器的内容将被保存到堆栈中)
无返回值,无参数传递,不可直接调用
void main()
{
EX0=1; // 允许外部中断0中断
EX1=1; // 允许外部中断1中断
IT0=1; // 选择外部中断0为跳沿触发方式
IT1=1; // 选择外部中断1为跳沿触发方式
PX0=0; // 外部中断0为低优先级
PX1=1; // 外部中断1为高优先级
EA=1; // 总中断允许
while( 1 )
{
;
}
}
void int0_isr(void) interrupt 0 // 外中断0的中断服务函数
{
;
}
void int1_isr(void) interrupt 2 // 外中断1的中断服务函数
{
;
}
定时器:对系统时钟信号12分频后的内部脉冲信号计数。(内部脉冲信号周期=机器周期)
计数器:对加在T0(P3.4)和T1(P3.5)两个引脚上的外部脉冲进行计数
位 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|
名称 | GATE | C/~T | M1 | M0 | GATE | C/~T | M1 | M0 |
定时器 | T1 | T1 | T1 | T1 | T0 | T0 | T0 | T0 |
GATE:门控位,控制启动方式
0,只受TR控制(TR=1,启动)
1,外部中断引脚 (INT0或INT1) 上的高电平 + TRx(TR=1,并且INT0或INT1引脚为高电平,启动)
C/~T:模式选择位(1计数器;0,定时器)
M1,M0:工作方式选择位
方式1,进入中断服务程序后,先要写初值
方式2,TH、TL写入初值,TL计数溢出后,将TH中第一次写入的初值自动打入TL,实现自动重载
方式3,T0分为两个独立的8位计数器TL0和TH0
TL0,使用T0的状态控制位C/T、GATE、TR0、TF0
TH0,固定为8位定时器,不能作为外部计数模式, 使用T1的状态控制位TR1,同时占用定时器T1的中断请求源TF1。
① 一般情况下,当T1用作串行口的波特率发生器时,T0才工作在方式3。
② T0处于工作方式3时,T1可设定为方式0、方式1和方式2,用来作为串行口的波特率发生器,或不需要中断的场合。
位 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|
名称 | TF1 | TR1 | TF0 | TR0 | IE1 | IT1 | IE0 | IT0 |
以方式1,16位定时/计数器为例
1个机器周期 = 12个时钟周期 = 12 / 晶振频率(如12MHz的晶振,机器周期为1us)
定时时间 = (65536 - X)* 12 / 晶振频率
X = 65536 − 定时时间 * 晶振频率 / 12
TH = X / 256;
TL = x % 256;
由于确认一次负跳变要花2个机器周期,因此外部输入的计数脉冲的最高频率为系统振荡器频率的1/24
输入信号至少要保持一个机器周期
定时器0,工作于方式1,定时时间设为50ms,实现LED每1s亮灭一次(12MHz晶振)
void main(void)
{
TMOD = 0x01; //设置定时器T0为方式1定时,0000 0001
TH0 = (65536-50000) / 256; //定时器T0赋初值
TL0 = (65536-50000) % 256;
ET0 = 1; //T1中断允许
EA = 1; //总允许
TR0 = 1; //T0启动
while(1)
{
;
}
}
void T0_interserve(void) interrupt 1 //定时器T0中断服务子程序,50ms
{
static unsigned char T0_counter = 0;
TH0 = (65536-50000) / 256; //定时器T0赋初值
TL0 = (65536-50000) % 256;
T0_counter++;
if(T0_counter >= 20) //1s=50ms*20
{
LED = ~LED;
T0_counter = 0;
}
}
位 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|
名称 | SM0 | SM1 | SM2 | REN | TB8 | RB8 | TI | RI |
多机通信只有在方式2和方式3时才能实现
写1,允许串行口接收数据
由软件置“1”或清“0”
① 在双机串行通信时,TB8一般用作奇偶校验位。
② 在多机通信时,用来表示主机发送的是地址帧还是数据帧,TB8=1为地址帧,TB8=0为
数据帧。
由硬件置“1”,必须由软件清“0”
由硬件置“1”,必须由软件清“0”
位 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|
名称 | SMOD | – | – | – | – | – | – | – |
SMOD:波特率选择
定时器T1的溢出率 = 1 / 定时器T1的溢出时间 = 1 / (256 - X)* 12 / 晶振频率
甲机发送
#include
#define UCHAR unsigned char
UCHAR Temp=0;
void main()
{
TMOD=0x20; // 设置定时器T1为方式2
TH1=0xfd; // 波特率9600
TL1=0xfd;
SCON=0x40; // 串口设置为方式1,只发送
PCON=0x00; // SMOD=0
ES = 1;
EA = 1;
TR1 = 1; // 启动T1
P1=0xff; // P1口为输入
Temp=P1; // 读入P1口开关的状态数据
SBUF=Temp; // 数据送串行口发送
while(1)
; // 循环等待
}
void sci_int(void) interrupt 4
{
if(TI)
{
TI=0; // 清TI
Temp=P1; // 读入P1口开关的状态数据
SBUF=Temp; // 数据送串行口发送
}
if(RI)
RI = 0;
}
乙机接受
#include
#define UCHAR unsigned char
UCHAR Temp;
void main( )
{
TMOD=0x20; // 设置定时器T1为方式2
TH1=0xfd; // 波特率9600
TL1=0xfd;
SCON = 0x50; // 方式1接收,REN=1
PCON = 0x00; // SMOD=0
ES = 1;
EA = 1;
TR1 = 1; // 启动T1
while(1)
;
}
void sci_int(void) interrupt 4
{
if(RI)
{
RI=0; // 接收到数据,清RI
Temp = SBUF;
P1=Temp;
}
if (TI)
TI = 0;
}
常用I/O端口编址有两种方式,一种是独立编址方式,另一种是统一编址方式。AT89S51单片机使用的是统一编址方式。
位 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|
名称 | 1 | A方式 | A方式 | A输入/输出 | C高4输入/输出 | B方式 | B输入/输出 | C低4输入/输出 |
PA口可工作于方式0、1和2
PB口只能工作在方式0和1
PC口分两部分,随PA口称为A组,随PB口称为B组
示例:AT89S51单片机向82C55的控制字寄存器(假设端口地址为FF7FH)写入工作方式控制字95H
#include
#define COM8255 XBYTE[0xff7f] // 0xff7f为82C55的控制寄存器地址
#define UCHAR unsigned char
……
void init8255( void )
{
COM8255 = 0x95; // 工作方式选择控制字写入82C55的控制寄存器
……
}
位 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|
名称 | 0 | – | – | – | PC口选择 | PC口选择 | PC口选择 | 1置位/0复位 |