简体   繁体   English

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

[英]Unit testing patterns for microcontroller C code

Although there are plenty of unit test frameworks that support C, I'm a little stumped on how to write unit tests for micro controller code (PIC in my case, but I think the question is more general than that). 虽然有很多单元测试框架支持C,但我对如何为微控制器代码编写单元测试感到有点困难(在我的情况下是PIC,但我认为问题比这更普遍)。

Much of the code written for micro controllers revolves around Writing configuration and data values to registers, reading incoming data from registers and responding to interrupt events. 为微控制器编写的大部分代码都围绕将配置和数据值写入寄存器,从寄存器读取输入数据以及响应中断事件。 I'm wondering if anyone can provide some pointers on the most effective way to this. 我想知道是否有人可以提供一些最有效的方法指针。

You write; 你写;

"Much of the code written for micro controllers revolves around Writing configuration and data values to registers, reading incoming data from registers and responding to interrupt events". “为微控制器编写的大部分代码都围绕将配置和数据值写入寄存器,从寄存器读取输入数据以及响应中断事件”。

I agree that this is often the case in practice, but I don't actually think this is a good thing, and I think rethinking things a little will help you with your test goals. 我同意这在实践中经常出现这种情况,但我实际上并不认为这是一件好事,我认为重新思考一些事情会帮助你实现你的测试目标。

Perhaps because microcontroller programmers can reach out and touch the hardware any time they like, many (most?) of them have got into the habit of doing just that, throughout their code. 也许是因为微控制器程序员可以随时联系并触摸硬件,许多(大多数?)他们已经养成了在整个代码中做到这一点的习惯。 Often this habit is followed unquestioningly, maybe because so many people doing this sort of work are EEs not computer scientists by training and inclination. 通常这种习惯是毫无疑问的,也许是因为很多人从事这种工作的是EEs而不是计算机科学家的训练和倾向。 I know, I started out that way myself. 我知道,我自己就这样开始了。

The point I am trying to make, is that microcontroller projects can and should be well designed like any other software project. 我想说的是,微控制器项目可以而且应该像任何其他软件项目一样进行良好设计。 A really important part of good design is to restrict the hardware access to hardware drivers! 良好设计的一个非常重要的部分是限制硬件访问硬件驱动程序! Partition off all the code that writes registers, responds to interrupts etc. into modules that provide the rest of your software with nice, clean, abstracted access to the hardware. 将所有编写寄存器的代码分区,将中断等响应到模块中,从而为软件的其余部分提供对硬件的良好,干净,抽象的访问。 Test those driver modules on the target using logic analyzers, oscilloscopes, custom test rigs or whatever else makes sense. 使用逻辑分析仪,示波器,自定义测试装置或任何其他有意义的测试来测试目标上的驱动程序模块。

A really important point is that now the rest of your software, hopefully the great majority of it, is now just C code that you can run and test on a host system. 一个非常重要的一点是,现在你的软件的其余部分,绝大多数,现在只是你可以在主机系统上运行和测试的C代码。 On the host system the hardware modules are stubbed out in a way that provides visibility into what the code under test is doing. 在主机系统上,硬件模块以一种方式存根,可以查看被测代码正在执行的操作。 You can use mainstream unit testing approaches on this code. 您可以在此代码上使用主流单元测试方法。 This needs some preparations and work, but if you are well organized you can create a reusable system that can apply to all your projects. 这需要一些准备和工作,但如果组织良好,您可以创建一个可以应用于所有项目的可重用系统。 The potential benefits are enormous. 潜在的好处是巨大的。 I wrote a little more about these ideas here; 我在这里写了一些关于这些想法的内容;

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

One approach to this might be to use an emulator. 一种方法可能是使用模拟器。 I've been working on an AVR emulator and one of the ideas for using it is indeed to unit test code. 我一直在研究AVR仿真器,其中一个使用它的想法确实是单元测试代码。 The emulator implements the CPU and registers, interrupts and various peripherals, and (in my case) bytes written to the emulated UART go to the regular stdout of the emulator. 仿真器实现CPU和寄存器,中断和各种外设,并且(在我的情况下)写入仿真UART的字节转到仿真器的常规stdout In this way, unit test code can run in the emulator and write its test results to the console. 通过这种方式,单元测试代码可以在模拟器中运行,并将其测试结果写入控制台。

Of course, one must also ensure that the emulator is correctly implementing the behaviour of the real CPU, otherwise the unit tests on top of that can't be trusted. 当然,还必须确保模拟器正确实现真实CPU的行为,否则单元测试无法信任。

Write mock versions of your register access functions/macros. 编写寄存器访问函数/宏的模拟版本。 Note that this assumes that your code uses a common set of register access functions, and not ad-hoc stuff like *(volatile int*)0xDEADBEEF = 0xBADF00D everywhere. 请注意,这假设您的代码使用一组通用的寄存器访问函数,而不是像*(volatile int*)0xDEADBEEF = 0xBADF00D这样的特殊内容。

Call your interrupt handlers directly from your test code (may be problematic on some architectures¹), a "software interrupt" if available, or from a timer interrupt handler if you need them to execute asynchronously. 直接从测试代码调用中断处理程序(在某些架构上可能有问题¹),如果可用则调用“软件中断”,或者如果需要它们异步执行,则从定时器中断处理程序调用。 This may require wrapping your interrupt enable/disable code in functions/macros that you can mock up. 这可能需要在您可以模拟的函数/宏中包装中断启用/禁用代码。

¹ 8051 comes to mind: at least with the Keil 8051 compiler, you can't call interrupt functions directly. ¹8051首先想到:至少使用Keil 8051编译器,你不能直接调用中断函数。 This could be worked out with the C preprocessor though. 这可以通过C预处理器来解决。

是否有任何类型的环回模式,以便您可以使用控制器本身生成可以测试的事件?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM