2019-05-31 23:49:49 jianming21 阅读数 645


前言

控制指令是将程序跳转到某个指定的地址,在顺序执行
控制指令是通过修改PC的内容来实现跳转的功能
PC的内容是将要执行的下一跳指令的地址


一、无条件转移指令

LJMP英文全称:Absolute Jump
AJMP英文全称:Long Jump
SJMP英文全称:Short Jump
JMP英文全称:Jump


LJMP addr16

指令名称:长转移指令
目的:程序无条件转向64KB程序存储器地址空间的任何单元
源操作数:16位跳转目标地址

助记符 功能 对标志位影响 字节数 周期数
P OV AC CY
LJMP addr16 addr16 -> PC × × × × 3 2
  • 地址范围为0000H—FFFFH;
  • addr16常采用标号地址(如:LOOP、LOOP1、MAIN、START、DONE、NEXT1……)表示;

AJMP addr11

指令名称:绝对转移指令
目的:程序无条件转向2KB程序存储器地址空间的任何单元
源操作数:11位跳转目标地址

助记符 功能 对标志位影响 字节数 周期数
P OV AC CY
AJMP addr16 (PC) + 2 -> PC, addr11 -> PC* × × × × 2 2

:PC* 表示 PC10 ~ 0,共计11位;

  1. AJMP跳转范围是AJMP后面指令的第一个字节开始的同一2KB范围,也就是说先对PC+2(命令长度为2B),在跳转到以PC当前位置为基准的2KB范围内,如下例子;
  2. AJMP addr11表示跳转到以 PC15 PC14PC13PC12PC11a10a9a8a7a6a5a4a3a2a1a0 为目标地址,最高5位为PC源最高5位的内容,剩下11位为addr11中对应的内容;
  3. AJMP因跳转的范围在LJMP(64KB)和SJMP(256B)之间,也可以叫中跳转指令。

例 若AJMP指令地址为2FFEH,跳转的范围为

  • PC + 2 = 3000H,故目标转移地址必在3000H—37FFH这2KB区域中;

例 若AJMP指令地址为2FFDH,跳转的范围为

  • PC + 2 = 2FFFH,故目标转移地址必在 2800H—2FFFH这2KB区域中;

SJMP rel

指令名称:相对短转移指令
目的:程序无条件转向256B程序存储器地址空间的任何单元
源操作数:8位跳转相对地址

助记符 功能 对标志位影响 字节数 周期数
P OV AC CY
SJMP rel (PC) + 2 -> PC, (PC) + rel -> PC × × × × 2 2
  1. rel是一个带符号的偏移字节数,其范围是-128~+127
  2. 00H~7FH(0000 0000B ~ 0111 1111B,第一个位为符号位)表示为0 ~ +127,正向转移;
  3. 80H ~ FFH(1000 0000B ~ 1111 1111B)表示为-128 ~ -1,反向转移;
  4. SJMP rel执行时是先将PC内容加2,在加相对地址;

例 (PC) = 0100H

  • SJMP 55H:表示正向转移到0100H + 2 + 0055H = 0157H地址;
  • SJMP F6H:表示反向转移到0100H + 2 + FFF6H = 00F8H地址。
  1. rel可以是转移的目的地址的标号;

例 SJMP RELADR,其中RELADR的标号为0123H,(PC) = 0100H;

  • 相对转移量 rel = 0123H - (0100 + 2)H = 21H;
  • rel并没有直接写出来,需要计算。

JMP @A + DPTR

指令名称:间接移指令/散转指令
目的:程序无条件转向DPTR和A之和的目标地址空间单元
源操作数:16位的DPTR和8位的累加器A

助记符 功能 对标志位影响 字节数 周期数
P OV AC CY
JMP @A + DPTR (A) + (DPTR) -> PC × × × × 1 2
  1. DPTR中存放16位基地址,累加器A存放目标转移地址对基地址的偏移量;
  2. 机器通过变址寻址转移指令便可实现程序的分支转移;
  3. DPTR中的值是固定的,通过修改A中的内容来选择跳转目标地址;
  4. 范围:以DPTR内容为首地址的256B范围内;

例 (DPTR) = 1000H,修改A中的内容

  • 设 A = 10H, (PC) = 1010H;
  • 设 A = 20H, (PC) = 1020H;
  • 设 A = 30H, (PC) = 1030H;

关于SJMP、AJMP、LJMP的选择

SJMP 如果跳转到的标号地址距离当前PC所指的地址小于256字节,用SJMP
AJMP 如果跳转到的标号地址距离当前PC所指的地址小于2K字节,用AJMP
LJMP 如果跳转到的标号地址距离当前PC所指的地址小于64K字节,用LJMP


二、条件转移指令

JZ英文全称:Jump if Zero
JNZ英文全称:Jump if Not Zero
CJNE英文全称:Compare Jump if Not Equal
DJNE英文全称:Compare Jump if Not Equal


JZ rel

指令名称:判零转移指令
目的:对累加器A中的内容进行零的判定
源操作数:8位跳转相对地址

JNZ rel

指令名称:判零转移指令
目的:对累加器A中的内容进行零的判定,同JZ
源操作数:8位跳转相对地址

助记符 功能 对标志位影响 字节数 周期数
P OV AC CY
JZ rel (PC) + 2 -> PC; 若 A = 0,则 (PC) + rel -> A;若 A != 0,则 顺序执行,不跳转 × × × × 2 2
JNZ rel (PC) + 2 -> PC; 若 A != 0,则 (PC) + rel -> A;若 A = 0,则 顺序执行,不跳转 × × × × 2 2
  1. JZ从英文字面上理解成A = Zero即0,就Jump,JNZ从英文字面上理解成A not Zero即!0,就Jump;
  2. 偏移量是一个带符号的8位,所有偏移量取值范围位-127~+128,同SJMP指令;
  3. 实际汇编中,rel用目标标号替代,如“JNZ NEXT”,此时rel并非一个在-127~+128之间的实际数,汇编时自动生成相对地址,同SJMP;

例 (PC) = 0100H

  • JNZ 55H:当 (A) = 01H, 非零时,表示正向转移到0100H + 2 + 0055H = 0157H地址;当 (A) = 00H,PC = 0102H,继续执行下一条指令,不跳转;

CJNE XXX, XXX, rel

指令名称:比较转移指令
目的:对指定的目的字节和源字节进行比较,不等转移,相等继续执行
源操作数:8位跳转相对地址,累加器A,直接地址direct,立即数#data,间接寄存器@Ri,寄存器Rn

助记符 功能 对标志位影响 字节数 周期数
P OV AC CY
CJNE A, direct, rel (PC) + 3 -> PC; 若(direct) < (A),则 (PC) + rel -> PC且 0 -> CY;若(direct) > (A),则 (PC) + rel -> PC且 1 -> CY;若 (direct) = (A),则顺序执行,不跳转且 0 -> CY; × × × 3 2
CJNE A, #data, rel (PC) + 3 -> PC; 若#data < (A),则 (PC) + rel -> PC且 0 -> CY;若#data > (A),则 (PC) + rel -> PC且 1 -> CY;若 #data = (A),则顺序执行,不跳转且 0 -> CY; × × × 3 2
CJNE Rn, #data, rel (PC) + 3 -> PC; 若#data < (Rn),则 (PC) + rel -> PC且 0 -> CY;若#data > (Rn),则 (PC) + rel -> PC且 1 -> CY;若 #data = (Rn),则顺序执行,不跳转且 0 -> CY; × × × 3 2
CJNE @Ri, #data, rel (PC) + 3 -> PC; 若#data < ((Ri)),则 (PC) + rel -> PC且 0 -> CY;若#data > ((Ri)),则 (PC) + rel -> PC且 1 -> CY;若 #data = ((Ri)),则顺序执行,不跳转且 0 -> CY; × × × 3 2
  1. 三字节指令:CJMP (目的字节), (源字节), rel
  2. 执行CJMP指令结果可以简单理解,想等继续执行,CY清零;不相等,跳转,CY置一还是清零看比较大小;
  3. 目的字节 大于 源字节(前 大于 后)CY清零;
  4. 目的字节 小于 源字节(前 小于 后)CY置一;
  5. 程序转移范围以(PC) + 3为起始地址的-128 ~ +127共256B;

(A) = 03H,(10) = 04H,CY = 0,rel = 30H,(PC) = 0100H

  • CJMP A, 10H
    (A) = 03H != (10H) = 04H,(PC) = (PC) + 3 + rel = 0133H;
    (A) < (10H) ,CY = 1;

DJNZ XXX, rel

指令名称:循环转移指令
目的:以直接地址或寄存器Rn的单元内容作为循环控制寄存器使用,利用其进行循环
源操作数:8位跳转相对地址,寄存器Rn,直接地址direct

助记符 功能 对标志位影响 字节数 周期数
P OV AC CY
DJNZ Rn, rel (PC) + 2 -> PC;(Rn) - 1 -> Rn;当(Rn) != 0时,则(PC) + rel -> PC;当(Rn) = 0时,则结束循环,程序往下执行 × × × × 2 2
DJNZ direct, rel (PC) + 3 -> PC;(direct) - 1 -> direct;当(direct) != 0时,则(PC) + rel -> PC;当(direct) = 0时,则结束循环,程序往下执行 × × × × 3 2
  1. 执行一次该语句,第一操作数减一,判断字节变量是否为0,不为0则继续循环;为0,则退出循环;
  2. DJNZ可以理解高级语言中的for (int i = n; i > 0; i–)循环语句;

例 设(R1)= 07H,rel = 10H,(PC) = 0100H

  • DJNZ R1, rel
    R1循环07H,需要进行7次循环才为00H;
    循环7次后,(PC) = 0114H;
    跳转后, (PC) = 0124H

三、调用和返回指令

ACALL英文全称:Absolute subroutine Call
LCALL英文全称:Long subroutine Call
RET英文全称:Return from Subroutine
RETI英文全称:Return from Interruption

调用和返回之间的过程:

  1. CPU在主程序中遇到调用子程序ADD1的指令;
  2. CPU下一条指令第一字节的地址(PC值,断点处)压入堆栈中;
  3. 栈指针(SP) + 2,并将ADD1的起始地址送入PC,开始执行子程序了。
  4. 子程序执行完,通过RET指令回调到主函数;
  5. 将SP中的地址弹回PC中,回到主函数中。

ACALL addr11

指令名称:短调用指令
目的:调用2KB范围内的所指定的子程序
源操作数:11位目的地址

助记符 功能 对标志位影响 字节数 周期数
P OV AC CY
ACALL addr11 (PC) + 2 -> PC;(SP) + 1 -> (SP), (PCL) -> (SP),(SP) + 1 -> (SP), (PCH) -> (SP),addr(10~0) -> PC(10~0); × × × × 2 2

  • PCL为PC7 ~ 0即PC的低8位值;
  • PCH为PC15 ~ 8即PC的高8位值;
  1. 断点压入栈的过程
    将栈指针SP向下移动一个单元空间(对其加一操作);
    将PC的低8位送入SP的内容指向的单元空间;
    再将栈指针SP向下移动一个单元空间;
    将PC的高8位送入SP的内容指向的单元空间;
  2. 跳转到子程序过程
    将addr10 ~ 0送入PC10 ~ 0, PC15 ~ 11保持不变,形成16位转移目的地址;
    PC就指向子程序的首地址;
  3. 所调用的子程序首地址必须在ACALL指令后第一字节开始的2KB范围内的ROM中。

例 (SP) = 40H,(PC) = 0100H,子程序ADD1首地址 0110H;

  • 执行ACALL ADD1
  • (PC) = (PC) + 2 = 0102H;先将PC加2,因指令长2字节;
  • (41H) = 02H ;先将PC的低8位放入SP指针内容的空间地址;
  • (42H) = 01H ;先将PC的高8位放入SP指针内容的空间地址,此时(SP) = 42H;
  • (PC) = 0110H;PC指向了子程序ADD1首地址;

LCALL addr16

指令名称:长调用指令
目的:调用64KB范围内的所指定的子程序
源操作数:16位目的地址

助记符 功能 对标志位影响 字节数 周期数
P OV AC CY
ACALL addr11 (PC) + 3 -> PC;(SP) + 1 -> (SP), (PCL) -> (SP),(SP) + 1 -> (SP), (PCH) -> (SP),addr(15~0) -> PC; × × × × 3 2

  • PCL为PC7 ~ 0即PC的低8位值;
  • PCH为PC15 ~ 8即PC的高8位值;
  1. 断点压入栈的过程
    将栈指针SP向下移动一个单元空间(对其加一操作);
    将PC的低8位送入SP的内容指向的单元空间;
    再将栈指针SP向下移动一个单元空间;
    将PC的高8位送入SP的内容指向的单元空间;
  2. 跳转到子程序过程
    将addr15 ~ 0送入PC15 ~ 0,形成16位转移目的地址;
    PC就指向子程序的首地址;
  3. 所调用的子程序首地址可以设置在64KB范围内的ROM中。

例 (SP) = 07H,(PC) = 0123H,子程序ADD1首地址 5678H;

  • 执行LCALL ADD1
  • (PC) = (PC) + 3 = 0126H;先将PC加3,因指令长3字节;
  • (08H) = 26H ;先将PC的低8位放入SP指针内容的空间地址;
  • (09H) = 01H ;先将PC的高8位放入SP指针内容的空间地址,此时(SP) = 09H;
  • (PC) = 5678H;PC指向了子程序ADD1首地址。

ACALL是你调用的子程序入口地址距离当前PC所指地址需介于0~2K,LCALL是0~64K


RET

指令名称:子程序返回指令
目的:从子程序返回

RETI

指令名称:中断返回指令
目的:从中断返回

助记符 功能 对标志位影响 字节数 周期数
P OV AC CY
RET ((SP)) -> PCH,(SP) - 1 -> SP,((SP)) -> PCL,(SP) - 1 -> SP × × × × 1 2
RETI ((SP)) -> PCH,(SP) - 1 -> SP,((SP)) -> PCL,(SP) - 1 -> SP × × × × 1 2

  • PCL为PC7 ~ 0即PC的低8位值;
  • PCH为PC15 ~ 8即PC的高8位值;
  1. 当子程序执行此指令表示子程序结束了
  2. 恢复断点过程
    先将(SP)内容执行的地址空间作为PC的高8位;
    SP指向上一个地址空间;
    在将(SP)内容执行的地址空间作为PC的低8位;
    SP指向上一个地址空间;
  3. 此时PC中有返回目的地址的16位;

例 (SP) = 09H,(09H) = 01H,(08H) = 26H,(PC) = 5678H

  • 在子程序中执行RET
  • (PC) = 0178H;先将(SP)内容执行的地址空间内容作为PC的高8位;
  • (SP) = 08H;将(SP)内容减1;
  • (PC) = 0126H;先将(SP)内容执行的地址空间内容作为PC的低8位;
  • (SP) = 07H;将(SP)内容减1;
  • 此时已经返回到地址为0126H的地址。

四、位条件转移类指令

JC英文全称:Jump if the Carry flag is set
JNC英文全称:Jump if Not Carry
JB英文全称:Jump if the Bit is set
JNB英文全称:Jump if the Bit is Not set
JBC英文全称:Jump if the Bit is set and Clear the bit


JC rel

指令名称:判布尔累加器C转移指令
操作数:8位目的地址

JNC rel

指令名称:判布尔累加器C转移指令
操作数:8位目的地址

助记符 功能 对标志位影响 字节数 周期数
P OV AC CY
JC rel (PC) + 2 -> PC,若(C) = 1,则(PC) + rel -> PC;若(C) = 0,则顺序执行 × × × × 2 2
JNC rel (PC) + 2 -> PC,若(C) = 0,则(PC) + rel -> PC;若(C) = 1,则顺序执行 × × × × 2 2
  1. 累加器C是一个布尔累加器,位累加器;
  2. 根据累加器C中的值进行判断转移。

JB bit, rel

指令名称:判位变量转移指令
操作数:位变量,8位目的地址

JNB bit, rel

指令名称:判位变量转移指令
操作数:位变量,8位目的地址

助记符 功能 对标志位影响 字节数 周期数
P OV AC CY
JB bit rel (PC) + 3 -> PC,若(bit) = 1,则(PC) + rel -> PC;若(bit) = 0,则顺序执行 × × × × 3 2
JNB bit rel (PC) + 3 -> PC,若(bit) = 0,则(PC) + rel -> PC;若(bit) = 1,则顺序执行 × × × × 3 2
  1. 根据位变量bit的值进行判断转移;
  2. JB、JNB相对于JC、JNC,其是对位变量bit进行判断转移,其他性质都一样。

JBC bit, rel

指令名称:判位变量并清零转移指令
操作数:位变量,8位目的地址

助记符 功能 对标志位影响 字节数 周期数
P OV AC CY
JBC bit rel (PC) + 3 -> PC,若(bit) = 1,则(PC) + rel -> PC,0 -> CY;若(bit) = 0,则顺序执行 × × × × 3 2
  1. 相比于JB,JBC仅仅是增加CY清零的步骤;
  2. 在位变量bit为1时,不仅仅要跳转,还要CY清零。

五、空操作指令

NOP英文全称:No Operation

NOP

指令名称:空操作指令

助记符 功能 对标志位影响 字节数 周期数
P OV AC CY
NOP 空操作 × × × × 1 1

51单片机之系统指令

51单片机之逻辑运算指令ANL、ORL、XRL等

51单片机之数据转移指令MOV、MOVX、MOVC等

51单片机之位操作指令SETB、CPL等

51单片机之算术运算指令ADDC、SUBB等

参考


由本人水平有限,文章难免有错误,望告知

2006-12-15 10:07:00 aaaaatiger 阅读数 809

$伪指令,表示当前程序地址或者PC寄存器值
譬如,sjmp $                             //也就是在本条指令上死循环,直到发生中断请求。死循环,等看门狗复位

 

BTW:
main()
{
    while(1){}
    exit(SUCCESS);
}



 

2011-04-30 18:05:00 dagobert1989 阅读数 341

 

认识单片机


输入输出引脚P0,P1,P2,P3
51单片机有4个并行I/O口,分别是P0,P1,P2,P3口。
每个并行口由8个引脚组成,都可以用作普通I/O操作。
除了P1口外,其他并行口都具有第二功能。

:-)单片机想正常运行必须具备的条件:
1.必须加电
2.必须接晶振电路
3.必须接复位电路
4.如果用内部程序存储器,31引脚必须接+5V

     ORG 0000H
     SJMP START
     ORG 0030H
START:     MOV SP,#60H  //要养成习惯一定要在初始化中把堆栈设置在一般
                            // 区域中
     MOV P1,#0FFH
;-------------主程序--------
MAIN:     CLR P0.7
     CALL DELAY
     SETB P0.7
     CALL DELAY
     SJMP MAIN
;------------延时子程序-----
DELAY:     MOV R0,#250
D2:     MOV R1,#250
D1:      DJNZ R1,D1
     DJNZ R0,D2
     RET
     END

ORG是一条伪指令,仅用来宣布其下面的一条指令编译后生成的二进制代码存放的
地点。




 

程序:
#include <reg52.h>   
sbit D1=P1^0;
void main()         //让第一个灯亮
{
     D1=0;
}


共阳、共阴数码管显示原理、定时器工作方式介绍、重点讲述工作方式 2 、中断概念及中断函数写法、外部中断试验、定时器中断应用。









2018-12-25 20:02:28 qq_39077333 阅读数 152

编程题目:

1.AD/DA

a.锯齿波

		ORG		2000H
START:
		MOV		R0,#0FEH;P0端口地址
		MOV		A,#00H
LOOP:
		MOVX		@R0,A			
		INC		A	;数据递增
		SJMP		LOOP

b.三角波

		ORG		2000H
START:
		MOV		R0,#0FEH
		MOV		A,#00H
		MOVX		@R0,A
UP:		
		MOVX		@R0,A  ;数据递增
		INC		A
		JNZ		UP
DOWN:
		DEC		A			;;数据递减
		MOVX		@R0,A
		JNZ		DOWN
		SJMP		UP

c.矩形波

		ORG		2000H
START:
		MOV		R0,#0FEH		;;FE为**P0**口的地址
LOOP:
		MOV		A,#data1	;;第一个电平
		MOVX		@R0,A
		LCALL		DELAY1
		MOV		A,#data2	;;第二个电平
		MOVX		@R0,A
		LCALL		DELAY2
		SJMP		LOOP

技术指标:

(1)分辨率;(2)建立时间;(3)精度

(1)分辨率指输入给AD转换器的单位数字量变化引起的模拟量输出变化。

(2)描述AD转换器转换快慢的一个参数

(3)位数越多精度越高

D/A的两种工作方式:(硬件链接方式)

a.单缓冲方式:指DAC0832内部的两个数据缓冲器有一个处于直通方式,另外一个处于受C51控制的锁存方式。在实际应用当中,如果只有一路模拟量输出,或者不要求多路同步输出时,可采用单缓冲方式。

在这里插入图片描述

b.双缓冲方式:对于DA转换,要求同步输出时,必须采用双缓冲同步方式,这种方式下,数据量的输入和AD转换是分两步进行的。单片机必须通过LE1来锁存待转换数字量,通过LE2来启动D/A转换

在这里插入图片描述

ADC0809硬件联接

技术指标:

(1)转换时间和转换效率(转换时间的倒数) ;(2)分辨率:1/2nx100%; n为量化时的位数

数码管

1.段码的定义:

在这里插入图片描述

代码位 D7 D6 D5 D4 D3 D2 D1 D0
显示段 dp g f e d c b a

a.静态显示

b.动态显示

​ 原理:在某一时刻,只让某一位选线处于选通状态,而其他各个位选线处于关闭状态,同时段码线上输出相应要显示的字符的段选信号,这样就可以使得多个数码管中的一个发光显示,而其他的数码管处于熄灭状态,在下一个时刻同样的来显示另外的数码管。虽然字符在不同的时间显示,但由于LED显示器的余晖和人眼的视觉暂留效应作用,只要每一位显示的时间间隔足够短,就会出现多个数码管同时显示的假象!!!

#include <reg52.h>

typedef unsigned int u16;	  
typedef unsigned char u8;

#define seg P0
#define sel P2

u8 smgduan[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};// 段选
u8 d1=0,d2=0,d3=0,d4=0;			
bit	flag=0;		
u8	i=0;									
								
void delay5ms(){
   unsigned char a,b;
    for(b=19;b>0;b--)
        for(a=130;a>0;a--);  
}
void InitTimer0(void){
    TH0 = 0x0D8;
    TL0 = 0x0F0;
    EA = 1;
    ET0 = 1;
    TR0 = 1;
}
void InitTimer1(void){
    TH1 = 0x0EC;
    TL1 = 0x78;
    EA = 1;
    ET1 = 1;
    TR1 = 1;
}

void InitExT0(void){
	EA = 1;
	EX0 = 1;
	IT0 = 1;		//“0”时,为电平触发,为“1”时,为下降沿触发
}
void InitExT1(void){
	EA = 1;
	EX1 = 1;
	IT1 = 1;		//“0”时,为电平触发,为“1”时,为下降沿触发
}
void key_clear()interrupt 0 { //外中断0控制清楚(P3^2)
	d1=d2=d3=d4=0;
	flag=0;
}

void key_stop()interrupt 2 {	//外中断1控制暂停(P3^3)
		flag = ~flag;
}

void cnt()interrupt 1{				//定时器中断 10ms计数
	TH0 = 0x0D8;
  TL0 = 0x0F0;
	if(flag==0){
			if(d1==9){
				d1 = 0;
				if(d2 == 9){
					d2 = 0;
					if(d3==9){
						d3=0;
						if(d4==5)
							d4=0;
						else
							d4++;
					}	
					else 
						d3++;
				}
				else 
					d2++;
			}
			else 
				d1++;
		}
	else
		;
}

void delay()interrupt 3{			//定时器中断 5ms数码管扫描速率
	TH1 = 0x0EC;
  TL1 = 0x78;
	i++;
	seg = 0x00;
	if(i==4)
		i=0;
}
void main(){
	TMOD=0x11;		
//0001_0001(<GATE><C/T><M1><M0>)//定义方式1,不启动多控制中断方式,计数模式(用内部时钟信号)
	IP=1;
//IP默认值为00H,此时优先级顺序为:外部中断0 > 定时/计数器0 > 外部中断1 > 定时/计数器1 > 串行中断 
//<--><--><PT2><PS:串口><PT1:T1中断><PX1:ET1中断><PT0:T0中断><PX0:ET0中断>
	InitExT0();
	InitExT1();
	InitTimer0();
	InitTimer1();
	
while(1){
	sel =i;
	switch(i){
		case 0:	seg = smgduan[d4];break;
		case 1: seg = smgduan[d3]+128;break;
		case 2: seg = smgduan[d2];break;
		case 3: seg = smgduan[d1];break;
		default: seg = 0;
	}
}	
}

矩阵键盘

2.按键消抖原理

常用软件方法去抖,即检测出键闭合后执行一个延时程序,5ms~10ms的延时,让前沿抖动消失后再一次检测键的状态,如果仍保持闭合状态电平,则确认为真正有键按下。当检测到按键释放后,也要给5ms~10ms的延时,待后沿抖动消失后才能转入该键的处理程序。>

一般来说,软件消抖的方法是不断检测按键值,直到按键值稳定。实现方法:假设未按键时输入1,按键后输入为0,抖动时不定。可以做以下检测:检测到按键输入为0之后,延时5ms~10ms,再次检测,如果按键还为0,那么就认为有按键输入。延时的5ms~10ms恰好避开了抖动期。

3.矩阵键盘:

#include <reg51.h>

#define uchar unsigned char
#define uint 	unsigned int
	
void matrixkeyscan()
{
uchar temp,key;
    P3=0xfe;
    temp=P3;
    temp=temp&0xf0;
    if(temp!=0xf0)
    {
     delayms(10);	
	temp=P3;
	temp=temp&0xf0;
      if(temp!=0xf0)
      {
        temp=P3;
        switch(temp)
        {
          case 0xee:
               key=0;
               break;
          case 0xde:
               key=1;
               break;
          case 0xbe:
               key=2;
               break;
          case 0x7e:
               key=3;
               break;
         }
         while(temp!=0xf0)
         {
           temp=P3;
           temp=temp&0xf0;
         }
        display(key);
      }
    }
    P3=0xfd;
    temp=P3;
    temp=temp&0xf0;
    if(temp!=0xf0)
    {
      delayms(10);
      temp=P3;
      temp=temp&0xf0;
      if(temp!=0xf0)
      {
        temp=P3;
        switch(temp)
        {
          case 0xed:
               key=4;
               break;
          case 0xdd:
               key=5;
               break;
          case 0xbd:
               key=6;
               break;
          case 0x7d:
               key=7;
               break;
         }
         while(temp!=0xf0)
         {
           temp=P3;
           temp=temp&0xf0;
         }
         display(key);
      }
      }
    P3=0xfb;
    temp=P3;
    temp=temp&0xf0;
    if(temp!=0xf0)
    {
      delayms(10);
			temp=P3;
      temp=temp&0xf0;
      if(temp!=0xf0)
      {
        temp=P3;
        switch(temp)
        {
          case 0xeb:
               key=8;
               break;
          case 0xdb:
               key=9;
               break;
          case 0xbb:
               key=10;
               break;
          case 0x7b:
               key=11;
               break;
         }
         while(temp!=0xf0)
         {
           temp=P3;
           temp=temp&0xf0;
         }
        display(key);
      }
      }
    P3=0xf7;
    temp=P3;
    temp=temp&0xf0;
    if(temp!=0xf0)
    {
      delayms(10);
      temp=P3;
      temp=temp&0xf0;
      if(temp!=0xf0)
      {
        temp=P3;
        switch(temp)
        {
          case 0xe7:
               key=12;
               break;
          case 0xd7:
               key=13;
               break;
          case 0xb7:
               key=14;
               break;
          case 0x77:
               key=15;
               break;
         }
         while(temp!=0xf0)
         {
           temp=P3;
           temp=temp&0xf0;
         }
        display(key);
      }
    }
}

串口

1.相关寄存器:

a.中断允许寄存器(IE

EA ES ET1 EX1 ET0 Ex0
AFH ACH ABH AAH A9H A8H

c.串行口中断标志寄存器(SCON

SM0 SM1 SM2 REN TB8 RB8 TI RI
控制模式 控制模式 控制多机通讯 使能接收 发送的第8位数据 j接收的第8位数据 发送中断标志位 接收中断标志位

d.定时器/计数器控制寄存器(TMOD

GATE C/T M1 M0 GATE C/T M1 M0
T1 控制段 1:计数/0:计时 模式控制(H) 模式控制(L) T0控制段 1:计数/0:计时 模式控制(H) 模式控制(L)

e. 串口波特率控制寄存器(PCON

SMOD
波特率控制

2.初始化程序设计:(波特率只和定时器/计数器1有关

void init_serialcomm(void)
{
    SCON  = 0x50;       
//SCON: mode 1, 8-bit【无多机通讯】 REN  <M0><M1><M2><REN><TB8><RB8><TI><RI>
    TMOD |= 0x20;       
 //TMOD: timer 1, mode 2,8-bit  <GATE><C/T><M1><M0><GATE><C/T><M1><M0>==[计数器1][计数器0]
    PCON |= 0x80;       
//SMOD=1;加倍波特率 		<SMOD><--><--><--><--><--><-->
    TH1 = 0xF4;       
//Baud:4800  fosc=11.0592MHz 	 <计数器方式2,为8位计数器,自动装载,由TH1--TL1>
    IE |= 0x90;       
//Enable Serial Interrupt 	 <EA> <X> <X> <ES> <ET1> <EX1> <ET0> <EX0>
    TR1 = 1;          
// timer 1 run 		 驱动计数器
}

3.多机通讯过程:

a.原理:

​ 在串行口以方式2或者方式3接收时,若SM2=1,表示设置为多及通信,这时:

​ 1.接收到的第9为数据为1时,数据才装入SBUF并且置中断标志RI=1,向CPU发出中断请求

​ 2.接收到的第9为数据为0时,则不会产生中断标志,信息被抛弃。

b.多机通讯的工作过程

​ 主机的RXD与所有从机的TXD相连接。

​ (1)从机初始化程序串行口中断,将串行口编程为方式2或者方式3接收,即9为数据异步通信方式,且SM2和REN位置1,使得从机只处于多及通讯且接收地址帧的状态。

​ (2)在主机和某一个从机通信之前,先将对应的设备地址通过串口发送出去,地址信息第9位为“1”,【和传送数据的区别在于数据的第9位为“0”】。当主机向各从机发送地址时,各从机的串口接收到的第9为数据为RB8=1;且由于SM2=1,则中断标志位RI置“1”,从机响应串口中断,执行中断服务程序,在中断服务程序中,判断主机发送的地址是否是本机的地址,若是本机地址,则使该从机SM2=0(即关闭多机通讯方式),准备接收主机发送的数据;若不相符合,则仍然保持SM2=1;【因为数据的第9位为0,SM2=0时对这一位不敏感;但是当SM2=1时,只对这一位的高电平敏感,从而实现定向传数据【多机通讯】】

在这里插入图片描述

4.实验程序(AD采样串口传输)

#include <reg51.h>

#define uchar unsigned char
#define uint 	unsigned int
	
#define sel P1
#define seg P0
uchar i;

uchar code smgduan[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};// 段选

sbit 	cs=			P2^4;
sbit	dclk = 	P2^7;
sbit	din = 	P2^6;
sbit	dout = 	P2^5;

void delay(uint i){

while(i--);
}

void XPT2046_writebyte(uchar wx)  //串行输入1个字节的控制字
{  	uchar i;
		dclk = 0;
	for(i=0;i<8;i++)
	{	din=wx>>7;
		wx<<=1;
		dclk=0;
		dclk=1;		  //上跳沿输入
	}
}

uint XPT2046_read()	 //读出12位的转换数据
{	uint rx=0;
	uchar i;
	for(i=0;i<12;i++)
	{	rx<<=1;
		dclk=1;
		dclk=0;
		rx|=dout;		//下跳沿输出
	}
	return(rx);
}

uint getdata(uchar cmd)
{
	uchar i;
	uint value;
	dclk = 0;
	cs = 0;
	XPT2046_writebyte(cmd);
	for(i=6; i>0; i--); 	//延时等待转换结果
	dclk = 1;	
	dclk = 0;
	value=XPT2046_read();
	cs = 1;
	return value;	
}

void initcomm(void)
{
    SCON=0x50;  //设置为工作方式1 0101 0000
    TMOD=0x20;  //设置计数器工作方式2
    PCON=0x80;  //波特率加倍
    TH1=0xF3;   //计数器初始值,波特率为4800
    TL1=0xF3;
    EA=1;       //打开总中断
    ES=1;       //打开串口中断
    TR1=1;      //打开计数器  	
}

void uart_rx(uchar ch)
{
    SBUF=ch;
    while(TI==0);
    TI=0;
}

void main(){
	uint	send_data = 0;
	uchar d1,d2,d3,d4;
	uchar i,j;
	initcomm();

		while(1){
			send_data=getdata(0xa4);
			d4=send_data/1000;
			send_data = send_data%1000;
			d3=send_data/100;
			send_data = send_data%100;
			d2=send_data/10;
			send_data = send_data%10;
			d1=send_data/1;
			for(j=0;j<10;j++){
				for(i=0;i<4;i++){
					delay(300);
					sel =i;
				switch(i){
						case 0:	seg = smgduan[d4];break;
						case 1: seg = smgduan[d3];break;
						case 2: seg = smgduan[d2];break;
						case 3: seg = smgduan[d1];break;
						default: seg = 0;
					}
				}
				}
				uart_rx(d4+48);
				uart_rx(d3+48);
				uart_rx(d2+48);
				uart_rx(d1+48);
				uart_rx(0x0A);
			}
}

四种工作方式(方式1、3的波特率与T1计数器有关

方式0:波特率固定 fosc/12[^串行方式0]

方式1:波特率 = 2SMOD/32*定时器T1溢出率[^串行方式1]

方式2:波特率 = 2SMOD/64*fosc [^串行方式2]

方式3:波特率 = 2SMOD/32*定时器T1的溢出率 [^串行方式3]

定时器溢出率 = 256X=fosc/12256X{\frac{计数速率}{256-X}=\frac{f_{osc}/12}{256-X}}

=2SMOD32fosc12(256X){波特率 = \frac{2^{SMOD}}{32}*\frac{f_{osc}}{12*(256-X)}}

若晶振11.0592MHz,选用T1方式2定时器作为波特率发生器,波特率为2400bps

因为只有方式1、3得波特率是可调的,所以方式选择这两个。

设T1方式2定时,选择SMOD=0;

=2SMOD32fosc12(256X){波特率 = \frac{2^{SMOD}}{32}*\frac{f_{osc}}{12*(256-X)}} = 2400

得:X=244=F4H

解:先求溢出率:2400 = 溢出率/32; 得:溢出率=76800

求初值:76800 = 计数速率/(256-X)=fosc/12256X{\frac{f_{osc}/12}{256-X}} 得:计数速率 = 244 【晶振用11.0592MHz来做】

定时器/计数器

1.相关得寄存器

a.中断允许寄存器(IE

EA ES ET1 EX1 ET0 Ex0
AFH ACH ABH AAH A9H A8H

b.中断请求标志寄存器(TCON

TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0
T1溢出中断 T0溢出中断 外部中断1 定时器1中断 外部中断0 定时器中断0

d.定时器/计数器控制寄存器(TMOD

GATE C/T M1 M0 GATE C/T M1 M0
T1 控制段 1:计数/0:计时 模式控制(H) 模式控制(L) T0控制段 1:计数/0:计时 模式控制(H) 模式控制(L)

2.定时器相关

在C51中我们可以利用的定时器/计数器只有两个:T0、T1

存在四种工作方式(12MHz):

方式0:计数器/定时器 为13位的1

方式1:计数器/定时器 为16位的 2

方式2:计数器/定时器为8位的【由硬件自动装载】3

方式3:计数器/定时器为两个8位的(只有T0能够工作在方式3,且此时T1停止计数)[^方式3]

装载值的计算:对于12MHz的晶振

例如:我们要计时100us,采用T0\T1的方式0、1、2都可以

方式0: (213 - X)*1us =100us; 可得:X = 8091 = 1F9B

方式1: (216 - X)*1us = 100us 可得:X = 65435 = FF9B

方式2: (28 - X)*1us = 100us; 可得:X = 155 = 9B

;;;;;;;;;;;;;;;;;;;;;  中断流水灯【T0方式1;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		ORG	0000H
		AJMP	START
		ORG	000BH;
		LJMP	TIMER0;
		ORG	0100H;
START:	
		MOV	TMOD,#01H;
		MOV	TH0,#3CH;
		MOV	TL0,#B0H;
		MOV	A,#FEH;
		MOV	R0,#20H;
		MOV	IE,#10000010B;
		MOV	IP,#10B;
		SETB	TR0;
		MOV	P1,A;
		SJMP	$;
TIMER0:	
		DJNZ	R0,LOOP;
		MOV	R0,#20;
		MOV	P1,A;
		RL	A;
LOOP:
		MOV	TH0,#3CH;
		MOV	TL0,#B0H;
		RETI
	END
*********************************   1s定时   *********************************
		ORG	0000H
RESET:	
		LJMP	MAIN
		ORG	000BH
		LJMP	IT0P
		ORG	1000H
MAIN:
		MOV	SP.#60
		MOV	B,#0AH
		MOV	TMOD,#01H
		MOV	TL0,#0B0H
		MOV	TH0,#3CH
		SETB	TR0
		SETB	ET0
		SETB	EA
HERE:
		SJMP	HERE
IT0P:
		MOV	TL0,#0B0H
		MOV	TH0,#3CH
		DJNZ	B,LOOP
		CLR	TR0
LOOP:
		RETI

  1. 最大可定时213x1us=8191us ~= 8.191ms ↩︎

  2. 最大可定时时间 216x1us=65535us ~= 65.535ms ↩︎

  3. 自动装载TH–>TL中重载,每次在定时器中断触发的时候,最大计时:28x1us=255us ↩︎

2014-05-08 14:07:08 u011467537 阅读数 2574
51单片机指令。
功能:短转移(Short Jump)
格式:SJMP rel ;
作用: PC 
PC+2 , PC 
PC+rel
短转移指令(-126—+129范围内的转移指令)
  短转移指令的功能是先使程序计数器PC加1两次(即:取出指令码),然后把加2后的地址和rel相加作为目标转移地址。因此,短转移指令是一条相对转移指令,是一条双字节双周期指令,指令码格式为:80H rel(操作码 地址偏移量),这里,80H是SJMP指令的操作码;rel是地址偏移量,在程序中也常采用符号地址,上机运行前才被代真成二进制形式。
  注意:遇到具体问题时,头脑中一定要清楚一个关系式:目标转移地址=源地址+2+rel[1]
常见用法:
SJMP$
即跳转到本指令的起始位置开始执行,这样就变成了循环执行,即原地跳转,一般用来等待中断。[2]
但是本指令也不宜滥用。这是一条死循环指令,如果系统的中断是开放的,那么SJMP $指令实际上是在等待中断,当有中断申请后,CPU 转至执行中断服务程序。中断返回时,仍然返回到这条死循环指令,继续等待中断,而不是返回到该指令的下一条指令。这是因为执行SJMP $后,PC 仍指向这条指令,中断的断点就是[3]这条指令的首字节地址。
没有更多推荐了,返回首页