与现代传感器接口:轮询 ADC 驱动器

在上一篇文章中,我们研究了开发人员应如何在现代嵌入式应用程序中创建一个接口,将低级驱动程序实现细节与应用程序代码分离。该接口提供了一种架构抽象,通过减少对硬件的依赖来提高应用程序代码的可伸缩性和可移植性。
现在我们将根据我们在微控制器的 3 种驱动程序设计技术中讨论的技术,开始研究开发人员可以实现 adc 驱动程序的几种不同方法。在本文中,我们将更详细地研究如何使用轮询技术并讨论阻塞驱动程序和非阻塞驱动程序之间的区别。
阻止还是不阻止,这是个问题
在为微控制器开发任何驱动程序时,开发人员必须决定他们的驱动程序是阻塞还是非阻塞。阻塞驱动程序实质上会暂停代码执行,直到驱动程序完成其任务。例如,映射到 uart 的printf的典型实现是阻塞的。
当您拨打以下电话时:
printf(“你好世界!”);
开发人员知道,该语句后面的任何代码行在整个“hello world!”之前都不会执行。语句已打印出uart。“你好世界!” 包含 12 个字节,96 位,但语句阻塞的时间量取决于 uart 波特率。对于配置为 1 mbps 的 uart,您预计大约需要 96 微秒。对于配置为 9600 bps 的 uart,您预计大约需要 10,000 微秒!这是一个很大的差异,具体取决于硬件的配置方式,并且在将 uart 驱动程序配置为阻塞驱动程序时,它会显着影响程序的执行。
非阻塞驱动程序是在驱动程序完成其任务时不会停止程序执行的驱动程序。例如,可以配置printf和上一个示例中的 uart 驱动程序,使其不会阻塞,而是允许应用程序在每个字节从 uart 发送出去时继续执行。这可以在适当的情况下提高应用程序的效率,但需要额外的设置,例如使用中断、dma 或至少一个传输缓冲区。
决定采用哪种方式设计驱动程序取决于您的应用程序和硬件。例如,如果 uart 配置为 1 mbps,则从效率的角度来看,编写非阻塞驱动程序可能不会获得太多收益,并且实际上可能会导致比通过额外的程序复杂性解决的问题更多。但是,如果应用程序要求 9600 bps,其中应用程序代码被阻塞 10 毫秒,则使用非阻塞驱动程序可以显着提高程序效率,并且额外时序复杂性问题的风险要小得多,而且更易于管理。
嵌入式 adc 驱动程序概述
需要注意的是,在一篇博客中,我无法完成编写完整 adc 驱动程序所需的所有步骤。我可以轻松地在其上写一篇 20 页的论文或提供一个完整的网络研讨会,但它可能仍无法涵盖所有​​细节,但我们至少可以查看一些核心部分。
我们可以通过多种方式组织 adc 驱动程序,但我喜欢组织它们的方式需要三个组件:
低级驱动 申请代码 一个配置模块 低级驱动程序在初始化期间获取配置模块,并根据配置设置硬件。低级驱动程序提供了一个通用硬件抽象层 (hal),然后应用程序代码可以使用该层。adc hal 调用应该是通用的,以便高级应用程序可以以任何必要的方式配置硬件,从而使其可重用和可扩展。例如,我过去使用的一些 adc hal 调用包括:
adcerror_t adc_init(const adcconfig_t * config); adcerror_t adc_startconversion(void); bool adc_conversioncomplete(void); 无效 adc_registerwrite(uint32_t 常量地址,uint32_t 常量值); uint32_t adc_registerread(uint32_t 地址); 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,并且根据我们的需要,实现可以是阻塞的,也可以是非阻塞的。阻塞驱动程序往往比非阻塞驱动程序更简单且不完整,但它们可能效率低下。非阻塞驱动程序允许其他代码在驱动程序工作时运行,但应用程序代码仍然需要检查状态,这在轮询实现中本身是低效的。
在本系列的下一篇文章中,我们将研究如何编写一个应用程序,通过使用中断的 adc 外设对传感器进行采样。


Spectrum仪器为高性能应用配备Julia工具包,开创行业先河
连锁店集中监控系统的设计及方案应用分析
cpu晶体管如何放进去的
数字IC的设计流程及验证方法介绍
华为云 ROMA Connect 行业生态联盟成立,携手共建行业软件合作新生态
与现代传感器接口:轮询 ADC 驱动器
一种适合于工业-4.0应用的解决方案
SMCJ58CA现货 上东沃电子 浙江二极管品牌厂家
一个硬件工程师到底需要做什么?
DS1307与兼容8051的微控制器接口
小米7现身地铁:刘海屏+竖向双摄+玻璃机身,快来看看
在构建下一代Wi-Fi 6E设备时必须考虑的问题和挑战以及测试解决方案
以国家安全为名,澳大利亚或将发出华为5G禁令
5G建设中,深化共建共享必将大幅降低投资
ThinkSystem DM7000是一款可扩展 统一的全闪存中端存储系统
华为P10最新消息:余承东反思华为P10闪存门事件,深刻反省迅速改进!还值得信赖吗?
关于电感型传感器的特点及应用介绍
起亚全新一代K900可能将于2018年正式推出
[组图]无线话筒(9018)
三屏幕电竞笔电原型机Project Valerie在CES展场上失窃