• 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_loopbackKeil调试输出窗口串口回环
    • 这是一个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个:
    地址0x000x010x020x030x040x050x060x07
    通用寄存器0组R00组R10组R20组R30组R40组R50组R60组R7
    地址0x080x090x0A0x0B0x0C0x0D0x0E0x0F
    1组R01组R11组R21组R31组R41组R51组R61组R7
    地址0x100x110x120x130x140x150x160x17
    2组R02组R12组R22组R32组R42组R52组R62组R7
    地址0x180x190x1A0x1B0x1C0x1D0x1E0x1F
    3组R03组R13组R23组R33组R43组R53组R63组R7
    地址0x200x210x220x230x240x250x260x27
    位地址00H~06H07H~0FH10H~16H17H~1FH20H~26H27H~2FH30H~36H37H~3FH
    地址0x280x290x2A0x2B0x2C0x2D0x2E0x2F
    40H~46H47H~4FH50H~56H57H~5FH60H~66H67H~6FH70H~76H77H~7FH
    地址0x300x310x320x330x340x350x360x37
    剩下都是用户RAM一般开辟成堆栈……
    地址0x380x390x3A0x3B0x3C0x3D0x3E0x3F
    地址…………………………………………
    地址0x780x790x7A0x7B0x7C0x7D0x7E0x7F
    1. R8051XC2特殊功能寄存器区(SFR)介绍,最大128个,8051通用的寄存器会加粗:
    地址0x800x810x820x830x840x850x860x87
    描述P0 IO口锁存器SP 堆栈指针DPL 数据地址低8位DPH 数据地址高8位WDTRELPCON
    地址0x880x890x8A0x8B0x8C0x8D0x8E0x8F
    TCON Timer控制TMOD Timer方式TL0 Timer0低8位TL1 Timer1低8位TH0 Timer0高8位TH1 Timer1高8位CKCON
    地址0x900x910x920x930x940x950x960x97
    P1 IO口锁存器DPSDPCPAGESELD_PAGESEL
    地址0x980x990x9A0x9B0x9C0x9D0x9E0x9F
    S0CON串口控制S0BUF串口锁存IEN2S1CONS1BUFS1RELL
    地址0xA00xA10xA20xA30xA40xA50xA60xA7
    P2 IO口锁存器DMAS0DMAS1DMAS2DMAT0DMAT1DMAT2
    地址0xA80xA90xAA0xAB0xAC0xAD0xAE0xAF
    IE0 中断允许IP0S0RELL
    地址0xB00xB10xB20xB30xB40xB50xB60xB7
    P3 IO口锁存器DMAC0DMAC1DMAC2DMASELDMAM0DMAM1
    地址0xB80xB90xBA0xBB0xBC0xBD0xBE0xBF
    IP 中断优先级 IEN1IP1S0RELHS1RELHIRCON2
    地址0xC00xC10xC20xC30xC40xC50xC60xC7
    IRCONCCENCCL1CCH1CCL2CCH2CCL3CCH3
    地址0xC80xC90xCA0xCB0xCC0xCD0xCE0xCF
    T2CONCRCLCRCHTL2TH2RTCSEL
    地址0xD00xD10xD20xD30xD40xD50xD60xD7
    PSW 程序状态字IEN4I2C2DATI2C2ADRI2C2CONI2C2STASMB2_SELSMB2_DST
    地址0xD80xD90xDA0xDB0xDC0xDD0xDE0xDF
    ADCCONP5 IO口I2CDATI2CADRI2CCONI2CSTASMB_SELSMB_DST
    地址0xE00xE10xE20xE30xE40xE50xE60xE7
    ACC 累加器SPSTASPCONSPDATSPSSNP6 IO口
    地址0xE80xE90xEA0xEB0xEC0xED0xEE0xEF
    P4 IO口MD0MD1MD2MD3MD4MD5ARCON
    地址0xF00xF10xF20xF30xF40xF50xF60xF7
    B 寄存器
    地址0xF80xF90xFA0xFB0xFC0xFD0xFE0xFF

    三、工程与源码介绍

    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调试输出窗口串口回环

  • 相关阅读:
    Three.js 实现3D开放世界小游戏:阿狸的多元宇宙 🦊
    系统学习SpringFramework:Spring AOP
    【LeetCode贪心#09】用最少数量的箭引爆气球,无重叠区间,合并区间(涉及区间重叠情况判断与处理)
    java版工程管理系统Spring Cloud+Spring Boot+Mybatis实现工程管理系统源码
    【MySQL】 MySQL亿级数据、主从架构,Sharding分片
    【赠书活动】AI时代项目经理必备技能
    C# VS CS1752解决办法
    探索iOS之CoreImage框架
    运行.sln 32/64位程序,启动不了,无法显示界面
    C#,人工智能(AI)机器人路径规划(Path Planning)ARA*(Anytime Replanning A* Algorithm)算法与源程序
  • 原文地址:https://blog.csdn.net/qq582880551/article/details/127594062