编写固件:使用汇编语言还是高级语言?

19

保护这段内容,因为它有点基于观点并且相当广泛(不同固件的复杂性和代码大小范围是巨大的,例如LED控制器与SSD控制器之间等)。大多数答案实际上都很好,我只是认为这不是新用户发表意见的好地方。 - Peter Cordes
17个回答

33

几点评论:

1) 绝对不要使用汇编语言,除非有性能或优化方面的限制。使用汇编语言会导致以下指标飙升:

  • 编写时间
  • 调试时间
  • 测试时间
  • 文件文档时间
  • 一年后回顾自己编写代码时所做的操作时间
  • 犯错误的几率

2) 我更喜欢C++而不是C语言,因为它具有命名空间封装和编译时面向对象实践的便利性。 C语言有太多全局变量和命名空间冲突的机会。(实时Java也很好,但据我了解,它的要求还是很高的)

或者说是C++子集:排除异常、虚函数、运行时类型识别,以及大多数情况下的动态内存分配 -- 基本上任何在编译时未指定的东西,因为它通常需要额外的资源来运行,这就是C++的“膨胀”。

我曾经使用过TI和IAR的C++编译器,分别用于TMS320和MSP430微控制器,并通过适当的优化设置,它们可以很好地减少你从C++中可能预期的开销。(特别是如果你通过合理使用inline关键字来帮助它)

我甚至使用模板来获得一些编译时的好处,以促进良好的代码重用:例如,编写一个单个源代码文件来处理8位、16位和32位CRC;并且使用编译时多态性,允许你指定类的通常行为,然后重用它但覆盖其中的某些函数。同样,TI编译器在适当的优化设置下具有极低的开销。

我一直在寻找Microchip PICs的C++编译器,唯一一个我发现的生产商是IAR。($$$是一个障碍,但我希望有一天能够购买一份副本) Microchip C18/C30编译器非常好,但它们是C而不是C++。

3) 关于编译器优化的特定注意事项:它可能会使调试非常困难;通常无法单步执行经过优化的C/C++代码,您的观察窗口可能显示与未经优化的代码中您认为应该包含的变量无关的变量。 (一个好的调试器会警告您某个特定变量已被优化出了存在感或转换成寄存器而不是内存位置。许多调试器不会。 >:(

此外,一个好的编译器会让您通过 #pragmas 在函数级别上选择/选择优化。我使用过的那些只允许您在文件级别上指定优化。

4) 将C代码接口到汇编语言:这通常很困难。最简单的方法是创建一个具有您想要的签名的桩函数,例如uint16_t foo(uint16_t a, uint32_t b) {return 0; },其中uint16_t=无符号短整型,我们通常使位数显式。然后编译它并编辑它产生的汇编代码(只需确保离开/退出代码的部分),小心不要在完成后破坏任何寄存器而不恢复它们。

内联汇编可能会出现问题,除非您正在执行非常简单的操作,例如启用/禁用中断。

我喜欢的方法是使用编译器内嵌函数或“扩展ASM”语法。Microchip公司的C编译器基于GNU C编译器,并支持“扩展ASM”,它允许您编写一些内联汇编代码,并指定使用的寄存器/变量,它会处理所有保存/恢复寄存器的工作以确保您的汇编代码与C“和谐共处”。TI的TMS320 DSP编译器不支持这些功能;它只有一组有限的内置函数可供使用。
我曾使用汇编来优化一些频繁执行的控制循环代码,或计算sin()、cos()和arctan()。但除此之外,我会避免使用汇编语言,而是坚持使用高级语言。

4
大部分同意,但我认为不需要排除使用虚拟函数。运行时开销非常小,比你可能会用来替代虚拟函数的方法(比如自己管理函数指针)要少,并且更重要的是,虚拟函数比你自己设计的任何方案更容易让其他程序员理解。在我看来,在排除虚拟函数之前应该先排除模板。模板本身没问题,只是我经常看到它们被误用,所以一想到它们我就下意识地感到不安。 - KeyserSoze
为IAR编译器套件升级。我也喜欢量子飞跃。http://www.state-machine.com/index.htm - GregC
大多数固件都不是面向对象的。因此,如果您从板子的IDE(如AVR Studio)获得良好的支持,则C语言将是最佳的固件编程语言。否则,您可以放心地选择汇编语言,只要您具备编译器能力和汇编技能。 - Aadishri
大多数固件都没有面向对象编程的倾向。没有理由不这样做,即使只考虑命名空间的原因,它也可以使设计变得更加容易。 - Jason S
调用汇编函数不应该那么难。您可以声明它为 extern "C" uint16_t foo(T1, T2, T3); 来绕过 C++ 名称重整。但是,从编译器输出开始是一个很好的方法,可以获得所有必要的汇编指令,将其放置在正确的链接部分,并且通常是优化汇编的良好起点。 - Peter Cordes

22
大多数微控制器制造商都提供了一些交叉编译器,您可以在PC上编译代码,然后将其传输到微控制器中。
为什么选择C语言?
C语言的一个优点是,您的代码将更容易移植到未来的其他微控制器中。计算机的历史表明,代码通常比硬件实现更持久。
第二个优点是控制结构(if,for,while),使代码更易读和易维护。
为什么选择汇编语言?
您可以手工优化。
结论
通常情况下,这种问题的权衡取决于具体的用途。请注意,通常可以通过在C代码中进行汇编调用来混合两者,因此您可以找到适合您项目的平衡。

针对PIC硬件的特定要求
似乎大多数PIC硬件没有GCC选项。另一方面,正如评论者所指出的那样,Microchip C30编译器适用于16位PIC24和dsPIC33是gcc。
PIC当前也不被SDCC支持。
新信息:根据评论,SDCC对PIC有可行的支持。
还有一些其他开源选项,但我没有使用过它们。


如果你想要的话,你可以在C语言中使用汇编。 - Joe Phillips
那就是我在上一句话中想要表达的。我会讲得更明确。 - John Mulder
Microchip C30编译器适用于16位PIC24和dsPIC33,其基于gcc。 - Doug Currie
这是gcc,但他们没有包含C++部分 :( - Jason S
SDCC已经支持Microchip PIC16和PIC18系列的芯片,目前正在进行相关工作。在当前版本中,它已经可以很好地运行。虽然它还没有被认为是“完整”的,但人们已经将其用于商业产品。 - Adam Davis
显示剩余2条评论

7

最好的选择可能是使用C语言编码,然后在极少数需要手动优化且比编译器更好的情况下,应将汇编代码编写到C文件中。


7

汇编语言在个人电脑上已经过时,但在嵌入式系统中仍然非常重要。

在嵌入式系统中编写汇编与在个人电脑上编写汇编不同。个人电脑的编译器在生成优化指令方面比人类更出色。嵌入式系统通常具有奇怪的体系结构,它们的优化编译器不像个人电脑的优化编译器那样成熟。


5

我在为微控制器编写汇编代码时遇到一个问题,就是需要非常小心地布置代码。如果跳转表跨越了内存边界,会导致代码跳转到非常奇怪的地方,这让人非常困扰。而在C语言中,编译器会为你处理这个问题。


5
我肯定会选择C语言。它更快,能够创建更可靠的软件。汇编提供的东西很少,仅在极少数情况下有用。 请注意,在C中:
  • 你可以轻松地从现有平台(甚至从PC)移植代码。
  • 你可以使用高级语言进行开发,而不会影响执行速度或代码大小。只要有质量的编译器可用(对于PIC18,有很多选择),这些可能比手工制作的汇编代码更好。
  • 调试、测试和维护代码要容易得多。C生成更可靠的代码。

另外,与PIC18相关的另一件事是,你无需处理非直观的PIC体系结构以及像存储器BANK这样的问题。


那么,你会如何为PIC 18编译你的C代码?还有更多相关信息吗? - cbrulak
更好但也更昂贵的编译器是来自IAR的。其他不错的选择包括Hitech编译器和Microchip的编译器,后者正在变得越来越好。 - kgiannakakis

4

我之前使用过IAR C编译器来编写8051的程序,效果不错。

我的最新做法是这样的:

使用优秀的优化编译器,用C语言编写代码。只有当存在大小或速度问题时,才考虑将某些部分重写为汇编语言。

然而,自从采用这种方法以来,我从未需要编写一行汇编代码...


4

选择C语言!

我曾在一家大型消费电子制造商工作。我最后一次看到汇编语言是在1996年,用于RC5和RC6解码以及电视调谐算法的一些小的中断服务例程中。 之后一直使用C和C++(只使用类,没有STL、异常或RTTI)。 我对8051的旧KEIL编译器、greenhills编译器(MIPS)和VxWorks工具集(基于PowerPC)有很好的经验。

正如Roddy所说,先用C编写,如果需要,再优化为汇编语言。


3

在许多情况下,汇编语言可能会更快;当你使用桌面电脑时,编译器往往已经优化到手写汇编不再必要的程度,但在微控制器领域,它经常是必须的。此外,如果您需要编写中断处理程序等内容,则通常无法使用C语言。

至于编译,可以在谷歌上搜索适用于您目标设备的C编译器。


专为嵌入式微控制器设计的编译器(例如IAR)往往具有编写中断处理程序所需的所有技巧。 - Roddy

2

除非

  • 程序存储空间非常有限。比如在经过费力的手动优化汇编代码后,你设法将程序放入这1024字节的Flash中,并且没有剩余空间。在这种情况下,任何C编译器都不会有好的表现。

  • 你想要绝对的时间控制。如果任何数量的中断延迟时间太长,你必须依靠汇编语言。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接