单片机原理(3):中断、定时/计数、串行通信

中断(Interrupt)是指在计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行。

定时器/计数器(Timer/Counter)在实时控制系统中,实现对于外界事件的定时延时及计数功能。

串行通信(Serial Communicate)是计算机与外界交换信息的一种基本通信方式。

中断系统

中断过程中,请求产生中断的事件称为中断源,中断源向CPU提出的请求为中断请求(Interrupt Requst,IRQ),CPU通过上下文切换保存好当前的工作状态后,转而去处理中断请求,也就是产生中断响应。直到处理完中断请求事件,才返回原来的工作状态,继续工作。整个过程如下图所示:

中断过程

51单片机中断系统的结构图如下:

中断系统结构

中断源

51单片机中有5个中断源,如下表所示:

中断号 优先级 中断源 中断入口地址
0 1(最高级) 外部中断0 0003H
1 2 定时器0 000BH
2 3 外部中断1 0013H
3 4 定时器1 001BH
4 5(最低级) 串口中断 0023H

每个中断源都分配了对应的中断号及中断服务入口地址,在这个中断入口地址里,存放着跳转到相应中断服务程序的跳转指令。当多个中断源同时向CPU提出中断请求时,CPU将根据中断源的优先级来依次响应中断。

相关寄存器

SFR中与中断有关的寄存器有:

IE

IE(Interrupt Enable),中断允许寄存器,可位寻址,其各位定义如下:

位地址 AFH AEH ADH ACH ABH AAH A9H A8H
定义 EA - (ET2) ES ET1 EX1 ET0 EX0
  • EA(Enable All):CPU中断总控制位,EA=1,CPU对所有中断开放,EA=0,CPU禁止一切中断响应。
  • ES(Enable Serial):串口中断允许控制位,ES=1,允许串行口接受、发送中断。
  • ET0/ET1(Enable Timer):定时/计数器0/1中断允许控制位,ET0/ET1=1,允许T0/T1中断。52系列单片机里还有ET2。
  • EX0/EX1(Enable Exterior):外部中断INT0/INT1中断允许控制位,EX0/EX1=1,允许外部中断INT0/INT1中断。
IP

IP(Interrupt Priority),中断优先级寄存器,可位寻址,其各位定义如下。未设置时或复位后,IP各位均为””则按照系统默认的优先级

位地址 BFH BEH BDH BCH BBH BAH B9H B8H
定义 - - (PT2) PS PT1 PX1 PT0 PX0
  • PS(Priority Serial):串行口优先级设定位,PS=1,串行口为高优先级。
  • PT0/PT1(Priority Timer):定时/计数器0/1优先级设定位,PT0/PT1=1,定时/计数器0/1为高优先级。
  • PX0/PX1(Priority Exterior):外部中断INT0/INT1优先级设定位,PX0/PX1=1,外部中断INT0/INT1为高优先级。
TCON

TCON(Timer Control),定时/计数器控制寄存器,可位寻址,其各位定义如下:

位地址 8FH 8EH 8DH 8CH 8BH 8AH 89H 88H
定义 TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0
  • TF0/TF1(Timer Flag):定时/计数器0/1溢出标志位,当定时/计数器计满溢出时,由硬件自动置“1”,并申请中断;在进入中断服务程序后,又由硬件自动置“0”。
  • TR0/TR1(Timer Run):定时/计数器0/1启停控制位,TR0/TR1=1,启动定时/计数器。
  • IE0/IE1(Interrupt Exterior):外部中断INT0/INT1中断请求标志位,外部中断源有请求时,对应的标志位IE0/IE1由硬件置“1”,当CPU响应该中断后,又由硬件自动置“0”。
  • IT0/IT1(Interrupt Touch):外部中断INT0/INT1的触发方式选择位,IT0/IT1=0,对应外部中断设置为低电平触发方式,IT0/IT1=1,对应外部中断设置为边沿触发方式。

中断处理过程

51单片机在CPU的每个机器周期的S5 P2期间,将自动查询TCON中各个中断申请标志,若查询到某个中断标志位被置位,将启动中断机制。

中断源发出中断请求后。要使CPU能够响应中断,IE中的中断总允许位EA及对应的中断允许位(ES/ET/EX)都需要置为“1”。

处理外部中断时,若外部中断设为低电平触发方式,则CPU在每个查询中断申请标志时也将对INTi引脚进行采样,测得INTi=0,则认为有中断申请,随即将IEi标志位置位,否则测得INTi=1,则认为无中断请求,而清除IEi标志位。所以施加在INTi引脚上的低电平持续时间应该大于一个机器周期,且小于中断服务程序得执行时间。

若外部中断设为边沿触发方式,则CPU在每个查询中断申请标志时将对INTi引脚进行采样,若在连续两个机器周期采样到先高后低的电平变化,则认为有中断申请,随即将IEi标志位置位,否则测得INTi=1,则认为无中断请求,而清除IEi标志位。所以,为了保证CPU在两个机器周期内能够检测到由高到低跳变得电平,输入的高低电平持续时间至少要保持12个振荡周期(即一个机器周期)时间。

在中断处理过程中,如果正在执行同级或高优先级的中断服务程序,或是正在执行的指令还没完成,则中断响应会受到阻断。51单片机的中断响应时间最短为3个机器周期,其他情况的中断响应时间一般是3~8个周期。

在CPU响应中断后,应该撤除该中断请求,否则会再次产生中断,进入死循环。

中断程序的编写

由中断的处理过程可知,在编写中断管理与控制程序时应该考虑一下几个方面:

  • CPU开中断和关中断
  • 某个中断源中断请求的允许或屏蔽
  • 各中断源优先级别的设定
  • 外部中断请求的触发方式

中断程序基本编写格式如下:

汇编:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
      ;中断入口设置
ORG 0000H ;起始地址
LJMP MAIN ;跳转到主程序
ORG 0003H ;中断入口地址1
LJMP INT1 ;跳转到外部中断INT0服务程序
ORG 000BH ;中断入口地址2
LJMP INT2 ;跳转到定时器0中断服务程序,没有则不写或写成“RETI”,下同
ORG 0013H ;中断入口地址3
LJMP INT3 ;跳转到外部中断INT1服务程序
ORG 001BH ;中断入口地址4
LJMP INT4 ;跳转到定时器1中断服务程序
ORG 0023H ;中断入口地址5
LJMP INT5 ;跳转到串口中断服务程序

;主程序
ORG 0030H ;起始地址
MAIN: SETB IT0 ;IT0=1,边沿触发
SETB EA ;EA=1,开启总中断
SETB EX0 ;EX0=1,允许外部中断INT0
……
LOOP: NOP
LJMP LOOP ;死循环

;中断服务程序
ORG 0100H ;起始地址
INT1: PUSH ACC ;保存原来状态,下同
PUSH PSW ;
……
INT2: ……
……
POP PSW ;恢复原始状态,下同
POP ACC ;
RETI ;中断返回

END ;结束

C语言:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "reg51.h"

// 主程序
void main() {
IT0 = 1//注释同汇编
EX0 = 1
EA = 1
while (1) {
……
}
}

// 中断处理程序
void int0() interrupt 0 { // 外部中断INT0服务程序
……
}

定时/计数器

51单片机内部有两个16位可编程的定时/计数器0和1,分别用T0及T1表示。它们的工作方式、定时时间、量程、启动方式、等均可通过程序来设置和改变。

计数功能用于统计从T0(P3.4)、T1(P3.5)引脚输入的脉冲负跳变数量,每输入一个脉冲负跳变,计数器就加1。负跳变指的是一个机器周期采样为高电平,后一个机器周期采样为低电平。

定时功能是单片机通过对内部机器脉冲信号计数实现的,计数值乘以机器周期即是相应的时间。如单片机采用12MHz晶振,机器内部脉冲频率为1MHz,机器周期为1us,计数1000次,即1ms时间。

当计数值溢出后,定时计数器给出中断请求,进而使CPU去处理中断事件。

51单片机定时/计数器结构如下:

定时/计数器结构

相关寄存器

除前面介绍过的中断相关寄存器外,SFR中与定时/计数器有关的寄存器有:

TMOD

TMOD(Timer Mode),定时/计数器模式控制寄存器,不可位寻址,其各位定义如下。其中TMOD的高半字节D4~D7用来控制定时/计数器1,低半字节D0~D3用来控制定时/计数器0。

位号 D7H D6H D5H D4H D3H D2H D1H D0H
定义 GATE C\T M1 M0 GATE C\T M1 M0
  • GATE:门控制位,用来控制定时/计数器的启动方式。GATE=1,由外部中断引脚INT0/INT1来启动定时器T0/T1, 当INT0/INT1引脚为高电平且TR0/TR1置位,启动定时器T0/T1;GATE=0,仅由TR0/TR1置位而启动定时器T0/T1。
  • C\T:功能选择位,C\T=0,为定时模式,计数脉冲由内部提供,计数周期等于机器周期;C\T=1,为计数模式,计数脉冲由外部引脚T0或T1引入。
  • M0/M1:工作方式控制位,用于设置定时/计数器的工作方式,如下表:
M0 M1 工作方式 功能
0 0 方式0 13位计数器
1 0 方式1 16位计数器
0 1 方式2 8位重装计数器
1 1 方式3 定时器0分为两个独立8位计数器
T0、T1

T0、T1(Timer),两个定时/计时器的初始赋值寄存器,不可位寻址,用于存放定时/计数的初始值。它们是两个16位寄存器,均可分为两个独立的8位寄存器,高8位记为TH,即TH0、TH1,低8位记为TL,即TL0、TL1。使用定时/计数器时,当外部或系统时钟振荡器输入一个脉冲时,对应寄存器的值便自动加1。

编程时需要注意,16位计数初始值要分两次写入对应初始值寄存器。

定时/计数过程

51单片机定时/计数器的工作模式、工作方式、计数初始值及启停操作均需要在使用前进行初始化。

首先是通过TMOD中的GATE位来设置定时/计数器T0/T1的启动操作方式,工作在定时还是计数模式则是通过C/T位来设置。其次就是选择它们的工作方式。

工作方式0、1、3为非自动重装方式,在初始化程序和对应中断服务程序中均需要对初始数据寄存器THi、TLi装载。方式0是一个13位定时/计数器,只用了16位寄存器的高8位THi和TLi的低5位0~4位,TLi高3位未用,装入数据时需要注意。方式1为16位寄存器。

方式3只适用于定时/计数器T0,一般在定时/计时器T1作串行口波特率发生器时,才会选择这个工作模式。此时T0拆分为两个独立8位计数寄存器TH0和TL0,其中TL0下为8位定时/计数器,操作方式同方式0、1;TH0只做简单的内部定时功能,它借用定时/计时器1的控制位TR1和溢出标志位TF1,占用T1的中断资源,启动和停止也仅受TR1控制,此时T1仅可用在不需要中断的场合。

方式2为8位重装寄方式,仅由TLi作为工作寄存器,THi的值一直保持不变。TLi溢出时,THi的值作为装载值由CPU自动装入TLi,自动完成计数值初始化。所以此种方式下需要初始化时在THi和TLi中放入相同的计数值。

T0/T1寄存器中的初值X与定时/计数器的工作方式、工作模式有关。

在工作方式0下,为13位寄存器,也就是说最大的计数值M=$2^{13}$=8192,超过这个数字就会溢出,触发中断。工作方式为1下,为16位寄存器,M=$2^{16}$=65536。工作方式为2下,为8位寄存器,M=$2^{8}$=256。工作方式为3下,定时/计数器0分为高8位和低8位两个独立8位计数器,THi、TLi的M均为$2^{8}$=256。

不管是进行定时还是计数模式,其具体实现都是归结于计数。

计数模式下,是对外部脉冲数计数,初值X = M - 计数值。定时模式下,是对机器周期进行计数,初值X = M - 计数值 = M - $\frac{定时时间T_c}{机器周期T_p}$ = M - $\frac{定时时间T_c × 晶振频率}{12}$

最后,中断中的相关寄存器也需要进行设置,设置TRi=1,来启动定时/计数器。

定时/计数程序编写

通过上面对定时/计数过程的分析,可知编写想关功能程序时,要先进行初始化,再根据公式计算出定时初值并装载。

定时/计数程序基本编写格式如下:

汇编:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
      ;中断入口设置
ORG 0000H ;起始地址
LJMP MAIN ;跳转到主程序
ORG 000BH ;中断入口地址2
LJMP INT2 ;跳转到定时器0中断服务程序
ORG 001BH ;中断入口地址4
LJMP INT4 ;跳转到定时器1中断服务程序

;主程序
ORG 0030H ;起始地址
MAIN: MOV TMOD, #xxH ;设置工作模式,方式
MOV TH0, #xxH ;计数初值,高八位
MOV TL0, #xxH ;低八位
SETB EA ;EA=1 ,开启总中断
SETB ET0 ;ET0=1,允许定时/计数器中断
SETB TR0 ;TR0=1,启动定时/计数器
……
LOOP: NOP
LJMP LOOP ;死循环

;中断服务程序
ORG 0100H ;起始地址
INT2: PUSH ACC ;保存原来状态,下同
PUSH PSW ;
MOV TH0, #xxH ;重新赋计数初值(非重装方式下)
MOV TL0, #xxH
……
INT4: ……
……
POP PSW ;恢复原始状态,下同
POP ACC ;
RETI ;中断返回

END ;结束

C语言:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "reg51.h"

// 主程序
void main() {
TMOD = 0xxx; //注释同汇编
TH0 = 0xxx;
TL0 = 0xxx;
EA = 1;
ET0 = 1;
TR0 = 1;
while (1) {
……
}
}

// 中断处理程序
void int2() interrupt 1{ // 定时器0中断服务程序
TH0 = 0xxx;
TL0 = 0xxx;
……
}

串口通信

通信相关概念

计算机通信方式可以分为并行(Parallel)串行(Serial)通信两大类,它将计算机技术和通信技术的相结合,完成计算机与外部设备或计算机与计算机之间的信息交换:

  • 并行通信:数据的各个二进制位在不同的数据线上同时传输。这样传输速度快,效率高,但所需的数据线多,成本高,抗干扰能力较差,适用于近距离传输。

  • 串行通信:将数据拆分成多个二进制位,逐一的在同一条数据线上输出。虽然这样传输速度较慢,效率较低,但所需的数据线少、硬件电路简单、抗干扰能力强,且适用于远距离数据传输。

串行通信又分为同步(Synchronous)通信和异步(Asynchronous)通信两种方式:

  • 同步通信:串行连续地传输数据,待发送的若干个字符数据构成一个数据块,在该数据块前部添加1~2个同步字符,在数据块的末尾添加校验信息,以此种方式构成数据帧,以数据帧为单位进行串行通信。

  • 异步通信:每个字符数据被封装成帧,之后以帧的形式发送。每一帧由四部分构成,分别是起始位、数据位、校验位和停止位。起始位是数据开始传送的标志,用逻辑0表示;数据位紧跟起始位,通常是5~8位二进制位;校验位用于校验数据位是否发送正确,可以选择奇校验、偶校验或者不使用校验位。帧和帧之间可以连续,或者加入任意的空闲位,空闲位用逻辑1表示。

串行数据的传输制式可分为单工(Simplex)半双工(Half Duplex)全双工(Full Duplex)

  • 单工:数据传输仅能沿一个方向,不能实现反向传输。
  • 半双工:数据传输可以沿两个方向,但需要分时进行。
  • 全双工:数据可以同时进行双向传输。

串行通信的错误校验方式有奇偶校验(Parity Check)代码和校验循环冗余校验(Cyclical Redundancy Check,CRC)三种:

  • 奇偶校验:在发送数据时,数据位尾随的1位为奇偶校验位(1或0)。奇校验时,数据中“1”的个数与校验位“1”的个数之和应为奇数;偶校验时,数据中“1”的个数与校验位“1”的个数之和应为偶数。接收字符时,对“1”的个数进行校验,若发现不一致,则说明传输数据过程中出现了差错。
  • 代码和校验:发送方将所发数据块求和(或各字节异或),产生一个字节的校验字符(校验和)附加到数据块末尾。接收方接收数据同时对数据块(除校验字节外)求和(或各字节异或),将所得的结果与发送方的“校验和”进行比较,相符则无差错,否则即认为传送过程中出现了差错。
  • 循环冗余校验:通过某种数学运算实现有效信息与校验位之间的循环校验,常用于对磁盘信息的传输、存储区的完整性校验等。这种校验方法纠错能力强,广泛应用于同步通信中。

波特率(Baud Rate)是串口通信时每秒钟传输二进制代码的位数,单位是位/秒(bps)。

51单片机的串行接口是一个全双工通信接口,即能够同时进行数据发送和接收。它可作通用异步收发传输器(Universal Asynchronous Receiver/Transmitter,UART)用,也可以作同步移位寄存器。其结构如下:

串行口结构

相关寄存器

除前面介绍过的中断及定时/计数器相关寄存器外,SFR中与串口通信相关的寄存器有:

SCON

SCON(Serial Control),串行口控制寄存器,可位寻址,其各位定义如下:

位地址 9FH 9EH 9DH 9CH 9BH 9AH 99H 98H
定义 SM0 SM1 SM2 REN TB8 RB8 TI RI
  • SM0和SM1(Serial Mode):串行口工作方式控制位,用于设置串行口工作方式,如下表:
SM0 SM1 工作方式 功能 波特率
0 0 方式0 8位同步移位寄存器 晶振频率/12
0 1 方式1 10位UART 可变
1 0 方式2 11位UART 晶振频率/64 或 /32
1 1 方式3 11位UART 可变
  • SM2:多机通讯控制位,主要在以上工作方式为2或3下使用,工作方式0或1下都应该设为“0”状态。
  • REN(Receive Enable):串行允许接收位,REN=1,允许接受数据。
  • TB8(Transfer Bit 8):工作方式为2或3下存放发送数据的第9位,由软件置”0”或”1”。
  • RB8(Receive Bit 8):工作方式为2或3下存放接受数据的第9位。方式0下不使用;方式1下,当SM2=0时,用于存放接收到的停止位。
  • TI(Transfer Interrupt):发送中断标志位,用于指示一帧数据是否发送完成。使用前必须软件复位为“0”,发送完一帧数据后硬件将自动置”1”。
  • RI(Receive Interrupt):接受中断标志位,用于指示一帧数据是否接受完成。接受完一帧数据后硬件将自动置”1”,之后必须软件复位为“0”
SBUF

SBUF(Serial Data Buffer),串行数据缓冲器,不可位寻址。串行口两个SBUF,分别为发送寄存器和接收寄存器,它们在物理结构上是完全独立的,在SFR中的字节地址都是99H。这个重叠的地址靠读/写指令区分:串行发送时,CPU向SBUF写入数据,此时99H表示发送SBUF;串行接收时,CPU从SBUF读出数据,此时99H表示接收SBUF。

PCON

PCON(Power Control),电源控制寄存器,不可位寻址,其中只有一位与串口设置有关,其余都用于电源控制。其各位定义如下:

位号 D7H D6H D5H D4H D3H D2H D1H D0H
定义 SMOD - - - GF1 GF0 PD IDL
  • SMOD(Serial Mode):波特率选择位。工作方式1、2、3下串行通信波特率与$2^{SMOD}$成正比。也就是SMOD=1,通信波特率可提高一倍。
  • GF0/GF1(General Flag):通用标志位,用户可自由使用
  • PD(Power Down):掉电控制位。PD=0,单片机正常工作;PD=1,进入掉电模式,外部晶振停振,CPU、定时器、串行口全部停止工作,只有外部中断工作。在该模式下,只有硬件复位和上电能够唤醒单片机。
  • IDL(Idle):空闲控制位。IDL=0,单片机正常工作;IDL=1,单片机进入空闲模式,除CPU不工作外,其余仍继续工作,在空闲模式下可由任一个中断或硬件复位唤醒。

串行通信过程

一般情况下,当CPU允许接收(REN=1)且接收中断标志RI复位时,就启动一次接收过程。外界数据通过引脚RXD(P3.0)串行输入,数据最低位首先输入一个大小为9位移位寄存器,当一帧数据接收完毕后再并行送入接收SBUF中,同时RI也置“1”。当用软件读取完数据并复位RI后,才进行下一次操作。

当发送中断标志TI复位后,CPU便开始执行一条写SBUF指令,启动一次发送过程,发送控制器同时启动,并开始发送数据。发送的数据通过引脚TXD(P3.1)输出,首先输出最低位。当一帧数据发送完毕即发送SBUF为空时,CPU自动将TI值“1”。使用软件将TI复位,才执行下一个发送过程。

51单片机串行口有4种工作方式,通过SCON寄存器中的SM0、SM1口选择。

方式0下,串行口为同步移位寄存器的输入输出方式,主要用于和外部同步移位寄存器外接,以达到扩展一个并行输入或输出口的目的。这种方式下,数据从RXD端串行输入或输出,同步移位信号从TXD输出,波特率固定为晶振频率的1/12。TXD引脚每输出一位同步移位脉冲,数据就由RXD引脚输入或输出一个二进制位,发送和接收均为8位数据,低位在先,高位在后,没有起始位和停止位。此时,SM2、RB8、TB8均设为“0”,不起作用。方式0工作时序图如下:

方式0工作时序

方式1下,串行口为10位异步通信方式,即1个起始位、8个有效数据位和1个停止位,波特率由定时/计数器T1溢出率及PCON中的SMOD位共同决定。进行发送操作时,发送电路会自动在8位发送数据前后分别加上一位起始位和一位停止位。接收操作时,接收器以所选择波特率的16倍速率采样RXD引脚电平,检测负跳变时,则说明起始位有效,将其移入输入移位寄存器,并开始接收这一帧信息的其余位。接收过程中,数据从输入移位寄存器右边移入,起始位移至输入移位寄存器最左边时,控制电路进行最后一次移位,随后将接收到的9位数据的前8位数据装入接收SBUF,第9位(停止位)进入RB8,并置RI=1,向CPU申请中断。如果上述条件不满足,数据则会被舍弃。此时,SM2也要设为“0”。方式1工作时序图如下:

方式1工作时序

方式2及方式3下,串行口都为11为异步收发方式,即1个起始位、8个有效数据位、1个附加数据位和1个停止位,其两者的差异在于通信波特率的不同:方式2的波特率取决于晶振频率和PCON中的SMOD位,固定为晶振频率的1/64或1/32;方式3的波特率由定时器T1的溢出率和SMOD位共同决定,故其波特率是可调的。比方式1多出来的一个附加位发送时为SCON中的TB8,接收时为RB8,由用户安排,可作奇偶校验位,也可作其他控制位。这两种方式很适合主从式的通信结构,在多机通讯时,主机的SM2位设为“0”,而从机的SM2位设为“1”,以便之间相互识别。

方式0下:$$波特率 = \frac{晶振频率 f_{osc}}{12}$$

方式2下:$$波特率 = \frac{2^{SMOD}}{64} * f_{osc}$$

方式1下及方式3下,波特率都由定时/计数器T1溢出率及PCON中的SMOD位共同决定。T1的溢出率又取决于计数速率和计数值。定时模式下,计数速率为晶振频率的1/12;计数模式下,计数速率取决于外部输入时钟频率,但不可超过晶振频率的1/24。作波特率发生器时,T1通常设置为定时模式,工作在工作方式2下,作8位重装寄存器,此时波特率计算公式为:$$ {T1溢出周期 = 定时时间 = \frac{12}{f_{osc}} * (256 - 计数初值X) }$$
$$ T1溢出率 = \frac{1}{T1溢出周期} $$
$$ {波特率 = \frac{2^{SMOD}}{32} * T1溢出率 } = \frac{2^{SMOD} * f_{osc}}{384 * (256 - X)}$$

则T1的计数初值,也就是装载值为:
$$ {计数初值X = 256 - \frac{2^{SMOD} * f_{osc}}{384 * 波特率}}$$

串行通信程序编写

由串行通信的基本过程可知,在使用串行口之前需要对串行口进行初始化,确定使用的工作方式并进行相关配置。

串行通信程序基本编写格式如下:

汇编:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
      ;中断入口设置
ORG 0000H ;起始地址
LJMP MAIN ;跳转到主程序
ORG 0023H ;中断入口地址5
LJMP INT5 ;跳转到串口中断服务程序

;主程序
ORG 0030H ;起始地址
MAIN: MOV TMOD, #20H ;设置定时/计数器T1工作模式为定时,工作方式2
MOV TH1, #F4H ;计数初值,高八位,波特率2400
MOV TL1, #F4H ;低八位
MOV SCON, #90H ;设置串行口工作方式2,单机,允许接收
MOV PCON, #00H ;波特率不加倍
SETB EA ;EA=1 ,开启总中断
SETB ES ;ES=1,开启串口中断
SETB TR1 ;TR1=1,启动定时/计数器
……
SEND: MOV A, #xxH ;待发送数据放入A,即刻生成了偶校验位放在P中
MOV C, P ;将偶校验位放入位寄存器C
CPL C ;奇校验则把P取反
MOV TB8, C ;将校验位放入TB8中
MOV SUBF, A ;发送数据
JBC TI, xxx ;发送完一帧数据后清除TI并进行下一步
LOOP: NOP
LJMP LOOP ;死循环

;中断服务程序
ORG 0100H ;起始地址
INT5: MOV A, SBUF ;取出接收到的数据
JB RB8, ERR ;进行校验,不同则跳转到错误处理
CLR RI ;复位,准备下次接收
……
RETI ;中断返回
ERR: ……
……
END ;结束

C语言:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include "reg51.h"

// 主程序
void main() {
TMOD = 0x20H; //注释同汇编
TH0 = 0xF4;
TL0 = 0xF4;
SCON = 0x90;
PCON = 0x00;
EA = 1;
ES = 1;
TR1 = 1;
while (1) {
send(data);
}
}

//发送数据
void send(unsigned char data) {
ACC = data;
TB8 = P;
SBUF = data;
while(!TI == 0){
……
TI = 0
}

}

// 中断处理程序,接收数据
void int5() interrupt 5{ // 定时器0中断服务程序
ACC = SBUF;
RI = 0;
if (RB8 == p){
……
}else{
……
}
}


更新历史:

  • 2017.11.27 完成初稿
文章作者: Hugsy
文章链接: http://binweber.top/2017/11/24/msc51_3/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Weber
支付宝打赏~
微信打赏~