8051寄存器、指令集、伪指令与关键字全面解析

8051寄存器、指令集、伪指令和关键字详细介绍

作者 将狼才鲸
创建日期 2022-04-09
修改日期 2024-0723
  • Gitee文档源码地址:01_8051寄存器、指令集、伪指令和关键字介绍.md
  • CSDN文章阅读地址:8051寄存器、指令集、伪指令和关键字介绍

  • 一、概述

  • C51是8位CPU。顾名思义,它的某个总线是8位,或者一些总线是8位的。实际上它的数据总线是8位的,每条CPU指令只能处理一个8位的数据,而它的外部地址总线是16位的,可以执行最大64KB的程序,也可以简单的理解为编译出来的可执行程序不能超过64KB(可以类比理解为在电脑上你只能下载安装64K以内的软件),这是C51的限制。
  • 为什么51单片机的地址总线是16位的,但是它却是8位机?

  • 不想使用盗版Keil的话,可以尝试使用SDCC开源编译器,只是没有IDE,还需要自己编写Makefile进行编译。
    C51 开源编译器SDCC学习笔记-安装
    开源SDCC编译器(一)–基本介绍
    还在用Keil做51单片机开发吗?快来试试开源的SDCC吧
    SDCC下载地址
    SDCC使用说明

  • 如果你只是自己学习,也可以控制将程序编译在2k的范围内(c51总共也才只支持64k的代码容量),去keil官方下载软件试用。
    Keil C51官方下载地址(评估版只能编译2k的代码)

  • 启动流程:
    8051 MCU学习之分析单片机的启动过程

  • C51资源:
    51单片机知识重点汇总一,干货分享,学习单片机必懂知识
    51单片机CPU的基本构成及作用
    mcs-51单片机CPU的内部结构及工作原理
    51单片机CPU结构各部件的原理详细分析
    第一章C51系列单片机的硬件结构
    51单片机的内部硬件结构(CPU工作原理,储存器结构,51,52和89C51,89S51型号对比)

  • 典型芯片:AT89C51

  • C51寄存器:
    C51 特殊功能寄存器
    51单片机寄存器一览表
    【实用】51单片机寄存器功能一览表
    寄存器一般使用格式

  • 二、寄存器和地址

  • 地址分为ROM地址和RAM地址,最大16位64K。

  • RAM:

  • 地址 大小 描述 备注
    0x00~0x2F 32 工作寄存器地址 4组R0~R7寄存器
    0x20~0x2F 16 位寻址 为了让寄存器可直接位寻址,用SBIT设置
    0x30~0x7F 48 内部RAM IRAM,可设置为堆栈
    0x80~0xFF 128 内部RAM和特殊寄存器共用 IRAM、SFR
    0x0100~0xFFFF 65280B 外部RAM RAM
  • ROM:
  • 地址 大小 描述 备注
    0x0000~0x0FFF 4KB 内部ROM IROM
    0x1000~0xFFFF 60KB 外部ROM ROM
  • 寄存器介绍:
    21个特殊功能寄存器(52系列是26个)不连续地分布在128个字节的SFR存储空间中,地址空间为80H-FFH,在这片SFR空间中,包含有128个位地址空间,地址也是80H-FFH,但只有83个有效位地址,可对11个特殊功能寄存器的某些位作位寻址操作(这里介绍一个技巧:其地址能被8整除的都可以位寻址)。
    SFR被称为特殊功能寄存器,芯片厂商自定义外设的寄存器地址也都在这组地址里面。
  • C51单片机的寄存器
    符号 地址 功能介绍
    R0~R7 0x00~0x2F 工作寄存器地址
    位寻址 0x20~0x2F 为了让寄存器可直接位寻址
    堆栈或内部RAM 0x30~0x7F
    P0 80H P0口锁存器
    SP 81H 堆栈指针
    DPL 82H 数据地址指针(低8位)
    DPH 83H 数据地址指针(高8位)
    PCON 87H 电源控制寄存器
    TCON 88H T0、T1定时器/计数器控制寄存器
    TMOD 89H T0、T1定时器/计数器方式控制寄存器
    TL0 8AH 定时器/计数器0(低8位)
    TL1 8BH 定时器/计数器0(高8位)
    TH0 8CH 定时器/计数器1(低8位)
    TH1 8DH 定时器/计数器1(高8位)
    P1 90H P1口锁存器
    SCON 98H 串行口控制寄存器
    SBUF 99H 串行口锁存器
    P2 A0H P2口锁存器
    IE A8H 中断允许控制寄存器
    P3 B0H P3口锁存器
    IP B8H 中断优先级控制寄存器
    PSW D0H 程序状态字
    ACC E0H 累加器
    B F0H B寄存器

    51单片机寄存器功能一览表
    C51/C52 特殊功能寄存器表

    三、指令集

  • 指令:
    8位总共256个,每条指令的耗时占一个到多个指令周期,也就是CPU主频每跳动一次所消耗的时间
  • 参考文档:
  • Keil官方8051 Instruction Set Manual指令集在线查看
  • MicroChip Atmel官方指令集文档8051 Microcontroller Instruction Set下载
  • MicroChip Atmel官方芯片手册Atmell 8051 Microcontrollers Hardware Manual下载
  • Keil官方MCS-51 INSTRUCTION SET指令集文档下载
  • 指令代码 指令长度 指令周期 助记符 操作对象 描述 举例
    00 1 1 NOP 延时1个指令周期的时间 NOP ; 延时
    01 2 2 AJMP addr11 短跳转,绝对转移,地址范围0xXX±0x000~07FF,转移范围为当前指令地址高5位相同的2K范围 AJMP ADDR1
    02 3 2 LJMP addr16 全域跳转,可以跳转到64K范围所有绝对地址,后面常用自定义的标号跳转 LJMP ADDR2
    03 1 1 RR A 累加器循环右移,实际上也是除以2
    04 1 1 INC A 累加器自增1,所有INC指令都不会产生借位 可用作循环处理
    05 2 1 INC direct 将给出地址当中的数据自增1(自增完后放回原处) 同上
    06 1 1 INC @R0 将R0中的数据当作地址,将这个地址中的数据自增1 同上
    07 1 1 INC @R1 同上 同上
    08 1 1 INC R0 将R0中的数据自增1 同上
    09 1 1 INC R1 同上 同上
    0A 1 1 INC R2 同上 同上
    0B 1 1 INC R3 同上 同上
    0C 1 1 INC R4 同上 同上
    0D 1 1 INC R5 同上 同上
    0E 1 1 INC R6 同上 同上
    0F 1 1 INC R7 同上 同上
    10 3 2 JBC bit, offset 如果某个可位寻址的位地址值为1,则清零后跳转到offset这个地址继续执行,否则顺序执行下一条指令 JBC BIT C
    11 2 2 ACALL addr11 短函数调用,函数中最后一条要是RET。绝对跳转,地址范围0xXX±0x000~07FF,跳转范围为当前指令地址高5位相同的2K范围,有参数的话子函数中还需要压栈和弹栈。调用完成后接着顺序执行本指令的下一条 ACALL FUNC1
    12 3 2 LCALL addr16 全域函数调用,函数中最后一条要是RET。地址范围0x0000~FFFF,有参数的话子函数中还需要压栈和弹栈。调用完成后接着顺序执行本指令的下一条 LCALL FUNC2
    13 1 1 RRC A 带进位累加器循环右移,也就是除以2
    14 1 1 DEC A 累加器自减1,所有DEC指令都不会产生借位 可用作循环处理
    15 2 1 DEC direct 将给出地址当中的数据自减1(自增完后放回原处) 同上
    16 1 1 DEC @R0 将R0中的数据当作地址,将这个地址中的数据自减1 同上
    17 1 1 DEC @R1 同上 同上
    18 1 1 DEC R0 将R0中的数据自减1 同上
    19 1 1 DEC R1 同上 同上
    1A 1 1 DEC R2 同上 同上
    1B 1 1 DEC R3 同上 同上
    1C 1 1 DEC R4 同上 同上
    1D 1 1 DEC R5 同上 同上
    1E 1 1 DEC R6 同上 同上
    1F 1 1 DEC R7 同上 同上
    20 3 2 JB bit, offset 如果某个可位寻址的位地址值为1,则跳转到offset这个地址继续执行,否则顺序执行下一条指令,该bit不清零 实现if else switch
    21 2 2 AJMP addr11 重复1
    22 1 2 RET 从子函数中返回
    23 1 1 RL A 累加器循环左移,也相当于乘以2
    24 2 1 ADD A, #immed 累加器和一个立即数(常数)相加,结果放回到A ADD A, #080H
    25 2 1 ADD A, direct 累加器和内存地址里的值相加,结果放回到A
    26 1 1 ADD A, @R0 累加器和R0里面存的内存地址里面指向的值相加,结果放回到A
    27 1 1 ADD A, @R1 同上
    28 1 1 ADD A, R0 累加器和R0里面的值相加,结果放回到A ADD A, R0
    29 1 1 ADD A, R1 同上
    2A 1 1 ADD A, R2 同上
    2B 1 1 ADD A, R3 同上
    2C 1 1 ADD A, R4 同上
    2D 1 1 ADD A, R5 同上
    2E 1 1 ADD A, R6 同上
    2F 1 1 ADD A, R7 同上
    30 3 2 JNB bit, offset 如果直接寻址位为0则转移 实现if else switch
    31 2 2 ACALL addr11 重复2
    32 1 2 RETI 中断程序返回
    33 1 1 RLC A 带进位累加器循环左移,也就是乘以2
    34 2 1 ADDC A, #immed 带进位求和
    35 2 1 ADDC A, direct
    36 1 1 ADDC A, @R0
    37 1 1 ADDC A, @R1
    38 1 1 ADDC A, R0
    39 1 1 ADDC A, R1
    3A 1 1 ADDC A, R2
    3B 1 1 ADDC A, R3
    3C 1 1 ADDC A, R4
    3D 1 1 ADDC A, R5
    3E 1 1 ADDC A, R6
    3F 1 1 ADDC A, R7
    40 2 2 JC offset 如果CY进位为1 则跳转,进位不清零
    41 2 2 AJMP addr11 重复3
    42 2 1 ORL direct, A 后面的与前面的相或,结果放到前面,*direct &= A
    43 3 2 ORL direct, #immed
    44 2 1 ORL A, #immed
    45 2 1 ORL A, direct
    46 1 1 ORL A, @R0
    47 1 1 ORL A, @R1
    48 1 1 ORL A, R0
    49 1 1 ORL A, R1
    4A 1 1 ORL A, R2
    4B 1 1 ORL A, R3
    4C 1 1 ORL A, R4
    4D 1 1 ORL A, R5
    4E 1 1 ORL A, R6
    4F 1 1 ORL A, R7
    50 2 2 JNC offset 如果CY进位为0 则转移
    51 2 2 ACALL addr11 重复4
    52 2 1 ANL direct, A 累加器“与”到直接地址
    53 3 2 ANL direct, #immed
    54 2 1 ANL A, #immed
    55 2 1 ANL A, direct
    56 1 1 ANL A, @R0
    57 1 1 ANL A, @R1
    58 1 1 ANL A, R0
    59 1 1 ANL A, R1
    5A 1 1 ANL A, R2
    5B 1 1 ANL A, R3
    5C 1 1 ANL A, R4
    5D 1 1 ANL A, R5
    5E 1 1 ANL A, R6
    5F 1 1 ANL A, R7
    60 2 2 JZ offset 累加器为0 则转移
    61 2 2 AJMP addr11 重复5
    62 2 1 XRL direct, A 累加器“异或”到直接地址
    63 3 2 XRL direct, #immed
    64 2 1 XRL A, #immed
    65 2 1 XRL A, direct
    66 1 1 XRL A, @R0
    67 1 1 XRL A, @R1
    68 1 1 XRL A, R0
    69 1 1 XRL A, R1
    6A 1 1 XRL A, R2
    6B 1 1 XRL A, R3
    6C 1 1 XRL A, R4
    6D 1 1 XRL A, R5
    6E 1 1 XRL A, R6
    6F 1 1 XRL A, R7
    70 2 2 JNZ offset 累加器为1 则转移
    71 2 2 ACALL addr11 重复6
    72 2 2 ORL C, bit 直接寻址位“或”到进位位
    73 1 2 JMP @A+DPTR 相对DPTR 的无条件间接转移
    74 2 1 MOV A, #immed
    75 3 2 MOV direct, #immed
    76 2 1 MOV @R0, #immed
    77 2 1 MOV @R1, #immed
    78 2 1 MOV R0, #immed
    79 2 1 MOV R1, #immed
    7A 2 1 MOV R2, #immed
    7B 2 1 MOV R3, #immed
    7C 2 1 MOV R4, #immed
    7D 2 1 MOV R5, #immed
    7E 2 1 MOV R6, #immed
    7F 2 1 MOV R7, #immed
    80 2 2 SJMP offset 无条件相对转移
    81 2 2 AJMP addr11 重复7
    82 2 2 ANL C, bit 直接寻址位“与”到进位位
    83 1 2 MOVC A, @A+PC 代码字节传送到累加器
    84 1 4 DIV AB 累加器除以B 寄存器
    85 3 2 MOV direct, direct
    86 2 2 MOV direct, @R0
    87 2 2 MOV direct, @R1
    88 2 2 MOV direct, R0
    89 2 2 MOV direct, R1
    8A 2 2 MOV direct, R2
    8B 2 2 MOV direct, R3
    8C 2 2 MOV direct, R4
    8D 2 2 MOV direct, R5
    8E 2 2 MOV direct, R6
    8F 2 2 MOV direct, R7
    90 3 2 MOV DPTR, #immed 16 位常数加载到数据指针
    91 2 2 ACALL addr11 重复8
    92 2 2 MOV bit, C 进位位位传送到直接寻址
    93 1 2 MOVC A, @A+DPTR 代码字节传送到累加器
    94 2 1 SUBB A, #immed 累加器减去立即数(带借位)
    95 2 1 SUBB A, direct
    96 1 1 SUBB A, @R0
    97 1 1 SUBB A, @R1
    98 1 1 SUBB A, R0
    99 1 1 SUBB A, R1
    9A 1 1 SUBB A, R2
    9B 1 1 SUBB A, R3
    9C 1 1 SUBB A, R4
    9D 1 1 SUBB A, R5
    9E 1 1 SUBB A, R6
    9F 1 1 SUBB A, R7
    A0 2 2 ORL C, /bit 直接寻址位的反码“或”到进位位
    A1 2 2 AJMP addr11 重复9
    A2 2 1 MOV C, bit 直接寻址位传送到进位位
    A3 1 2 INC DPTR 数据指针加1
    A4 1 4 MUL AB 累加器和B 寄存器相乘
    A5 reserved
    A6 2 2 MOV @R0, direct
    A7 2 2 MOV @R1, direct
    A8 2 2 MOV R0, direct
    A9 2 2 MOV R1, direct
    AA 2 2 MOV R2, direct
    AB 2 2 MOV R3, direct
    AC 2 2 MOV R4, direct
    AD 2 2 MOV R5, direct
    AE 2 2 MOV R6, direct
    AF 2 2 MOV R7, direct
    B0 2 2 ANL C, /bit 直接寻址位的反码“与”到进位位
    B1 2 2 ACALL addr11 重复10
    B2 2 1 CPL bit 取反直接寻址位
    B3 1 1 CPL C 取反进位位
    B4 3 2 CJNE A, #immed, offset 比较直接地址和累加器,不相等转移
    B5 3 2 CJNE A, direct, offset
    B6 3 2 CJNE @R0, #immed, offset
    B7 3 2 CJNE @R1, #immed, offset
    B8 3 2 CJNE R0, #immed, offset
    B9 3 2 CJNE R1, #immed, offset
    BA 3 2 CJNE R2, #immed, offset
    BB 3 2 CJNE R3, #immed, offset
    BC 3 2 CJNE R4, #immed, offset
    BD 3 2 CJNE R5, #immed, offset
    BE 3 2 CJNE R6, #immed, offset
    BF 3 2 CJNE R7, #immed, offset
    C0 2 2 PUSH direct 直接地址压入堆栈
    C1 2 2 AJMP addr11 重复11
    C2 2 1 CLR bit 清直接寻址位
    C3 1 1 CLR C 清进位位,和CLR CY是一样的效果
    C4 1 1 SWAP A 累加器高、低4 位交换
    C5 2 1 XCH A, direct 直接地址和累加器交换
    C6 1 1 XCH A, @R0
    C7 1 1 XCH A, @R1
    C8 1 1 XCH A, R0
    C9 1 1 XCH A, R1
    CA 1 1 XCH A, R2
    CB 1 1 XCH A, R3
    CC 1 1 XCH A, R4
    CD 1 1 XCH A, R5
    CE 1 1 XCH A, R6
    CF 1 1 XCH A, R7
    D0 2 2 POP direct 直接地址弹出堆栈
    D1 2 2 ACALL addr11 重复11
    D2 2 1 SETB bit 置位直接寻址位
    D3 1 1 SETB C 置位进位位
    D4 1 1 DA A 累加器十进制调整
    D5 3 2 DJNZ direct, offset 直接地址减1,不为0 则转移
    D6 1 1 XCHD A, @R0 间接RAM 和累加器交换低4 位字节
    D7 1 1 XCHD A, @R1
    D8 2 2 DJNZ R0, offset 寄存器减1,不为0 则转移
    D9 2 2 DJNZ R1, offset
    DA 2 2 DJNZ R2, offset
    DB 2 2 DJNZ R3, offset
    DC 2 2 DJNZ R4, offset
    DD 2 2 DJNZ R5, offset
    DE 2 2 DJNZ R6, offset
    DF 2 2 DJNZ R7, offset
    E0 1 2 MOVX A, @DPTR 外部RAM(16 地址)传送到累加器
    E1 2 2 AJMP addr11 重复12
    E2 1 2 MOVX A, @R0 外部RAM(8 地址)传送到累加器
    E3 1 2 MOVX A, @R1
    E4 1 1 CLR A 累加器清零
    E5 2 1 MOV A, direct
    E6 1 1 MOV A, @R0
    E7 1 1 MOV A, @R1
    E8 1 1 MOV A, R0
    E9 1 1 MOV A, R1
    EA 1 1 MOV A, R2
    EB 1 1 MOV A, R3
    EC 1 1 MOV A, R4
    ED 1 1 MOV A, R5
    EE 1 1 MOV A, R6
    EF 1 1 MOV A, R7
    F0 1 2 MOVX @DPTR, A 累加器传送到外部RAM(16 地址)
    F1 2 2 ACALL addr11 重复13
    F2 1 2 MOVX @R0, A 累加器传送到外部RAM(8 地址)
    F3 1 2 MOVX @R1, A
    F4 1 1 CPL A 累加器求反
    F5 2 1 MOV direct, A 累加器传送到直接地址
    F6 1 1 MOV @R0, A 直接地址传送到间接RAM
    F7 1 1 MOV @R1, A
    F8 1 1 MOV R0, A
    F9 1 1 MOV R1, A
    FA 1 1 MOV R2, A
    FB 1 1 MOV R3, A
    FC 1 1 MOV R4, A
    FD 1 1 MOV R5, A
    FE 1 1 MOV R6, A
    FF 1 1 MOV R7, A
    伪指令 ORG 汇编起始伪指令
    伪指令 END 结束伪指令
    伪指令 DB 字节数据定义伪指令
    伪指令 DW 字数据定义伪指令
    伪指令 DS 空间定义伪指令
    伪指令 EQU 赋值伪指令
    伪指令 MACRO ENDM 宏定义函数 NOP2 MACRO \ NOP \ NOP \ ENDM 该举例为无参数宏定义函数 也可以带参数
    伪指令 BIT 位地址符号定义伪指令
    伪指令 DATA 片内RAM直接字节地址定义伪指令
    伪指令 XDATA 片外RAM直接字节地址定义伪指令
    伪指令 HIGH 16位数的高字节 #HIGH(65536)
    伪指令 LOW 16位数的低字节 #LOW(65536)

    还有一些编译器自定义的符号,如Keil的伪指令:
    $NOMOD51
    $NOPRINT
    NAME ; 给当前模块命令,同时也是一段代码的入口
    SEGMENT ;类似于typedef
    PUBLIC
    ?C_START ; main函数入口
    IF
    ELSE
    ENDIF
    标号:
    CODE
    IDATA
    EXTRN
    RSEG ; 段选择指令
    CSEG
    AT
    $INCLUDE(USER.ASM)

    C51 各个存储区说明
    keil C51中各个地址的区别
    51单片机片内RAM的128B(00H~FFH) 分为哪几部分各部分地址范围及功能?
    51单片机特殊功能寄存器中的字节寻址和位寻址
    C51 特殊功能寄存器SFR的名称和地址
    C51最全111条汇编指令合集,以及使用时的注意事项,超详细
    51单片机指令表
    正确区分LJMP、AJMP、SJMP、JMP单片机跳转指令
    51单片机的汇编指令中AJMP 和SJMP都是两个字节,都是两个机器周期,它们有什么区别呢?
    谁能帮我解释一下 INC A ; INC direct INC Rn INC @Ri INC DPTR
    MCS51单片机的伪指令有哪些?
    keil_C51伪指令

    四、扩展

  • Keil官网上显示支持98家公司的9500款芯片(截止到2022-09-29),其中一半基于ARM核,一半基于8051核,少量基于其它核。

  • 点击Legacy Device List查看所有器件

  • 参考网址
    厂商列表 MDK5 Device List:https://www.keil.com/dd2/,里面有几十家公司
    器件列表 Legacy Device List:https://www.keil.com/dd/

  • 除了Keil,其它的8051模拟器还有:
    emu8051:
    https://github.com/jarikomppa/emu8051
    https://www.cnblogs.com/jikexianfeng/p/6357529.html
    EdSim51:
    http://edsim51.com/
    https://zhuanlan.zhihu.com/p/371060362


  • Keil伪指令
    1. Keil A51汇编代码中支持很多常用的伪指令,需要掌握,写汇编时经常会用到,这些伪指令可以在A51相关的英文文档里看到所有的描述;国内网站上没找到有人完整的翻译所有的伪指令,但是能在Keil官网上找到英文原版的,我没有仔细去翻找,但是应该在C51用户手册里面的一系列文档中的某些章节里面;Keil安装好的文件里的帮助文档的a51文档中能搜到所有的伪指令含义。

    2. Keil汇编伪指令介绍详见同级目录下的文档[《Keil A51汇编伪指令》](./02_doc/Keil A51汇编伪指令.md)

  • Keil 8051伪指令相关参考网址
    Keil文档:https://developer.arm.com/documentation#
    C51用户手册:https://www.keil.com/support/man_c51.htm
    ARM用户手册:https://www.keil.com/support/man_arm.htm
    A51 伪指令
    keil+A51
    Keil伪指令
    keilA51汇编语言伪指令
    RSEG用法和汇编问号的涵义
    Keil伪指令

  • Keil创建工程以及使用的参考网址如下:
    51单片机实训(一)————Keil 基本操作
    C8051单片机BootLoader心得
    Keil C51软件的使用
    第13章 Keil c51 和Proteus 虚拟仿真平台的使用
  • 后面的用例中,我都会提供创建好的Keil工程和源码,可以直接使用;但是如果你想自己从头到尾创建一个工程的话,可以参考以下步骤:
  • 已经用过Keil的可以自行下载Keil破解版并进行破解。
    1. 从官网下载Keil C51程序,这是一个IDE,集成了编辑器、编译器、链接器、模拟器。
    2. 下载地址 https://www.keil.com/demo/eval/c51.htm 需要注册并填写个人信息,评估版只支持编译2k容量的代码。
    3. 安装过程中,安装路径不要有空格,不要有中文目录。
    4. 安装完成后打开“Keil uVision5”软件,
      点击“Project”–>“new uVision Project”–>选中你愿意放工程的目录–>
      在选择设备弹窗中,我选择Cadence公司的R8051XC2(8DPTR),选择哪款8051芯片都无所谓,前期只操作基础的8051寄存器,不同公司的基础寄存器是一致的,我这里以这款芯片为例–>
      点击下一步后,弹出“Copy ‘STARTUP.A51’ to Project Folder and Add File to Project?”,点是,这样编译器会自动给你填充一份Boot汇编代码模板,这个Boot代码能让你跳转到main函数。
    5. 点击左上角两个箭头的按钮,编译程序,下方“Build Output”区域提示
      “.\Objects\cadence_first_project” – 0 Error(s), 2 Warning(s).
      错误为零则代表编译通过,生成的可执行文件是没有后缀的Objects\cadence_first_project
    6. 点击右上角红色的‘d’图标,能直接使用软件自带的模拟器仿真运行8051程序,
      如果提示“EVALUATION MODE…2K”,表示未注册的评估版只支持2K代码,我前期的代码没有超过2K,直接点确定下一步–>
      使用Keil默认提供的boot汇编程序,测试时断点会停在“?C_STARTUP”这一行–>
      点击行号前面可以创建和取消断点–>
      点击左上角几个带箭头或者叉叉的图标,可以单步执行、跳转到函数内部执行、持续运行、立即停止运行,快捷键是F10、F11、F5–>
      进入调试模式后,Keil里有各种窗口看串口输出的信息、RAM里的数据值、当前各个变量和寄存器的值、所有寄存器的值,修改当前变量的值,让程序中的变量按自己手动输入的值生效并运行,如果程序跑飞了可以查看异常寄存器和地址寄存器存储的上一个语句的地址。
  • 如果熟悉了这款芯片后,你不使用Keil自带的Boot程序,而是自己写整个寄存器宏定义,则在Keil工程配置里面,魔法棒图标–>Device–>勾选使用LX51和使用AX51,使用自己定义的SFR特殊功能寄存器。
  • 如果你需要将程序下到板子里面去,甚至还需要将hex可执行文件转成容量更小的bin文件,则在Output页面中勾选"Create HEX File"。

  • 在Keil使用过程中的一些技巧:
    1. 不使用Keil自带的GB2312中文编码,而是使用UTF-8中文编码,这样在用Git进行版本管理时能正常显示中文,在Linux和Windows之间来回切换工程后也不容易产生乱码,导致中文信息丢失无法恢复,步骤如下:
      打开工程–>点击左上角“Edit”–>点击弹出菜单最下方Configuration–>
      在弹出页面最左侧Editor页面中点击"Encoding"–>
      从ANSI改为UTF-8,点击“OK”,这样可以输入中文。

    2. Keil将Tab设置为固定4个空格(为了和Linux内核还有Git Tab以8个字节显示进行兼容,空格能让显示格式固定)
      Configuration–>Editor–>C/C++ Files–>Tab size: 4


    4.1、8051资源描述

  • 为了直观,这里直接列出了8051的所有寄存器,而8051所有的汇编指令表格在这个寄存器表格后面以文章的链接给出来。
  • 8051单片机数据存储器可划分为两大区域:00H~7FH为片内低128字节RAM区;80H~FFH为特殊功能寄存器区(SFR)。
  • 我举例用的8051 IP核使用的是Cadence的r8051xc,相关的通用寄存器需要查看r8051xc相关的文档。
  • 8051寄存器中地址以0和8结尾的都是可以位寻址的,如0x80 P0、0x88 TCON,而且8051中对每一个可位寻址的位都有一个对应的名字,直接操作这个名字就能操作这个位,具体的含义请在程序源码中看注释,或者需要时直接在网上搜索。
  • 地址为00H~7FH的低128字节片内RAM区又可划分为三个区域:通用寄存器区地址(00H~1FH)、可位寻址区(20H~2FH)、用户RAM区(30H~7FH,堆栈也可以设置在这里)。
    1. 8051通用寄存器介绍,共128个:
    地址 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07
    通用寄存器 0组R0 0组R1 0组R2 0组R3 0组R4 0组R5 0组R6 0组R7
    地址 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F
    1组R0 1组R1 1组R2 1组R3 1组R4 1组R5 1组R6 1组R7
    地址 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17
    2组R0 2组R1 2组R2 2组R3 2组R4 2组R5 2组R6 2组R7
    地址 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F
    3组R0 3组R1 3组R2 3组R3 3组R4 3组R5 3组R6 3组R7
    地址 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27
    位地址 00H~06H 07H~0FH 10H~16H 17H~1FH 20H~26H 27H~2FH 30H~36H 37H~3FH
    地址 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F
    40H~46H 47H~4FH 50H~56H 57H~5FH 60H~66H 67H~6FH 70H~76H 77H~7FH
    地址 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37
    剩下都是 用户RAM 一般开辟 成堆栈 ……
    地址 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F
    地址 …… …… …… …… …… …… …… ……
    地址 0x78 0x79 0x7A 0x7B 0x7C 0x7D 0x7E 0x7F
    1. R8051XC2特殊功能寄存器区(SFR)介绍,最大128个,8051通用的寄存器会加粗,未加粗的是R8051XC2特有的:
    地址 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87
    描述 P0 IO口锁存器 SP 堆栈指针 DPL 数据地址低8位 DPH 数据地址高8位 WDTREL PCON
    地址 0x88 0x89 0x8A 0x8B 0x8C 0x8D 0x8E 0x8F
    TCON Timer控制 TMOD Timer方式 TL0 Timer0低8位 TL1 Timer1低8位 TH0 Timer0高8位 TH1 Timer1高8位 CKCON
    地址 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97
    P1 IO口锁存器 DPS DPC PAGESEL D_PAGESEL
    地址 0x98 0x99 0x9A 0x9B 0x9C 0x9D 0x9E 0x9F
    S0CON串口控制 S0BUF串口锁存 IEN2 S1CON S1BUF S1RELL
    地址 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 0xA6 0xA7
    P2 IO口锁存器 DMAS0 DMAS1 DMAS2 DMAT0 DMAT1 DMAT2
    地址 0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE 0xAF
    IE0 中断允许 IP0 S0RELL
    地址 0xB0 0xB1 0xB2 0xB3 0xB4 0xB5 0xB6 0xB7
    P3 IO口锁存器 DMAC0 DMAC1 DMAC2 DMASEL DMAM0 DMAM1
    地址 0xB8 0xB9 0xBA 0xBB 0xBC 0xBD 0xBE 0xBF
    IP 中断优先级 IEN1 IP1 S0RELH S1RELH IRCON2
    地址 0xC0 0xC1 0xC2 0xC3 0xC4 0xC5 0xC6 0xC7
    IRCON CCEN CCL1 CCH1 CCL2 CCH2 CCL3 CCH3
    地址 0xC8 0xC9 0xCA 0xCB 0xCC 0xCD 0xCE 0xCF
    T2CON CRCL CRCH TL2 TH2 RTCSEL
    地址 0xD0 0xD1 0xD2 0xD3 0xD4 0xD5 0xD6 0xD7
    PSW 程序状态字 IEN4 I2C2DAT I2C2ADR I2C2CON I2C2STA SMB2_SEL SMB2_DST
    地址 0xD8 0xD9 0xDA 0xDB 0xDC 0xDD 0xDE 0xDF
    ADCCON P5 IO口 I2CDAT I2CADR I2CCON I2CSTA SMB_SEL SMB_DST
    地址 0xE0 0xE1 0xE2 0xE3 0xE4 0xE5 0xE6 0xE7
    ACC 累加器 SPSTA SPCON SPDAT SPSSN P6 IO口
    地址 0xE8 0xE9 0xEA 0xEB 0xEC 0xED 0xEE 0xEF
    P4 IO口 MD0 MD1 MD2 MD3 MD4 MD5 ARCON
    地址 0xF0 0xF1 0xF2 0xF3 0xF4 0xF5 0xF6 0xF7
    B 寄存器
    地址 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF
  • 8051的指令集和boot原理介绍,含指令集中完整256条指令的表格
    embedded-knowledge-wiki/ documents / 2.3.1.1_C51汇编介绍、boot程序编写.md – https://gitee.com/langcai1943/embedded-knowledge-wiki/blob/develop/documents/2.3.1.1_C51汇编介绍、boot程序编写.md

  • 其它8051资源描述的网页链接:
    8051单片机内部RAM低128单元划分为哪三个部分?各有什么特点?
    8051基础之三:数据存储类型
    8051内部RAM位寻址区
    8051系列单片机

  • R8051XC2的寄存器描述在网上没搜到,但是创建完R8051XC2工程后,在Keil中进入debug模式后,View–>Symbols Windows里面能看到所有寄存器地址。

  • Keil调试时“Register”窗口有最简单的寄存器:r0~r7、a、b、sp、sp_max、PC $、dpspl、dptr07、dpc07、states、sec、psw(p、f1、ov、rs、f0、ac、cy)。

  • Keil调试时“Symbols”窗口中有Virtual Registers寄存器:PPAGE、XPAGE、XTAL、CLOCK、INTPINS、INT0PIN、INT1PIN、PORT03O、PORT03I、SO1IN、S01OUT、SO1TIME、T01PIN、SWD、I2S、SPI、RTC。

  • Keil调试时“Symbols”窗口中有Special Function Registers:SP、PSW、ACC、A、B、DPL、DPH、DPS、DPC、CKCON、PCON、IEN04、IP01、IRCON、IRCON2、P0P3、S01CON、SO1BUF、SO1RELL、SO1RELH、ADCON、IEN2、TCON、TMOD、TL01、TH01、T2CON、TL2、TH2、CRCL、CRCH、CCEN、CCL13、CCH13、WDTREL、MD05、ARCON、I2CDAT、I2CADR、I2CCON、I2CSTA、I2C2ADR、I2C2CON、I2C2STA、SPSTA、SPCON、SPDAT、SPSSN、DMAS02、DMAT02、DMAC0~2、DMASEL、DMAM0、DMAM2、SRST、RTCSEL、RTCDAT

  • 参考网址:
    r8051中文资料,r8051xc所有寄存器描述
    8051单片机21个特殊功能寄存器和指令汇总
    R8051XC 数据表(PDF)
    ATT7035A_7037A_7037B用户手册 – 钜泉
    Toolchain Extensions for R8051XC/R8051XC2 Core
    特殊功能寄存器(SFR)详解 ——以8051单片机为例
    实验二 8051单片机IO口输出操作实验

  • 五、boot编写

  • 如何写纯汇编程序
  • ; $NOMOD51 ; 使A51不使用8051所有预定义的符号,使用自定义符号
    ; 不同的芯片厂商可以将SFR寄存器进行全新的定义
    
    	;==== SFR寄存器定义====
    	P0		DATA	80H  ; P0 IO口
    	SP		DATA	81H  ; 堆栈指针
    	DPL		DATA	82H  ; 数据指针低字节
    	DPH		DATA	83H  ; 数据指针高字节
    	PCON	DATA	87H  ; 电源控制
    	TCON	DATA	88H  ; 定时器控制
    		TF1	BIT	TCON.7
    		TR1	BIT	TCON.6
    		TF0	BIT	TCON.5
    		TR0	BIT	TCON.4
    		IE1	BIT	TCON.3
    		IT1	BIT	TCON.2
    		IE0	BIT	TCON.1
    		IT0	BIT	TCON.0
    	TMOD	DATA	89H  ; 定时器方式
    	TL0		DATA	8AH  ; 定时器0低字节
    	TH0		DATA	8CH  ; 定时器0高字节
    	TL1		DATA	8BH  ; 定时器1低字节
    	TH1		DATA	8DH  ; 定时器1高字节
    	P1		DATA	90H  ; P1 IO口
    	SCON0	DATA	98H	 ; UART0
    		TI0	BIT	SCON0.1
    		RI0	BIT	SCON0.0
    	SBUF0	DATA	99H  ; 串口0数据
    	SCON1	DATA	9BH	 ; UART1 ; 芯片厂商自行添加的
    	SBUF1	DATA	9CH  ; 串口1数据
    	P2		DATA	0A0H ; P2 IO口 ; 对于最高位大于等于10(ABCDEF)的数前面必须带0
    	IEN0	DATA	0A8H ; 中断使能
    		EA	BIT	IEN0.7	
    		WDT BIT	IEN0.6	 ; 芯片厂商自行添加
    		EX1	BIT	IEN0.2
    		EX0	BIT	IEN0.0	
    	P3		DATA	0B0H ; P3 IO口
    	T2CON	DATA	0C8H ; 定时器2控制
    	TL2		DATA	0CCH ; 定时器2低字节
    	TH2		DATA	0CDH ; 定时器2高字节
    	PSW		DATA	0D0H ; 程序状态寄存器
    		CY	BIT	PSW.7
    		AC	BIT	PSW.6
    		F0	BIT	PSW.5
    		RS1	BIT	PSW.4
    		RS0	BIT	PSW.3
    		OV	BIT	PSW.2
    		F1	BIT	PSW.1
    		P	BIT	PSW.0
    	ACC		DATA	0E0H ; 累加器
    	B		DATA	0F0H ; 寄存器B
    	EXADR	DATA	0FEH ; SFR扩展接口 ; 支持更多的寄存器
    	EXDATA	DATA	0FFH
    
    	; 赋值
    	APP_MODE    EQU  0F8H ; 类似于宏定义
    
    	; 中断入口,程序入口(程序从0地址开始执行)
        ORG     0000H
        LJMP    RESET
    
        ORG		000BH ; 中断入口的地址都是固定的
        LJMP	T0INT
    
        ORG		001BH
        LJMP	T1INT
    
        ORG		002BH
        LJMP	T2INT
    
    	ORG		0100H ; 程序起始地址
    	
    	$INCLUDE(USER.ASM)
    	
    RESET:
    	; 你的汇编代码,初始化各个模块,执行函数,响应中断,执行程序
    	
    END
    
  • 如何写汇编boot程序,并引导到main()函数执行
  • 	;;;;
    	; 其它未写出的准备操作:
    	; 用DATA申明所有的SFR寄存器名字,P0(80H) ~ B(0F0H)
    	; 自定义的宏定义,如DEBUG_LEVEL EQU 01H,用于配置软件的不同功能
    
    	CSEG	AT	  0000H	  ; 板子复位后执行的第一条指令
    	LJMP	STARTUP		  ; 执行初始化函数
    
    	CSEG	AT	  0003H	  ; 外部中断0
    	LJMP	interupt_0	  ; 依次注册好所有中断处理函数
    	;;;; 省略其它中断处理函数
    
    	; SEGMENT申明本模块在CODE代码段,CODE代码段起始地址是0x100,这也是程序默认运行的起始地址,前面的地址是一些固定的中断处理的函数地址
    	STARTUP_FUNC  SEGMENT  CODE AT 0100H  ; 等同于ORG	0100H
    	RSEG  STARTUP_FUNC ; 定义函数再定义段
    	
    	PUBLIC STARTUP ; 申明函数,并向别的.asm暴露出函数接口
    	
    STARTUP: ; 标号,同时也是函数名,和C语言中标号类似,C语言的标号可以goto跳转
    	NOP ; 延时一个时钟周期
    	CLR EAL ; SBIT(EAL, IE, 7) ; 关闭中断7
    	CLR RS0 ; RS0 BIT PSW.3 ; 
    	CLR RS1 ; RS0 BIT PSW.3 ; 和上条命令一起选择第一组R0~R7寄存器
    	MOV IE, #0H ; 关闭所有中断
    	NOP
    	MOV SP, #ORIGIN_SP ; ORIGIN_SP EQU 40H ; 初始化堆栈起始地址
    	NOP
    	LCALL _hardware_init ; 调用你写的函数写驱动模块寄存器初始化你需要的硬件,如引脚、PLL时钟倍频分频、JTAG设置、看门狗复位、IO输出、引脚复用、软件配置判断、内存初始化、串口、SPI、I2C等初始化
    	NOP
    	LCALL _crt0Startup ; 调用crt0.c里面的C语言函数,其实这时候已经可以直接调用main函数了,但是有些main函数之前的准备工作是用C写的,所以要提前调用一下
    		;;;;
    		; extern int main(int, char * const []);
    		; extern int sysExit(int exit_code);
    		; #define sysMain main
    		; int crt0Startup(int argc, char * const argv[])
    		; {
    		;     // 关闭所有中断、DMA缓存刷新、CPU工作模式选择、硬件频率进一步设置、串口的完整初始化(设置波特率)、中断初始化、时钟初始化(更新当前实时时间)、有操作系统的话初始化task、内核、使能中断、调用main函数、main结束后进行资源销毁,便于软复位后系统能再次正常运行
    		;     // sysMain(argc, argv); // 跳转到main函数执行
    		;     // sysExit();
    		; }
    	NOP
    	LJMP _cpuStop ; 关闭PLL时钟分频倍频,将时钟设置为晶振的原始频率
    	NOP
    	RET
    	NOP
    	
    	END
    

    CSEG ; 绝对地址指示的代码段,可以当成一个函数的入口
    RSEG ; 再定位段选择指令,它用来选择一个在前面已经定义过的再定位段作为当前段,例如先申明一个函数段,后面写这个函数段。PS: 程序代码放到代码段,数据对象放到数据段,段分两种,一是种绝对段,一种是再定位段。
    SEGMENT ; 申明是哪种段,类似C语言的{}花括号,和END配和使用
    AT ; 该段的起始地址
    PUBLIC ; 给别的.asm文件暴露出函数接口,类似于C语言 int api_func(void);放在头文件中
    $SAVE ; 存储最近的LIST和GEN的设置
    $NOLIST ; 不使用最近的LIST配置
    $RESTORE ; 恢复最近的LIST和GEN的设置
    EXTRN CODE (YOUR_FUNCTION_NAME) ; EXTRN 是与PUBLIC 配套使用的,要调用其它模块的函数,就必须先在模块前声明

    汇编语言段和RSEG用法
    A51零散笔记
    STC8头文件

  • 函数参数:
    可用作函数参数的,及时压栈和弹栈的寄存器有ACC累加器、B寄存器(为乘法和除法指令而设置)、PSW程序状态字(处理进位、非零、正负、溢出等)、DPH/DPL(数据地址指针,读外部RAM数据)、R0~7(工作寄存器);函数调用时,让这些寄存器放弃它们本来的用法,当作函数参数使用。压栈和弹栈时顺序要刚好相反
  • 寄存器B
    标志寄存器(PSW)
    单片机DPH DPL是什么
    求教解释R0~R7.还有,RS0,RS

    作者:才鲸嵌入式

    物联沃分享整理
    物联沃-IOTWORD物联网 » 8051寄存器、指令集、伪指令与关键字全面解析

    发表回复