06 C51 汇编boot程序编写,C51资源介绍

C51 boot程序编写,C51资源介绍

作者 将狼才鲸
创建日期 2022-04-09

Gitee文档源码地址:embedded-knowledge-wiki/ documents / 2.3.1.1_c51编程.md
CSDN文章阅读地址:
B站视频讲解(待完成):才鲸嵌入式
这篇文章是一系列文章中的一部分,文章根入口:才鲸嵌入式 / 嵌入式知识图谱WiKi

一、概述

  • 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 你操作0x00~0x7F这128个的位地址, 实际上操作的就是这里16个字节里面的位
堆栈或内部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寄存器
  • 其它这里没标明的寄存器地址,一般都会被各个生产8051CPU的厂商给使用完,所以每家厂商的其它寄存器都是不一样的,可以有DMA、I2C、SPI、额外的串口等外设控制。
  • 上面寄存器能被8整除的都是可以位寻址的,如0x80、0x88、0x90、0x98,所以如果0x80~0xFF做个表,每行8个的话,基本上每行靠前的寄存器都被8051通用的特殊功能寄存器给使用了。

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

三、指令集

  • 指令:
    8位总共256个,每条指令的耗时占一个到多个指令周期,也就是CPU主频每跳动一次所消耗的时间
指令代码 指令长度 指令周期 助记符 操作对象 描述 举例
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 可用作循环处理
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 可用作循环处理
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 如果进位位为1 则跳转
41 2 2 AJMP addr11 重复3
42 2 1 ORL direct, A 后面的与前面的相或,结果放到前面,*direct &= A
43 3 1 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 2 ORL A, R0
49 1 2 ORL A, R1
4A 1 2 ORL A, R2
4B 1 2 ORL A, R3
4C 1 2 ORL A, R4
4D 1 2 ORL A, R5
4E 1 2 ORL A, R6
4F 1 2 ORL A, R7
50 2 2 JNC offset 如果进位位为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 1 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 2 XRL A, R0
69 1 2 XRL A, R1
6A 1 2 XRL A, R2
6B 1 2 XRL A, R3
6C 1 2 XRL A, R4
6D 1 2 XRL A, R5
6E 1 2 XRL A, R6
6F 1 2 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 1 MOV direct, #immed
76 2 1 MOV @R0, #immed
77 2 1 MOV @R1, #immed
78 2 2 MOV R0, #immed
79 2 2 MOV R1, #immed
7A 2 2 MOV R2, #immed
7B 2 2 MOV R3, #immed
7C 2 2 MOV R4, #immed
7D 2 2 MOV R5, #immed
7E 2 2 MOV R6, #immed
7F 2 2 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 1 MOV direct, R0
89 2 1 MOV direct, R1
8A 2 1 MOV direct, R2
8B 2 1 MOV direct, R3
8C 2 1 MOV direct, R4
8D 2 1 MOV direct, R5
8E 2 1 MOV direct, R6
8F 2 1 MOV direct, R7
90 3 1 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 1 MOV @R0, direct
A7 2 1 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 清进位位
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 2 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 2 MOV @R0, A 直接地址传送到间接RAM
F7 1 2 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 赋值伪指令
伪指令 BIT 位地址符号定义伪指令
伪指令 DATA 片内RAM直接字节地址定义伪指令
伪指令 XDATA 片外RAM直接字节地址定义伪指令

还有一些编译器自定义的符号,如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伪指令

四、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

你可能感兴趣的:(1,嵌入式知识图谱WiKi,嵌入式,51单片机,c语言,单片机,mcu)