Blogs

微控制器介绍 - 进一步的开始

Mike Silva.2013年9月1日4评论

嵌入式编程基础知识

本教程条目将讨论一些进一步的嵌入式编程基础,在继续前进到LED Blinky和其他之前需要了解 示例程序。我们将通过查看大多数微控制器中的一般组织和指令的一般组织和类型,以及该组织和这些指令如何反映(或在某些情况下, 忽略了C编程语言。

快速链接

基本CPU组织

当您为您的微控制器编写程序时,您就会写作由执行的程序μC CPU (中央处理单元),执行设计成CPU指令集的各种指令,因此值得一段时间才能简要介绍典型的内部μC CPU.  如果程序以ASM编写,则程序员将直接使用这些CPU指令写入程序。 如果程序以高级语言编写,则编译器将HLL行转换为相应的CPU指令序列。 以下是什么意义意味着对CPU的全面讨论 架构设计。相反,它只是足够的细节(我希望!)让这些部分遵循可理解的部分。 网上和数据表中有很多其他细节。 

本文以PDF格式提供,便于打印

在最简单的意义上,CPU是执行指令的微控制器的一部分。 它在一系列步骤中确实如此:

•从“下一个指令”内存位置指针获取指令

•执行该指令

•相应地前进“下一个指令”指针

每个计算机程序都只是重复执行此序列。

CPU注册

任何CPU都将具有一组板载寄存器,可以将其视为非常快的内存位置。 这些寄存器将自动解决(指令 I 始终在注册时运行 R)或者它们将在指令操作代码(op代码)中的几个位进行解决。 典型的CPU将具有以下类型的寄存器: 

数据寄存器

这些寄存器充当算术,逻辑和转换指令的来源和目的地。有时这些寄存器称为累加器。如果数据寄存器也可用于通用寻址功能,则它将成为“通用”寄存器,如下所述。

解决寄存器

这些寄存器用于保存用于存储器数据访问的地址。根据CPU设计,这些寄存器可以是全面的通用寄存器(相同的寄存器可用于数据操纵或数据寻址,或者这些寄存器可以仅受到用于保持用于数据访问的地址的限制和设计。

堆栈指针

堆栈指针是一个地址寄存器,它指向用于CPU硬件堆栈的内存部分。硬件堆栈是子程序调用的硬件和返回的硬件和中断调用和返回的堆栈。用户程序也可以使用堆栈指针指向的相同堆栈,以保存和恢复其他数据。或者,用户程序可以使用另一堆叠,由另一个地址寄存器指向。这种软件堆栈和硬件堆栈之间的差异是仅由子程序调用的CPU指令调用硬件堆栈并由中断机制返回,并且通过推动和突破堆栈数据的指令返回许多情况。

并非所有CPU设计都使用硬件堆栈指针。 有些只是保留了一个地址寄存器,通常称为链接寄存器,它用作CPU本身的单个堆栈,从而导致非常快速的子程序调用和返回。 如果需要更深层次的堆栈(在程序中的某个点几乎总是这种情况),则用户或OS代码必须复制链接寄存器和软件维护堆栈之间的存储器地址。

程序计数器(也称为指令指针)

这是地址寄存器,指向要执行的当前(或下一个)指令。它可以通过特殊说明访问,或者它可能是标准地址regiser甚至是一个完整的通用寄存器。 它将自动前进到程序中的下一个指令,并将根据程序跳转,呼叫和返回指令自动调整。

CPU指令类型

微控制器CPU将执行一系列 指令,其中一些操作数据,其中一些影响程序控制或CPU行为,其中一些执行其他操作。 以下是CPU指令主要类型的简要概述。 当然存在有变化的说明性细节,如何访问源操作数,以及结果最终的位置。 以下列表非常微小 - 不同的CPU架构可以执行更丰富的指令集,但始终将始终执行这些基础知识的变体。

数据操纵指令

artitemetic指令

算术指令允许CPU添加和减去数字,并且在许多情况下乘以和划分数字。这些数字可以是常量,在程序运行时始终固定,或者它们可以是可变的,可修改的值,在数据存储器或寄存器中保持。 签名的数字恰好是以2S补充形式普遍代表。

• 添加

a = b + c

• 减去

a = b-c

• 比较

公元前

比较两个值的指令实际上是一个减法指令,但其中只有标志的一个,其中没有更改值。

• 否定

a = -b.

占用签名号码并将其转换为该数字的负数。相当于a = 0-b。

重要的是要明白,在大多数情况下, 您的CPU只有对其自然字大小的算术操作的说明。 因此,8位AVR将有一个添加17 + 43的指令(两个值适合8位,结果),但不是170,000,000 + 43,000,000。 AVR能够完美地执行后者添加,但它只是需要一系列指令,每个指令都在对数字的各个8位部分工作。 如果在ASM中编写程序员,程序员将不得不明确地编写此指令序列。 如果以C或其他语言编写,则编译器将自动生成指令序列(通过查看编译程序的ASM列表输出,您可以看到。

CPU也具有增量和减少指令,这是用于添加或减去1的简写指令(或在某些情况下,较小的数字高达+/- 7或+/- 15)。 由于这些操作在程序中非常常见,因此CPU值得支持其有效指令。

• 公司12月

a = a + 1

a = a-1

逻辑指令

与算术指令一样,这些指令通常对CPU的自然字大小或更小的数据工作。 AVR上的8位,ARM Cortex M3上的32,16或8位。 在较大数据上执行逻辑操作需要算术运算所需的一系列指令。

请注意,所有以下示例都以二进制格式(每个位位置1或0)显示数据,而不是十进制格式!

• COMPLEMENT (NOT)

X = ~A (在a到0中设置每1位,每个0位为1)

a = 00110110.

x = 11001001.

• 

x = A. & B

产生按位 AND of A and B, e.g.

a = 00110110.

B = 01101100.

x = 00100100.  : 1在每个位位置,A和B两个是1,0其他地方

• 或者

x = A. | B

产生按位 OR of A and B, e.g.

a = 00110110.

B = 01101100.

x = 01111110.  : 1在每个位位置,A和B为1,0其他位置

• 独家或者

x = A. ^ B

产生按位 独家或A和B,例如,

a = 00110110.

B = 01101100.

x = 01011010:  0在A和B相同的每个位位置, 1他们是不同的

 

转移说明

• SHIFT LEFT/RIGHT

将每个位向右或向左移动一个位置。 对于左移换档,将加载“空”位位置(D0,最低有效位,LSB)。 对于右移空位位置(大多数Siginifccant位,MSB)通常会保持它具有的值(符号扩展),但是可能有向MSB转换为0的指令的版本。 对于两个方向,移出的位通常被移入携带比特,这提供了用于多级移位的连杆。

• ROTATE LEFT/RIGHT

与移位的比特相同,除了移出的位被移回为空位位置。 它同时也被移入携带比特。

• 通过携带位向左/向右移动

与移位相同,不同之处在于随身携带位被移位到空位位置。

• 通过携带左/右转 BIT

除了旋转中包括携带比特之外,旋转相同,因此随身值旋转到空位中,并且偏移向输出移入携带比特(但不进入空位位置)。

 

程序流指令: Unconditional Jumps

• JUMP

PC(程序计数器)=跳转目的地地址。 执行在这个新地址继续。

程序流指令:条件分支

• 分支等于/不等于(至零)

• 分支携带/没有携带

• 分支正/消极

如果条件为真,则PC =分支目标地址,否则PC =下一个指令地址

程序流指令:子程序调用和返回

• CALL

保存返回地址

PC =呼叫目的地地址

• RETURN

PC =保存返回地址

子程序是最基本的代码重用形式之一。如果您有一段需要在不同时间和/或使用不同的数据时运行的代码,则子程序允许您隔离该代码并在任何其他时间段内运行它(“调用它”)。事实上,一个子程序甚至可以称呼自己,但那正在进入递归,这不是我们将讨论的东西。

子程序调用指令的本质是它是一个跳跃(跳转到子程序代码),但跳跃的跳跃记得它来自哪里。通过记住它来自的地址,在子程序结束时,它可以跳回它来自的位置,所以可以继续调用代码。要更精确地,子程序调用指令是跳转指令,其保存子程序调用指令之后的指令的地址,而不是子程序调用指令本身的地址。它是在子程序返回后需要执行的下一个指令。如果子程序返回到子程序调用指令,则程序将在无限循环中找到自己,如果没有结尾调用子程序。

呼叫指令需要具有已知位置以保存PC值,因此子程序可以返回。通常,这种已知的位置可以是两个地方之一。 PC值可以保存在堆栈上的内存中,该堆栈由CPU寄存器指向,或者它可以直接保存在寄存器中(通常称为“链接”寄存器)。堆栈的优点是子程序可以调用其他子例程,并且堆栈将继续增长以保持所有返回地址。链接寄存器的优点在于,存储和检索来自寄存器的数据比存储和从存储器中检索的速度快。链接寄存器的缺点,如果要调用它,那么如果子程序想要调用另一个子例程,则需要在堆栈上显式保存链接寄存器内容。调用其他子程序的子程序通常称为分支子程序,该子程序不调用任何其他子例程的子例程称为叶子子程序。链接寄存器的呼叫和返回从叶子子程序呼叫和返回的呼叫和返回的速度可以是要求分支子程序手动保存和还原链接寄存器的费用。在任何情况下,任一方法都执行将PC值保存在已知位置中的必要功能,以便可以检索并将其加载到子程序末尾的PC中。

要从子程序返回,如上所述,必须将PC加载到调用子程序时保存的地址。如上所述,此地址可以在堆栈上的内存中,或者它可以在Alink寄存器中。许多CPU具有称为“返回”指令的特殊指令,用于获取地址并将其粘在PC中。一些CPU只是使用标准移动指令将已保存的地址移动到PC中。但在任何情况下,结果都是一样的 - 程序继续执行它离开的地方。

接下来是什么?

毕竟这个后台终于是时候考虑编写我们的第一个嵌入式程序,一个闪烁LED。 在传统的尊重中,我正在呼唤这个第一个计划“Embedded Hello World”。这将是本系列下一个教程的主题。 与此同时,您可能希望查看微控制器的数据表或用户手册,以更好地了解它执行的特定指令集。


[]
评论 玛克172013年9月9日
嗨micheal,
嵌入式代表的好东西 编程.Really. 熟练的教程......

我在Windows Platofrm上有一个C / C ++编程的背景,使用VS IDE ..我期待着将我的Carrer更改为嵌入式。
等待下一个教程..

问候,
玛克

[]
评论 求助2013年9月28日
你好,
良好的文章,但我认为可能有一个小错误。我相信Xor实际上与所描述的那样相反。在每个位位置应该是1,其中A和B不同,否则为0。上面描述的是xnor。
[]
评论 mjsilva.2013年9月29日
哎呀!当然,你绝对是对XOR的对立面,我不知道我写的时候发生了什么。谢谢你把它带到了。 “XOR”中的“或”是一个良好的提醒,因为0或0 = 0,1或0 = 1,以及0或1 = 1,只留下1 XOR 1 = 0差异。再次感谢。
[]
评论 Busketzz2019年10月17日

绝对介绍嵌入式系统。必须拥有想要成为嵌入式世界的专业人士的每个人。

要发布回复评论,请单击连接到每个注释的“回复”按钮。发布新的评论(不是回复评论),请在评论的顶部查看“写评论”选项卡。

注册将允许您参加所有相关网站的论坛,并为您提供所有PDF下载。

注册

我同意 使用条款隐私政策.

尝试我们偶尔但流行的时事通讯。非常容易取消订阅。
或登录