1-1 请说明CPU的功能以及CPU是如何执行指令和程序的。
答:CPU的功能是执行程序和统筹处理计算机系统中各类事务。
CPU执行指令分为3步:取指令、分析指令、执行指令;计算机程序是由一条条指令按一定的顺序排列组成的,CPU执行程序的过程就是一条条指令累计执行的过程,其方式分为串行作业方式和流水线作业方式。
1-2 请说明单片机内部主要是由哪些部件组成的,并说明各部件的作用。
答:CPU:由控制器和运算器构成,控制器的作用是执行指令和协调系统各部件的工作;运算器的作用是进行逻辑运算和算术运算。
存储器:存储计算机工作时使用的信息,即指令代码和数据代码。
I/O接口电路:具有数据缓冲、数据隔离及数据转换的功能。
1-3 请问对于容量位8K的存储器芯片,它的地址线是多少根?
答:8K=8192=213,故地址线为13根。
另附:存储器的数据线由存储器的字长决定,例如一块32K×16(存储器容量显示格式:存储单元数×存储单元的字长)的存储器,其地址线为15根,数据线为16根。
1-4 将十进制数78,134,分别用二进制数、十六进制数和8421BCD吗表示。
答:(78)D=(1001110)B=(4E)H=(01111000)8421BCD
(134)D=(10000110)B=(86)H=(000100110100)8421BCD
注:8421BCD码为4位表示一个十进制数符,本质是符号不是数值,所以不可省略0。
1-5 将下列真值分别转化为用8位和16位二进制数表示的原码、补码和反码。
X=1000100;
[X]8位原=[X]8位反=[X]8位补=01000100;[X]16位原=[X]16位反=[X]16位补=0000000001000100
X= -1000100
[X]8位原=11000100,[X]8位反=10111011,[X]8位补=10111100;
[X]16位原=1000000001000100,[X]16位反=1111111110111011,[X]16位补=1111111110111100;
X= -0111111
[X]8位原=10111111,[X]8位反=11000000,[X]8位补=11000001;
[X]16位原=1000000000111111,[X]16位反=1111111111000000,[X]16位补=1111111111000001;
1-6 将下列补码转化成二进制数的真值。
[X]补=00101100;
X=101100
[X]补=11111111;
X= -1
[X]补=10000000;
X= -10000000
1-7 已知下列补码[X]补和[Y]补,分别求[X+Y]补、[X-Y]补。并判断运算结果是否出现溢出。
[X]补=10011001, [Y]补=00101100;
[-Y]补=11010100, [X+Y]补=[X]补+[Y]补=11000101不溢出;[X-Y]补=[X]补+[-Y]补=[X]补-[Y]补=01101101溢出;
[X]补=11111111, [Y]补=10000000;
[-Y]9位补=010000000, [X+Y]补=[X]补+[Y]补=01111111溢出;[X-Y]补=[X]补+[-Y]补=[X]补-[Y]补=01111111不溢出;
[X]补=00110111, [Y]补=11100000;
[-Y]补=00100000, [X+Y]补=[X]补+[Y]补=00010111不溢出;[X-Y]补=[X]补+[-Y]补=[X]补-[Y]补=01010111不溢出;
[X]补=10000111, [Y]补=11000000;
[-Y]补=01000000, [X+Y]补=[X]补+[Y]补=01000111溢出;[X-Y]补=[X]补+[-Y]补=[X]补-[Y]补=11000111不溢出;
方法提示:由于补码是按序列排列的,所以可以直接进行加和减,即[X+Y]补=[X]补+[Y]补;[X-Y]补=[X]补-[Y]补
另补码减法也可用加法实现[X-Y]补=[X]补+[-Y]补。上题的第2小题,由于[Y]8位补=10000000=28,Y=-28,所以(-Y)= 28,已不能用8位补码表示,可以先扩补位9位补码,然后进行运算,或直接用[X-Y]补= [X]补-[Y]补进行计算。判断结果是否溢出,可按下列方法:加法时,如果正负数相加(即两数的符号位不同),则结果肯定不溢出;如果同号数相加,结果与被加数和加数异号的则溢出(即正正相加结果为负或负负相加结果为正时)。减法时,如果同号数相减(即两数的符号位相同),则结果肯定不溢出;如果异号数相减,结果与被加数异号的则溢出(即正负相减结果为负或负正相减结果为正时)。此法比用变形补码直观,加和减都适用。
2-1 请说明单片机89C52内部有哪些资源。
答:1个8位CPU、8KB的FLASH程序存储器、256B的SRAM数据存储器、4个8位的并行I/O口(P0,P1,P2,P3)、1个全双工串行口、中断系统(5个中断源、2个中断优先级)、3个16位的定时/计数器(T0,T1,T2)、时钟电路(时钟频率6~24MHZ)。
2-2 为什么51系列单片机的存储器系统采用哈佛结构。
答:哈佛结构指的是指令代码和数据分别存放在程序存储器和数据存储器中,两部分存储器分别采用不同的地址总线系统。单片机在工作时一般执行固定不变的应用程序代码,而作为嵌入式控制系统的核心,受限于体积要求,单片机系统一般不会带有辅助存储器(例如硬盘等),为了在断电时也能保存用户的应用程序,故需将程序固化在只读存储器中,而单片机工作时程序运行过程中的数据是变化的,所以需要放在随机访问存储器中。
2-3 51单片机中的工作寄存器分布在存储器的哪个区域?
答:分布在内部数据存储器的00H~1FH区域。
2-4 在51系列单片机中,工作寄存器分几个区?如何改变工作寄存器区?
答:分为0、1、2、3四个区。修改特殊功能寄存器PSW的RS1和RS0位可改变当前工作寄存器区。
2-5 特殊功能寄存器和工作寄存器在存放信息方面有和区别?
答:特殊功能寄存器(SFR)中存放的是一些专用信息,这些信息与下列内容有关:计算机指令的执行条件及状态标志,定时/计数器的使用控制、中断系统的使用、并行I/O及串行I/O接口的使用。
工作寄存器只是用于暂时存放指令执行过程中一般的被操作数据。
2-6 特殊功能寄存器的地址空间如何?
答:特殊功能寄存器(SFR)的地址为8为二进制编码,地址范围为80H~0FFH,但各特殊功能寄存器的地址并非连续分布的。指令通过直接寻址的方式才能访问到。
2-7 51单片机中的位寻址区在哪里?它们的地址空间如何?
答:51单片机的位寻址区分布在两个地方。一部分位于内部数据存储器中字节地址为20H~2FH的16个单元中,这部分包括128个位,位地址空间为00H~7FH;另一部分位于字节地址能被8整除的特殊功能寄存器中, 位地址空间为80H~0FFH。
2-8 请指出下列位地址所在的内部数据存储器单元的字节地址或SFR名称。
答: 00H 内部RAM的20H单元;(20H).0
20H 内部RAM的24H单元;(24H).0
0A0H P2;P2.0
0B0H P3;P3.0
64H 内部RAM的2CH单元;(2CH).4
E6H 累加器ACC; ACC.6。
提示:1) 内部数据存储器内的可寻址位,其位地址(00H~7FH)与所在单元的字节地址(20H~2FH)间的关系如下:
位地址=(字节地址-20H)×8+DX, DX-该位在字节单元中的位置(D0~D7)
位地址÷8,商+20H=字节地址,余数=DX
2) SFR中的可位寻址(位地址80H~0FFH)的寄存器,其最低位的位地址与其字节地址相同。关系如下:
位地址÷8,商*8=SFR的字节地址,余数=DX,DX-该位在SFR中的位置(D0~D7)
2-9 若某51单片机应用系统将F000H~FFFFH地址空间分配给它外部的I/O接口,那么该单片机应用系统最多给外部数据存储器分配多少单元?地址空间如何?
答:51单片机的外部I/O接口和外部数据存储器是统一编制的,占用同一个地址空间,地址空间的容量为64KB,地址范围为0000H~FFFFH。据题意,系统已将F000H~FFFFH地址空间分配给它外部的I/O接口,则只剩下0000H~EFFFH可分配给外部数据存储器,容量为60KB。
2-10 在图2-9中的电容C,如果它取值太小,对复位电路有何影响?
答:51单片机上电复位,需要在RST引脚上保持10ms以上的高电平。如果C太小,则其充电时间变短,上电后,RST引脚上高电平保持的时间太短,则单片机内部复位将不能完全完成,有些寄存器内容将变得不确定。
2-11 上电复位和人工按钮复位后对内部数据存储器具有什么不同的影响?
答:上电复位后,内部数据存储器中的内容为不确定的状态。
人工按钮复位后,内部数据存储器中的内容不变(因为没有断电)。
2-12 51应用系统中,为何要对堆栈指针SP重新设置?
答:复位后(SP)=07H,则堆栈是从08H开始存放数据的。而内部数据存储器中00H~1FH单元为工作寄存器区,而20H~2FH单元为位寻址区,在实际的应用系统中,这些区域都可能使用到。故一般将堆栈设置在地址30H以后的单元中,所以需要对堆栈指针SP重新设置。
2-13 51单片机中的I/O接口中,那个接口在作为准双向口时需要外接电阻?若对某一接口进行读引脚的操作,必须事先对该接口做什么操作?
答:P0口需外接上拉电阻(因为P0是集电极开路结构)。
若需对某个接口读引脚(即读取外部输入信号的状态),需要对该接口的口锁存器写入1(例如:若需要读取P1.0、P1.1、P1.2、P1.3的引脚状态时,需要先执行MOV P1, #0FH。这也是为什么复位后(P0)= (P1)=(P2)=(P3)=0FFH的道理。)
3-1 指令的格式是由哪些部分组成的?每部分的含义是什么?
答:指令由操作码和操作数组成。在形式上操作码和操作数都是二进制代码。操作码用来表示指令的种类和功能,经由控制器中的指令译码器译码后产生控制信号。操作数是指令的操作对象,表示被操作数据或数据所在的存储单元地址。
3-2 什么是寻址方式?51系列指令系统有哪些寻址方式?
答:指令中给出操作数的方式叫做寻址方式。51系列机给出的寻址方式一般有7中:立即寻址、直接寻址、寄存器寻址、寄存器间接寻址、变址寻址、相对寻址、位寻址(直接寻址的一个特例――地址指向位单元)。
3-3 对于内部数据存储器00H~1FH区域的访问有哪些寻址方式?对于外部数据存储器的访问有哪些寻址方式?对于特殊功能寄存器的访问有哪些寻址方式?
答:对于内部数据存储器00H~1FH区域的访问有直接寻址、寄存器寻址、寄存器间接寻址三种方式。
对于外部数据存储器的访问只有寄存器间接寻址一种方式(以DPTR或R0、R1为指针)。
对于特殊功能寄存器的访问只有直接寻址一种方式。同时对于内部数据存储器80H~0FFH的128个单元的访问只有寄存器间接寻址一种方式(以R0、R1或SP为指针);借助于两种不同的寻址方式,可以将在地址上重合(80H~0FFH)的SFR和内部RAM高128字节单元的两部分空间加以区分。
3-4 51系列单片机有哪些标志位?这些标志位存放在哪里?
答:51单片机在程序运行时通常需要一下标志位:
Cy,AC,OV,P,RS1,RS0,它们都存放在特殊功能寄存器PSW(程序状态字寄存器)中。
3-5 分析下列各指令的操作数,指出它们的寻址方式。
MOV R4, 38H ;寄存器寻址,直接寻址
ADD A, @R1 ;寄存器寻址,寄存器间接寻址
MOVC A, @A+DPTR ;寄存器寻址,变址寻址(又称基址寄存器加变址寄存器间接寻址)
MOVX A, @DPTR ;寄存器寻址,寄存器间接寻址
DEC B ;直接寻址
SETB 24H ;位寻址(直接寻址的一种,只是给出的直接地址是位地址)
CJNE A, #100, NEXT ;寄存器寻址,立即寻址,相对寻址
ANL 30H, #00H ;直接寻址,立即寻址
PUSH P1 ;寄存器间接寻址(指针为SP,只是在堆栈操作指令中省略了),直接寻址
堆栈操作除了用PUSH和POP指令,完全可以用其它指令来完成,举例如下:
提示:上题答案中按操作数先后顺序给出其对应的寻址方式。
3-6 下列各指令或指令组执行前有关寄存器和存储器的状态如下表,要求分析各指令或指令组执行后有关寄存器、存储器和标志位的状态。
内部数据存储器和特殊功能寄存器 | 外部数据存储器 | 程序存储器 | ||||||
寄存器名 | 内容 | 单元地址 | 内容 | 单元地址 | 内容 | 单元地址 | 内容 | 程序计数器内容 |
B | 64H | 73H | 10H | 900BH | 12H | 1206H | 35H | (PC)=1200H |
ACC | 03H | 72H | 11H | 900AH | 83H | 1205H | 34H | |
PSW | 80H | 71H | 00H | 9009H | D1H | 1204H | 33H | 标号及标号值 |
DPL | 05H | 70H | 80H | 9008H | 79H | 1203H | 32H | NEXT1=0800H |
DPH | 90H | 9007H | 0CH | 1201H | 31H | NEXT2=0900H | ||
SP | 71H | 36H | F8H | 9006H | 23H | 1200H | 30H | NEXT3=1280H |
R0 | 00H | 35H | 2BH | 9005H | 13H | LOOP=1148H | ||
R1 | 36H | 34H | 36H | 9004H | 4DH | |||
R2 | 35H | 33H | 74H | 9003H | 2EH | |||
R3 | B7H | 32H | 59H | 9002H | 7FH | |||
R4 | 03H | 9001H | 54H | |||||
R5 | F6H | 26H | 66H | 9000H | 38H | |||
R6 | E4H | 25H | 55H | |||||
R7 | 21H | 24H | 44H | |||||
P0 | 7CH | |||||||
P2 | 90H | |||||||
提示:在上表中需注意几点:(PSW)=80H,即Cy=1, AC=0, RS1=RS0=0(故当前工作寄存器区为0区)。工作寄存器区为0区时,R0~R7指向内部数据存储器的00H~07H,所以当指令中出现直接地址00H~07H中的某个时,其初始条件即为R0~R7中某个对应的寄存器的值。另,因为(DPH)=90H, (DPL)=05H, 所以(DPTR)=9005H。标号值实质上是代表标号所在处的指令在程序存储器中的地址,标号往往出现在程序转移指令中,指出转移指令的目标地址。
1) MOV R0,#32; (R0)=32=20H
2) MOV 25H,@R1; (25H)= 0F8H
3) MOVX A,@DPTR; (A)= 13H P=1
4) MOVX A,@R0; (A)= 38H P=1
5) MOVC A,@A+PC; (A)= 33H P=0
6) MOV A,04H; (A)= 03H P=0
7) XCH A,34H; (A)= 36H (34H)= 03H
8) XCHD A,@R1; (A)= 08H (36H)=0F3H
9) PUSH DPL; (SP)=72H (72H)=05H
10) POP DPH; (DPH)=00H (SP)=70H
11) SUBB A,R1; (A)= 0CCH Cy=1 P=0 AC=1 OV=0
12) ADD A,R6; (A)= 0E7H Cy=0 P=0 AC=0 OV=0
13) ADDC A,36H; (A)= 0FCH Cy=0 P=0 AC=0 OV=0
14) MUL AB; (A)= 2CH (B)=01H
15) INC R0; (R0)= 01H
16) DEC A; (A)= 02H P=1
17) ADD A,#49H;
DA A; (A)=52H Cy=0 P=1
18) ANL A, R1; (A)= 02H (R1)=36H P=1
19) ORL A,32H; (A)= 5BH P=1
20) ORL 26H,#35H; (26H)=77H P=0
21) XRL A,@R0; (A)= 03H P=0
22) XRL A, ACC; (A)=0 P=0
23) XRL A,#0FFH; (A)= 0FCH P=0
24) CPL A; (A)=0FCH P=0
25) RL A; (A)=06H Cy=1
26) RRC A; (A)=81H Cy=1
27) MOV C,(25H).2; Cy=1
28) MOV F0,C; (PSW)=0A0H
29) SETB RS0; (PSW)=88H
30) CLR C; (PSW)=0
31) ANL C,(24H).0 Cy=0
32) JZ NEXT1; (PC)=1202H
33) JC NEXT2; (PC)= 0900H
34) CJNE A, 25H, NEXT3; (PC)= 1280H Cy=1
35) DJNZ R7,LOOP; (PC)= 1148H (R7)=20H
36) LCALL 1800H; (PC)=1800H (SP)=73H (72H)=03H (73H)=12H
37) RET; (PC)=0080H (SP)=6FH
38) ANL C, /32H; Cy=0 (32H)=1 ,提示此处32H为位存储器
39) STOP: JBC P0.3, STOP; (PC)=1200H (P0)=74H
40) JNB P0.4, NEXT1; (PC)=1203H
红色部分为附加题,答案就在本期内找^_^,看看你们的本事了,哈哈哈哈
3-7 分析下列程序段的功能。
1) MOV A, R3
MOV R4, A
功能:将R3中的内容送入R4,即(R3)→R4
2) MOV A, R5
CPL A
MOV R5, A
功能:R5中的数据按位取反后送回R5
3) MOV A, R4
MOV B, R5
DIV AB
MOV R4, B
MOV R5, A
功能:R4中的数除以R5中的数,结果商送入R5,余数送入R4
4) MOV C, P1.1
ANL C, P1.2
ANL C, /P1.3
MOV P1.6, C
功能:P1.1P1.2→P1.6
5) MOV C, 0
ORL C, 1
MOV F0, C
MOV C, 2
ORL C, 3
ANL C, F0
MOV P1.7, C
功能:((20H).0∨(20H).1) ∧ ((20H).2∨(20H).3) →P1.7
6)
CLR C
MOV A, R4
RLC A
MOV R4, A
MOV A, R3
RLC A
MOV R3, A
功能:R3、R4中的内容左移一位,R4最低位移入0,R4最高位移入R3最低位,R3最高位移出至Cy。
7) CLR C
MOV A, R5
RLC A
ADD A, R5
MOV R5, A
功能:
8) CLR A
MOV R0, A
MOV R7, A
LOOP: MOV @R0, A
INC R0
DJNZ R7, LOOP
STOP: SJMP STOP
功能:将内部数据存储器00H~0FFH 256个单元全部清零。
9) PUSH ACC
PUSH B
POP ACC
POP B
功能:利用堆栈将ACC与B中的内容互换,即(ACC) (B)
10) MOV R0, #30H
XCHD A, @R0
SWAP A
INC R0
XCHD A, @R0
SWAP A
MOV 40H , A
功能:将ACC的低四位送入30H单元低四位,ACC的高四位送入31H的低四位,而原先30H单元的低四位送入40H单元的低四位,原31H单元的低四位送入40H单元的高四位。
举例说明如下,设程序段运行前有(ACC)=12H,(30H)=34H,(31H)=56H;
则程序段运行后有(30H)=32H,(31H)=51H, (ACC)= (40H)=64H
3-8 指出下列指令中哪些是合法指令,哪些是非法指令。
MOV P1, R4 ;合法
MOV R2,R4 ;非法
CLR R3 ;非法
RLC R5 ;非法
MOV 30H, 31H ;合法
MOV 00H, P ;非法
ORL 40H, R7 ;非法
PUSH R6 ;非法
POP R0 ;非法
INC DPTR ;合法
注:常见的错误还有类似:MOV R0, C; ADD 30H,31H; MOV A, @R5; DEC DPTR等,编程时切记勿错!
3-9 按要求编制下列各程序段。
将内部数据存储器30H和31H单元的内容互换。
比较法一、法二的优缺点,你认为哪个方法更好?
将寄存器R7的内容向右循环移位一次。
XCH A, R7
RR A
XCH A, R7
将寄存器R3的内容乘以4(结果不超出8为二进制数的范围)。
将寄存器DPTR的内容减1。
比较以上各方法,其中法三利用了-1的补码是0FFFFH的原理,将减法改为了加法。
将寄存器R6的内容压入堆栈(设寄存器工作在3区)
PUSH 1EH
将R4, R5寄存器连接起来循环右移一位。(设R4为高8位,R5为低8位;执行完后R4R5中的内容右移一位,R4的最低位移入R5的最高位,同时R5的最低位移入R4的最高位)
XCH A, R4 ;将R4中的内容送入ACC,同时将ACC的内容放入R4中暂存。
RRC A ;ACC中原先R4的内容右移一位,同时Cy移入最高位,而原先R4的最低位移入Cy位
XCH A, R5 ;R5中的内容送入ACC,上一步中产生的ACC的内容送入R5暂存
RRC A ;ACC中原先R5的内容右移一位,Cy(即原R4的最低位)移入最高位,而原R5的最低位移入Cy位
XCH A, R5 ;将结果送入R5(R5移位已完成),同时将第三步暂存在R5中的内容取出。
MOV ACC.7, C ;将Cy位中存放的原R5的最低位送入ACC的最高位(即送入R4的最高位)
XCH A, R4 ; 将结果送入R4,同时取出ACC原来的值
4-1 用伪指令将下列常数依次定义在1600H为首地址的程序存储器中。
0,1,4,9,16,25,36,49,64,81
答:ORG 1600H
DB 0,1,4,9,16,25,36,49,64,81
4-2 用伪指令将下列常数依次定义在1700H为首地址的程序存储器中,要求数据类型一致。
0,1,8,27,64,125,216,343,512,729
答:提示:因为343,512,729为双字节数据(>255),所以所有数据均应以双字节存入。
ORG 1700H
DW 0,1,8,27,64,125,216,343,512,729
4-3 用伪指令将字节型变量X1、X2定义在内部数据存储器30H、31H单元中,将字节型变量Y1、Y2定义在外部数据存储器2000H、2001H单元中。
答: X1 DATA 30H
X2 DATA 31H
Y1 XDATA 2000H
Y2 XDATA 2001H
4-4 用伪指令将ASCII码字符串“Beijing,tjjtds!”定义在1200H为首地址的程序存储器中。
答: ORG 1200H
DB ‘Beijing,tjjtds!’
4-5 用伪指令将逻辑变量A1、A2定义在00H、01H位单元中
答: A1 BIT 00H
A2 BIT 01H
4-6 编一程序段,将1400H为首地址的外部数据存储器中200个单字节数据转移至1500H为首地址的外部数据存储器中。
MOV DPTR, #1400H ;用DRTR指向源数据块单元地址
MOV P2, #15H ;用P2,R0指向目标地址
MOV R0, #00H
MOV R7, #200 ;数据个数送入R7
LOOP: MOVX A, @DPTR
MOVX @R0, A
INC DPTR ;修改源数据块指针
INC R0 ;修改目标单元地址指针
DJNZ R7, LOOP
SJMP $
4-7 编一程序段,将30H为首地址的内部数据存储器中20个单字节补码数据中的负数传送至2400H为首地址的外部数据存储器中。
MOV R0, #30H ;用R0指向源数据块首地址
MOV DPTR, #2400H ;用DRTR指向目标区首地址
MOV R7, #20 ;数据个数送入R7
LOOP: MOV A, @R0 ;取出源数据
JNB ACC.7, NEXT ;若源数据最高位=0,则表示数据为非负数,无需传送,可直接取下个数据
MOVX @DPTR, A ;若取出的数据为负数,则传送到外部RAM,同时修改DPTR
INC DPTR
NEXT: INC R0
DJNZ R7, LOOP
SJMP $
4-8 编一程序段,将40H为首地址的内部数据存储器中25个单字节数据,依次下移一个单元。
提示:根据题意即将40H~58H中的数据依次送入41H~59H中
XCH A, 40H ;ACC内容送入40H暂存保护,同时取出40H单元中内容
MOV R0, #41H ;R0指向目标单元首地址
MOV R7, #25 ;数据长度送R7
LOOP: XCH A, @R0 ;前一个单元数送后一个单元,同时取出后一个单元原先的数据暂存入ACC
INC R0
DJNZ R7, LOOP
MOV A, 40H ;恢复ACC原来的内容
STOP: SJMP STOP
4-9 编一程序段,完成函数y=x2+5x+6的计算。设0≤x≤10。
提示:据题意6≤y≤156,即结果为单字节数据。
X DATA 30H
Y DATA 31H
MOV A, X
MOV B, X
MUL AB
MOV Y, A ;X2→Y
MOV A, X
MOV B, #5
MUL AB
ADD A, Y ; X2+5X → ACC
ADD A, #6 ; X2+5X+6 → ACC
MOV Y, A ; X2+5X+6 → Y
STOP: SJMP STOP
讨论:有时仔细分析问题,可以将程序变得更简单,如上题中y=x2+5x+6=(x+2)(x+3),则程序为
X DATA 30H
Y DATA 31H
MOV A, X
ADD A, #2
MOV B, A ; (x+2)
INC A ; (x+3)
MUL AB
MOV Y, A ; X2+5X+6 → Y
STOP: SJMP STOP
4-10 编一程序段,完成逻辑函数L= 的计算。
提示:此程序按照51汇编程序标准格式编写,整个程序构成一个完整结构,单片机运行时将反复执行该程序,即当输入变量发生变化时,输出逻辑函数L将立刻发生相应的变化。
X BIT P1.0
Y BIT P1.1
Z BIT P1.2 ;分别定义变量X,Y,Z由P1口的低三位(P1.0,P1.1,P1.2)输入
L BIT P1.7 ;定义函数L由P1.7输出
ORG 0 ;用户程序第一条指令必须放在程序存储器0000H单元中
LJMP MAIN ;此处安排一条长调换指令,跳到主程序处,目的:避开03H开始的中断入口
ORG 200H ;主程序安排在程序存储器200H单元开始
MAIN: MOV C, X
ANL C, /Y
ANL C, Z
CPL C
MOV L, C
SJMP MAIN ;真正的实用程序必须构成一个死循环结构,使得单片机可以反复地执行
;用户设定的功能
讨论一:若上列函数改为L=XY+XZ+YZ,如何编程,给两个答案,自己比较体会!
讨论二:若上列函数改为L=(X+Y)(X+Z)(Y+Z),如何编程,给两个答案,结合讨论一自己比较体会!
4-11 阅读下列各程序段,并说明其功能。
START: MOV DPTR, #1000H
MOV R7, #10
MOVX A,@DPTR
MOV B, A ;取出外部RAM单元1000H单元中的数送入B
LOOP: INC DPTR ;每次循环逐个取出外部RAM单元1001H开始的单元中的内容
MOVX A, @DPTR
CJNE A, B, COMP ;比较(A)和(B),无论是否相等,均转向下条指令,判断Cy位
COMP: JC NEXT ;Cy=1,则(A)<(B),不作处理,直接进下个循环,取下个数据判断
MOV B, A ;若Cy=0,则(A)≥(B),将(A)→B
NEXT: DJNZ R7, LOOP
STOP: SJMP STOP
功能:判断外部数据寄存器1000H开始的11个单元中的最大值,将最大值送入寄存器B。
START: MOV R2, #0
MOV R7, #8
MOV A, R3 ;(R3) →ACC
LOOP: RLC A ;8次循环,每次循环,将R3中的内容由最低位开始,逐位移入Cy
JNC NEXT ;Cy=0,则不做任何操作,直接进入下个循环
INC R2 ;若上句条件不成立,即R3中移出的位=1, 则(R2)+1 →R2
NEXT: DJNZ R7, LOOP
STOP: SJMP STOP
功能:统计R3中1的个数,并将统计结果送入R2。
START: MOV 30H, #0
MOV R0, #50H
LOOP: MOV A, @R0
CJNE A, #0FFH, NEXT
SJMP STOP
NEXT: INC 30H
INC R0
SJMP LOOP
STOP: SJMP STOP
功能:统计存放在内部数据存储器50H开始的数据块的长度(即数据块占多少个字节),数据块以0FFH为结束标志。
4-12 编一子程序,将一个非压缩8421BCD码(即单字节BCD码)转换成七段显示码。设0~9的BCD码对应的七段显示码分别为3FH、06H、6BH、4FH、66H、6DH、7DH、07H、7FH、6FH。进子程序前,BCD码被放在累加器ACC中;子程序运行后,相应的七段码也放在ACC中。(即入口参数和出口参数均在ACC中)。
;BCD码转换成显示码
;入口参数:子程序名CHSEG,单字节BCD码放在累加器ACC中
;出口参数:七段显示码放在ACC中
CHSEG: ADD A, #1 ;加上偏移量,偏移量为MOVC A, @A+PC指令与数据表首间的字节数
MOVC A, @A+PC
RET ;单字节指令
DB 3FH, 06H, 6BH, 4FH, 66H, 6DH, 7DH, 07H, 7FH, 6FH ;数据表一般紧跟着RET指令
有另一法,不需计算偏移量
CHSEG: ADD A, #SEGTB-SSG ;用标号表达式,让编译程序计算偏移量
MOVC A, @A+PC
SSG: RET
SEGTB: DB 3FH, 06H, 6BH, 4FH, 66H, 6DH, 7DH, 07H, 7FH, 6FH
4-13 编一子程序,将一个0~9的七段显示码转换成对应的格雷码。0~9的格雷码请参阅本书表1-2。设进子程序前,七段显示码被放在内部数据存储器40H中;子程序运行后,相应的格雷码放在内部数据存储器50H中。(即入口参数为40H,出口参数为50H)。
算法一提示:根据0~9的序号依次查出对应的显示码,然后与40H中的内容比较,如果相等,则根据当前序号查表得到对应的格雷码。
; 显示码转换成格雷码
;入口参数:子程序名CHGRY,七段显示码被放在内部数据存储器40H中,影响ACC,B,Cy位
;出口参数:格雷码放在内部数据存储器50H中
CHGRY: PUSH ACC ;保护现场
PUSH B
PUSH PSW
MOV B, #0 ;用B记录0~9的序号
NEXT: MOV A, B ;
ADD A, #SEGTB-SSG ;用标号表达式,让编译程序计算偏移量
MOVC A, @A+PC ;根据当前序号,查取对应的显示码
SSG: CJNE A, 40H, NEQ ;比较取得的显示码与源单元中的显示码
MOV A, B ;如果相等,则根据当前序号,查取对应的格雷码
ADD A, #GRYTB-SGR
MOVC A, @A+PC
SGR: MOV 50H, A ;将查取的格雷码送入目标单元
POP PSW ;恢复现场
POP B
POP ACC
RET ;返回
NEQ: INC B ;如果不想等,则将序号增1,查取下个显示码作比较
SJMP NEXT
SEGTB: DB 3FH, 06H, 6BH, 4FH, 66H, 6DH, 7DH, 07H, 7FH, 6FH ;显示码表
GRYTB: DB 00H, 01H, 03H, 02H, 04H, 05H, 07H, 06H, 08H, 09H ;格雷码表
算法二提示:直接将显示码转化成格雷码,程序烦了些,但方法很简单。
; 显示码转换成格雷码
;入口参数:子程序名CHGRY,七段显示码被放在内部数据存储器40H中,影响ACC,Cy位
;出口参数:格雷码放在内部数据存储器50H中
CHGRY: PUSH ACC ;保护现场
PUSH PSW
MOV A, 40H
CJNE A, #3FH, NEQ0
MOV 50H, #00H ;40H单元中的内容=0的显示码,则将0的格雷码送入50H
NEQ0: CJNE A, #06H, NEQ1
MOV 50H, #01H ;40H单元中的内容=1的显示码,则将1的格雷码送入50H
NEQ1: CJNE A, #6BH, NEQ2
MOV 50H, #03H ;40H单元中的内容=2的显示码,则将2的格雷码送入50H
NEQ2: CJNE A, #4FH, NEQ3
MOV 50H, #02H ;40H单元中的内容=3的显示码,则将3的格雷码送入50H
NEQ3: CJNE A, #66H, NEQ4
MOV 50H, #04H ;40H单元中的内容=4的显示码,则将4的格雷码送入50H
NEQ4: CJNE A, #6DH, NEQ5
MOV 50H, #05H ;40H单元中的内容=5的显示码,则将5的格雷码送入50H
NEQ5: CJNE A, #7DH, NEQ6
MOV 50H, #07H ;40H单元中的内容=6的显示码,则将6的格雷码送入50H
NEQ6: CJNE A, #07H, NEQ7
MOV 50H, #06H ;40H单元中的内容=7的显示码,则将7的格雷码送入50H
NEQ7: CJNE A, #7FH, NEQ8
MOV 50H, #08H ;40H单元中的内容=8的显示码,则将8的格雷码送入50H
NEQ8: CJNE A, #6FH, QUIT
MOV 50H, #09H ;40H单元中的内容=9的显示码,则将9的格雷码送入50H
QUIT: POP PSW ;恢复现场
POP ACC
RET
4-14 编一子程序,完成两双字节无符号数相加。设加数和被加数分别放在0区寄存器R2、R3和R4、R5中,运算结果存放在0区寄存器R6、R7中。若运算结果发生进位,使00H位单元=1;反之,使00H位单元=0。
;双字节无符号数相加
;入口参数:子程序名NADD,加数和被加数分别放在0区寄存器R2、R3和R4、R5中,影响ACC, 位Cy
;出口参数:运算结果存放在0区寄存器R6、R7中,00H位单元存放双字节相加的进位标志
NADD: PUSH ACC ;保护现场
PUSH PSW
MOV A, R2 ;(R2)+(R4)→R6
ADD A, R4
MOV R6, A
MOV A, R3 ;(R3)+(R5)→R7
ADDC A, R5
MOV R7, A
MOV 00H, C ;Cy→00H
POP PSW
POP ACC ;恢复现场
RET
4-15 编制一子程序,完成10ms较精确延时功能。设系统时钟频率为24MHz。
提示:时钟频率为24MHz,则每个机器周期T=0.5us,10ms延时即需要10000us /0.5us =20000=500×40个机器周期T。软件延时子程序,就是用循环结构反复执行一些指令,而指令执行时都需要时间,所以执行完该子程序后,即完成了延时功能。
;软件延时10ms
;入口参数:子程序名DELAY,影响2区寄存器R0, R1
;出口参数:无
DELAY: PUSH PSW ;1T
MOV PSW, #18H ;1T
MOV R0, #40 ;1T
DL: MOV R1, #248 ;1T*40
DL1: DJNZ R1, DL1 ;2T*248*40=19840T
NOP ;1T*40
DJNZ R0, DL ;2T*40
POP PSW ;1T
RET ;2T,总延时3T+40T+19840T+40T+80T+3T=20006T,误差6T=3 us,相当准了
4-16 编制一子程序,将10个非压缩BCD码转换成5个压缩BCD码。设进子程序前,非压缩BCD码被放在40H为首地址的内部数据存储器中;子程序运行后,压缩BCD码放在50H为首地址的内部数据存储器中。
功能说明:若进子程序前40H~49H单元中的内容为01H,02H,03H,04H,05H,06H,07H,08H,09H,00H,则子程序运行后50H~54H中的内容为12H,34H,56H,78H,90H
;BCD码压缩
;入口参数:子程序名BCDCH,非压缩BCD码被放在40H为首地址的内部数据存储器中
;影响ACC,2区寄存器R0, R1, R7
;出口参数:压缩BCD码放在50H为首地址的内部数据存储器
BCDCH: PUSH ACC ;保护现场
PUSH PSW
MOV PSW, #10H ;设定当前工作寄存器区为2区
MOV R0, #40H ;R0指向源数据块首地址
MOV R1, #50H ;R1指向目标数据块首地址
MOV R7, #5 ;转换5次
LOOP: MOV A, @R0 ;前一单元内的BCD码送入ACC的高四位
SWAP A
INC R0 ;R0指向下个源数据
ORL A, @R0 ;后一单元内的BCD码送入ACC的低四位,同时并未改变源数据
MOV @R1, A ;压缩BCD码送入目标地址
INC R1 ; R1指向下个目标单元
DJNZ R7, LOOP
POP PSW ;恢复现场
POP ACC
RET ;返回
4-17 编制一子程序,完成15个单字节补码数据按绝对值大小从小到大进行排队。设数据放在30H为首地址的内部数据存储器中。
提示:排序的基础是比较!无论是对原码、补码还是绝对值排序,基本算法都可沿用无符号数冒泡法的算法,只是在读取数据时需对数据进行一些处理,或在比较两个数的大小时改变一下方法(比如符号位的判断)。补码按绝对值排序的算法我想到了两种(当然不排除有其它方法)。一种是将补码转换成原码,由于原码是在最高位表示符号,而其余各位表示数值部分(即绝对值),这样只需比较原码的低7位即可;或者直接将其中负数的补码转换成其相反数的补码(这样所有比较的数据均为正数的补码,形式上也就是其绝对值,转换的方法是连同符号位一起取反后加1,这种方法也适用于对-128的补码进行转换)。另一种方法,判断两个待比较数的符号,同号时相减,如果差数与减数异号,则被减数绝对值<减数绝对值;两数异号时相加,如果和与被加数异号(或与加数同号),则被加数绝对值<加数绝对值;无论加减,结果为0,则两数绝对值必定相同。
;绝对值排序,算法一
;入口参数:子程序名PAIXU,影响ACC,寄存器B,2区寄存器R0, R2, R3, 标志位Cy,F0
;出口参数:排序后数据仍放在30H开始的15个内部数据存储器单元中
对上述程序稍作改动,程序的效率就高了(每次比较时执行的指令少了,速度就快了)
;绝对值排序,算法二
;入口参数:子程序名PAIXU2,影响ACC,寄存器B,2区寄存器R0, R2, R3, R4,标志位Cy,F0
;出口参数:排序后数据仍放在30H开始的15个内部数据存储器单元中
4-18 编制一子程序,将内部数据存储器30H~39H单元的数据连起来向左移动一位,39H最低位添0。
;10个单元数据块左移一位子程序
;入口参数:子程序名MBRL1,数据块位于30H~39H单元,影响ACC,3区寄存器R0,标志位Cy
;出口参数:移位后数据仍位于30H~39H单元中
MBRL1: PUSH PSW ;保护PSW内容
PUSH ACC ;保护ACC内容
MOV PSW, #18H ;设置3区为当前工作寄存器区,同时清除Cy位
MOV R0, #39H ;数据块尾地址送R0
LOOP: MOV A, @R0 ;单元数据送ACC
RLC A ;带进位左移
DEC R0 ;R0指向前一个单元
CJNE R0, #2FH ,LOOP ;判断R0是否已指向2FH(即30H已移位完成)
POP ACC ;恢复ACC
POP PSW ;恢复PSW
RET ;返回
END
方法2:将上述子程序修改一下,可以适用m个单元左移n位的功能。
;m个单元数据块左移n位子程序
;入口参数:子程序名MBRLN,数据块起始地址在R0中,数据块长度m放在R6中,移位数n放在R7中
;影响ACC,寄存器B,标志位Cy
;出口参数:移位后R0指向数据块起始地址
MBRLN: PUSH PSW ;保护PSW内容
PUSH ACC ;保护ACC内容
PUSH B ;保护B内容
MOV B, R6 ;数据块长度m暂存入寄存器B
NEXT: MOV R6, B ;数据块长度m重新赋值给R6
MOV A, R0
ADD A, R6
DEC A ;数据块首地址+m-1=数据块尾地址→ACC
MOV R0, A ;R0指向数据块尾地址
CLR C ;清除Cy位
LOOP: MOV A, @R0
RLC A
DEC R0
DJNZ R6 , LOOP ;内层循环完成m个单元左移一位
INC R0 ;使R0指向数据块首地址
DJNZ R7, NEXT ;外层循环完成n次移一位,即移动n位
POP B ;恢复现场
POP ACC
POP PSW
RET ;返回
END
5-1.中断申请信号如何才能被CPU检测到?
答:首先需中断系统开放(1→EA),然后相应的中断源需开放(即相关的标志EX0、ET0、EX1、ET1、ES、ET2需置1)
5-2.中断响应时CPU需要做哪些事情?
答:先将被响应的中断源所属的优先级存入优先级状态触发器;再将PC当前值(即断点)压入堆栈(先PCL,后PCH),然后将被响应中断源对应的中断入口地址送入PC。
5-3.中断入口与中断服务子程序入口有什么区别?
答:中断入口指的是当一个中断被响应时,由CPU自动调用的程序存储器的某个单元地址,这些地址是按不同中断源预先安排好的;而中断服务子程序入口指的是用户编制的中断服务子程序的第一条指令在程序存储器中存放的地址,两者一般来讲是不一样的,通常会在中断入口处安排一条跳转指令(LJMP或AJMP)指向中断服务子程序的入口。
5-4.89C52单片机中有哪些中断源?它们的中断申请标志分别是什么?
答:外部中断0,标志IE0
定时器/计数器T0中断,标志TF0
外部中断1,标志IE1
定时器/计数器T1中断,标志TF1
串行口中断,标志RI、TI
定时器/计数器T2中断,标志TF2、EXF2
5-5.若在某一个89C52单片机应用系统中,在系统初始化中将特殊功能寄存器IE和IP分别设置为10101111B和00101100B。当该系统正在运行时,问:
1) 如果外部中断1和定时器/计数器1同时申请中断,CPU将为哪一个中断源服务?为什么?
2) 如果CPU正在执行外部中断0的中断服务子程序,这时CPU还能响应系统哪些中断源的中断申请?为什么?
提示:根据IE,IP的内容可知,当前开放的中断源为外部中断0,T0中断,外部中断1,T1中断,T2中断;其中外部中断1,T1中断,T2中断为高级中断,外部中断0,T0中断为低级中断。
答:1) 如果外部中断1和定时器/计数器1同时申请中断,CPU将为外部中断1服务,因为它们同属高级中断,而在硬件查询序列中外部中断1排在T1前。
2) 由于外部中断0为低级中断,所以它的中断过程可以被其它任何高级中断源打断,在此处即CPU还能响应外部中断1,T1,T2的中断申请。
5-6.若在某一个单片机应用系统中,有一个外部中断1,中断级别为低级中断,中断申请信号为脉冲信号,中断服务子程序的首地址为1100H,中断服务子程序的任务是将P1口的数据传递至外部数据存储器2400H单元。编制初始化程序及中断服务子程序。
ORG 0 ;主程序入口
LJMP MAIN ;跳转到用户程序
ORG 13H ;外部中断1入口
LJMP X1IPG ;跳转到中断服务子程序入口
ORG 100H ;用户程序入口地址
MAIN: MOV SP, #60H ;堆栈指针初始化
SETB IT1 ;外部中断1设为脉冲模式
SETB EA ;允许中断
SETB ET1 ;开放外部中断1
CLR PT1 ;外部中断1设为低级中断
SJMP $ ;主程序原地等待,等待中断发生(即表示CPU可以做任何其它事情)
ORG 1100H ;中断服务子程序入口
X1IPG: PUSH ACC ;保护现场(由于ACC和DPTR被使用,所以先要对其原先内容进行保护)
PUSH DPL
PUSH DPH
MOV DPTR,#2400H
MOV A, P1
MOVX @DPTR , A ;(P1)→2400H
POP DPH ;恢复现场(即退出中断前,恢复ACC,DPTR中原来的内容)
POP DPL
POP ACC
RETI ;中断返回指令
END
5-7.有一个单片机实验系统,实验线路如实验八所示。要求编制一程序,当开关5发出一脉冲信号时,程序由此转入中断服务子程序,该中断服务子程序的任务是将P1口的内容取反,然后返回到主程序。
分析:由实验八(105页)可知,开关5接在 (P3.2)引脚上,故该实验其实是编制一个带外部中断0的程序。并且由于开关5发出的是脉冲信号,所以外部中断0必须工作在边沿触发方式。
ORG 0 ;主程序入口
LJMP MAIN
ORG 3 ;外部中断0入口
CPL P1
RETI ; 由于中断服务子程序的内容较少(只有两条指令,占3个字节),所以直接安排在入口处
ORG 200H
MAIN: MOV SP, #60H ;堆栈指针初始化
SETB IT0 ;外部中断0边沿触发方式
SETB EA ;开放外部中断0
SETB EX0
SJMP $ ;主程序在此循环等待,等待中断发生
6-1.单片机的定时器/计数器具有哪些功能?
答:定时/计数器T0,T1具有一般的定时和计数的功能。当它们对内部机器周期信号进行计数时,由于此信号的周期时确定的,则此时它们实现的是定时器功能;当它们对外部脉冲信号进行计数时,它们实现的是计数器的功能。另外,T1可作为串行通讯时的波特率发生器。
T2是一个高级CTC,其具有四个功能:自动装入初值的定时器/计数器、捕捉外部信号、信号发生器、串行通讯的波特率发生器。
6-2.请说明CTC的定时器工作方式的工作原理。
答:当CTC设置成对内部信号计数时,由于该内部计数信号的周期和频率是确定的(频率为fosc/12,周期即为一个机器周期),所以其计入信号的个数就能换算成时间,在实际使用中,一般根据定时的需要,先给CTC一个初值,然后启动其计数工作,当其计数溢出时会置1溢出标志,产生一个定时信号。
6-3.请说明T2捕捉工作模式的工作原理、
答:略,参见113页。大致原理:外部信号(P1.1脚)每来一个下降沿,便触发一次中断,同时记录下当前定时器T2计数值,这样可通过对相邻两次中断(即两个相邻的脉冲)时记录下来的计数值相减,便可得该脉冲信号的周期。其实这种功能也可通过T0,T1实现,只不过T2功能更强,实现起来相对容易。
6-4.若系统时钟的频率为fosc=6MHZ,请分析T1工作在模式1和模式2时,定时器最长的定时时间分别为多少?
答:已知fosc=6MHZ,故机器周期=12/fosc=2us
T1在模式1时为16位计数器,当其工作在定时方式(即作为定时器使用)时,每个机器周期加1,则其最长定时时间为216=65536个机器周期=131072(us)=131.072(ms)。
T1在模式2时为自动装入初值的8位计数器,当其工作在定时方式(即作为定时器使用)时,每个机器周期加1,则其最长定时时间为28=256个机器周期=512(us)。
6-5.已知系统时钟频率为fosc=6MHZ,若要求T1在模式1进行5ms定时,采用内部启动。请计算T1计数器的初值a,并对T1进行初始化编程。
答:由上题计算可知,当fosc=6MHZ时,T1在模式1最大定时为131.072ms > 5ms,所以T1在模式1可满足5ms定时需要。
初值计算:a=216- T定时/T机器=216- T定时×fosc/12=65536-5ms×6MHz/12=65536-5000/2=63036=F63CH
初始化编程
INIT: MOV TMOD,#10H ;T1工作在定时器方式,内部启动,模式1(即TMOD=0001XXXXB)
MOV TH1, #0F6H ;T1装入初值a
MOV TL1, #3CH
SETB TR1 ;启动T1计时
6-6.已知系统时钟频率为fosc=6MHZ,若要求T0在模式2进行250us定时,采用外部启动。请计算T0计数器的初值a,并对T0进行初始化编程。
答:由上题计算可知,当fosc=6MHZ时,T0在模式2最大定时为512us > 250us,所以T0在模式2可满足250us定时需要。
初值计算:a=28-T定时/T机器=256-250us/2us=256-125=131=83H
初始化编程
INIT: MOV TMOD,#0AH ;T0工作在定时器方式,外部启动,模式2(即TMOD=XXXX1010B)
MOV TL0, #83H ;T0装入初值a
MOV TH0, #83H ; 模式2时,TH0必须和TL0装入同样的初值,以便在溢出时自动重装初值。
SETB TR0 ;准备接收外部启动命令
6-7.已知系统时钟频率为fosc=24MHZ,若要求T0在模式1计数器方式,计满500个信号,向CPU提出中断申请,采用内部启动。问该系统对外部计数信号的频率最高是多少?请计算T0计数器的初值a,并对T0进行初始化编程。
答:在计数器方式下,T0每个机器周期采集一次P3.4引脚上的电平信号,当前一次采集到低电平而后一次采集到高电平(即相邻两次采集捕捉到一个上升沿)时,T0加1;因此为了有效的捕捉到外部计数信号的上升沿,对信号有如下要求:外部信号的高电平和低电平都必须维持1个机器周期以上(即高低电平的脉宽都必须不小于1个机器周期);由前一条件可知,外部计数信号的频率不得高于fosc/24(即外部计数信号的周期必须不小于2个机器周期)!
由以上分析可知:外部计数信号的频率最高为fosc/24=1MHZ。
计数方式下的初值计算:a=216-C所需计数=65536-500=65036=FE0CH
初始化编程:
ORG 0
LJMP INIT ;转到用户编制的初始化程序起始处
ORG 0BH ;T0中断入口地址
LJMP T0IPG ;转到T0中断服务子程序入口
ORG 100H ;此处假设初始化程序从程序存储器100H处开始
INIT: MOV TMOD, #05H ;设置T0为内部启动,计数方式,模式1(TMOD=XXXX0101B)
MOV TH0, #0FEH ;装入初值
MOV TL0, #0CH ;
SETB EA ;允许T0中断
SETB ET0
SETB TR0 ;启动T0计数
SJMP $ ;原地等待(表示CPU可做其它工作),等待T0计数溢出中断发生。
ORG 400H ;假设T0中断服务子程序从程序存储器400H处开始
T0IPG: ORL TL0, #0CH ;重装初值,不用MOV指令可消除误差,为什么,自己想一下。
MOV TH0, #0FEH
…… ;中断服务子程序需完成的实际动作
RETI ;由中断返回
END
说明:既然用到了中断,就必须对中断系统进行相关的初始化操作,以上程序中粗体部分为必须完成的初始化内容。
6-8.已知系统时钟频率为fosc=24MHZ,若要求T2工作在初值自动装入的定时/计数器工作模式0,进行50ms定时,每隔50ms向CPU申请一次中断。请计算T2计数器的初值a,并对T2进行初始化编程。
分析:T2工作在初值自动装入的定时/计数器模式0,即16位初值自动装入计数器,由于fosc=24MHZ时,其最大定时时间为65536*0.5us=32.768ms < 50ms,所以本题出错了,无解。
若fosc=12MHZ,可参见书上例6-6。
6-9.若有某51系列的单片机应用系统,试编制程序,分别采用三种方式使得P1.0上产生周期为200us的方波。方法1是将T1设置在模式1的定时器方式;方法2是将T1设置在模式2的定时器方式;方法3是将T2设置在信号发生器模式。设时钟频率为fosc=12MHZ。
分析算法:方波周期200us,即每过100us后,P1.0的状态变化一次。
方法1:初值a=65536-100us×12MHz/12=65436=FF9CH
ORG 0
LJMP MAIN
ORG 1BH
LJMP T1IPG
ORG 200H
MAIN: MOV TMOD, #10H ;T1内部启动,定时方式,模式1
MOV TL1, #9CH ;装入初值
MOV TH1, #0FFH
MOV SP, #60H ;堆栈指针初始化
SETB EA ;允许T1中断
SETB ET1
SETB TR1 ;启动T1定时
SJMP $ ;等待中断发生,也表示CPU可以去做任何其它事情!
ORG 400H
T1IPG: CPL P1.0 ;取反P1.0
ORL TL1, #9CH ;重装T1初值
MOV TH1, #0FFH
RETI ;中断返回
END
方法2:初值a=256-100us×12MHz/12=9CH,在此例中不采用中断,用软件查询完成定时,同学们可比较一下它们的区别。
ORG 0
LJMP MAIN
ORG 200H
MAIN: MOV TMOD, #20H ;T1内部启动,定时方式,模式2
MOV TL1, #9CH ;模式2下,TL1、TH1必须装入相同的初值。
MOV TH1, #9CH
SETB TR1
WAIT: JNB TF1, WAIT ;等待T1溢出(TF1=1)
CPL P1.0 ;T1溢出后(即100us到),取反P1.0
CLR TF1 ;清除溢出标志TF1
SJMP WAIT ;返回WAIT处,等待下次溢出
END
方法2的程序中有以下几点需要注意:
1) 如果使用T1中断,则溢出标志TF1在中断响应时由硬件自动清零,而当使用软件查询方法(即用指令JNB或JB来判断TF1状态)时,必须由程序清零(即CLR TF1)。
2) 模式2为自动装入初值模式,故在溢出产生后,不必用指令重新装入初值!
3) 使用查询方式,占用了CPU资源,CPU不能再执行其它功能,如果一定要执行其它功能的指令,则将不能及时地对TF1进行判断,一定会影响到方波输出的精度,所以用T0或T1产生定时时,一般总是使用其溢出中断。
方法3:因为T2工作在信号发生器模式下,由f信号=fosc/(4*(216-a)),所以初值a=216-fosc/4 f信号
因为方波周期为200us,即f信号=0.005MHz
所以a=65536-12/(4*0.005)=64936=FDA8H
ORG 0
LJMP MAIN
ORG 200H
MAIN: MOV T2CON, #00H
MOV T2MOD, #02H ;将T2设置为信号发生器方式,不需要T2中断即可完成信号发生功能
MOV TL2, #0A8H ;设置计数器初值
MOV TH2, #0FDH
MOV RCAP2L, #0A8H ;设置重装寄存器初值
MOV RCAP2H, #0FDH
SETB TR2 ;启动T2定时
SJMP $ ;等待,也表示CPU可以去做任何其它事情!
END
6-10.若有某51系列单片机应用系统,要求其利用T0的定时,编一个程序使得P1.2上产生周期为1S,脉冲宽度为100ms的脉冲波。设时钟频率为fosc=12MHZ。
分析:脉冲宽度指的是高电平的时间,即P1.2输出1,保持100ms,然后P1.2输出0,保持900ms。
已知fosc=12MHZ,则机器周期=1us,所以T0在模式1和模式2下分别可定时的最大时间为65536us和256us。无论何种模式都不能在一次定时中完成100ms的定时,故可采用模式1产生50ms(即50000us)定时中断,连续两次中断即完成了100ms定时,然后再连续18次中断即完成了900ms定时。
计算初值:a=65536-T定时×12/fosc=65536-50000=3CB0H
程序:
ORG 0 ;用户程序入口
LJMP MAIN ;转到主程序入口
ORG 0BH ;T0中断入口
LJMP T0IPG ;转到T0中断服务子程序入口
ORG 200H
MAIN: MOV TMOD, #01H ;T0工作在内部启动,定时方式,模式1
MOV TL0, #0B0H ;装入初值3CB0H
MOV TH0, #3CH
MOV IE, #82H ;允许T0中断,此处假定其它中断均被禁止
MOV SP, #60H ;堆栈指针初始化
SETB P1.2 ;设定P1.2的初始状态为高电平输出
MOV R0, #2 ;设置连续中断次数计数器R0(由于P1.2初始为高电平,所以R0=2)
;以上两条指令也可这样CLR P1.2 P1.2初始为低电平,所以R0=18
; MOV R0, #18
SETB TR0 ;启动T0计时
SJMP $ ;原地等待T0中断
ORG 400H ;中断服务子程序入口
T0IPG: DJNZ R0, QUIT ;判断连续中断次数到否,若未到,则直接返回
JB P1.2, LOW ;若已到连续中断次数,则判断P1.2当前状态
SETB P1.2 ;若P1.2当前状态为0,则1→P1.2
MOV R0, #2 ;将R0设为P1.2输出高电平时的连续中断次数(2)
SJMP QUIT ;由中断返回
LOW: CLR P1.2 ;若P1.2当前状态为1,则0→P1.2
MOV R0, #18 ;将R0设为P1.2输出低电平时的连续中断次数(18)
QUIT: ORL TL0, #0B0H ;返回前重装计数初值
MOV TH0, #3CH
RETI ;由中断服务子程序返回
END
注:可将T0IPG优化如下
ORG 400H ;中断服务子程序入口
T0IPG: DJNZ R0, QUIT ;判断连续中断次数到否,若未到,则直接返回
CPL P1.2 ;连续计数到后,先对P1.2取反
JNB P1.2, LOW ;若P1.2取反后为0,则转到LOW,对R0赋值18
MOV R0, #2 ;若P1.2取反后为1(即上条指令条件不成立),则对R0赋值2
SJMP QUIT ;由中断返回
LOW: MOV R0, #18 ;将R0设为P1.2输出低电平时的连续中断次数(18)
QUIT: ORL TL0, #0B0H ;返回前重装计数初值
MOV TH0, #3CH
RETI ;由中断服务子程序返回
END
附加题1:用T0测量外部正脉冲的宽度,脉冲信号由(P3.2)输入,假设系统fosc=12MHZ,待测脉冲宽度<65.536ms,将测量结果送入R2R3。
分析:测量脉冲宽度可借助于T0的外部启动定时方式,因为T0的外部启动信号就是(P3.2)上的高电平,故可将T0初值设为0,当外部启动信号到来后,T0开始计时;而当(P3.2)上信号变为低电平时T0停止计时,同时此信号的下降沿可触发外部中断0,用外部中断0的中断服务程序读取T0的当前值。
ORG 0
LJMP MAIN
ORG 3
LJMP X0IPG
ORG 200H
MAIN: MOV SP, #50H ;堆栈指针初始化
MOV TMOD, #09H ;T0外部启动,定时器方式,模式1
MOV TH0, #0 ;TH0、TL0初值为0
MOV TL0, #0
SETB IT0 ;外部中断0边沿触发模式
SETB EA ;开放中断
SETB EX0 ;允许外部中断0
SETB TR0 ;T0内部启动信号置1,准备好接收外部启动信号(即P3.2引脚上的高电平)
SJMP $ ;等待中断发生
ORG 400H
X0IPG: MOV R3, #TL0 ;将刚过去的那个高电平的宽度送入R2,R3
MOV R2, #TH0
MOV TH0, #0 ;TH0、TL0重装初值为0,为下次测量作好准备
MOV TL0, #0
RETI
END
若上题中被测信号的宽度大于65.536ms,即可能超过两个字节,我们假定其结果不超过3个字节(即在fosc=12MHZ的条件下,被测信号宽度小于16777.216ms),这时为正确记录整个宽度,必须借助一个高位字节寄存器记录第三字节的内容,当T0计时溢出时,该寄存器加1。
程序修改如下(设结果放入R1,R2,R3)
ORG 0
LJMP MAIN
ORG 3 ;外部中断0入口
LJMP X0IPG
ORG 11 ;T0中断入口
INC 30H ;T0每溢出一次,高位字节寄存器30H加1
RETI ;由T0中断返回
ORG 200H
MAIN: MOV SP, #50H ;堆栈指针初始化
MOV TMOD, #09H ;T0外部启动,定时器方式,模式1
MOV 30H, #0 ;清除高位字节寄存器
MOV TH0, #0 ;TH0、TL0初值为0
MOV TL0, #0
SETB IT0 ;外部中断0边沿触发模式
SETB EA ;开放中断
SETB EX0 ;允许外部中断0
SETB ET0 ;允许T0中断
SETB TR0 ;T0内部启动信号置1,准备好接收外部启动信号(即P3.2引脚上的高电平)
SJMP $ ;等待中断发生
ORG 400H
X0IPG: MOV R3, #TL0 ;将刚过去的那个高电平的宽度送入R1,R2,R3
MOV R2, #TH0
MOV R1, 30H
MOV TH0, #0 ;TH0、TL0重装初值为0,为下次测量作好准备
MOV TL0, #0
MOV 30H, #0 ;清除高位字节寄存器
RETI
附加题2:用T0测量外部脉冲信号的周期,脉冲信号由(P3.2)输入,假设系统fosc=12MHZ,待测脉冲周期<65.536ms,将测量结果送入R2R3。
分析:测量信号周期可借助T0的内部定时方式来完成,当外部脉冲信号的第一个下降沿到来时,触发中断,中断服务子程序启动T0计时(T0的初值预设为0);当第二个下降沿再次触发中断时,中断服务子程序将T0当前值寄存器(TH0,TL0)的内容送入结果单元R2,R3,同时清零TH0,TL0,作为下一次测量的起点;当第三个下降沿触发中断时,中断服务子程序重复第二次中断的动作,即输出结果,清零TH0,TL0。依此类推,子子孙孙无穷匮矣。
ORG 0
LJMP MAIN
ORG 3
LJMP X0IPG
ORG 200H
MAIN: MOV SP, #50H ;堆栈指针初始化
MOV TMOD, #01H ;T0内部启动,定时器方式,模式1
MOV TH0, #0 ;TH0、TL0初值为0
MOV TL0, #0
SETB IT0 ;外部中断0边沿触发模式
SETB EA ;开放中断
SETB EX0 ;允许外部中断0
SJMP $ ;等待中断发生
ORG 400H
X0IPG: JB TR0, OUT ;TR0=1,标志T0已开始计时动作,所以可将结果输出
SETB TR0 ;若上式不成立,则TR0=0,表示这是第一次进入中断,开启T0计时,然后返回
SJMP QUIT
OUT: MOV R3, #TL0 ;将刚过去的那个信号周期送入R2,R3
MOV R2, #TH0
MOV TH0, #0 ;TH0、TL0重装初值为0,为下次测量作好准备
MOV TL0, #0
QUIT: SETB TR0
RETI
本文来源:https://www.2haoxitong.net/k/doc/bc047cd0a8956bec0875e395.html
文档为doc格式