单片机结构原理

详解

指令系统

详解
  • 思维导图

    单片机原理及应用2.png

  • 小结

    屏幕截图 2023-10-23 092916.jpg

51系列单片机的中断系统

详解
  1. 由于各中断入口间只有8个字节,一般情况下不够安排一个完整的中断服务程序。因此,通常总是在中断入口地址处放置一条无条件转移指令,使程序转向真正存放中断服务程序的地址
  2. 中断服务程序编程注意点:
    • 根据需要保护现场
    • 及时清除不能被硬件自动清除的中断请求标志
    • 中断服务程序中的压栈和出栈指令必须成对使用,以避免堆栈数据出错
  3. 串口中断提出申请, 且主程序累加器A需保护,编程注意:
    • 在 0000H放一条跳转到主程序的跳转指令, 这是因为 MCS-51单片机复位后, PC的内容变为 0000H, 程序从 0000H 开始执行, 紧接着 0023H是中断程序入口地址, 故在此中间只能插入一条转移指令
    • 响应中断时, 先自动执行一条隐指令“LCALL 0023H”, 而 0023H至 002BH(串行口中断入口地址)之间可利用的存储单元不够, 故放一条无条件转移指令
    • 对串行口中断标志位硬件不能自动清除,所以一定要在中断服务程序中要有清标志位RI和TI的指令CLR RI和CLR TI
    • 在中断服务程序的末尾, 必须安排一条中断返回指令RETI, 使程序自动返回主程序

应用

题目一

  • P1.4~P1.7接有四个发光二极管,P1.0~P1.3接四个开关,消抖电路产生中断请求信号,当消抖电路的开关来回拔动一次产生一个下降沿信号,通过INT0 向CPU申请中断,初时发光二极管全灭,每中断一次,P1.0~P1.3所接的开关状态反映到发光二极管上,且要求开关断开的对应发光二极管亮

  • SJMP $:

    跳转到本指令的起始位置开始执行,如果系统的中断是开放的,那么SJMP $指令实际上是在等待中断,当有中断申请后,CPU 转至执行中断服务程序
    中断返回时,仍然返回到这条死循环指令,继续等待中断,而不是返回到该指令的下一条指令。这是因为执行该指令后,PC 仍指向这条指令,中断的断点就是这条指令的首字节地址

  • 汇编语言

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        ORG   0000H             
AJMP MAIN ;初始化
ORG 0003H ;INT0中断入口
AJMP SER1 ;转中断服务程序
ORG 0030H ;主程序
MAIN: MOV P1,#0FH ;高4位灯灭,低四位输入写1
SETB IT0 ;边沿触发中断
SETB EX0 ;允许外中断0中断
SETB EA ;开中断开关
SJMP $ ;等待中断
ORG 0050H
SER1: MOV A,P1 ;
SWAP A ;累加器A的高半字节和低半字节互换
MOV P1,A ;P1.0~P1.3所接的开关状态反映到发光二极管上
RETI
END

  • C语言(C51编译器)
    编译器在规定的中断源的矢量地址中放入无条件转移指令,使CPU响应中断后自动地从矢量地址跳转到中断服务程序的实际地址,而无需用户去安排
    中断服务程序定义为函数,函数的完整定义如下:
    返回值 函数名([参数]) interrupt n[using m]
    interrupt n:将函数声明为中断服务函数,n为中断源编号,0~31间的整数,编译器从8n+3处产生中断向量地址,n不允许是带运算符的表达式
    using m:函数使用的工作寄存器组,m的取值范围为0~3,可缺省
    • 影响:函数入口处将当前寄存器保存,使用m指定的寄存器组,函数退出时原寄存器组恢复。选不同的工作寄存器组,可方便实现寄存器组的现场保护
1
2
3
4
5
6
7
8
9
10
11
12
13
#include<reg51.h>  
int0( ) interrupt 0 /*INT0中断函数*/
{ P1=0x0f; /*输入端先置1,灯灭*/
P1<<=4; /* 读入开关状态,并左移四位,
} 使开关反映在发光二极管上*/
main( )

EA=1; /*开中断总开关*/
EX0=1; /*允许INT0中断*/
IT0=1; /*下降沿产生中断*/
while(1); /*等待中断,语句进入死循环等待中断,当拨动INT0的开关后,进入中断函数,读入P1.0~P1.3的开关状态并将状态数据右移四位到P1.4~P1.7的位置上输出控制LED亮,执行完中断,返回到等待中断的while(1)语句,等待下一次的中断。*/


题目二

  • AT89S51的P1口接一个共阴极的数码管,利用消抖开关产生中断请求信号,每来回拔动一次开关,产生一次中断,用数码管显示中断的次数(最多15次,十六进制数显示)

  • 汇编语言

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
           ORG   0000H                
    AJMP MAIN
    ORG 0013H ;INT1中断入口
    AJMP INT1 ;转中断服务程序
    ORG 0030H ;主程序
    MAIN: SETB IT1 ;边沿触发中断
    SETB EX1 ;允许INT1中断
    SETB EA ;开中断开关
    MOV R0,#0 ;计数初值为0
    MOV A,#3FH ;“0”的字形码送A
    MOV DPTR,#TAB ;指向数码表
    WAIT: SJMP WAIT ;等待中断
    INT1: INC R0 ;中断次数加1
    MOV A, R0
    MOVC A, @A+DPTR ;查表
    MOV P1,A
    CJNE R0,#0FH RE
    MOV R0,#0
    RE: RETI ;AL1地址→PC,返主程序AL处
    TAB: DB 3FH,06H,5BH,4FH,66H,6DH
    DB 7DH,07H,7FH,6FH,77H,7CH
    DB 39H,5EH,79H,71H ;字形码表
    END

  • C语言(在中断服务程序中控制中断次数)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #include<reg51.h>    
    char i;
    code char tab[16]= {0x3f,0x06,0x5b,0x4F0x66,0x6d,0x7d,
    0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

    int() interrupt 2

    i++
    if (i<16) P1=tab[i];
    else{i=0;P1=0x3f;}

    main()

    EA=1;
    EX1=1;
    IT1=1;
    P1=0x3f
    while(1); /*等待中断*/

MCS - 51单片机定时/计数器

详解
  1. 定时/计数器用途:

    • 输出一定频率、一定占空比的波形
    • 测量脉冲宽度
    • 对外部信号计数
    • 扩展外部中断
  2. 初始化编程:

    • 方式选择、定时或计数的选择(1计数,0定时)、是否使用门控信号反映在TMOD中
    • 计算计数值,填写在TL0、TH0或TL1、TH1中
    • 如果使用定时中断,则需要进行中断的初始化,包括IE(开放中断EA=1, 定时器Tx 中断允许ETx=1 )、IP寄存器的设定
    • 启动定时器工作,设置TCON中的TR0或TR1
  3. T0/T1对外部时钟计数(外部脉冲的下降沿触发计数)时,外时钟的最大频率振荡频率的1/24
    计数器在每个机器周期S5P2(第5个状态周期的P2节拍)期间采样,若一个机器周期采样值为1,下一个机器周期采样值为0,则计数器加1
    因此 ,外部计数脉冲一个周期最少两个机器周期,即24个振荡周期

  4. JBC指令:判断可位寻址区域内指定位是否为1,为1则跳转到指定位置,并同时清除该位(置0)

  5. CPL指令:直接寻址位取反

  6. 系统复位后,SP的初始值为07H,使得堆栈实际上是从08H开始的。但我们从RAM的结构分布中可知,08H—1FH隶属1—3工作寄存器区,若编程时需要用到这些数据单元,必须对堆栈指针SP进行初始化,原则上设在任何一个区域均可,但一般设在30H—1FH之间较为适宜。
    在8051单片机中,入栈SP+2,出栈SP-2

  7. 通常T1用作串行接口的波特率发生器时,T0工作在方式3

方式 0 的应用

题目:利用定时器T1定时,在P1.0输出周期为 1 ms的方波, 设单片机晶振频率为 6 MHz
分析:

  • 每隔 0.5ms对 P1.0 取反一次即可得到这个方波
  • 计算计数初值:
    机器周期=12÷6 MHz= 2 μs
    需要计数次数N:N=0.5ms÷2 μs =250
    初值X=M-N=8 192-250=7 942=1F06H 0001 1111 000 | 0 0110
    13 位计数器,TL1 使用了低5位 00110(06H),TH1用8位(6~13位)1111 1000(F8H)
    TMOD初始化: TMOD=0000 0000B=00H
    TCON初始化: 启动TR1=1
    IE初始化: 开放中断EA=1, 定时器T1 中断允许ET1=1
  • 汇编语言(直接查溢出标志位)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
           ORG  0000H     
    AJMP START ; 复位入口
    ORG 0030H
    START: MOV SP, #60H ; 数据缓冲区(30H~7FH),用于堆栈
    MOV TH1, #0F8H ; T1赋初值
    MOV TL1, #06H
    MOV TMOD, #00H
    SETB TR1 ; 启动T1
    LP1: JBC TF1, LP2 ;查询定时器1溢出标志位是否置1,为1转到LP2
    AJMP LP1
    LP2: MOV TH1, #0F8H ; T1赋初值
    MOV TL1, #06H
    CPL P1.0 ;P1.0位取反
    AJMP LP1

  • C语言

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #include <reg51.h>
    sbit p10=p1^0;
    main()
    {
    TMOD=0;
    TH1=0xf8;
    TL1-0x06;
    TR1=1;
    While(1)
    {
    do { } while(TF1==0);
    P10=~p10;
    TH1=0xf8;
    TL1-0x06;
    TF1=0;
    }
    }

  • 汇编语言(采用中断)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
           ORG  0000H     
    AJMP START ; 复位入口
    ORG 001BH
    AJMP T1INT ; T1中断入口
    ORG 0030H
    START: MOV SP, #60H ; 初始化程序
    MOV TH1, #0F8H ; T0赋初值
    MOV TL1, #06H
    MOV TMOD, #00H
    SETB TR1 ; 启动T1
    SETB ET1 ; 开T1中断
    SETB EA ; 开总允许中断
    MAIN: AJMP MAIN ; 主程序,等待中断
    T1INT: CPL P1.0
    MOV TL1, #06H
    MOV TH1, #0F8H
    RETI


单片机串行口及应用

详解
  1. 在串行异步传送中,CPU与外设之间事先必须约定:
    • 字符格式:用ASCII码通信,有效数据为7位,加1个奇偶校验位、1个起始位(”0”)和1个停止位(”1”)共10位。停止位也可大于1位
    • 波特率(Baudrate):波特率是数据的传送速率,即每秒钟传送的二进制位数,单位为位/秒。它与字符的传送速率(字符/秒)之间存在如下关系
      波特率=位/字符×字符/秒=位/秒
      发送端与接收端的波特率必须一致
      这里的波特率相当于通原中的传信率bit/s,传码率(符号/s)
      波特率是可变的, 它取决于定时器 T1 的溢出速率及SMOD的状态
  2. 与方式1不同, 方式2和3中装入RB8的是第9位数据, 而不是停止位。所接收的停止位的值与SBUF、 RB8 和 RI都没有关系, 这一特点可用于多机通信
  3. 串行口的初始化编程:

    • 按选定的串口工作方式设定SCON的SM0、SM1位
    • 对于工作方式 2 或 3, 应根据需要在TB8中写入待发送的第9位数据
    • 若选定的不是方式 0,还需设定接收/发送的波特率
    • 设定SMOD(在PCON的最高位)的状态, 以控制波特率是否加倍
    • 若选定工作方式1或3, 则应对定时器T1进行初始化以设定其溢出率
  4. 四种工作方式:
    方式1为8位通信, 波特率可变
    方式2为9位通信,波特率为两种可选
    方式3为9位通信, 波特率可变

  5. 方式1和方式3波特率与T1溢出率有关,
    通常T1工作在方式2,对机器周期计数,
    计算溢出率 时,如果T1工作在0,1方式,则会产生误差

  6. 定时器T1作为波特率发生器, 通常选用定时方式2(8 位重装载初值方式),此时禁止 T1 中断

  7. 波特率设计:

    • 方式0:波特率(固定)=fosc(晶振频率)/12
    • 方式2:波特率(两种情况)
      • SMOD=0,fosc/64
      • SMOD=1,fosc/32
    • 方式1(传10位,8位数据位)和方式3(传11位,有个用户定义位,一般是奇偶校验位)
  1. 总结:
    • SCON(串行接口控制寄存器,可位寻址):串口工作方式选择,是否允许接收,查询有无发送/接收中断
    • PCON(电源控制寄存器,不可位寻址):D7位SMOD,为“1”,波特率加倍,为“0”,波特率不加倍
    • 若用到定时器T1
      TR1置1,定时器启动
      TMOD(定时器/计数器方式寄存器,不可位寻址):控制定时器的工作方式,T1在方式2
      设置计数初值:TH1,TL1

应用

题一

设某单片机系统需通过串行口与一微机系统双向通信,采用1位起 始位、8位数据和1位停止位的协议,波特率为2400。单片机上电复位后,首先向微机发送一个55H。编写单片机的初始化程序

  • 分析:
    单片机串行口应工作于方式1,允许接收,SCON=01010000B;
    采用Timer1作波特率发生器,T1工作于方式2,定时方式,TMOD=20H
    T1初值为F4H
1
2
3
4
5
6
7
8
9
10
MOV   SCON,   #01010000B ;初始化串口
MOV PCON, #00H ;SMOD=0
MOV TMOD, #20H ; # 0010 0000 初始化定时器1
MOV TH1, #0F4H ;TL1计数溢出时,将TH1的内容重新装载到TL1
MOV TL1, #0F4H
SETB TR1 ; 启动定时器
SETB ES ; 允许串口中断
SETB EA ; 开中断总开关
MOV SBUF , #55H ; 向微机发送#55H

题二

设有两个单片机系统甲和乙。两系统均工作于全双工中断方式,串行口工作于方式3,第9位数据为奇偶校验位,CPU 时钟为11.0592MHz。定时器T1工作于方式2,波特率2400, SMOD=0,将系统乙内外部数据存储器7C00H~7CC7H共200个字节的数据传送到系统甲中外部数据存储器7E00H~7EC7H中;将系统甲内外部数据存储器7C00H~7CC7H共200个字节的数据传送到系统乙中外部数据存储器7E00H~7EC7H中。编写两个系统的程序

  • 分析:
    源数据均在7C00H~7CC7H,共200个字节,目的数据区首址为7E00H
     SCON=11010000B=D0H ,
    PCON=00H ,
    TMOD=00100000B=20H
    2400=(20/32) x(11.0592/12(28-Z)) , Z=F4H

  • 位传送时需通过累加器C
    奇偶标志位P位于PSW(程序状态寄存器),观测累加器A中“1”的个数,P=0,1有偶数个;P=1,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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
ADDR1H   EQU     30H        ;源数据指针
ADDR1L EQU 31H ;
ADDR2H EQU 32H ;目的数据指针
ADDR2L EQU 33H
RECV EQU 34H ;接收数据计数器
SEND EQU 35H ;发送数据计数器
ORG 0000H
LJMP MAIN
ORG 0023H
LJMP INTS ;保护断点
ORG 0030H
MAIN: MOV ADDR2H, #7EH ; 目的指针初值,存发送数据
MOV ADDR2L, #0H
MOV ADDR1H, #7CH ; 源指针初值,存接收数据
MOV ADDR1L, #0H
MOV RECV, #0H ; 接收数据初值
MOV SEND, #0H ; 发送数据初值

MOV TMOD, #20H ;T1初始化
MOV TH1, #0F4H
MOV TL1, #0F4H
SETB TR1
MOV SCON, #0D0H ; 串口初始化 1101 0000
MOV PCON , #0
SETB ES ; 开串口中断
SETB EA

MOV DPH, ADDR1H ;源指针初值送DPTR
MOV DPL, ADDR1L
MOVX A, @DPTR  ;取第一个要发送的数
MOV C, P ; 取奇偶校验位
MOV TB8, C     ;奇偶校验位送TB8
MOV SBUF, A    ;发送一个数 
INC SEND   ;发送计数器加1
LOOP: LJMP LOOP     

INTS: PUSH PSW  ;保护断点
PUSH ACC
PUSH DPL
PUSH DPH
JB TI, TPROG ;每发送完一个数据,发送中断标志位TI置1
JB RI, RPROG
LJMP INTSE ;没有中断,恢复现场
TPROG: CLR TI        ;发中断处理,清标志
MOV A, SEND
CJNE A, #200, TPROG1  ;200个数没发完
LJMP INTSE        ;200个数发完,退出中断
TPROG1: INC DPTR
MOV ADDR1H, DPH  ;改源指针
MOV ADDR1L, DPL 
MOV DPH, ADDR1H
MOV DPL, ADDR1L
MOVX A, @DPTR
MOV C, P
MOV TB8, C
MOV SBUF, A  
INC SEND      ;发送计数器加1
LJMP INTSE

RPROG: CLR RI     ;接收中断处理程序
MOV A, RECV
CJNE A, #200, RPROG1
LJMP INTSE   ;200个数接收完,退出中断服务程序
RPROG1: MOV A, SBUF  ;取收到的数据
MOV C, RB8  ;收到的第9位送C
ANL C, /P
CPL C
JC ERR   ;C为1,校验出错   
MOV DPH, ADDR2H
MOV DPL, ADDR2L ;
MOVX @DPTR, A
INC DPTR
MOV ADDR2H, DPH
MOV ADDR2L, DPL  ;修改目的数据指针
INC RECV      ;修改接收计数器
LJMP INTSE

ERR: SETB F0
INTSE: POP DPH ;恢复断点
POP DPL
POP A
POP PSW
RETI   ;中断返回
END