查看: 3533|回复: 1

[分享] 【我要分享】Cortex-M3 (NXP LPC1788)之ADC数模转换器的应用

[复制链接]

该用户从未签到

17

主题

32

帖子

0

注册会员

Rank: 2

积分
85
最后登录
2018-6-13
发表于 2017-2-28 08:53:55 | 显示全部楼层 |阅读模式
A/D转换器的功能是将模拟输入信号采样得到可以提供计算机进行处理的数字信号。LPC1788的ADC是一个12位的逐次逼近型模数转换器,有8个复用的输入管脚,它的时钟使用PCLK分频得到。开发板的A/D输入模块电路图如下
1341469486_6341.jpg
要使用ADC转换,也要配置PCONP寄存器,配置ADC的时钟以及管脚和中断等。A/D转换控制寄存器AD0CR用来设置ADC的通道,时钟分频,工作模式和启动A/D转换的方式。开发板使用的是AIN2即A/D转换通道2,管脚为P0[25]。根据之前的文章,配置了系统的PCLK位60M,所以设置时钟分频5分频,将ADC的时钟设置成12M,而ADC完成一次转换需要31个时钟,所以ADC的转换频率约为400KHZ。AD0CR的START和EDGE用来控制ADC转换的触发方式,我们可以配置成通过定时器和外部中断来触发AD转换以及触发的边沿的方式。

ADC转换完成后,转换的结果保存在A/D数据寄存器,有两个数据寄存器,他们分别是全局数据寄存器AD0GDR和每个通道的数据寄存器AD0DR0~AD0DR7,他们包含了数据转换结果和一些转换的状态标志。ADC中断使能寄存器

AD0INTEN,控制每个通道转换完成后是否产生中断,以及全局数据寄存器AD0GDR中的DONE标志是否产生中断。

下面的程序中,我将ADC配置成P2[10]外部中断触发AD转换,AD转换完成后会触发AD中断,在中断中进行数据的处理。

  1.     #include "LPC1788_REG.h"
  2.     #include "uart.h"
  3.      
  4.     #define rIOCON_P0_25    (*(volatile unsigned*)(0x4002C064))
  5.     #define rIOCON_P2_10    (*(volatile unsigned *)0x4002C128)
  6.      
  7.     #define rEXTINT         (*(volatile unsigned *)0x400FC140)
  8.     #define rEXTMODE        (*(volatile unsigned *)0x400FC148)
  9.     #define rEXTPOLAR       (*(volatile unsigned *)0x400FC14C)
  10.      
  11.     #define rAD0CR      (*(volatile unsigned*)(0x40034000))
  12.     #define rAD0INTEN   (*(volatile unsigned*)(0x4003400C))
  13.     #define rADGDR      (*(volatile unsigned*)(0x40034004))
  14.     #define rAD0DR2     (*(volatile unsigned*)(0x40034018))
  15.     #define rAD0STAT    (*(volatile unsigned*)(0x40034030))
  16.     #define rAD0TRM     (*(volatile unsigned*)(0x40034034))
  17.      
  18.     unsigned int adc_value;
  19.      
  20.     void EINT0_IRQHandler()
  21.     {
  22.         rEXTINT |= (0x1<<0);//中断产生之后必须清除改位
  23.      
  24.         Uart2SendS("SW6 ON!\r\n");
  25.     }
  26.      
  27.     void ADC_IRQHandler()
  28.     {
  29.         if(rAD0DR2&(1UL<<31))
  30.         {
  31.             adc_value = ((rAD0DR2)>>4) & 0xFFF;
  32.             Uart2SendD(adc_value);
  33.             Uart2SendS("\r\n");
  34.         }
  35.         else
  36.         {
  37.             Uart2SendC('x');
  38.         }
  39.     }
  40.      
  41.     void EINT_INIT()
  42.     {
  43.         rEXTMODE |= 0x1<<0;     //配置成边沿触发
  44.         rEXTPOLAR &= ~(0x1<<0); //下降沿触发
  45.          
  46.         rISER0 = (0x1<<18);//打开EINT0中断使能
  47.     }
  48.      
  49.     int main()
  50.     {
  51.         char menu[]={"Press SW6 to get a ADC_Value.\r\n"};
  52.         Init_Uart2();
  53.         EINT_INIT();
  54.      
  55.         rPCONP |= 0x1<<12;  //使能PCADC功率控制  
  56.          
  57.         rIOCON_P2_10 = (rIOCON_P2_10&(~0x7))|(0x1<<0);  //配置FUNC字段为EINT0模式
  58.          
  59.         rIOCON_P0_25 &= ~(0x1<<7);  //P0[25]做模拟管脚
  60.         rIOCON_P0_25 &= ~(0x3<<3);  //无效上下拉电阻
  61.         rIOCON_P0_25 &= ~0x7;       //P0[25]作为ADC[2]功能
  62.         rIOCON_P0_25 |= 0x1;
  63.          
  64.          
  65.         rAD0CR |= 0x1<<2;       //使用通道2
  66.         rAD0CR |= 0x4<<8;       //A/D转换时钟设置成12M
  67.         rAD0CR |= 0x1<<21;      //A/D工作在正常模式
  68.         rAD0INTEN |= 0x1<<2;    //使能A/D通道2转换完中断
  69.      
  70.         rAD0INTEN &= ~(0x1<<8);    //无视全局数据寄存器的DONE标志
  71.      
  72.         rAD0CR |= 0x1<<27;      
  73.         rAD0CR &= ~(0x7<<24);
  74.         rAD0CR |= 0x2<<24;      //P2[10]下降沿出现时启动转换  
  75.         rISER0 |= 0x1<<22;      //使能A/D中断   
  76.          
  77.         Uart2SendS(menu);
  78.         while(1);
  79.     }
复制代码
  1. #include "LPC1788_REG.h"
  2. #include "uart.h"

  3. #define rIOCON_P0_25    (*(volatile unsigned*)(0x4002C064))
  4. #define        rIOCON_P2_10        (*(volatile unsigned *)0x4002C128)

  5. #define rEXTINT                        (*(volatile unsigned *)0x400FC140)
  6. #define rEXTMODE                (*(volatile unsigned *)0x400FC148)
  7. #define rEXTPOLAR                (*(volatile unsigned *)0x400FC14C)

  8. #define rAD0CR      (*(volatile unsigned*)(0x40034000))
  9. #define rAD0INTEN   (*(volatile unsigned*)(0x4003400C))
  10. #define rADGDR      (*(volatile unsigned*)(0x40034004))
  11. #define rAD0DR2     (*(volatile unsigned*)(0x40034018))
  12. #define rAD0STAT    (*(volatile unsigned*)(0x40034030))
  13. #define rAD0TRM     (*(volatile unsigned*)(0x40034034))

  14. unsigned int adc_value;

  15. void EINT0_IRQHandler()
  16. {
  17.         rEXTINT |= (0x1<<0);//中断产生之后必须清除改位

  18.         Uart2SendS("SW6 ON!\r\n");
  19. }

  20. void ADC_IRQHandler()
  21. {
  22.     if(rAD0DR2&(1UL<<31))
  23.     {
  24.         adc_value = ((rAD0DR2)>>4) & 0xFFF;
  25.         Uart2SendD(adc_value);
  26.         Uart2SendS("\r\n");
  27.     }
  28.     else
  29.     {
  30.         Uart2SendC('x');
  31.     }
  32. }

  33. void EINT_INIT()
  34. {
  35.         rEXTMODE |= 0x1<<0;     //配置成边沿触发
  36.         rEXTPOLAR &= ~(0x1<<0); //下降沿触发
  37.        
  38.         rISER0 = (0x1<<18);//打开EINT0中断使能
  39. }

  40. int main()
  41. {
  42.     char menu[]={"Press SW6 to get a ADC_Value.\r\n"};
  43.     Init_Uart2();
  44.     EINT_INIT();

  45.     rPCONP |= 0x1<<12;  //使能PCADC功率控制
  46.    
  47.     rIOCON_P2_10 = (rIOCON_P2_10&(~0x7))|(0x1<<0);  //配置FUNC字段为EINT0模式
  48.    
  49.     rIOCON_P0_25 &= ~(0x1<<7);  //P0[25]做模拟管脚
  50.     rIOCON_P0_25 &= ~(0x3<<3);  //无效上下拉电阻
  51.     rIOCON_P0_25 &= ~0x7;       //P0[25]作为ADC[2]功能
  52.     rIOCON_P0_25 |= 0x1;
  53.    
  54.    
  55.     rAD0CR |= 0x1<<2;       //使用通道2
  56.     rAD0CR |= 0x4<<8;       //A/D转换时钟设置成12M
  57.     rAD0CR |= 0x1<<21;      //A/D工作在正常模式
  58.     rAD0INTEN |= 0x1<<2;    //使能A/D通道2转换完中断

  59.     rAD0INTEN &= ~(0x1<<8);    //无视全局数据寄存器的DONE标志

  60.     rAD0CR |= 0x1<<27;      
  61.     rAD0CR &= ~(0x7<<24);
  62.     rAD0CR |= 0x2<<24;      //P2[10]下降沿出现时启动转换
  63.     rISER0 |= 0x1<<22;      //使能A/D中断   
  64.    
  65.     Uart2SendS(menu);
  66.     while(1);
  67. }
复制代码
程序运行的效果是,按下控制P2[10]的按键,每按一次得到一个AD采样的结果,改变R94的输入,可以得到不同的结构,最大最小分别是0和4095。
1341469637_8240.jpg

程序中需要注意的有如下几点:

1,P2[10]必须配置成EINT0模式,才能用于在边沿上触发ADC转换。

2,必须关闭ADC输入管脚的上拉或下拉电阻,否则AD采样会有偏差。

3,ADC转换完成的中断使能,最好把AD0INTEN的最高位无效,否则需要在ADC转换完成后同时清除通道数据寄存器AD0DRn和全局数据寄存器AD0GDR中的DONE标志(该标志通过读取数据寄存器清除)。可以尝试把程序中的rAD0INTEN &= ~(0x1<<8)屏蔽,可以看到串口一直在输出'x',即AD数据没转换完成,也有中断一直产生。原因就是AD0GDR中的DONE标志引起。


回复

使用道具 举报

  • TA的每日心情
    擦汗
    2017-10-15 13:16
  • 签到天数: 191 天

    连续签到: 1 天

    [LV.7]常住居民III

    11

    主题

    664

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    1722
    最后登录
    2017-10-15
    发表于 2017-2-28 09:22:21 | 显示全部楼层
    谢谢分享                                          
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

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

    本版积分规则

    关闭

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

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

    GMT+8, 2025-9-2 19:53 , Processed in 0.093544 second(s), 23 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

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