现代传感器的接口:中断驱动的ADC驱动程序

Interfacing with modern sensors: Interrupt driven ADC drivers

研究了如何编写一个阻塞的模数转换器(ADC)驱动程序和一个使用轮询技术不阻塞应用程序流的驱动程序。轮询外围设备的驱动程序效率低下,如果系统处于低功耗状态,可能会浪费宝贵的时钟周期,否则会浪费能量。开发人员实现ADC驱动程序的一种有效方法是使用中断来通知应用程序转换周期已经完成。在本文中,将研究如何做到这一点。

更新ADC驱动程序示例函数

有几种不同的方法可以编写ADC驱动程序来使用中断。在本文中,将介绍如何修改上一篇文章中介绍的非阻塞ADC驱动程序。应用程序可以通过调用函数ADC_Sample来启动ADC转换。

这是一个很好的例子,为什么有一个好的硬件抽象层(HAL)可以派上用场。无论是阻塞,还是阻塞、轮询或中断,都会调用完全相同的函数,其行为只是根据驱动程序的配置设置而改变,或者可能会根据应用程序的需要链接到不同版本的Adc_Sample函数中。

非阻塞系统的Adc_Sample函数如下所示:

bool Adc_Sample(void)

{

AdcPin_t AdcPin = AdcChannel0;

static bool SampleInProgress = false;

bool SampleComplete = false;

if(SampleInProgress == false)

{

if(Adc_SampleIndex == ADC_SAMPLE_SIZE)

{

Adc_SampleIndex = 0;

}

SampleInProgress = true;

Adc_StartConversion();

}

else

{

if(Adc_ConversionComplete == true)

{

for(AdcPin = AdcChannel0; AdcPin < NUM_ANALOG_PINS; AdcPin++)

{

Adc_SampleBuffer[i][Adc_SampleIndex] = *AD1BufPtr++;

}

Adc_SampleIndex++;

SampleComplete = true;

}

return SampleComplete;

}

新版本中,Adc_Sample函数可能实现如下所示:

  1. bool Adc_Sample(void)
  1. {
  1.     Adc_StartConversion();
  1.     return true;          
  1. }

非阻塞驱动程序有各种各样的检查和对缓冲区的访问等。对于基于中断的驱动程序,所要做的就是启动基于外围设备的ADC通道转换,这是在初始化期间配置的。因此,例如,如果要对通道0、1和3进行采样,这些通道将是在初始化过程中启用的通道。这个驱动程序是一次采样所有指定的通道,而不是只采样一个或两个。正如所提到的,有很多方法可以做到这一点,并帮助澄清概念,正在使用最简单的解决方案。             

此时,如果调用Adc_StartConversion,希望Adc外围设备对通道进行采样,但是当中断触发时,此时不会发生任何事情。需要填充ADC中断处理程序,但是在驱动程序中这样做是有问题的。相反,如果可以的话,希望尝试抽象中断处理程序代码。             

中断的抽象化             

开发人员在编写驱动程序时经常遇到的一个问题是,当开发一个中断驱动的解决方案时,常常将中断与应用程序代码紧密耦合。最佳情况下,中断将驻留在驱动程序层中的驱动程序代码中,而不是位于体系结构中最高层的应用程序代码中。将中断与应用程序代码紧密耦合会使移植代码变得困难,甚至在某些情况下甚至会对其进行缩放。             

开发人员可以使用一个解决方案,将中断保留在驱动程序层中,并仍然为应用程序自定义,这就是使用回调。回调函数是对可执行代码的引用,该代码作为参数传递给其代码,后者允许较低级别的软件层调用在高级层中定义的函数[1]。回调函数最简单的就是作为参数传递给另一个函数的函数指针。在大多数情况下,回调将包含三个部分:             

回调函数             

回调注册              

回调执行             

在典型的回调实现中,这三个部分是如何协同工作的,如下图所示: 

Figure: Typical callback architecture.

ADC驱动程序HAL包含以下功能:

  1. void Adc_CallbackRegister(AdcCallback_t const Function, void (*CallbackFunction)(void));

如果仔细看一下,这个函数被设计成从应用程序代码向ADC驱动程序注册一个回调函数。第一个参数指定回调将分配给哪个中断,而第二个参数通过向函数传递函数指针来指定要调用的函数。             

此时的低级驱动程序会将函数指针分配给指定的中断。这是非常灵活的,因为开发人员可以轻松地更新和更改中断执行的函数,而不必返回、修改和重新编译adc驱动程序。这有助于将应用程序代码从驱动程序代码中分离出来,从而创建一个可伸缩和灵活的解决方案。              

有了这些知识,可以实现ADC中断处理程序,如下所示:   

  1. void ADC_IRQHandler(void)
  1. {
  1.     (*ADC_Interrupt1)();   
  1. }

中断只不过是取消对通过Adc_CallbackRegister()函数分配的指针的引用。             

编写中断处理程序             

对于使用这种方法的开发人员来说,中断处理程序将被写在应用程序层中,并且可以有喜欢的几乎任何函数名。把命名为Adc_InterruptCallback,该回调的实现可能因应用程序而异。例如,在一个应用程序中,回调可能如下所示:  

  1. void Adc_CallbackRegister(void)
  1. {
  1.     tx_semaphore_put(&Adc1Semaphore);
  1. }

在本例中,回调只是简单地放置一个信号量来通知任务ADC数据可用。另一个示例可能如下所示:

  1. void Adc_CallbackRegister(void)
  1. {
  1.     AdcPin = AdcChannel0;
  1.     // Loop through and store the buffer data
  1.     for(AdcPin = AdcChannel0; AdcPin < NUM_ANALOG_PINS; AdcPin++)
  1.     {
  1.         Adc_SampleBuffer[i][Adc_SampleIndex] = *AD1BufPtr++;
  1.     }
  1.    
  1.     Adc_SampleIndex++;
  1.     if(Adc_SampleIndex == ADC_SAMPLE_SIZE)
  1.     {
  1.         Adc_SampleIndex = 0;
  1.     }
  1. }

如所见,由开发人员决定如何在中断处理程序中处理模拟数据,并且根据应用程序及其需要,会有很大的不同。             

需要注意的是,对于这些真正是中断处理程序的回调函数,遵循中断处理程序的最佳实践是很重要的。这意味着最小化代码,并使其尽可能快地减少对系统其余性能的影响。             

结论             

正如在本文中看到的,使用中断驱动驱动程序设计模式可以显著提高驱动程序的效率。使用回调可以将中断实现保留在应用程序代码中,并通过驱动程序的回调机制分配给中断。这使得解决方案和代码具有高度可重用性、灵活性和可伸缩性。               

   

现代传感器的接口:中断驱动的ADC驱动程序的更多相关文章

  1. 与现代传感器的接口:轮询ADC驱动程序

    与现代传感器的接口:轮询ADC驱动程序 Interfacing with modern sensors: Polled ADC drivers 我们研究了在现代嵌入式应用程序中,开发人员应该如何创建一 ...

  2. JZ2440 裸机驱动 第14章 ADC和触摸屏接口

    本章目标:     了解S3C2410/S3C2440和触摸屏的结构:     了解电阻触摸屏的工作原理和等效电路图:     了解S3C2410/S3C2440触摸屏控制器的多种工作模式:     ...

  3. Linux驱动程序接口

    §1. Linux驱动程序接口 系统调用是操作系统内核与应用程序之间的接口,设备驱动程序则是操作系统内核与机器硬件的接口.几乎所有的系统操作最终映射到物理设备,除了CPU.内存和少数其它设备,所有的设 ...

  4. 关于esp32的ADC采集

    对于ADC采集 程序源码如下: /* ADC1 Example This example code is in the Public Domain (or CC0 licensed, at your ...

  5. 玩转X-CTR100 l STM32F4 l ADC 模拟数字转换

    我造轮子,你造车,创客一起造起来!塔克创新资讯[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ]      本文介绍X-CTR100控制器 AD转换接 ...

  6. 第44章 MPU6050传感器—姿态检测—零死角玩转STM32-F429系列

    第44章     MPU6050传感器—姿态检测 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.co ...

  7. jdbc java数据库连接 2)jdbc接口核心的API

    JDBC接口核心的API java.sql.*   和  javax.sql.*(java2.0以后更新的扩展) |- Driver接口: 表示java驱动程序接口.所有的具体的数据库厂商要来实现此接 ...

  8. sja1000芯片can驱动程序

    应用层使用socketCan的方法:http://pan.baidu.com/s/1ntsvbb7#path=%252Floongson1%252Ftools%252Fcan 功能:对can驱动程序的 ...

  9. 基于WDF的PCI/PCIe接口卡Windows驱动程序(4)- 驱动程序代码(源文件)

    原文出处:http://www.cnblogs.com/jacklu/p/4687325.html 本篇文章将对PCIe驱动程序的源文件代码作详细解释与说明.整个WDF驱动程序工程共包含4个头文件(已 ...

随机推荐

  1. IPC$共享和其他共享(C$、D$)

    目录 net use共享命令的用法 IPC$ IPC空连接 ipc$使用的端口 关闭IPC$共享 net use共享命令的用法 net use #查看连接 net share              ...

  2. Windows核心编程 第25章 未处理异常和C ++异常(下)

    这一节东西比较少,本应该归并在上一节里,但是昨天太晚了.就先把那些东西分为上了.这节里面就一个问题,C++异常与结构性异常的对比(try和__try的区别): C++异常与结构性异常的对比 S E H ...

  3. github图文入门教程

    目录 1.注册,安装git 2.初始化git 3.git本地仓库结构 4.初始化第一个git仓库 5.远程仓库的修改 6.总结 1.注册,安装git ①.注册一个github账号 并建立一个仓库 ②. ...

  4. Mybatis学习之自定义持久层框架(一) 为什么要用框架而不直接用JDBC?

    前言 说起Mybatis,相信大家都不会感到陌生,它是一款优秀的持久层框架,应用于java后端开发中,为客户端程序提供访问数据库的接口. 我们都知道,JDBC是Java语言中用来规范客户端程序如何来访 ...

  5. 基于RestAssured实现接口自动化

    RestAssured是一款强大的接口自动化框架, 旨在使用方便的DSL,简化的接口自动化. 下面是基于RestAssured扩展的一个简单框架示例, 先看看用例的风格: package testca ...

  6. MongoDB&#183;Windows下管理员密码重置解决方案

    阅文时长 | 1.07分钟 字数统计 | 1730.4字符 主要内容 | 1.问题切入 2.详细步骤 3.声明与参考资料 『MongoDB·Windows下管理员密码重置解决方案』 编写人 | SCs ...

  7. java基础——简易计算器的实现

    计算器: import java.util.Scanner;​public class CalculateDemo {    public static void main(String[] args ...

  8. powercli The SSL connection could not be established, see inner exception. 问题解决

    Connect-VIServer -Server 这里是"SSL连接不能建立......"这实际上意味着你没有一个有效的证书.如果你想连接到vCenter没有一个有效的证书,您必须 ...

  9. Kibana常用语法

    GET brand201811_v2/_search 方法一:查询数据源,及相关url的文章 { "query": { "bool": { "must ...

  10. 用户添加到sudoer列表## Allow root to run any commands anywhere root ALL=(ALL) ALL Iron ALL=(ALL) ALL

    将用户添加到sudoer列表 李序锴关注 2017.12.20 15:03:25字数 605阅读 4,067 默认情况下,linux没有将当前用户列入到sudoer列表中(在redhat系列的linu ...