技术热线: 4007-888-234

了解汇编语言和C语言:单片机开发为何要懂汇编

更新时间: 2019-10-19
阅读量:3958

当前,大多数单片机编程都是使用C语言完成的,如果不是C,则是另一种高级语言,如C++。但真实情况并非总是如此,在使用单片机的早期,所有代码都是用汇编语言编写的,在那时这是唯一的选择。记得在那时候,内存是极其有限的,因此必须非常严格地控制它的使用。而且除此之外,没有可用的高级语言工具。

QQ截图20191019153849.png

随着计算机技术的发展,程序开发语言变得更多,单片机的功能也变得越来越强大(16位、32位,再到64位),价格变得更便宜,集成度更密集,应用程序也变得更复杂。

那么,为什么现在还需要学会汇编语言?单片机开发人员应具有阅读汇编语言的能力,这其中有两个原因。

首先,单片机中的代码效率几乎总是至关重要的。现代编译器通常在优化代码方面做得非常出色。但是,了解编译器工作原理很重要。否则,开发人员在做调试时可能会造成混乱。

此外,编译器也可能不够完美的运行,比如用C语言编写代码时,不是以最清晰的方式编写的,开发人员需要能够理解出了什么问题。检查编译器生成的代码应该是开发过程中的日常工作,这提供了机会来确保编译器的输出确实能够达到程序员的预期。

有些开发人员需要能够读懂汇编的第二个原因是,在做“硬件开发”进行编程时,这是必不可少的。如今,驱动程序不一定是100%汇编的,但是某些汇编语言的内容几乎是不可避免的。为了最有效地使用驱动程序并进行故障排除,必须能够详细了解驱动程序在做什么。

为什么要学会编写汇编语言

编写汇编语言呢?如今,用汇编语言编写整个应用程序是非常少见的,至少大多数代码都是用C编写的。因此,C编程技能是单片机开发的关键要求。但是,一些开发人员需要掌握汇编语言编程。当然,此技能是针对特定处理器的。但是,如果设计人员已经掌握了一个CPU的汇编语言,则迁移到另一个CPU并不会太有挑战性。

编写汇编语言有两个原因。第一个也是最重要的原因是实现一些用C语言无法表达的功能。一个简单的例子:禁用中断功能。这可以通过编写汇编语言子例程并像调用C函数一样调用它来实现。为此,必须知道正在使用的C编译器的调用/返回协议,但这通常很容易弄清楚。例如,你可以只看编译器生成的代码。

实现汇编语言代码的另一种方法是,通常使用asm扩展关键字将其内联插入C代码中。当需要单个或仅几个汇编程序指令时,这特别有意义,因为消除了调用/返回开销。此扩展的实现因编译器而异,但通常,asm语句采用以下形式:

asm(" trap #0");

通常,唯一需要用C语言表示的功能的地方是启动代码和设备驱动程序。嵌入式软件应用程序开发的这一部分涉及少量开发人员。因此,如上所述,对汇编编写技能的需求仅限于一组选定的工程师。

一些开发人员认为,他们需要知道如何编写汇编语言,才能以比编译器“更有效”的方式实现代码。在极少数情况下,这可能是正确的。因为,现在大多数现代编译器在优化和生成高效代码方面,已经做得非常出色。

这是一个例子:

#define ARRAYSIZE 4
char aaa[ARRAYSIZE];
int main()
{
    int i;
    for (i=0; i<ARRAYSIZE; i++)
    aaa[i] = 0;
}

这看起来像一个简单的循环,将数组的每个元素设置为零。如果你在激活了合理数量的优化的情况下进行编译并尝试调试代码,你将得到一个奇怪的结果:它将直接跳入循环(即,表现得好像根本没有循环)。这是因为编译器确定将零移动32位到数组中比循环更有效。

结果代码如下所示:

mov r3, #0
ldr r2, .L3
mov r0, r3
str r3, [r2]
bx lr
.L3:
.word .LANCHOR0

调整ARRAYSIZE的值会产生一些有趣的结果。将其设置为5可得到以下效果:

mov r3, #0
ldr r2, .L3
mov r0, r3
str r3, [r2]
strb r3, [r2, #4]

仍然没有循环。使它继续进行下去是8:

然后,为64位CPU构建此代码将变得更好:

mov w0, 0
str xzr, [x1, #:lo12:.LANCHOR0]

因此,它可以继续运行。较大的数组大小会导致有效的循环,或者可能只是调用诸如memset()之类的库函数,这是可以从汇编中调用的标准C库函数。

最重要的是,汇编语言技能远不是过时的,单片机开发人员不应该仅限于会阅读汇编语言。