8051(c51)单片机从汇编到C语言,从Boot到应用[开源系列教程]

8051(c51)单片机从汇编到C语言,从Boot到应用[开源系列教程]

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

一、仓库介绍

工程名 作用
01_Hello_world 直接从Keil调试窗口中输出Hello world
02_Keil_boot_annotation 对Keil自带的汇编boot源码进行注释
03_Assemble_register 展示8051真正的程序入口, 和添加自定义寄存器头文件
04_Macro_func_and_irq 展示汇编宏定义函数和中断处理
05_Assemble_hello_world 用汇编从Keil调试窗口中输出Hello world
06_uart0_loopback Keil调试输出窗口串口回环
  • 这是一个8051教学仓库。不使用具体的硬件,直接使用Keil做模拟器,使用虚拟串口做输入输出,直接在电脑上编译运行,保证不被硬件问题卡住,从Keil官网下载Keil软件后再下载此仓库,打开仓库里的工程运行程序后能直接看到结果。重点介绍8051的寄存器、指令集、Keil伪指令、汇编Boot、汇编编程套路、C语言编程套路、软件框架、通信框架。
  • 仓库中有多个Keil工程和源码,每个仓库都是独立的,能够直接打开、编译和运行。
  • 本仓库面向的人员有:
  1. 在学校学过《C51单片机原理(汇编)》、《C语言程序设计》等类似课程,但是并没有使用一款8051的芯片进行过商用的项目开发的。
  2. 使用一款8051芯片做过C语言的商用项目开发,但是对8051从芯片上电开始到main()函数执行前的boot流程不了解的。
  3. 没有进行过8051纯汇编编程的。
  4. 没有使用汇编从头开始写过8051的boot程序的。
  5. 主业是32位CPU的C语言开发,工作中临时接触到了8051芯片的编程,或者只是想复习一下8051相关的知识,特别是汇编的逻辑的。

  • 为什么直接使用Keil中的模拟器来运行程序,而不选用一款8051的芯片?
  1. 编程习惯:
    在学习C语言过程中,或者单纯验证C语言纯逻辑功能时,可以直接使用GCC+Makefile、Qt或者VS(Microsoft Visual Studio)编译运行;一条printf就能验证编译环境的正确性。
    而如果使用带8051芯片的硬件,则搭建环境的过程中会遇到各种各样的问题,没有人指导的话经常会遇到瓶颈;购买开发板也需要额外的开支。
    如果是进行32位CPU的嵌入式开发,也有开源的QEMU模拟器可供使用。
  2. 工作习惯:
    在芯片原厂,当一款芯片正在开发中,还不能在FPGA上跑的时候,嵌入式软件工程师的工作也不会等着,往往是直接先用模拟器搭建软件工程,同步编写和测试程序。
  3. 节省时间,方便随时随地调试程序:
    只要不涉及到具体的硬件驱动编写,使用软件模拟器已经能模拟各种通讯驱动的逻辑和业务逻辑,只需要一台电脑,你就可以在家里、在外地都编写和调试代码。
  4. 普适性:
    嵌入式芯片各种各样,五花八门,没有谁能对所有的芯片都熟悉,而芯片的最大公约数:内核,在模拟器中已经能完美运行。如果是32位CPU,QEMU中已经能模拟USB、网络、串口、SPI、I2C、显示屏等各种外设;而Keil C51中也能模拟串口、IO,这对于学习软件逻辑已经够用了。
  5. 简单:
    打开Keil工程,直接运行就能在软件上看到串口输出的结果。

  • 为什么不选用Keil + Proteus的方式来模拟8051硬件?
  1. 的确是有一些单片机开发人员软件硬件都熟悉,能接受这种方式,但是大部分嵌入式软件开发人员,是没有硬件相关软件的使用经验的,Proteus大大增加了学习成本,而且以后的工作中也用不到。
  • 网上能搜到大量8051的教学文章,为什么还要编写这个仓库?
  1. 在网上能搜到的大量8051教程,都很多是学校里的那一套逻辑,分章节描述各种寄存器、汇编指令,没有形成一个完整的工程,不能开箱即用。
  2. 网上有很多8051的文章都是重复的,在查找时浪费时间。
  3. 我自己其实也是在学习8051的过程中,学到哪写到哪加深记忆,也方便以后时间久了以后遇到同样的问题能回来查阅。

二、环境准备及知识储备

  • 开始下一步前,你需要下载并安装Keil软件,并且了解Keil的基本使用。如果你只是看一下源码中的一些写法,并不需要实际运行程序看结果,则忽略此条。Keil软件安装的基本流程如下,其它安装教程的网址会在后面列出:
  1. 从官网下载Keil C51程序,这是一个IDE,集成了编辑器、编译器、链接器、模拟器。
  2. 下载地址 https://www.keil.com/demo/eval/c51.htm 需要注册并填写个人信息,评估版只支持编译2K容量的代码,但本仓库前面一部分的工程在2K范围内,可以直接运行和调试。
  3. 已经用过Keil的可以自行下载Keil破解版并进行破解。
  4. 安装过程中,安装路径不要有空格,不要有中文目录。
  5. 安装完成后打开“Keil uVision5”软件。
  • Keil安装与介绍参考链接
  1. 一是在Keil官网注册账号并下载Keil C51安装,但是安装好的软件只支持编译2K以内的程序。
    https://www.keil.com/demo/eval/c51.htm

  2. 二是安装破解的Keil C51。
    51单片机——如何安装Keil5(保姆级教程)
    【嵌入式学习】单片机入门——1.Keil安装(51版本)


  • 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用户手册里面的一系列文档中的某些章节里面。

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


  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


二、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通用的寄存器会加粗:
地址 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

三、工程与源码介绍

1)Hello world输出

  • 本工程主要演示使用Keil创建一个R8051XC2的默认工程,使用Keil自带的Boot汇编文件,然后新建一个main.c文件,写一个printf函数 + 简单的串口0驱动,并能从软件窗口上看到printf的结果。

  • 创建工程的步骤详见章节“二、环境准备及知识储备”中“Keil创建工程”小节中的内容,你可以省掉这步,直接打开现有的工程。

  • 工程路径:本文档同级目录/01_proj_and_src/01_Hello_world/

  • 你可以直接双击打开 ./01_proj_and_src/01_Hello_world/01_Hello_world.uvproj工程

  • 然后编译:点击软件上面状态栏第三排左侧两个向下小箭头的图标。看到.\Objects\01_Hello_world" - 0 Error(s)表示编译通过。

  • 然后开始运行:点击软件上面状态栏第二排右侧黑色放大镜+红色“d”的小图标;如果你的软件是官网下载的未破解的评估版,会出现一个弹窗,关掉那个弹窗不管它;程序会停在main()函数的第一行,先不要继续运行。

  • 输出的结果会在Keil Debug状态下的UART #1窗口中;这个窗口Keil不会主动为你打开,你需要点击在软件上面第三排图标中的小串口带一个黑色串口的图标旁边的小三角形,选中里面的UART #1,然后软件右下角就会出现UART #1窗口。

  • 继续运行:点击软件左上角一个向下箭头的图标,UART #1窗口中出现了Hello world!的输出。

  • 额外的知识:

    • Keil输出窗口选项中,除了有UART #1、UART #2和UART #3外,还有一个Debug (Printf) Viewer窗口,这个窗口C51是用不了的,这是Keil MDK为ARM等芯片准备的,例如调试STM32时,不需要写串口驱动,而且直接写串口驱动还有点麻烦,而直接对fputc()函数进行重定向之后,能直接在这个窗口看到printf()的输出;这和在PC上直接写C语言程序有点类似,就更方便了。
  • *参考网址 *
    keil C51 重定向printf到串口

2)Keil自带的汇编boot源码解析注释

  • 本工程主要演示使用Keil创建一个R8051XC2的默认工程,使用Keil自带的Boot汇编文件,然后对这个STARTUP.A51进行注释。
  • 工程路径:本文档同级目录/01_proj_and_src/02_Keil_boot_annotation/
  • 你可以直接双击打开 ./01_proj_and_src/02_Keil_boot_annotation.uvproj/02_Keil_boot_annotation.uvproj工程

3)展示8051真正的程序入口, 和添加自定义寄存器头文件

  • 本工程主要演示使用Keil创建一个空工程,不使用Keil自带的boot汇编文件,也不使用Keil自带的寄存器头文件,而是自己添加一切文件,展示8051真正的程序入口,添加自定义寄存器头文件,顺便对8051的每个寄存器进行注释。
  • 工程文件:本文档同级目录/03_Assemble_register/03_Assemble_register.uvproj

4)展示汇编宏定义函数和中断处理

  • 工程文件:本文档同级目录/04_Macro_func_and_irq/04_Macro_func_and_irq.uvproj

5)用汇编从Keil调试窗口中输出Hello world

  • 工程文件:本文档同级目录/05_Assemble_hello_world/05_Assemble_hello_world.uvproj
    双击打开并直接运行,能在Keil UART #1串口中看到hello world输出(这个窗口可能需要你手动在软件中打开)

6)Keil调试输出窗口串口回环

猜你喜欢

转载自blog.csdn.net/qq582880551/article/details/127594062