微控制器C代码的单元测试模式

26

虽然有许多支持C语言的单元测试框架,但我对如何编写微处理器代码(在我的情况下是PIC)的单元测试感到有些困惑,但我认为这个问题比那更加普遍。

微控制器的许多代码都围绕着向寄存器写入配置和数据值,从寄存器读取传入数据并响应中断事件。我想知道是否有人可以提供一些关于最有效的方法的指导。


有足够声望的人可以给这个问题添加“嵌入式”标签吗?谢谢。 - Steve Melnikoff
4个回答

36

你写道:

"大部分针对微控制器编写的代码都涉及将配置和数据值写入寄存器、从寄存器中读取传入数据以及响应中断事件"。

我认为实践中通常是这样,但我实际上认为这并不是一件好事,我认为重新思考一下会帮助你实现你的测试目标。

也许是因为微控制器程序员可以随时触摸硬件,所以他们中的许多(大多数?)人已经养成了在整个代码中都这样做的习惯。通常这种习惯被毫无保留地遵循,可能是因为这种工作的许多人是电气工程师而不是计算机科学家,这是出于训练和倾向。我知道,我自己也是这样开始的。

我试图说明的重点是,微控制器项目可以像任何其他软件项目一样进行良好设计。良好设计的一个非常重要的部分是将硬件访问限制为硬件驱动程序!将所有编写寄存器、响应中断等的代码分区到模块中,为您的软件提供对硬件的良好、干净、抽象的访问。使用逻辑分析仪、示波器、定制测试夹具或任何其他有意义的工具在目标上测试这些驱动程序模块。

一个非常重要的点是,现在您的其余软件(希望是大多数软件)现在只是您可以在主机系统上运行和测试的C代码。在主机系统上,硬件模块被挂壁,以便提供对正在测试的代码正在做什么的可见性。您可以对此代码使用主流单元测试方法。这需要一些准备工作和工作,但如果你组织良好,你可以创建一个可重用的系统,适用于所有你的项目。潜在的好处是巨大的。我在这里稍微多写了一点关于这些想法的东西;

[http://discuss.joelonsoftware.com/default.asp?joel.3.530964.12][1]


5
好观点。我可以补充一下:习惯使用uint16_t、uint8_t等类型(而不仅仅是int、char),这样在从嵌入式平台到个人电脑之间以及不同的嵌入式平台之间跳转时,您的类型更加可预测。 - Craig McQueen
4
这个答案存在问题:硬件驱动程序抽象会产生很大的开销,通常是无法接受的,除非用汇编语言编写。但是混合使用C语言和汇编语言非常麻烦——不仅是PIC架构很难处理,而且编译器在处理不同寄存器组时需要跳过一些障碍,这对于同时编写汇编语言来说是一个极其巨大的麻烦。 - Jodes

3
一种解决方法是使用模拟器。我一直在开发一个AVR模拟器,其中一个想法就是用它来进行单元测试代码。该模拟器实现了CPU和寄存器、中断和各种外设,并且(在我的情况下)写入模拟UART的字节会传输到模拟器的常规stdout。这样,单元测试代码可以在模拟器中运行,并将其测试结果写入控制台。
当然,还必须确保模拟器正确地实现了真实CPU的行为,否则在此基础上进行的单元测试将无法信任。

2

编写模拟版本的寄存器访问函数/宏。注意,这假设您的代码使用一组公共的寄存器访问函数,而不是在每个地方都使用类似于 *(volatile int*)0xDEADBEEF = 0xBADF00D 的特定代码。

直接从测试代码中调用中断处理程序(在某些体系结构上可能存在问题¹),如果有“软件中断”则可用,或者如果需要异步执行,则从计时器中断处理程序中调用中断处理程序。这可能需要将中断使能/禁用代码包装在函数/宏中以进行模拟。

¹ 8051 系列微控制器可能会有问题:至少在 Keil 8051 编译器中,您不能直接调用中断函数。不过,这可以通过 C 预处理器解决。


0

也许有一种回环模式,这样您就可以使用控制器本身生成事件进行测试吗?


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