微控制器编程与面向对象编程


11

我已经用C ++完成了一些基本的面向对象的编程(创建B树,哈希算法,双链表),并且已经在C中完成了小项目(例如制作科学计算器等)。

就程序员必须具有的思维方式和“思维”而言,硬件编程(特别是针对微控制器)与面向软件/对象的编程有何不同?

我大多数人通常认为一个人比另一个人难吗?

以我的背景(如上所述),我是否需要为硬件编程做很多准备工作,还是可以在没有太多准备工作的情况下直接涉足?


4
最大的学习曲线将是如何驱动微型计算机中的特定硬件。这将涉及数小时的数据手册。不幸的是,没有简单的出路。
drxzcl 2011年

@rrazd,我注意到您已包含arduino标签。这是因为您要使用arduino接线语言和库吗?还是将用纯C编写嵌入式应用程序?如果您打算坚持使用arduino环境,则可以很安全,轻松地进行操作,因为他们已经对硬件做了一些抽象。
乔恩·L

@Jon我打算为初学者使用arduino板。它不类似于C语言吗?我认为这涉及的相同的基本概念....
rrazd

1
我想知道您是说很多人会称之为“ I / O编程”,还是您期望重新布置带有代码的硬件。arduino绝对是前者;后者将是FPGA的领域。
JustJeff 2011年

1
@rrazd-我更改了标题;“硬件编程”听起来太像HDL(硬件描述语言),例如VHDL和Verilog,用于对FPGA和CPLD进行编程。
stevenvh 2011年

Answers:


10

与大多数微控制器打交道时,您将必须完全放弃面向对象的范例。

微控制器通常受寄存器和RAM的限制,时钟速率慢且没有流水线/并行代码路径。例如,您可以忘记PIC上的Java。

您必须进入汇编语言的思维方式,然后进行程序编写。

您必须使代码保持相对平坦并避免递归,因为RAM限制通常会导致堆栈问题。

您必须学习如何编写高效的中断服务例程(通常使用汇编语言)。

您可能必须以汇编语言手动重构部分代码,以实现编译器不支持(或支持不佳)的功能。

您必须编写数学代码,其中要考虑到大多数微控制器的字长和缺乏FPU功能(即在8位微指令上进行32位乘法=邪恶)。

这是一个不同的世界。对我而言,拥有计算机科学或专业编程背景可能像对待微控制器时完全不了解一样是一个障碍。


1
您不必完全放弃面向对象的范例,但是在较小的Micros上,可能有必要放弃重量级的对象实现,并真正考虑解决每个问题的最佳方法是什么。通常这是程序性的,但是轻巧的对象(很好地实现(通常是手工操作))有时会缩小复杂的微控制器项目的大小。
克里斯·斯特拉顿

6
除了放弃面向对象之外,所有这些都是正确的。您可能不会使用具有OO功能的语言,但这并不排除面向对象。对于微控制器,您将编写用于所有硬件外设(ADC,串行总线控制器,PWM等)的驱动程序。此类驱动程序应始终以面向对象的方式编写,以使其具有以下功能:1)自治且不了解/不在乎程序的其余部分,以及2)实现私有封装,以使程序的其余部分无法进去摆弄它。在C语言中这是100%可能的,并且不会影响性能。
伦丁

1
我非常不同意第一句话,我的所有微控制器项目都是使用C ++和面向对象的方法构建的,我们使用的micros不太大(ROM为32kB),面向对象的引导加载程序还不到2kB,我并没有真正看到限制。您不能做疯狂的事情,但是设计可以是面向对象的,没有问题。
阿森纳

@Arsenal请注意,我说的是“最多”,请注意,您在评论已有四年历史的主题。:)
亚当·劳伦斯

我完全不同意第一句话和最后一句话。而且汇编很少使用,并且大多数情况下仅用于8位MCU(只需查看此论坛,您可以找到多少篇带有汇编代码的文章?)。您当然可以并且(IMHO)应该以面向对象的方式编写32位MCU
Andrejs Gasilovs 2016年

10

您需要考虑以下几件事:

  • 您将使用C作为语言
  • 您仍然可以使用函数指针创建面向对象的感觉,以便您可以覆盖函数等。我在过去和当前的项目中都使用过这种方法,并且效果很好。因此,OO部分存在,但不是C ++。

还有其他限制,例如速度和内存有限。因此,作为一般准则,我避免:

  • 使用堆,如果有一种方法可以在没有Malloc的情况下解决问题,那么我可以这样做。例如,我预分配缓冲区并仅使用它们。
  • 我有意减少编译器设置中的堆栈大小,以尽早解决堆栈大小问题,请仔细进行优化。
  • 我假设每行代码都会被一个事件中断,所以我避免使用不可重入的代码
  • 我假设甚至中断都是嵌套的,所以我相应地编写了该代码
  • 除非有必要,否则避免使用OS。70%的嵌入式项目确实不需要操作系统。如果必须使用操作系统,则仅使用可提供源代码的软件。(Freertos等)
  • 如果我使用的是操作系统,则几乎总是对事物进行抽象处理,以便可以在数小时内更改操作系统。
  • 对于驱动程序等,我将只使用供应商提供的库,除非没有其他选择,否则我永远不会直接摆弄这些东西。这使代码可读,并改善了调试。
  • 我查看了循环和其他内容,尤其是在ISR中,以确保它们足够快。
  • 我总是方便地使用一些GPIO来测量内容,上下文切换,ISR运行时间等。

清单还在继续,在软件编程方面,我可能低于平均水平,我相信有更好的做法。


3
+1表示“可以根据需要使用OO范例”。您需要在门口检查的不是OO设计。OOD只是一种鼓励您将相关代码和数据保持在一起的哲学。您需要留下的是在企业系统中实现OO的方式,它具有多层抽象,控制反转以及所有这些爵士乐。固件的任务就是驱动硬件,仅此而已。
drxzcl 2011年

7

我都做,所以这是我的看法。

我认为到目前为止,嵌入式中最重要的技能是调试能力。所需的思维方式有很大不同,因为有更多的地方可能出错,并且您必须非常开放地考虑尝试采取的所有不同方式都可能出错。

对于新的嵌入式开发人员来说,这是最大的问题。PC人往往会觉得比较粗糙,因为他们已经习惯了为他们工作。他们往往会浪费大量时间寻找工具来代替他们做事(提示:没有太多)。一遍又一遍地撞墙撞墙,不知道该怎么办。如果您觉得自己陷入困境,请退后一步,确定是否可以找出所有可能出问题的地方。系统地缩小您的潜在问题列表,直到找到答案。从此过程中可以直接得出结论,您应该通过一次不进行太多更改来限制问题的范围。

经验丰富的嵌入式人员倾向于将调试视为理所当然的事情……大多数不能很好地完成调试的人不会持续很长时间(或在大型公司中工作,而这些公司只是接受“固件很困难”作为某种功能为何的答案。已经晚了)

您正在开发在开发系统的外部系统上运行的代码,各个平台对目标的可见程度不同。如果在您的控制之下,请寻求开发辅助工具以帮助提高对目标系统的可见性。使用调试串行端口,调试中的比特输出,著名的闪烁灯等。当然,至少要了解如何使用示波器,并将引脚I / O与“范围”一起使用,以查看某些功能何时进入/退出,ISR触发等。我已经看到人们为之奋斗的时间比实际需要的时间更长,这仅仅是因为他们从不费心去设置/学习如何使用适当的JTAG调试器链接。

重要的是要非常清楚您相对于PC拥有的资源。仔细阅读数据表。考虑您正在尝试做的任何事情的资源“成本”。学习面向资源的调试技巧,例如使用魔术值填充堆栈空间以跟踪堆栈使用情况。

虽然PC和嵌入式软件都需要一定程度的调试技能,但对于嵌入式而言,这更为重要。


5

我假设您的C ++经验是基于PC的。

程序员从PC转移到微控制器的一个经常犯的错误是,他们没有意识到有限的资源是多么有限。在PC上,当您创建具有100 000项的表或编写可编译为1MB机器代码的程序时,没人会阻止您。
这里它拥有丰富的内存资源,尤其是在高端微控制器,但它仍然是相去甚远什么,你会来。对于业余项目,您可能总是可以发挥最大作用,但是在专业项目中,由于价格更便宜,您经常会被迫使用较小的设备。 在一个项目中,我正在使用TI MSP430F1101
。1KB的程序存储器,128字节的配置Flash,128字节的RAM。该程序不适合1K,因此我必须在配置Flash中编写一个23字节的函数。使用这些小型控制器,您可以按字节计算。在另一情况下,程序存储器太小了4个字节。老板不会让我使用带有更多内存的控制器,而是我不得不优化一个已经优化的机器代码(它已经用汇编器编写了)以适合额外的4个字节。您得到了图片。

根据你在你的工作平台上就必须处理非常低的水平的I / O。一些开发环境具有可写入LCD的功能,但在其他开发环境上则需要您自己完成,并且必须从头到尾阅读LCD的数据表以了解如何进行控制。
您可能需要控制一个继电器,这比LCD还要容易,但是这将需要您进入微控制器的寄存器级别。再次提供数据表或用户手册。您必须再次在数据表中了解微控制器的结构,您可以在框图中找到它。在微处理器时代,我们谈论一种编程模型,基本上是处理器寄存器的组合。当今的微控制器是如此复杂,以至于对所有寄存器的描述都占据了100页数据表的最佳部分。IIRC仅对MSP430的时钟模块进行了25页的描述。

μ

微控制器通常用C编程。C ++占用大量资源,因此通常不用担心。(大多数用于微控制器的C ++实现提供有限的C ++子集。)就像我说的那样,根据平台的不同,您可能拥有广泛可用功能库,可以节省大量开发时间。值得花一些时间研究它,如果您知道有什么用,它可能为您节省很多时间。


我为Atari 2600编写了游戏,这是一个相当有限的平台。我最初发布的游戏实质上是4K代码(因为我有32K的购物车,所以添加了一些额外的东西,但是4K版本完全可以玩);RAM是128个字节。我发现可以想到,在我写游戏(2005年)的那一年,其他游戏的发行量实际上是百万倍。
supercat

@supercat-是的,但这是可以预料的,2005年的Atari 2600已经有200年的历史了!我从来没有玩过像FPS这样的动作游戏,但是当我看玩它们需要什么时,无论是在编程上还是在电气上,GPU都比您的CPU功能强大得多,我不禁摇头:-)。我在16k TRS-80 IIRC上下棋(氩气)。我兄弟的飞行模拟器不需要更多。
stevenvh 2011年

还不到200岁。它于1977年首次亮相,所以它甚至还不到30岁。虽然我同意这在技术上是千载难逢的,但我仍然被这样的事实震惊,那就是不仅数量增加了一百,而且数量也没有增加千倍,但RAM和代码大小均增加了100万倍。由于2600的频率为1.19MHz,而更新的系统仅在低GHz范围内,因此速度并未获得太大的提升。它们每个周期的性能要比2600(每个周期可以并且必须生成1/76的视频行)多得多,但我认为它们的速度不是1,000,000x。
supercat

3

“硬件编程”可能意味着很多事情。编写非常小的芯片(例如10F200、512条指令,几个字节的RAM)几乎就像设计电子电路一样。另一方面,使用大型GUI工具包对大型Cortex微控制器(1 Mb FLASH,64 kB RAM)进行编程可能非常类似于PC / GUI编程。恕我直言,一个好的嵌入式/实时程序员需要软件(例如工程学方面)和电路设计方面的技能。对于较大的uC,C ++是不错的语言选择,对于很小的语言,C可能是唯一的选择。Assemby知识可能很方便,但是我不建议您完全在组装中进行严肃的项目。

我已经与(SWI和EE)双方的人员进行了认真的嵌入式工作。我通常更喜欢SWI人员,只要他们具有多线程编程方面的经验。

您的问题听起来像您想深入了解嵌入式编程。一定要这样做。对于低级方面(连接芯片的外设及其周围的硬件),您将需要学习一些新技能,但这是很多工作而没有很多新概念。对于项目的较高层,您可以利用现有的知识。


1

对于您调用的每个arduino库方法,都有大量的C / C ++代码使之成为可能,它被很好地打包以供您用作API。查看一下hardware / arduino / *目录下的arduino源代码,您将看到为您编写的所有C / C ++,它们直接与AVR微控制器的寄存器交互。如果您的目标是学习如何编写这样的内容(直接针对硬件),那么这里有很多内容要讲。如果您的目标是使用它们的库进行某些工作,那么可能没有什么要讨论的,因为大多数艰苦的工作都为您完成,并且它们的库和开发环境非常易于使用。

但是,在使用资源受限的设备时,一些经验法则可能适用于arduino环境或其他环境:

请注意您正在使用多少内存。代码大小(用于闪存)和静态RAM使用率(代码中的常数将始终存在于RAM中)。我认为静态RAM的使用从一开始就更为重要,因为它很容易忽略。对于堆栈,堆和常量,只有1000个字节可以使用的情况并不少见。明智地使用它,所以当字节或无符号char的整数(每个1字节)就足够时,请避免使用长整数数组(每个4字节)之类的东西。这里的另一个答案很好地涵盖了其他一些重要方面,所以我就在这里停止,我主要是想指出一点,如果您不使用arduino库并编写自己的 C库,那么还有很多要讲的内容。


0

关于微控制器与OOP编程,它们并非相反。确实所有供应商库都使用纯C语言,但是所有平台也都支持C ++ OOP。开发人员可以在此基础上构建并确实构建C ++高级库和设备固件。很好的例子是Arduino库,它们是官方的和用户构建的-大多是C ++类。也许并不是所有的OOP优势都可以在嵌入式环境中得到充分利用,但是众所周知的C ++ vs C优势在这里也是有效的。

关于思维方式和思维,如其他答案所述,微控制器是非常受资源限制的平台(特别是在RAM中,速度较慢)-诸如动态内存分配之类的东西,通常都排除了C ++异常。只要选择了正确的硬件,就很容易采用这些限制并使用其他技术(在其他平台中也广泛使用)。

在我看来,更艰巨的挑战可能是嵌入式编程中的另一个额外维度-时序。这是因为通常嵌入式软件会处理大量实时事件,严格定时的协议以驱动外围硬件和一般任务本身(这些在其他“高级”平台中也有一些相似之处,例如多线程应用程序)。

在处理新硬件时,请准备好阅读大量数据表-我想这可能与“心态”问题部分有关:)当然,需要一些EE和硬件知识。

我还要指出的是,如今嵌入式软件开发不需要汇编语言。实际上,Java(默认情况下为OOP)已经存在并且正在变得强大(至少对于某些类型的嵌入式设备(例如IoT设备),它的前途可能非常光明)。


在关注方面,动态内存(重新)分配所带来的影响比时序更容易成为传统OO的障碍。
克里斯·斯特拉顿

也许你是对的。但是有些人在80到90年代为MSDOS实模式软件编程,具有64K(数据存储段)RAM空间可用,对他们来说这是“自然的”。也许MSDOS PC比今天的STM32F4更“嵌入式”环境:)
Flanker

STM32F4通常以闪存的形式具有更多的程序存储器,但是PC通常带有更多的RAM存储器来存储可变的运行时对象。尽管通过分段寻址强制执行的整个远指针操作很痛苦,但两者都缺少真正的MMU,而对于RAM较少的系统(即STM32F4),这将成为更多问题。此外,PC的正常运行时间往往更短,并且可接受的故障率更高。
克里斯·斯特拉顿
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.