现代传感器的接口:中断驱动的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函数可能实现如下所示:

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

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

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

中断的抽象化             

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

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

回调函数             

回调注册              

回调执行             

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

Figure: Typical callback architecture.

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

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

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

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

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

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

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

编写中断处理程序             

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

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

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

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

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

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

结论             

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

   

现代传感器的接口:中断驱动的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. hdu2833 Floyd + dp

    题意:      给你一个无向图,给你两组起点和终点,问你这两组起点和终点的最短路上最多有多少个交点... 思路:      开一个数组dp[i][j]记录最短路上i,j之间的点有多少个,这个数组是根 ...

  2. hdu1572 水搜索

    题意: 中文的不解释; 思路:           其实就是一个水的搜索,直接搜索不会超时,还有别跑最短路了,题目没要求跑最短路,别读错题,刚开始自己嘚嗖的跑了一边最短路 wa了 ,正好最近看了STL ...

  3. Python中对序列数据的汇总(collections模块)

    目录 Counter most_common 对于序列如字符串str.列表list和tuple可以统计里面数据出现的次数.我们使用的是 collections 模块. collections模块的常用 ...

  4. Python 爬虫与HTTP协议简介

    爬虫的实际例子: 搜索引擎(百度.谷歌.360搜索等). 伯乐在线. 惠惠购物助手. 数据分析与研究(数据冰山知乎专栏). 抢票软件等. 什么是网络爬虫: 通俗理解:爬虫是一个模拟人类请求网站行为的程 ...

  5. 【Android Jetpack高手日志】DataBinding 从入门到精通

    前言 DataBinding 数据绑定库是 Android Jetpack 的一部分,借助该库可以使用声明性格式(而非程序化地)将布局中的界面组件绑定到应用中的数据源.我个人觉得,使用 DataBin ...

  6. 40 图 |我用 Mac M1 玩转 Spring Cloud

    我的开源 Spring Cloud 项目 PassJava 一直可以在 Windows 上正常运行,最近不是换 Mac M1 了么,想把这个项目在 M1 上跑起来,毕竟我的那台 Windows 用起来 ...

  7. 【CSS】CSS3从入门到深入(复习查漏向

    CSS3从入门到深入(复习查漏向 pre_section CSS:层叠样式表,决定网页表现 网页为多层结构,CSS为每一层设置样式,最后显示最上一层 CSS语句 = 选择器 + 声明块 形式 内联样式 ...

  8. 多线程-5.JMM之happens-before原则

    a happens-before b 翻译为a操作对b操作是可见的.可见即是指共享变量的更改能获知. 特性:传递性 原则:volatile定义的变量 写操作 happens-before 读操作 同一 ...

  9. mysql搭建多主一从源复制环境

    问题描述:搭建过一主多从的环境,由于数据库数据一致性要求高,有些情景会搭建一主多从的架构,搭建多主一从的模式,相对来说适合数据整合,将多个业务的库整合到一起,方便做查询,也可以当做一个监控其他主库数据 ...

  10. ThreadLocal不好用?那是你没用对!

    在 Java 中,如果要问哪个类使用简单,但用好最不简单?我想你的脑海中一定会浮现出一次词--"ThreadLocal". ​ 确实如此,ThreadLocal 原本设计是为了解决 ...