首页 > 编程语言 >51单片机如何运行程序

51单片机如何运行程序

时间:2022-08-23 16:55:06浏览次数:70  
标签:字节 程序 存储器 51 MOV 单片机 地址 寄存器

目录

51单片机储存器结构

80C51单片机的内部存储器分为内部程序存储器和内部数据存储器,这种程序与数据分开存放的存储器结构称为“哈佛”结构。所谓哈弗就是数据与程序分开存储,这也是51单片机的缺点:速度不快;对应的是冯诺依曼结构,是数据与程序存储一块。

程序存储器

单片机复位后,程序计数器(PC)的内容为0000H,从0000H单元开始执行程序。STC89C52系列HD版本单片机除可以访问片上Flash存储器外,还可以访问64KB的外部程序存储器。因此,对于STC89C52系列HD版本单片机而言,其利用EA引脚来确定是访问片内程序存储器还是访问片外程序存储器。当EA引脚接高电平时,STC89C52系列HD版本单片机首先访问片内程序存储器

当PC的内容超过片内程序存储器的地址范围时,系统会自动转到片外程序存储器。以STC89C54单片机的HD版本为例,当若EA引脚接高电平,单片机首先从片内程序存储器的0000H单元开始执行程序,当PC的内容超过3FFFH时系统自动转到片外程序存储器中取指令。此时外部程序存储器的地址从4000H开始。

另外中断服务程序的入口地址(又称中断向量)也位于程序存储器单元。在程序存储器中,每个中断都有一个固定的入口地址,当中断发生并得到响应后,单片机就会自动跳转到相应的中断入口地址去执行程序。外部中断0的中断服务程序的入口地址是0003H,定时器/计数器0中断服务程序的入口地址是000BH,外部中断1的中断服务程序的入口地址是0013H,定时器/计数器1的中断服务程序的入口地址是001BH等。由于相邻中断入口地址的间隔区间(8个字节)有限,一般情况下无法保存完整的中断服务程序,因此,一般在中断响应的地址区域存放一条无条件转移指令,指向真正存放中断服务程序的空间去执行。

数据存储器

内部RAM共256字节,可分为3个部分:低128字节RAM(与传统8051兼容)、高128字节RAM(Intel在8052中扩展了高128字节RAM)及特殊功能寄存器区。

低128字节的数据存储器既可直接寻址也可间接寻址。高128字节RAM与特殊功能寄存器区貌似共用相同的地址范围,都使用80H~FFH,地址空间虽然貌似重叠,但物理上是独立的,使用时通过不同的寻址方式加以区分。

高128字节RAM只能间接寻址,特殊功能寄存器区只可直接寻址,通过不同的寻址方式,区别使用相同的地址空间

在这里插入图片描述

寄存器A是专门用来放操作数和运算结果的,51单片机的所有运算几乎都要通过累加器A来实现,不通过累加器A实现不了。 而寄存器B是专门为乘法和除法设计的寄存器

特殊功能寄存器(SFRs)

特殊功能寄存器(SFR)是用来对片内各功能模块进行管理、控制、监视的控制寄存器和状态寄存器,是一个特殊功能的RAM区。STC89C52系列单片机内的特殊功能寄存器(SFR)与内部高128字节RAM貌似共用相同的地址范围,都使用80H-FFH,但特殊功能寄存器(SFR)必须用直接寻址指令访问。单片机上电后SP=0x07

image-20220823155931095

程序计数器PC在物理上是独立的,不属于SFR之列。PC字长16位,是专门用来控制指令执行顺序的寄存器。单片机上电或复位后,PC=0000H,强制单片机从程序的零单元开始执行程序。

累加器ACC是8051单片机内部最常用的寄存器,也可写作A。常用于存放参加算术或逻辑运算的操作数及运算结果。

B寄存器在乘法和除法运算中须与累加器A配合使用。MUL AB指令把累加器A和寄存器B中的8位无符号数相乘,所得的16位乘积的低字节存放在A中,高字节存放在B中。DIV AB指令用B除以A,整数商存放在A中,余数存放在B中。寄存器B还可以用作通用暂存寄存器。

堆栈指针SP是一个8位专用寄存器。它指示出堆栈顶部在内部RAM块中的位置。系统复位后,SP初始化位07H,使得堆栈事实上由08H单元开始,考虑08H~1FH单元分别属于工作寄存器组1-3,若在程序设计中用到这些区,则最好把SP值改变为80H或更大的值为宜。STC89C52系列单片机的堆栈是向上生长的,即将数据压入堆栈后,SP内容增大。

直接与间接寻址

比如MOV A,#01H

MOV R0,A ;执行完这一句之后,R0=#01H, 直接寻址

MOV A,#20H

MOV @R0,A ;把#20H送给R0指向的单元0x01H,执行完之后01地址中存储的内容就变成#20H,间接寻址

汇编

新建一个空项目,并新建一个c文件,写如下代码

在这里插入图片描述

编译文件后,按下调试按钮,放大镜中间有个d字母就是它

在这里插入图片描述

代码的位置   指令的字节形式   指令  
C:0x0000    020030   LJMP     C:0030 
//main函数开始的地方
C:0x0003    751000   MOV      0x10,#0x00  //给0x10 0x11这2个字节的位置赋值5
C:0x0006    751105   MOV      0x11,#0x05
C:0x0009    7B03     MOV      R3,#0x03   //给R3赋值3
C:0x000B    7A00     MOV      R2,#0x00   
C:0x000D    7D02     MOV      R5,#0x02   //给R5赋值2
C:0x000F    7C00     MOV      R4,#0x00
C:0x0011    7F01     MOV      R7,#0x01   //给R7赋值1,参数传递过程是从后向前的,在调用函数前会将参数赋值
C:0x0013    7E00     MOV      R6,#0x00
C:0x0015    12001D   LCALL    add(C:001D) //调用add函数,会把返回地址0x0018压入栈
C:0x0018    8E08     MOV      0x08,R6     //add函数的结果放在0x08和0x09这2个字节的位置,这是计算的结果
C:0x001A    8F09     MOV      0x09,R7
C:0x001C    22       RET
//ADD函数
C:0x001D    EF       MOV      A,R7
C:0x001E    2D       ADD      A,R5
C:0x001F    FF       MOV      R7,A
C:0x0020    EE       MOV      A,R6
C:0x0021    3C       ADDC     A,R4
C:0x0022    CF       XCH      A,R7
C:0x0023    2B       ADD      A,R3
C:0x0024    CF       XCH      A,R7
C:0x0025    3A       ADDC     A,R2
C:0x0026    FE       MOV      R6,A
C:0x0027    E511     MOV      A,0x11
C:0x0029    2F       ADD      A,R7
C:0x002A    FF       MOV      R7,A
C:0x002B    E510     MOV      A,0x10
C:0x002D    3E       ADDC     A,R6
C:0x002E    FE       MOV      R6,A
C:0x002F    22       RET			//返回的时候会把栈顶的地址0x0018弹出给PC
//建立栈
C:0x0030    787F     MOV      R0,#0x7F
C:0x0032    E4       CLR      A         //将A寄存器置0
C:0x0033    F6       MOV      @R0,A     //间接寻址,将A的值0赋值给0x7F的位置
C:0x0034    D8FD     DJNZ     R0,C:0033 //循环,将0x7F到0x01位置赋值0
C:0x0036    758111   MOV      SP(0x81),#0x11  //栈指针SP设置为0x11 SP寄存器位置是0x81 用直接寻址
C:0x0039    020003   LJMP     main(C:0003)

在单片机中,DJNZ指令的具体功能是使操作数的内容减1,并判断操作数是否等于0,如果不等于0,则跳转至标号处,如果等于0,则顺序往下执行

C字母代表这是代码区,0x0000地址存放了一条3B大小的指令 LJMP C:0030

为什么第一条是跳转指令?

为啥单片机的SP复位后指向0x07, 因为0x00~0x07这8个字节用于R0 ~R7这8个寄存器
准确的说,栈空间的起始位置在0x08开始,所以a变量的位置是0x08~0x09, int变量占2B

C:0x0030处的代码建立了栈,Sp等于0x11,注意SP=0x11即指向第4个参数的低位字节的地址,说明单片机的sp指向的栈顶是有数据的

压栈指令会先将sp增加,留出空间,后填入数据

例如压入返回地址0x18, 先将sp+2指向0x13, 然后将0x12~0x13这2个字节的地方填入返回地址0x0018,注意地址的填入是反着填,0x12位置填入18,0x13位置填入00

在这里插入图片描述

当程序执行main函数结束后,即将执行RET指令,在执行前SP=0x11

image-20220823163827292

执行后SP=0x0f,比0x11少了2,把之前SP指向的2个字节(0x10位置和0x11位置)当做返回地址赋给PC指针,而且赋值的时候把05作为高位,00作为低位,PC=0x0500

image-20220823164054703

PC最后指向0x0500,并非程序所占用的空间,也就是超出了程序的大小空间,会提示access violation at C:0x0500 : no 'execute/read' permission

标签:字节,程序,存储器,51,MOV,单片机,地址,寄存器
From: https://www.cnblogs.com/cyfuture/p/16616909.html

相关文章

  • swift-计算器实例(小程序)
    通过小项目开发的实例,学习swift。为大家分享swift实现简单的计算器项目,具体如下:////ViewController.swift//计算器////Createdbyyaoyezhifanon2022/8/23.......
  • 创建maven的java工程和创建maven时创建web程序
    创建maven的java工程      这样一个maven项目就创建完成了创建maven时创建web程序      这样一个创建maven是创建web程序......
  • Python小程序(三):自动读取secure文件,并封禁异常IP地址
    Python小程序(三):自动读取secure文件,并封禁异常IP地址Python小白编写的内容。欢迎大家指正。#!python#-*-coding:utf-8-*-#时间:20220812#作者:ColoFly#转载请注......
  • 程序员被京东淘汰转身痛哭,HR扎心了
    大家好呀,我是小千学姐程序员真的越老越被嫌弃吗?相信很多人都会附和“就是青春饭”“35岁是个槛”“年龄大的程序员没市场”这些言论听起来很刺耳但是也确实是程序员......
  • Qt将程序打包成.exe文件,并添加图标
    1、在工程中添加一个QtResourceFile,文件名任意  2、将.ico后缀的图片放到跟工程文件(.pro)文件同目录下,并在QtResourceFile文件中添加该.ico文件  3、添加相......
  • Net6 应用程序运行在Linux系统
    一、运行环境LinuxCentOS7系统,.Net6应用程序二、在系统中安装运行环境,可以去官网上去下载相应得版本https://dotnet.microsoft.com/zh-cn/download/dotnet/6.0我用得......
  • taro小程序日期选择器
    taro-swiper-weektaro-swiper-week是一个基于taro的日期选择器控件。可以用在h5、微信小程序等众多平台!简体中文|English......
  • 【Go实战基础】数组实战,程序员的基本功
     数组实战,程序员的基本功。实战需求:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。实战思路:......
  • 小程序提交审核提示接口未配置在app.json文件中
    以下接口未正确配置在app.json文件中,勾选协议可继续提交,该版本发布后,用户将无法使用相关接口能力。 接口未正确配置:wx.chooseLocation、wx.getLocation    ......
  • 微信小程序day01
    微信小程序小程序App大小有限制,不超过2M(功能相对局限)大小无限制(功能更强大)不用安装,不用更新(方便)需要到商城下载,定期更新(复杂)打开方......