k60内部AD模块

非原创 转自http://blog.chinaaet.com/jihceng0622/p/25675 作者jicheng0622,如有不便请通知删除

1.Kinetis的ADC模块的一些特点(以K60为例),挑重要的说了,一些AD模块常见的特点就不提了,呵呵:

(1)最高16位AD转换精度,逐次逼近型的,所以速度没问题,而且能做到如此精度已实属不易了,再往高估计就该换Σ-Δ的了;

(2)最多4对差分模拟输入通道和24个单端模拟输入通道,对一般工业应用足够了,其实在对AD要求不高的应用还是用内部AD好些,选外部AD的话一是操作起来麻烦,还有就是对模拟电路布局布线上还是有些技巧的;

(3)输出精度可选,例如差分的话可编程16位,13位,11位和9位模式,单端的话可编程为16位,12位,10位和8位,不明白为什么差分精度非要比单端多1位,有知道的希望不吝告诉一下,在下面留言即可,呵呵;

(4)输入时钟可选四种时钟,即bus_clock,bus_clock/2,ALTCK,ADACK;

(5)内设内部温度传感器,用于监控芯片温度,这个还是有一定用途的,不过对他的精度不要有过高期望;

(6)硬件平均功能,对AD转换结果在队列里平均之后输出,挺实用的,要是再能对列排列一下就好了,咳咳,有点要求太高了,哈哈;

(7)带自校准模式,用过外部AD的知道,这个功能是必须的但又颇有点小道道的,深入做过项目的肯定知道,呵呵;

(8)最高64倍PGA(programable gain Amplifier),加上这个还是让俺们给飞思卡尔加点满意分的,哈哈。

2.Kinetis的ADC内部结构框图,是我们接下来的编程的依据,老套路,上图:

可能第一眼我们的感觉都是。。。有点复杂哈,咳咳,所以我在图中对重要的部分用红线圈出来逐个分析了下,怎样,应该初步了然了吧,图中我圈出来的是重点抓住的,下面软件编程的时候需要用到,其他的可以随便看看,前提是你有足够的耐心去看一堆英文说明了,哈哈。

3.软件编程部分,其实无非就是操作寄存器,其实按照datasheet的来就可以,另外强调一下,官方例程给出的是PDB硬件触发,觉着有点麻烦,所以按照平时常用的方法(对我来说,还是习惯软件触发)针对Tower系统写了下,采用的是单端模式。如下:

 

/**********************************************************************************

**Routine:ADC_Init

**input:    ADC---ADC0 and ADC1 module selection

  bits:     0--8bit, 1--12bit, 2--10bit, 3--16bit

  channel:  0~23 in total of 24 channels in single-ended convertion mode

  mode:     INT_MODE, SEARCH_MODE(母语解释一下吧,哈哈,这里分为中断方式和查询方式)

**********************************************************************************/

void ADC_Init(ADC_MemMapPtr ADC, uint8 bits, uint8 channel, uint8 mode)

{

    if(ADC == ADC0_BASE_PTR)

      SIM_SCGC6 |= SIM_SCGC6_ADC0_MASK;              /* turn on the ADC0 clock */ 

    else if(ADC == ADC1_BASE_PTR)

      SIM_SCGC3 |= (SIM_SCGC3_ADC1_MASK );           /* turn on the ADC1 clock */

    

    ADC_CFG1_REG(ADC) |= ADC_CFG1_ADIV(3)            /* normal power, clock rate is (inputclock)/8 */

                         + ADC_CFG1_ADLSMP_MASK      /* long sample time */

                         + ADC_CFG1_MODE(bits)       /* bits range 0 to 3(0--8bit, 1--12bit, 2--10bit, 3--16bit) */

                         + ADC_CFG1_ADICLK(1);       /* inputclock is busclock/2 */

                                                                                                                                              

    ADC_CFG2_REG(ADC) &= ~(ADC_CFG2_MUXSEL_MASK      /* a registers is selected */

                         + ADC_CFG2_ADACKEN_MASK     /* Asynchronous clock output disabled */

                         + ADC_CFG2_ADHSC_MASK       /* Normal conversion sequence selected */

                         + ADC_CFG2_ADLSTS_MASK);    /* Default longest sample time. */               

/***********************************************************************************

**set default status:Software triger(a convertion is initated following a write to 

  SC1A)compare function disabled, DMA is disabled, default voltage reference pin

  (external pins VREFH and VREFL).

***********************************************************************************/

    ADC_SC2_REG(ADC) = 0;

    

    ADC_SC3_REG(ADC) |= ADC_SC3_ADCO_MASK            /* continuous conversions */

                        + ADC_SC3_AVGE_MASK          /* hardware averages enabled. */

                        + ADC_SC3_AVGS(3);           /* 4 samples average */

                 

  //---when in software triger mode,  a conversion is actived after the ADC_SC1A is writed.   

    ADC_SC1_REG(ADC,0)  = ADC_SC1_ADCH(channel);     /* single-ended AD20 channel is selected */

    

    if(mode == INT_MODE)

    {

      ADC_SC1_REG(ADC,0)  |= ADC_SC1_AIEN_MASK;      /* conversion complete interrrupt enabled */

      if(ADC == ADC0_BASE_PTR)

        enable_irq(adc0_isr_no);                     /* enable the ADC0 IRQ interrupt */

      else if(ADC == ADC1_BASE_PTR)

        enable_irq(adc1_isr_no);                     /* enable the ADC1 IRQ interrupt */

    }

    else if(mode == SEARCH_MODE)

      ADC_SC1_REG(ADC,0)  &= ~ADC_SC1_AIEN_MASK;     /* conversion complete interrrupt disabled */

}

/**********************************************************************************

**Routine:Read_ADC

**input:    ADC---ADC0 and ADC1 module selection

  result:   the pointer of the return value of the convertion result.

**********************************************************************************/

void Read_ADC(ADC_MemMapPtr ADC, uint16 * result)

{

    while(!(ADC_SC1_REG(ADC,0)&ADC_SC1_COCO_MASK));  /* wait until the selected numbers of convertion(determined by the AGVS bits) */

    *result = ADC_R_REG(ADC,0);                      /* clear the COCO flag by reading the corresponding data register. */

}

/**********************************************************************************

**Routine:adc0_isr

**Description: the interrupt service routine of ADC0

**********************************************************************************/  

void adc0_isr(void)

{

    (void) ADC0_RA;   

}

/**********************************************************************************

**Routine:adc1_isr

**Description: the interrupt service routine of ADC1

**********************************************************************************/

void adc1_isr(void)

{

    (void) ADC1_RA;

}

在这里解释下上面代码,其实看英文注释就行,我每步都做了简单的注释,按照步骤来即可。其实主要分两部分,一个就是其AD初始化部分,主要操作寄存器为ADC_SC1~ADC_SC3和ADC_CFG1~ADC_CFG2。输入参数包括ADC模块选择(包括两个,即ADC0和ADC1),转换精度选择(8位,10位,12位,16位),通道号(由于是单端模式,所以范围为0~23共24个通道)和输出模式(查询或者中断模式);另外就是读结果寄存器部分,包括了查询方式读和中断方式读(我使用了查询方式,所以中断方式我设置了空读,呵呵,其实根本没用到),完整文件见附件。

4.再补充一部分,即主函数内部的调用方法,由于本例程是根据Tower系统写的,而系统板上电位器的分压端是连在ADC1_DM1端上的,不过对单端模式来说其实是连在了AD20这个通道上的,如下图通道安排(看到Chapter3了吧,呵呵,find it in chapter3, you can get it,哈哈):

下面是具体在main函数里的调用方法,如下:

void main(void)

{

  //---------------insert your code in the following--------------

  uint16 AD_Result;       /* 声明AD转换结果变量,存储AD值 */

  

  ADC_Init(ADC1, 3, 20, SEARCH_MODE);   /* 初始化AD1位单通道20输入,转换结果16bit, 查询模式 */

  EnableInterrupts;

  

  while(1)

  {

    Read_ADC(ADC1, &AD_Result);         /* 查询方式读取AD转换结果 */

  }

}

    呵呵,这里ADC模块部分就写这么多了,没办法逐个说寄存器(那样的话篇幅太长了,而且的确心有余力不足),不过觉着如果

顺序看下来还是大概能看懂的,如果有不明白的或者疑问可以留言,会尽量解答,呵呵。好了,老话再次重现江湖,未完待续,哈哈~

    附件为完整的ADC底层文件,需要的话可以瞅瞅,其实这部分我早就在当初开源那个开发底层框架的时候一块传上去了,这里单独传一下AD部分~

你可能感兴趣的:(K60,ADC)