本文来源于微信微信官方账号:巧学模电数电单片机
当单片机需要调用程序/函数/固定数据时,需要读取ROM,然后在RAM中执行这些程序/函数的功能。产生的临时数据也存在于RAM中,这些临时数据在断电后丢失。
ROM:(Read Only Memory)
单片机中的程序存储器用于存储程序数据、常量数据或变量数据。
c文件和h文件中的所有代码、全局变量、局部变量const常量数据限制符定义,startup.a ** 所有文件中的代码都存储在ROM中。
RAM:(Random Access Memory)
存储程序中使用的变量可以随机访问存储器。
所有需要在整个程序中重写的数量都存储在RAM中,包括全局变量、局部变量和堆栈段。
在编译、汇编和链接程序后,生成hex文件。
使用专用烧录软件,通过烧录器将hex文件烧录到ROM中。
Hex文件究竟是如何传输到MCU内部ROM的?
所以,此时的ROM包含了所有的程序内容。
无论是一行程序代码、函数中使用的局部变量、头文件中声明的全局变量、const声明的只读常量,都生成了二进制数据,包括在hex文件中,并将其全部烧录到ROM中。
此时,ROM包含了程序的所有信息,正是因为这些信息,才“指导”了CPU的所有动作。
有些人可能会有疑问,既然所有的数据都在ROM中,RAM中的数据从何而来?
CPU何时将数据加载到RAM?
将需要放在RAM中的数据烧录到RAM中吗?
要回答这个问题,首先必须明确一点:ROM只读取存储器,CPU只读取数据,而不是写数据,数据仍然保存在存储器中;
RAM是一个随机存储器。CPU不仅可以从中读取数据,还可以将数据写入其中。断电后,数据不会保存。这是一个永恒的真理,总是记在心里。
如果你知道上面的问题,很容易想到RAM中的数据在烧录时没有写入。
因为烧录完成后,拔下电源,再次给MCU上电时,CPU可以正常执行动作,RAM中仍有数据。
这说明RAM中的数据不是在烧录时写入的,也说明RAM中的数据是在CPU运行时写入的。
关键在于:这些数据不是人工写入的,CPU写入的,那么CPU是什么时候写入的呢?
听我说,ROM包含了所有的程序内容,当MCU上电时,CPU开始从第一行代码处执行指令。
这里的工作是为整个程序的顺利运行做好准备,或者说是RAM的初始化(注:ROM只读不写),有几项工作任务:
1、全局变量分配地址空间---à若全局变量已经赋予初始值,则将初始值从ROM复制到RAM。
如果没有赋予初始值,则全局变量对应的地址下的初始值为0或不确定。
当然,如果变量的地址空间已经指定,则可以直接定位到相应的地址,然后由“连接器”完成分配地址和定位地址的任务。
2、设置堆栈段的长度和地址---àC语言开发的单片机程序一般不涉及堆栈段长度的设置,但这并不意味着没有必要设置。
栈段主要用于中断处理时“保存现场”和“现场还原”,其重要性不言而喻。
而且如此重要的内容,也包含在编译器预设的内容中,确实省事,但不一定省心。
3、分配数据段data,常量段const,代码段code的起始地址。
无论代码段和常量段的地址如何,它们都固定在ROM中,无论它们如何排列,都不会影响程序。
但必须注意数据段的地址。
数据段的数据应该从ROM复制到RAM,在RAM中,有数据段data、堆栈段stack和通用工作寄存器组。
一般情况下,工作寄存器组的地址是固定的,这就要求在绝对定址数据段时,数据段不能覆盖所有工作寄存器组的地址。
必须引起严重关注!
这里提到的“第一行代码处”不一定是你自己写的程序代码,大部分都是由编译器或编译器自带的demo程序文件代表的。
由于您自己编写的程序(C语言程序)中没有包含这些内容。
更先进的单片机,这些内容,都在startup文件中,仔细阅读,是有益的。
通常的做法是:普通flashMCU上电或复位时,PC指针中存储“万”,表示CPU从ROM万地址执行指令,并在该地址放置跳转指令,使程序跳转到_ ** 在in函数中。
然后,根据不同的指令,一个接一个地执行。当中断发生时(中断数量也非常有限,2~5个中断),根据系统分配的中断向量表地址,将跳转到中断服务程序的指令放置在中断向量中。这样,整个程序就会运行起来。
这种ROM结构决定CPU这样做。
事实上,在这里,C语言编译器做了很多工作,只是,你不知道而已。
假如你仔细阅读编译器自带的help文件,你就会知道很多事情,这是了解编译器的最佳方式。
I/O口寄存器:它也是一个可以更改的数量。它被安排在一个特殊的RAM地址上供系统访问,而不是在这些位置上定义其他变量。
中断向量表:中断向量表是指固定在MCU内部的ROM地址,不同的地址对应不同的中断。
每次出现中断时,直接调用相应的中断服务子程序,将程序的入口地址放在中断向量表中。
ROM的大小:对于flashMCU,ROM空间的大小通常是整个字节,即ak*8bits。
这个很容易理解,一目了然,ROM的空间就是AK。
然而,对于一些OTP类型的单片机,如holtek或sonix公司的单片机,我们经常看到数据手册上写着“OTP progarming ROM 2k*15bit。”
可能会有疑问。这个“15bit”认为是一个字节多,两个字节不够。ROM空间是2k,2k以上还是4k,但少了一点?
这里有两个概念:一个是指令的位宽,另一个是指令的长度。
指令的位宽是指指指指令所占数据位的宽度;有的是8位宽,有的是15位宽。
指令长度是指每个指令所占用的存储空间,包括一个字节、两个字节、三个字节甚至四个字节。
比如我们做广播体操的时候,有很多动作要做,但是每一个复杂的动作都可以分解成几个简单的动作。
例如,当我们做伸展运动时,我们只听到广播大喊“2”、2、3、4、5、6、7、8”。
这里的每个数字都代表一个指令。
听到“3”指令后,我们的头、手、腰、腿、脚分别做出了不同的动作:眼睛向前看,左手叉腰,右手抬起,五指伸直,自然并拢打开,右腿伸直,左腿弓步等等。
完成这些动作的指令只有一个“3”,但有许多动作需要执行,因此将多个分解动作合并为一个指令,每个分解动作的“位宽”为15位。
实际上也是如此,在反汇编或汇编时,可以看出,复合指令确实是一种简单的指令组合。
回答之前的问题,OTP的ROM空间应该是2K,指令位宽应该是15位。
一般来说,当指令位宽不是8倍时,这意味着MCU的大部分指令长度是一个字节(注:字节宽度为15位,不是8位),少数字节为2个或多个字节。虽然它的总空间很小,但它可以容纳很多空间数据。