打印
[应用方案]

单片机是什么?它是怎样执行程序的?

[复制链接]
2466|39
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
janewood|  楼主 | 2024-2-23 23:54 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
CPU是如何执行程序的?
1、我们先来看下两位全加器
A = 01B = 1H
B = 11B = 3H
A + B = 1 + 3 = 4 = 100B




为了方便更多比特位的运算,我们使用内部集成8个全加器芯片74283来运算
DATA1 = 0000 0101B = 5H
DATA2 = 0000 1010B = 10H
SUM = 0000 1111B = 15H


2、那么数字电路是如何进行加减乘除运算的?
注意:我们这里不考虑一些特殊的情况,我们8位数最大能表示的数为255,所以只考虑数值小于255的情况,更深入的探讨大家可以去寻找更专业的资源学习。
加法运算:
假设我们要进行8+13运算:
十进制运算:8+13= 21;
二进制运算:0000 1000 + 0000 1101 = 00010101;
我们通过8位全加器来验证下



减法运算:
加法是进位,减法需要考虑的则是借位,小学时对加减法的经验是这样的,但是计算机不是这么处理的。计算机只有加法,没有减法。那么 int a = b - c 是怎么得出来结果的呢?首先要了解一个概念——补码。
计算机中对于有符号数,用最高位作为符号位,“0” 代表 “+” ,“1” 代表 “负号-” ;其余数位用作数值位,代表数值。比如 Byte 类型的取值范围为 -128 ~ 127。其中,表示数值的只有 7 位,首位表示正负。
补码规定,正数和 0 的补码就是其原码(原码、反码的定义这里就不多赘述),负数的补码是其正数的原码取反再加 1 。
举个例子,求负 -10 的补码:十进制 10 的原码(按 8 位举例)为 0000 1010,其反码为 1111 0101,取反后再加 1 即为其补码1111 0110。因此,负10 的补码为 1111 0110。
不知道写到这里,大家有没有发现什么端倪?我们再回到减法计算来,a = b - c 实际上等同于a = b + ( -c )。
情形1,减数>被减数
  • 12 - 5= 0000 1100 + 1111 1011= (1)0000 0111= 7 括号里为进位,因为只有 8 位,所以高于 8 位的进位要去掉。
  • (-5 )二进制: 000 0101;
  • 反码:1111 1010;
  • 补码 = 反码+1:1111 1011
  • 最终通过加入反相电路和加1电路得到的最终结果,进位去掉后为0000 0111换算成10近制就是7
Proteus仿真文件:




情形2,减数>被减数
  • 再来计算下7 - 9= 0000 0111 + 1111 0111= 1111 1110= -2
  • (-9)二进制:0000 1001,
  • 反码:1111 0110,
  • 补码:1111 0111
  • 然后得到的是负数,我们又要把它反回来
  • 补码-1:1111 1110-1 = 1111 1101
  • 反码反过来:0000 0010
  • 0000 0111 + 1111 1101
通过这两个例子是不是就清楚了计算机是如何计算减法的了?
乘法运算:
通过说减法,我们是不是对乘法也有一定的启发了呢?乘法其实就是循环的加法。比如 5 * 3 实际上就是 5 + 5 + 5。貌似就说完了。实际上不仅仅如此的。现在有一个电子器件叫做乘法器,其可以实现二进制的乘法、除法等运算。我们同样以 5 * 3 做为例子,讲解一下乘法器计算乘法的流程。
  • 5 * 3 = 0000 0101 * 0000 0011
  • 第一步:5 + 5 = 10
  • 00000 0101 + 0000 0101 = 0000 1010
  • 第二步:10 + 5 = 15
  • 0000 0101 + 0000 1010 = 0000 1111


小提示:当然也可以通过移位电路来运输也是可以的,这里就不举例子了
虽然CPU中有乘法器,但是我们发现实际的最终操作流程还是加法和位移操作计算的乘法运算。我们写的代码中的乘法到底是用乘法器运算还是转化成加法运算,我们也并不太确定,有些编译器编译的时候会对代码进行优化,选取最优的一种算法来计算结果。
除法运算:
除法可以通过减法来实现,比如 10 / 3 等价于 10 一直减 3 直到被减数小于 3 ,减了 3 次,那么 10 / 3 的结果就为 3 了,余数为减完剩下的值 1
其实上面已经提到了乘法器,除法的原理同样也类似(这里不说浮点数的除法,只说整数的除法),但是稍微复杂一点。
同样我们举个例子来说明一下。
  • 10 / 3 = 000 1010 / 0000 0011
  • 第一步:10 - 3 = 7
  • 000 1010 - 0000 0011 = 0000 0111


  • 第二步:7 - 3 = 4
  • 0000 0111 - 0000 0011 = 0000 0100


  • 第三步:4 - 3 = 1,通过比较大小,不能再继续减下去。
  • 0000 0100 - 0000 0011 = 0000 0001


小提示:这里只是展示其中一种除法运算,大家可以去思考其他方式的除法运算,比如说使用移位方式。
然后我们再来看一个完整的CPU计算电路
这里面包含有完整的8位与运算电路,或运算电路,右移运算电路,左移运算电路,还有加法运算电路等,我们实际运算的时候就通过取到的指令通过内部解码来决定当前操作是进行加法操作,还是移位操作,又或是对外部I/O进行锁存操作。
然后这里面我们发现复杂的运算会产生中间数据,比如说乘法,除法,要计算好几次才能得到结果,所以我们就需要寄存器来临时存储这些数据,这样我们就可以计算了.
CPU执行整个程序流程分解

我们以这个代码为例来详细讲解下。
#include <reg52.h>sbit LED = P0^0;void delay( unsigned int nTime){    unsigned char i;    while(nTime--)        for(i=10; i>0; i--);}void main(){   while(1)   {      LED = 0;      delay(10);      LED = 1;      delay(10);    }}
我们再来看下汇编指令,我们的程序从main函数开始执行
C:0x0000    02002D   LJMP     C:002D5: void delay( unsigned int nTime)6: {7:     unsigned char i;8:     while(nTime--)C:0x0003    EF       MOV      A,R7C:0x0004    1F       DEC      R7C:0x0005    AA06     MOV      R2,0x06C:0x0007    7001     JNZ      C:000AC:0x0009    1E       DEC      R6C:0x000A    4A       ORL      A,R2C:0x000B    600B     JZ       C:00189:         for(i=10; i>0; i--);C:0x000D    7D0A     MOV      R5,#0x0AC:0x000F    ED       MOV      A,R5C:0x0010    D3       SETB     CC:0x0011    9400     SUBB     A,#0x00C:0x0013    40EE     JC       delay(C:0003)C:0x0015    1D       DEC      R5C:0x0016    80F7     SJMP     C:000F10: }11:C:0x0018    22       RET12: void main()13: {14:    while(1)15:    {16:       LED = 0;C:0x0019    C280     CLR      LED(0x80.0)17:       delay(10);C:0x001B    7F0A     MOV      R7,#0x0AC:0x001D    7E00     MOV      R6,#0x00C:0x001F    120003   LCALL    delay(C:0003)18:       LED = 1;C:0x0022    D280     SETB     LED(0x80.0)19:       delay(10);C:0x0024    7F0A     MOV      R7,#0x0AC:0x0026    7E00     MOV      R6,#0x00C:0x0028    120003   LCALL    delay(C:0003)20:    }C:0x002B    80EC     SJMP     main(C:0019)C:0x002D    787F     MOV      R0,#0x7FC:0x002F    E4       CLR      AC:0x0030    F6       MOV      @R0,AC:0x0031    D8FD     DJNZ     R0,C:0030C:0x0033    758107   MOV      SP(0x81),#0x07C:0x0036    020019   LJMP     main(C:0019)
小提示:我们的单片机默认都是跳转到main函数处执行

第一步:取指令
C:0x0019 C280
PC计数器指向读取指令的地址,然后存储到指令寄存,通过指令解码器解码后输送给运算单元,执行相应操作. 示例:我们的单片机程序一般都是直接跳转到main函数,这时PC = 0x0019地址里面的指令是C280
第二步:解码
CLR LED(0x80.0)
指令寄存器中的指令通过译码电路进行译码,然后CPU根据译码的结果来执行加减乘除,移位等操作,示例:通过译码器电路我们得知C280代表的意思是C2表示清除位指令
第三步:执行
在执行阶段会根据指令的类型,将算数/逻辑单元(ALU)用于不同的目的。对其他指令,它会作为一个加法器来计算增加或减少栈指针,或者计算有效地址,或者只是简单地加0,将一个输入传递到输出
示例:这里相当于是清除0x80的第0位,也就是将P0.0置低,然后PC更新PC的值,没有对PC值进行操作的话,它就自动累加这里自动累加后是0x001B,然后继续第一步循环操作就完成了我们整个程序的一个执行。
这里只是给出大致的程序执行方式,省略了很多细节操作,大家可以进一步参考更详细的程序执行过程。
晶振在单片机中是起什么作用?
上面的运算,我们都是通过手动的方式来进行的, 我们知道数字电路本身是不工作的,它也不能工作,否则电路就会出乱子,它必须依赖其它电路产生的高低电平才能驱动它工作,我们把这种有规律的高低电平定为脉冲,单片机也是数字电路,它又是怎么工作的?我们必须要有一个能源源不断产生脉冲的电路,它才能持续不断的工作下去,这也就是晶振在单片机电路中为什么被称作为“心脏”的原因,我们把这个“心脏”去掉,相应的整个单片机系统也会**。
为什么有些单片机没有晶振?我们知道单片机工作只要有持续不断的脉冲输入就行,我们有些场合对单片机没有精确的时间要求,所以一般使用内部自带的振荡器为单片机提的时钟脉冲也能确保单片机正常工作,所以在有些地方我们就看不到晶振。那是因为内部自带了RC振荡电路。
复位:CPU执行程序需要有一个初始状态,通过复位可以进入到一个初始状态。这样单片机知道自己的起始位置,它才能按照既定的方式运行程序。

使用特权

评论回复
沙发
tpgf| | 2024-3-1 13:50 | 只看该作者
看着这个图 总有一种单片机和cpld是一个东西的感觉

使用特权

评论回复
板凳
xiaoqizi| | 2024-3-1 14:24 | 只看该作者
普通单片机的乘法器用起来会不会导致死机呢

使用特权

评论回复
地板
晓伍| | 2024-3-1 14:54 | 只看该作者
有时候我们必须要注意细节 即便是 一样的加法  将家数和被加数调换位置  执行顺序就会不同

使用特权

评论回复
5
磨砂| | 2024-3-1 19:14 | 只看该作者
这个代码实现的功能是什么呢  实在没看明白

使用特权

评论回复
6
木木guainv| | 2024-3-1 19:45 | 只看该作者
从我个人感觉 广义上来讲 所有的这些芯片都可以叫单片机

使用特权

评论回复
7
wowu| | 2024-3-1 20:16 | 只看该作者
不同结构的的单片机 它们执行指令的过程是一样的吗

使用特权

评论回复
8
pixhw| | 2024-4-6 11:43 | 只看该作者
程序计数器是单片机中的一个特殊寄存器,用于指示下一条将要执行的指令的地址。在单片机启动后,程序计数器会自动加载预置的起始地址,通常是程序存储器的起始位置。

使用特权

评论回复
9
benjaminka| | 2024-4-6 19:54 | 只看该作者
将编写的程序通过特定的编程器或软件烧录到单片机的闪存(Flash)中。这个过程通常称为“烧录”或“固化”。

使用特权

评论回复
10
ingramward| | 2024-4-8 16:06 | 只看该作者
当单片机接通电源时,会先进行一次复位操作。复位操作主要是将单片机内部的数据存储单元(如寄存器、RAM等)清零,以便在新的程序运行前初始化系统。

使用特权

评论回复
11
uptown| | 2024-4-8 16:18 | 只看该作者
单片机按照程序中的指令序列执行操作。这些操作可能包括数据运算、条件判断、I/O操作、调用子程序等。

使用特权

评论回复
12
louliana| | 2024-4-9 11:40 | 只看该作者
当指令被译码后,单片机会执行相应的操作。这些操作可能包括算术运算、逻辑运算、数据传输、控制流程(如跳转、子程序调用等)等。在执行操作的过程中,单片机会使用内部的寄存器、累加器等部件来暂存中间结果,并根据操作的结果更新程序计数器的值。

使用特权

评论回复
13
alvpeg| | 2024-4-9 15:50 | 只看该作者
单片机的指令集也是其执行程序的关键。例如,ADD指令用于将两个操作数相加并将结果存储到目标操作数中;SUB指令用于将目标操作数减去源操作数并将结果存储到目标操作数中;JMP指令用于无条件跳转到指定的地址;JZ指令用于当目标操作数为零时跳转到指定的地址等。这些指令按照程序中的顺序被取出并执行,从而实现各种复杂的功能。

使用特权

评论回复
14
pmp| | 2024-4-9 16:02 | 只看该作者
程序可能会设计成一个无限循环,或者在完成特定任务后结束。结束时,单片机会执行必要的清理工作,如关闭外设,然后进入休眠模式或等待下一次启动。

使用特权

评论回复
15
febgxu| | 2024-4-9 16:25 | 只看该作者
上层软件提供了一个与硬件无关的接口,使得软件可以独立于硬件进行开发和运行。系统服务层则提供了系统级的各种服务,如任务调度、内存管理、时间管理等,使得上层应用程序可以更加专注于业务逻辑的实现。

使用特权

评论回复
16
1988020566| | 2024-4-9 21:21 | 只看该作者
执行完一条指令后,程序计数器根据指令类型自动更新,以指向下一条指令的地址。对于顺序执行的指令,PC的值通常增加,指向下一条指令;对于跳转指令,PC的值会根据跳转地址更新。

使用特权

评论回复
17
1988020566| | 2024-4-10 14:43 | 只看该作者
单片机根据程序计数器(PC)中的值从程序存储器中读取当前要执行的指令,并将其送到指令寄存器中。

使用特权

评论回复
18
uiint| | 2024-4-10 15:57 | 只看该作者
当程序加载到单片机内存后,单片机会从程序的起始地址开始读取指令。每读取一条指令,程序计数器就会自动加1,以便指向下一条指令的地址。读取到的指令会被送到指令译码器进行解析。指令译码器会根据指令的编码格式,将其翻译成相应的操作。

使用特权

评论回复
19
lzbf| | 2024-4-11 23:01 | 只看该作者
单片机根据分析结果执行指令,可能包括数据计算、数据传输、控制流程等操作。

使用特权

评论回复
20
mmbs| | 2024-4-12 01:38 | 只看该作者
在单片机上电复位后,需要将待执行的程序加载到单片机的内存中。程序通常以机器语言(二进制代码)的形式存储在外部存储设备(如Flash ROM、EEPROM等)中。在程序加载过程中,单片机通过内部的程序计数器(PC)来跟踪程序的执行进度。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

57

主题

1273

帖子

1

粉丝