8051寄存器、指令集、伪指令和关键字详细介绍
作者将狼才鲸创建日期2022-04-09修改日期2024-07-23
Gitee文档源码地址:01_8051寄存器、指令集、伪指令和关键字介绍.mdCSDN文章阅读地址: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~0x2F32工作寄存器地址4组R0~R7寄存器0x20~0x2F16位寻址为了让寄存器可直接位寻址,用SBIT设置0x30~0x7F48内部RAMIRAM,可设置为堆栈0x80~0xFF128内部RAM和特殊寄存器共用IRAM、SFR0x0100~0xFFFF65280B外部RAMRAM
ROM:
地址大小描述备注0x0000~0x0FFF4KB内部ROMIROM0x1000~0xFFFF60KB外部ROMROM
寄存器介绍: 21个特殊功能寄存器(52系列是26个)不连续地分布在128个字节的SFR存储空间中,地址空间为80H-FFH,在这片SFR空间中,包含有128个位地址空间,地址也是80H-FFH,但只有83个有效位地址,可对11个特殊功能寄存器的某些位作位寻址操作(这里介绍一个技巧:其地址能被8整除的都可以位寻址)。 SFR被称为特殊功能寄存器,芯片厂商自定义外设的寄存器地址也都在这组地址里面。
C51单片机的寄存器符号地址功能介绍R0~R70x00~0x2F工作寄存器地址位寻址0x20~0x2F为了让寄存器可直接位寻址堆栈或内部RAM0x30~0x7FP080HP0口锁存器SP81H堆栈指针DPL82H数据地址指针(低8位)DPH83H数据地址指针(高8位)PCON87H电源控制寄存器TCON88HT0、T1定时器/计数器控制寄存器TMOD89HT0、T1定时器/计数器方式控制寄存器TL08AH定时器/计数器0(低8位)TL18BH定时器/计数器0(高8位)TH08CH定时器/计数器1(低8位)TH18DH定时器/计数器1(高8位)P190HP1口锁存器SCON98H串行口控制寄存器SBUF99H串行口锁存器P2A0HP2口锁存器IEA8H中断允许控制寄存器P3B0HP3口锁存器IPB8H中断优先级控制寄存器PSWD0H程序状态字ACCE0H累加器BF0HB寄存器
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指令集文档下载
指令代码指令长度指令周期助记符操作对象描述举例0011NOP无延时1个指令周期的时间NOP ; 延时0122AJMPaddr11短跳转,绝对转移,地址范围0xXX±0x000~07FF,转移范围为当前指令地址高5位相同的2K范围AJMP ADDR10232LJMPaddr16全域跳转,可以跳转到64K范围所有绝对地址,后面常用自定义的标号跳转LJMP ADDR20311RRA累加器循环右移,实际上也是除以20411INCA累加器自增1,所有INC指令都不会产生借位可用作循环处理0521INCdirect将给出地址当中的数据自增1(自增完后放回原处)同上0611INC@R0将R0中的数据当作地址,将这个地址中的数据自增1同上0711INC@R1同上同上0811INCR0将R0中的数据自增1同上0911INCR1同上同上0A11INCR2同上同上0B11INCR3同上同上0C11INCR4同上同上0D11INCR5同上同上0E11INCR6同上同上0F11INCR7同上同上1032JBCbit, offset如果某个可位寻址的位地址值为1,则清零后跳转到offset这个地址继续执行,否则顺序执行下一条指令JBC BIT C1122ACALLaddr11短函数调用,函数中最后一条要是RET。绝对跳转,地址范围0xXX±0x000~07FF,跳转范围为当前指令地址高5位相同的2K范围,有参数的话子函数中还需要压栈和弹栈。调用完成后接着顺序执行本指令的下一条ACALL FUNC11232LCALLaddr16全域函数调用,函数中最后一条要是RET。地址范围0x0000~FFFF,有参数的话子函数中还需要压栈和弹栈。调用完成后接着顺序执行本指令的下一条LCALL FUNC21311RRCA带进位累加器循环右移,也就是除以21411DECA累加器自减1,所有DEC指令都不会产生借位可用作循环处理1521DECdirect将给出地址当中的数据自减1(自增完后放回原处)同上1611DEC@R0将R0中的数据当作地址,将这个地址中的数据自减1同上1711DEC@R1同上同上1811DECR0将R0中的数据自减1同上1911DECR1同上同上1A11DECR2同上同上1B11DECR3同上同上1C11DECR4同上同上1D11DECR5同上同上1E11DECR6同上同上1F11DECR7同上同上2032JBbit, offset如果某个可位寻址的位地址值为1,则跳转到offset这个地址继续执行,否则顺序执行下一条指令,该bit不清零实现if else switch2122AJMPaddr11重复12212RET从子函数中返回2311RLA累加器循环左移,也相当于乘以22421ADDA, #immed累加器和一个立即数(常数)相加,结果放回到AADD A, #080H2521ADDA, direct累加器和内存地址里的值相加,结果放回到A2611ADDA, @R0累加器和R0里面存的内存地址里面指向的值相加,结果放回到A2711ADDA, @R1同上2811ADDA, R0累加器和R0里面的值相加,结果放回到AADD A, R02911ADDA, R1同上2A11ADDA, R2同上2B11ADDA, R3同上2C11ADDA, R4同上2D11ADDA, R5同上2E11ADDA, R6同上2F11ADDA, R7同上3032JNBbit, offset如果直接寻址位为0则转移实现if else switch3122ACALLaddr11重复23212RETI中断程序返回3311RLCA带进位累加器循环左移,也就是乘以23421ADDCA, #immed带进位求和3521ADDCA, direct3611ADDCA, @R03711ADDCA, @R13811ADDCA, R03911ADDCA, R13A11ADDCA, R23B11ADDCA, R33C11ADDCA, R43D11ADDCA, R53E11ADDCA, R63F11ADDCA, R74022JCoffset如果CY进位为1 则跳转,进位不清零4122AJMPaddr11重复34221ORLdirect, A后面的与前面的相或,结果放到前面,*direct &= A4332ORLdirect, #immed4421ORLA, #immed4521ORLA, direct4611ORLA, @R04711ORLA, @R14811ORLA, R04911ORLA, R14A11ORLA, R24B11ORLA, R34C11ORLA, R44D11ORLA, R54E11ORLA, R64F11ORLA, R75022JNCoffset如果CY进位为0 则转移5122ACALLaddr11重复45221ANLdirect, A累加器“与”到直接地址5332ANLdirect, #immed5421ANLA, #immed5521ANLA, direct5611ANLA, @R05711ANLA, @R15811ANLA, R05911ANLA, R15A11ANLA, R25B11ANLA, R35C11ANLA, R45D11ANLA, R55E11ANLA, R65F11ANLA, R76022JZoffset累加器为0 则转移6122AJMPaddr11重复56221XRLdirect, A累加器“异或”到直接地址6332XRLdirect, #immed6421XRLA, #immed6521XRLA, direct6611XRLA, @R06711XRLA, @R16811XRLA, R06911XRLA, R16A11XRLA, R26B11XRLA, R36C11XRLA, R46D11XRLA, R56E11XRLA, R66F11XRLA, R77022JNZoffset累加器为1 则转移7122ACALLaddr11重复67222ORLC, bit直接寻址位“或”到进位位7312JMP@A+DPTR相对DPTR 的无条件间接转移7421MOVA, #immed7532MOVdirect, #immed7621MOV@R0, #immed7721MOV@R1, #immed7821MOVR0, #immed7921MOVR1, #immed7A21MOVR2, #immed7B21MOVR3, #immed7C21MOVR4, #immed7D21MOVR5, #immed7E21MOVR6, #immed7F21MOVR7, #immed8022SJMPoffset无条件相对转移8122AJMPaddr11重复78222ANLC, bit直接寻址位“与”到进位位8312MOVCA, @A+PC代码字节传送到累加器8414DIVAB累加器除以B 寄存器8532MOVdirect, direct8622MOVdirect, @R08722MOVdirect, @R18822MOVdirect, R08922MOVdirect, R18A22MOVdirect, R28B22MOVdirect, R38C22MOVdirect, R48D22MOVdirect, R58E22MOVdirect, R68F22MOVdirect, R79032MOVDPTR, #immed16 位常数加载到数据指针9122ACALLaddr11重复89222MOVbit, C进位位位传送到直接寻址9312MOVCA, @A+DPTR代码字节传送到累加器9421SUBBA, #immed累加器减去立即数(带借位)9521SUBBA, direct9611SUBBA, @R09711SUBBA, @R19811SUBBA, R09911SUBBA, R19A11SUBBA, R29B11SUBBA, R39C11SUBBA, R49D11SUBBA, R59E11SUBBA, R69F11SUBBA, R7A022ORLC, /bit直接寻址位的反码“或”到进位位A122AJMPaddr11重复9A221MOVC, bit直接寻址位传送到进位位A312INCDPTR数据指针加1A414MULAB累加器和B 寄存器相乘A5reservedA622MOV@R0, directA722MOV@R1, directA822MOVR0, directA922MOVR1, directAA22MOVR2, directAB22MOVR3, directAC22MOVR4, directAD22MOVR5, directAE22MOVR6, directAF22MOVR7, directB022ANLC, /bit直接寻址位的反码“与”到进位位B122ACALLaddr11重复10B221CPLbit取反直接寻址位B311CPLC取反进位位B432CJNEA, #immed, offset比较直接地址和累加器,不相等转移B532CJNEA, direct, offsetB632CJNE@R0, #immed, offsetB732CJNE@R1, #immed, offsetB832CJNER0, #immed, offsetB932CJNER1, #immed, offsetBA32CJNER2, #immed, offsetBB32CJNER3, #immed, offsetBC32CJNER4, #immed, offsetBD32CJNER5, #immed, offsetBE32CJNER6, #immed, offsetBF32CJNER7, #immed, offsetC022PUSHdirect直接地址压入堆栈C122AJMPaddr11重复11C221CLRbit清直接寻址位C311CLRC清进位位,和CLR CY是一样的效果C411SWAPA累加器高、低4 位交换C521XCHA, direct直接地址和累加器交换C611XCHA, @R0C711XCHA, @R1C811XCHA, R0C911XCHA, R1CA11XCHA, R2CB11XCHA, R3CC11XCHA, R4CD11XCHA, R5CE11XCHA, R6CF11XCHA, R7D022POPdirect直接地址弹出堆栈D122ACALLaddr11重复11D221SETBbit置位直接寻址位D311SETBC置位进位位D411DAA累加器十进制调整D532DJNZdirect, offset直接地址减1,不为0 则转移D611XCHDA, @R0间接RAM 和累加器交换低4 位字节D711XCHDA, @R1D822DJNZR0, offset寄存器减1,不为0 则转移D922DJNZR1, offsetDA22DJNZR2, offsetDB22DJNZR3, offsetDC22DJNZR4, offsetDD22DJNZR5, offsetDE22DJNZR6, offsetDF22DJNZR7, offsetE012MOVXA, @DPTR外部RAM(16 地址)传送到累加器E122AJMPaddr11重复12E212MOVXA, @R0外部RAM(8 地址)传送到累加器E312MOVXA, @R1E411CLRA累加器清零E521MOVA, directE611MOVA, @R0E711MOVA, @R1E811MOVA, R0E911MOVA, R1EA11MOVA, R2EB11MOVA, R3EC11MOVA, R4ED11MOVA, R5EE11MOVA, R6EF11MOVA, R7F012MOVX@DPTR, A累加器传送到外部RAM(16 地址)F122ACALLaddr11重复13F212MOVX@R0, A累加器传送到外部RAM(8 地址)F312MOVX@R1, AF411CPLA累加器求反F521MOVdirect, A累加器传送到直接地址F611MOV@R0, A直接地址传送到间接RAMF711MOV@R1, AF811MOVR0, AF911MOVR1, AFA11MOVR2, AFB11MOVR3, AFC11MOVR4, AFD11MOVR5, AFE11MOVR6, AFF11MOVR7, A伪指令ORG汇编起始伪指令伪指令END结束伪指令伪指令DB字节数据定义伪指令伪指令DW字数据定义伪指令伪指令DS空间定义伪指令伪指令EQU赋值伪指令伪指令MACRO ENDM宏定义函数NOP2 MACRO \ NOP \ NOP \ ENDM 该举例为无参数宏定义函数也可以带参数伪指令BIT位地址符号定义伪指令伪指令DATA片内RAM直接字节地址定义伪指令伪指令XDATA片外RAM直接字节地址定义伪指令伪指令HIGH16位数的高字节#HIGH(65536)伪指令LOW16位数的低字节#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伪指令
Keil A51汇编代码中支持很多常用的伪指令,需要掌握,写汇编时经常会用到,这些伪指令可以在A51相关的英文文档里看到所有的描述;国内网站上没找到有人完整的翻译所有的伪指令,但是能在Keil官网上找到英文原版的,我没有仔细去翻找,但是应该在C51用户手册里面的一系列文档中的某些章节里面;Keil安装好的文件里的帮助文档的a51文档中能搜到所有的伪指令含义。
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破解版并进行破解。
从官网下载Keil C51程序,这是一个IDE,集成了编辑器、编译器、链接器、模拟器。下载地址 https://www.keil.com/demo/eval/c51.htm 需要注册并填写个人信息,评估版只支持编译2k容量的代码。安装过程中,安装路径不要有空格,不要有中文目录。安装完成后打开“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函数。点击左上角两个箭头的按钮,编译程序,下方“Build Output”区域提示 “.\Objects\cadence_first_project” - 0 Error(s), 2 Warning(s). 错误为零则代表编译通过,生成的可执行文件是没有后缀的Objects\cadence_first_project点击右上角红色的‘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使用过程中的一些技巧:
不使用Keil自带的GB2312中文编码,而是使用UTF-8中文编码,这样在用Git进行版本管理时能正常显示中文,在Linux和Windows之间来回切换工程后也不容易产生乱码,导致中文信息丢失无法恢复,步骤如下: 打开工程–>点击左上角“Edit”–>点击弹出菜单最下方Configuration–> 在弹出页面最左侧Editor页面中点击"Encoding"–> 从ANSI改为UTF-8,点击“OK”,这样可以输入中文。
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,堆栈也可以设置在这里)。
8051通用寄存器介绍,共128个:
地址0x000x010x020x030x040x050x060x07通用寄存器0组R00组R10组R20组R30组R40组R50组R60组R7地址0x080x090x0A0x0B0x0C0x0D0x0E0x0F1组R01组R11组R21组R31组R41组R51组R61组R7地址0x100x110x120x130x140x150x160x172组R02组R12组R22组R32组R42组R52组R62组R7地址0x180x190x1A0x1B0x1C0x1D0x1E0x1F3组R03组R13组R23组R33组R43组R53组R63组R7地址0x200x210x220x230x240x250x260x27位地址00H~06H07H~0FH10H~16H17H~1FH20H~26H27H~2FH30H~36H37H~3FH地址0x280x290x2A0x2B0x2C0x2D0x2E0x2F40H~46H47H~4FH50H~56H57H~5FH60H~66H67H~6FH70H~76H77H~7FH地址0x300x310x320x330x340x350x360x37剩下都是用户RAM一般开辟成堆栈……地址0x380x390x3A0x3B0x3C0x3D0x3E0x3F地址…………………………………………地址0x780x790x7A0x7B0x7C0x7D0x7E0x7F
R8051XC2特殊功能寄存器区(SFR)介绍,最大128个,8051通用的寄存器会加粗,未加粗的是R8051XC2特有的:
地址0x800x810x820x830x840x850x860x87描述P0 IO口锁存器SP 堆栈指针DPL 数据地址低8位DPH 数据地址高8位WDTRELPCON地址0x880x890x8A0x8B0x8C0x8D0x8E0x8FTCON Timer控制TMOD Timer方式TL0 Timer0低8位TL1 Timer1低8位TH0 Timer0高8位TH1 Timer1高8位CKCON地址0x900x910x920x930x940x950x960x97P1 IO口锁存器DPSDPCPAGESELD_PAGESEL地址0x980x990x9A0x9B0x9C0x9D0x9E0x9FS0CON串口控制S0BUF串口锁存IEN2S1CONS1BUFS1RELL地址0xA00xA10xA20xA30xA40xA50xA60xA7P2 IO口锁存器DMAS0DMAS1DMAS2DMAT0DMAT1DMAT2地址0xA80xA90xAA0xAB0xAC0xAD0xAE0xAFIE0 中断允许IP0S0RELL地址0xB00xB10xB20xB30xB40xB50xB60xB7P3 IO口锁存器DMAC0DMAC1DMAC2DMASELDMAM0DMAM1地址0xB80xB90xBA0xBB0xBC0xBD0xBE0xBFIP 中断优先级 IEN1IP1S0RELHS1RELHIRCON2地址0xC00xC10xC20xC30xC40xC50xC60xC7IRCONCCENCCL1CCH1CCL2CCH2CCL3CCH3地址0xC80xC90xCA0xCB0xCC0xCD0xCE0xCFT2CONCRCLCRCHTL2TH2RTCSEL地址0xD00xD10xD20xD30xD40xD50xD60xD7PSW 程序状态字IEN4I2C2DATI2C2ADRI2C2CONI2C2STASMB2_SELSMB2_DST地址0xD80xD90xDA0xDB0xDC0xDD0xDE0xDFADCCONP5 IO口I2CDATI2CADRI2CCONI2CSTASMB_SELSMB_DST地址0xE00xE10xE20xE30xE40xE50xE60xE7ACC 累加器SPSTASPCONSPDATSPSSNP6 IO口地址0xE80xE90xEA0xEB0xEC0xED0xEE0xEFP4 IO口MD0MD1MD2MD3MD4MD5ARCON地址0xF00xF10xF20xF30xF40xF50xF60xF7B 寄存器地址0xF80xF90xFA0xFB0xFC0xFD0xFE0xFF
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