与现代传感器的接口:轮询ADC驱动程序
与现代传感器的接口:轮询ADC驱动程序
Interfacing with modern sensors: Polled ADC drivers
我们研究了在现代嵌入式应用程序中,开发人员应该如何创建一个接口,将底层驱动程序实现细节与应用程序代码分离。这个接口提供了一个体系结构抽象,通过减少对硬件的依赖,提高了应用程序代码的可伸缩性和可移植性。
现在我们将开始研究几种不同的方法,开发人员可以根据我们在3个微控制器驱动程序设计技术中讨论的技术来实现ADC驱动程序。在本文中,我们将更详细地研究如何使用轮询技术,并讨论阻塞和非阻塞驱动程序之间的区别。
阻止还是不阻止,这是个问题
当为微控制器开发任何驱动程序时,开发人员必须决定他们的驱动程序是阻塞的还是非阻塞的。阻塞驱动程序基本上会暂停代码的执行,直到驱动程序完成其任务为止。例如,printf映射到UART的典型实现是阻塞的。
当你打电话时:
printf(“你好,世界!”);
开发人员知道,无论该语句后面的哪一行代码都不会执行,直到整个“Hello World!“声明已经在通用异步收发器上打印出来了。“你好,世界!“包含12个字节,96位,但语句阻塞的时间取决于UART波特率。对于配置为1Mbps的UART,您将期望大约96微秒。对于配置为9600bps的UART,您将期望大约10000微秒!这是一个很大的区别,这取决于硬件的配置,它可以显著地影响程序的执行,UART驱动程序被配置为阻塞驱动程序。
非阻塞驱动程序是在驱动程序完成其任务时不会暂停程序执行的驱动程序。例如,上一个例子中的printf和UART驱动程序可以被配置成不阻塞,而是允许应用程序在每个字节被发送出UART时继续执行。这可以在适当的情况下实现更有效的应用,但需要额外的设置,例如使用中断、DMA或至少一个传输缓冲区。
如何设计驱动程序取决于应用程序和硬件。例如,如果UART被配置为1Mbps,那么从效率的角度来看,编写非阻塞驱动程序可能不会获得太多好处,实际上可能会导致更多的问题,而不是通过增加程序复杂性来解决问题。然而,如果应用程序调用9600bps,其中应用程序代码被阻塞10毫秒,那么拥有一个非阻塞驱动程序可以显著提高程序效率,并且额外的时间复杂度问题的风险更小,也更易于管理。
嵌入式ADC驱动程序概述
需要注意的是,在一个博客中,我无法完成编写完整ADC驱动程序所需的所有步骤。我可以很容易地写一篇20页的论文,或者开一个完整的网络研讨会,它可能还不能涵盖所有的细节,但我们至少可以看看一些核心部分。
低级驱动程序在初始化时接收配置模块,并根据配置设置硬件。低级驱动程序提供了一个公共硬件抽象层(HAL),应用程序代码可以使用它。ADC-HAL调用应该是通用的,以便高级应用程序可以以任何必要的方式配置硬件,并且可以重用和扩展。例如,我过去使用的一些ADC HAL调用包括:
· AdcError_t Adc_Init(const AdcConfig_t * Config);
· AdcError_t Adc_StartConversion(void);
· bool Adc_ConversionComplete(void);
· void Adc_RegisterWrite(uint32_t const Address, uint32_t const Value);
· uint32_t Adc_RegisterRead(uint32_t Address);
· void Adc_CallbackRegister(AdcCallback_t const Function, TYPE (*CallbackFunction)(type));
前三个API提供初始化ADC硬件、启动转换并检查转换状态的功能。最后三个函数的设计是为了允许低层硬件的可伸缩性。例如,如果HAL不提供应用程序所需的选项(例如转换单个ADC信道),则可以使用ADC_RegisterRead和ADC_RegisterWrite函数扩展HAL。这提供了基于应用程序需求的灵活性,而不需要创建一个压倒性的API。
编写一个简单的阻塞ADC驱动程序
我们可以编写一个非常简单的ADC驱动程序,它位于硬件层之上。例如,我们可以创建一个名为Adc_Sample的简单函数,该函数启动Adc硬件,然后将所有结果存储在缓冲区中,然后应用程序可以访问该缓冲区。存储模拟值计数值的缓冲区不一定只需要存储一个值,而是可以存储多个值,这些值以后可以根据应用程序的需要进行平均或过滤。采样函数的阻塞版本可能如下所示:
正如您在这段代码中看到的,while循环会阻止执行,直到ADC硬件完成转换,然后将值存储在应用程序缓冲区中。
编写一个简单的无阻塞ADC驱动程序
将阻塞驱动程序转换为非阻塞代码非常简单,但是需要对更高级别的应用程序代码进行更改。例如,现在,如果应用程序要对传感器进行采样,开发人员会调用:
Adc_Sample();
在非阻塞版本中,开发人员必须检查Adc_Sample的返回值,以查看示例是否已完成并可以使用。这使示例可以在后台运行,应用程序代码在驱动程序代码的以下更新后继续运行:
结论
正如我们在这篇文章中看到的,有多种方法来编写ADC,并且实现可以是阻塞的,也可以是非阻塞的,这取决于我们的需要。阻塞驱动程序往往比非阻塞驱动程序更简单、更不完整,但它们可能效率低下。非阻塞驱动程序允许其他代码在驱动程序工作时运行,但是应用程序代码仍然需要检查状态,这在轮询实现中本身效率低下。