查看: 7470|回复: 10

[分享] 【经验】最简单的ADC应用实例:软件触发轮询采样

[复制链接]
  • TA的每日心情
    奋斗
    2017-1-17 10:45
  • 签到天数: 3 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    38

    主题

    395

    帖子

    3

    高级会员

    Rank: 4

    积分
    780
    最后登录
    2023-11-17
    发表于 2015-5-23 15:31:22 | 显示全部楼层 |阅读模式
    本帖最后由 suyong_yq 于 2015-5-23 15:35 编辑

    最简单的ADC应用实例:
        软件触发轮询采样片上温度传感器
    suyong_yq     suyong_yq@126.com
    2015-05


    【概述】

    ADC通用应用模型】
      【配置阶段】
      【使用阶段】
    【在KL26上接地气】
    【总结】


    ----我是可爱的分割线----

    【概述】

    大多数Kinetis芯片上使用的ADC都是SAR ADC(successive approximation ADC),例如我们熟悉的K60, K64, KL25及最近在社区里比较火的KL26。这个SAR ADC是一个非常好用的模块,一方面是说它在功能上可以很容易地执行模拟量到数字量的转换,但如果你深入了解一下这个ADC模块的软件编程模型,就会发现其中无处不体现着设计模型的经典。在下文中,我们将统一使用“KL26的ADC”指代我们今天要了解的这个漂亮的小东西。


    当然,在这个文档里,我们的重点在于如何以最快、最简便和最好用的方式将这个ADC模块添加到应用程序当中,至于这个ADC经典的编程模型,以后我们还会在合适的时间详细讨论。对于忙碌的嵌入式软件工程师来讲,有太多的原理图要看,要写很多关于项目的程序和文档,实在没有时间去深究芯片内部一个功能模块的奥妙,好吧,那么我们这篇文档就有意义了,因为,因为通过这篇文档就是提供了一个“快餐”式的说明,能用起来就OK。


    ADC通用应用模型】
    在单片机中使用任何一款ADC, 不论是哪家公司设计的IP,对ADC应用的模型基本上是相似的,主要包含两个阶段:配置阶段和使用阶段。呵呵,这里是有点废话了,因为所有的IP模块几乎都是以这两个阶段进行编程的。当我们要在应用程序中使用这些ADC的时候,只要对号入座,找到相应的代码填写到程序中即可。


    【配置阶段】
    对于一般的ADC来讲,配置阶段要做哪些必要的工作呢?

    · 参考电压源。从ADC转换的本质来看,无非是拿外部采样回来的模拟信号同参考电压进行比较,“我是你的几分之几”,最终得到一个量化的参考值。在这个比较过程中,比较的次数就对应着转换的分辨率,然而,能执行更多次比较的关键在于ADC内部能够对参考电压进行细分,从而能够提供精细的分辨粒度。

    · 驱动时钟。这是单片机上所有模块都必须的,要驱动数字系统工作。通常情况下,单片机会将某个总线上的时钟引出来一条信号线连接到模块上,如果模块内部希望调整这个时钟,还可以设计一个分频因子的选项,将这个从总线上引出来的时钟信号分频后再输入到模块里。同时,为了低功耗应用的需求(公共使用的总线时钟可能被停掉以降低功耗),模块内部也可以专门设计一个独立的时钟。

    · 分辨率。分辨率之于ADC,就如波特率之于串行总线通信类的模块一样,标识了ADC模块的工作性能。


    至于其它的功能,各家实现的ADC都有自己的特点,比如说对齐方式、单端差分、硬件平均、比较触发等等,都属于附加功能,用起来可以提升某些应用的性能,不用的话软件也可以搞定。


    总之,只要选择好参考电压源、驱动时钟和分辨率,ADC基本上就可以工作了。如果你要跟我抬杠的话,好吧,供电和引脚也要考虑到。


    【使用阶段】
    那么使用阶段呢?


    对于ADC来讲,使用ADC就是要读到ADC的转换值,至于怎么才能读到,大体上要考虑两个点:

    · 触发方式。毕竟是集成在数字系统中,ADC不会自己无休无止地执行转换,否则芯片会转到火爆,ADC只有在需要的情况下才勉为其难地执行那么一次转换,所以你安排什么人适时地踹它一脚,叫它起来工作,一个任务做晚之后,它又会自动懒在那里。怎么感觉跟猪有点像,哈哈,不踹它就不运动。

    · 多通道复用转换器。基于ADC是触发式地工作方式,通常多会将一个转换器复用给多个输入通道,每次在触发时指定转换哪个输入通道的电压值,这样会为芯片制造解决节约很多成本,不需要为每个引脚都安排一个专门的转换器。


    【在KL26上接地气】
    前面我们已经了解到ADC工作的一般模型,那么在使用KL26的ADC时,只要对号入座就可以了。在文档中贴出了代码,大家一看就明白,多余的话我就不再多说了(为什么要用“再”呢?)。

    1. #include "app_inc.h"
    2. #include "fsl_device_registers.h"

    3. #define APP_ADC_IDX                 0U
    4. #define APP_ADC_CONV_CMD_GROUP_IDX  0U
    5. #define APP_ADC_CONV_CHN 26U /* Internal thermal sensor channel. */

    6. static const ADC_ConverterConfig_T gAdcConverterConfigStruct =
    7. {
    8.     .RefVoltSource = eADC_RefVoltSource_VREF,
    9.     .ClkSource = eADC_ClkSource_ASYNCCLK,
    10.     .ClkDivider = eADC_ClkDivider_1,
    11.     .SampleMode = eADC_SampleSingle_12Bit,
    12.     .HwAverageSampleMode = eADC_HwAverageSampleDisable,
    13.     .enContiConvMode = false
    14. };

    15. /*
    16. static ADC_ConvCmd_T gAdcConvCmdStruct =
    17. {
    18.     .enIntOnComplete = false,
    19.     .enDiffConv = false,
    20.     .ChnIdx = APP_ADC_CONV_CHN
    21. };
    22. */

    23. static void init_ADC(void);

    24. int main(void)
    25. {
    26.     uint16_t adc_value;

    27.     init_board();
    28.    
    29.     printf("\r\nHello, Board.\r\n");
    30.     printf("Compiled at %s on %s\r\n", __TIME__, __DATE__);
    31.    
    32.     printf("initialization ...\r\n");

    33.     init_ADC();

    34.     printf("system ready.\r\n");

    35.     /* ADC auto calibration. */
    36.     if (!ADC_ExecAutoCalibration(APP_ADC_IDX))
    37.     {
    38.         printf("ADC_ExecAutoCalibration() failed!\r\n");
    39.     }
    40.     else
    41.     {
    42.         printf("ADC_ExecAutoCalibration() done.\r\n");
    43.     }

    44.     while (1)
    45.     {
    46.         printf("\r\nPress any key to trigger the ADC conversion and get value ...\r\n");
    47.         getchar();

    48. /*
    49.         ADC_ExecConvCmd(APP_ADC_IDX, APP_ADC_CONV_CMD_GROUP_IDX, &gAdcConvCmdStruct);
    50.         ADC_WaitConvCmdDone(APP_ADC_IDX, APP_ADC_CONV_CMD_GROUP_IDX);
    51.         adc_value = ADC_GetConvValue(APP_ADC_IDX, APP_ADC_CONV_CMD_GROUP_IDX);
    52. */
    53.         adc_value = ADC_GetConvSingleEndValueBlocking(APP_ADC_IDX, APP_ADC_CONV_CMD_GROUP_IDX, APP_ADC_CONV_CHN);
    54.         printf("Internal thermal ADC value: %d \r\n", adc_value);
    55.     }
    56. }

    57. static void init_ADC(void)
    58. {
    59.     /* Clock. */
    60.     SIM_EnableClockForADC(APP_ADC_IDX, true);

    61.     /* Pin mux. */
    62.     /* No need, since using internal sensor. */

    63.     /* Configuration. */
    64.     ADC_ResetConverter(APP_ADC_IDX);
    65.     ADC_ConfigConverter(APP_ADC_IDX, &gAdcConverterConfigStruct);

    66. }

    67. /* EOF. */
    复制代码

    下载运行后,在终端输出的log如下所示:
    figure_0.png
    图0

    此处仅列举几个要点:

    · 自动校准转换器。对于KL26的ADC,在配置阶段有个特别的要求,就是要执行一下自动校准,对ADC转换器进行调校,虽然也可以手动触发自动校准过程(ADC_GetAutoCalibration)并写数(ADC_SetCalibration),但是既然在硬件上提供了自动校准的机制,不用白不用,省掉我们一部分的麻烦。为此,我专门封装了一次性搞定自动校准的API,ADC_ExecAutoCalibration。

    · 软件触发。当KL26的ADC被配置为软件触发时,使用的是“命令式”触发,一旦更新转换通道,向SC1[0]寄存器写数,就会触发一次新的转换。具体地,可以通过调用ADC_ExecConvCmd进行软件触发。

    · 封装API。尽管也提供了比较灵活地专门用于软件触发(ADC_ExecConvCmd)、等待转换完成(ADC_WaitConvCmdDone)和读取数据(ADC_GetConvValue)的API,但考虑到这几个函数在比较简单的应用中经常会连在一起用,所以我又把它们3个封装成一个可以直接获取转换结果的API(ADC_GetConvSingleEndValueBlocking)

    另外,采样对象上,我设定为转换ADC内部一个温度传感器的值。哈哈,KL26上的ADC确实提供了这么一个信号源,通过26号通道输入,不用任何外部连接就可以完成我们的实验。

    figure_1.png
    图1

    这个时候玩家们可能会想自己动手改造一下样例程序,把YL-KL26Z板子上那个大大的电位器用起来玩耍一番。
    figure_2.png
    图2

    小case,只要改变一下采样通道即可。
    figure_3.png
    图3

    在代码中将“APP_ADC_CONV_CHN”值改为“0”即可
    figure_4.png
    图4

    不过看样子还需要重新设定一下pin mux,也不是麻烦事。在init_ADC()函数中新增配置PTE20复用功能为ADC的语句:

    1.     /* Pin mux. */
    2.     PORTE->PCR[0] = PORT_PCR_MUX(0);
    复制代码

    在应用程序中直接访问芯片的功能寄存器是比较暴力的做法,我不是很推荐使用,此处仅仅作为快速演示才勉强用一下,若是在工程代码里,这里必须要在bsp_config.h/.c中封装一个专门的函数才能在应用程序中调用。

    为了能让应用程序找到寄存器,还需要额外地在main.c中包含寄存器定义文件。

    1. #include "fsl_device_registers.h"
    复制代码

    编译OK,下载OK,运行后在终端输出log如下:
    figure_5.png
    图5

    看着这张图,童鞋们是不是能想象到我在转动电位器的场景呢。


    【总结】
    在本文档中,首先说明了使用ADC编程的一般概念,将对ADC的编程过程归类为配置阶段和使用阶段。在配置过程中,需要关注三个必要的内容:参考电压源、模块工作的时钟信号源及ADC采样的分辨率。在转换过程中,需要关注触发方式及了解多通道复用转换器的实现内容。在将这些概念套用到KL26的具体程序中,仅仅使用:ADC_ConfigConverter、ADC_ExecAutoCalibration和ADC_GetConvSingleEndValueBlocking就能够实现一个最简单的ADC采样功能,并演示了如何采样ADC内部温度寄存器和YL-KL26Z开发板上的电位器的实例。

    --End



    附件
    文档: AN_SY20150523.pdf (562.4 KB, 下载次数: 17)
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2017-1-17 10:45
  • 签到天数: 3 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    38

    主题

    395

    帖子

    3

    高级会员

    Rank: 4

    积分
    780
    最后登录
    2023-11-17
     楼主| 发表于 2015-5-23 15:36:48 | 显示全部楼层
    自己占个沙发,发帖调格式好辛苦。为了不影响阅读,不得不再上传一个pdf文档。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2017-1-24 09:50
  • 签到天数: 2 天

    连续签到: 1 天

    [LV.1]初来乍到

    654

    主题

    3262

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    13140
    最后登录
    2019-1-27
    发表于 2015-5-23 16:20:07 | 显示全部楼层
    辛苦楼主
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2020-5-24 10:39
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    140

    主题

    2087

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    3913
    最后登录
    2020-5-24
    发表于 2015-5-23 18:19:49 | 显示全部楼层
    楼主好辛苦哦
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2017-1-17 10:45
  • 签到天数: 3 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    38

    主题

    395

    帖子

    3

    高级会员

    Rank: 4

    积分
    780
    最后登录
    2023-11-17
     楼主| 发表于 2015-5-23 21:59:43 | 显示全部楼层

    还不是被忽悠了,辛辛苦苦赚金币嘛。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2017-1-17 10:45
  • 签到天数: 3 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    38

    主题

    395

    帖子

    3

    高级会员

    Rank: 4

    积分
    780
    最后登录
    2023-11-17
     楼主| 发表于 2015-5-23 22:00:56 | 显示全部楼层

    还好。下载代码跑跑程序呗,尤其ADC的驱动程序,用着很方便。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2018-4-12 10:22
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    15

    主题

    386

    帖子

    0

    高级会员

    Rank: 4

    积分
    541
    最后登录
    2018-6-28
    发表于 2015-5-23 23:35:45 | 显示全部楼层
    辛苦,支持
    falajf
    回复

    使用道具 举报

    该用户从未签到

    0

    主题

    14

    帖子

    0

    新手上路

    Rank: 1

    积分
    40
    最后登录
    2015-10-17
    发表于 2015-5-24 22:06:40 | 显示全部楼层
    学习学习!!
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2018-7-2 06:04
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    59

    主题

    2888

    帖子

    10

    金牌会员

    Rank: 6Rank: 6

    积分
    6020
    最后登录
    2020-9-28
    发表于 2015-5-25 16:27:03 | 显示全部楼层
    非常感谢你关于Kinetis的经验分享 !
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2017-5-27 11:02
  • 签到天数: 4 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    15

    主题

    566

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    1890
    最后登录
    2017-5-27
    发表于 2015-5-31 23:02:37 | 显示全部楼层
    写的好详细,好好学习一下
    klntuo累
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-7-27 04:15 , Processed in 0.103734 second(s), 29 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表