zoukankan      html  css  js  c++  java
  • KL25的AD采集操作

    飞思卡尔的KL25单片机AD做的是很不错的,SAR型能做到16位。不过数据手册就写得不怎么样了,简直可以说是坑爹,很难看懂。有的描述让人难以理解,你指望在别的地方对不理解的地方会有其他角度的描述,结果你发现关于同一描述,他们坚定的采用了复制粘贴的办法!擦!

    而且,我还发现了数据手册的错误。用户手册上给出了一个案列,AD工作在16bit单端模式下ADCK为1MHZ,但是数据手册上注明如果AD工作在16比特模式,ADCK必须至少2MHZ,你说这不是坑爹不是!我给官网发了邮件,他们打哈哈让我去社区搜帖子。

    结果,我看了整整一天的时间,跳过了很多不重要的功能,才能写出AD采集代码。这玩意寄存器20多个,手册有50页,很复杂。

    我要采集的是地震波,只需要1K的采样率即可,特别低,通道为ADC0_SE4b。

    下面是初始化代码,全是配置寄存器,中间用到了飞思卡尔自己提供的自校准函数,老实说,自校准这一块我根本没看。本函数使用连续采样,用到了硬件平均功能,让采集的32点做个平均之后再保存到结果寄存器中,目的也是降低采样率。禁用中断,禁用DMA。

    void init_ADC16(void){
      
              // Turn on the ADC0 clock as well as the PDB clocks to test ADC triggered by PDB
                SIM_SCGC6 |= (SIM_SCGC6_ADC0_MASK );
    //            SIM_SCGC6 |= SIM_SCGC6_PDB_MASK ; pdb
       //         PMC_REGSC |= PMC_REGSC_BGBE_MASK ;  
                   
                // setup the initial ADC default configuration              
                Master_Adc_Config.CONFIG1  = ADLPC_LOW
                  | ADC_CFG1_ADIV(ADIV_4)
                  | ADLSMP_LONG
                  | ADC_CFG1_MODE(MODE_16)
                  | ADC_CFG1_ADICLK(ADICLK_BUS_2);
                Master_Adc_Config.CONFIG2  = MUXSEL_ADCB    //通道选择
                  | ADACKEN_DISABLED
                  | ADHSC_NORMAL
                  | ADC_CFG2_ADLSTS(ADLSTS_20) ;        //增加20时钟
           //     Master_Adc_Config.COMPARE1 = 0x1234u ;                 // can be anything
           //     Master_Adc_Config.COMPARE2 = 0x5678u ;                 // can be anything
                // since not using
                // compare feature
                Master_Adc_Config.STATUS2  = ADTRG_SW             //软件触发
                  | ACFE_DISABLED                              //禁止比较                                
                  | ACFGT_GREATER
                  | ACREN_DISABLED
                  | DMAEN_DISABLED                  //禁止DMA
                  | ADC_SC2_REFSEL(REFSEL_EXT);      //设定电压参考源
                
                Master_Adc_Config.STATUS3  = CAL_OFF  
                  | ADCO_CONTINUOUS                        //连续采集
                  | AVGE_ENABLED                      //允许硬件平均
                  | ADC_SC3_AVGS(AVGS_32);               //32点平均,降低采样速率
                
                Master_Adc_Config.STATUS1A = !AIEN_ON | DIFF_SINGLE | ADC_SC1_ADCH(4);
                  
                // Configure ADC as it will be used, but becuase ADC_SC1_ADCH is 31,
                // the ADC will be inactive.  Channel 31 is just disable function.
                // There really is no channel 31.
                
                ADC_Config_Alt(ADC0_BASE_PTR, &Master_Adc_Config);  // config ADC
                  
                
                // Calibrate the ADC in the configuration in which it will be used:
                ADC_Cal(ADC0_BASE_PTR);                    // do the calibration
                
                // The structure still has the desired configuration.  So restore it.
                // Why restore it?  The calibration makes some adjustments to the
                // configuration of the ADC.  The are now undone:
                
                // config the ADC again to desired conditions
                ADC_Config_Alt(ADC0_BASE_PTR, &Master_Adc_Config);
    }

    主函数部分

    void init_ADC16(void);
    tADC_Config Master_Adc_Config;
    int main(void)
    {    
     char j=0;
     char i=0;
     uint16 xinhao[216];   //定义数组
     init_ADC16();
        for (j=0;j<216;j++)
        {
          while (!(ADC0_SC1A & ADC_SC1_COCO_MASK) );  //查询办法,标志位没有置1,就一直等着
          xinhao[j]=ADC0_RA;
        }
        ADC0_SC1A =0x0000001F ; //停止AD采样
     for (i=0;i<216;i++)
     printf("第%d点为%d", i,xinhao[i]);
     return 0;
    }

    这里要说的是,IAR调试经常会发现单步执行和全速执行结果不一样,这是因为缺少延时控制。尤其是对外设的操作代码最容易出错。

    外设反应较慢,需要较长的时钟周期,而CPU执行很快,它必须等待外设。比如,我们某一句代码擦除flash,下一句就判断flash的寄存器是否为0,如果单步执行这是正确的,但是全速执行就不会正确。因为单步执行的时候,步与步之间的延时使得CPU有时间擦除flash,但是全速执行的时候根本没有这个时间。

    还有,如果某一标志位大部分时间为0,一瞬间为1表示某过程结束,代码怎么写也是有讲究的。比如AD采样,COCO标志位在结果没出来之前一直为0,直到结果出来了为1,我们采用查询的方法来判断COCO的时候,正确的写法

    不是while (COCO==1){  执行。。。。。。}

    而是while (!COCO); 执行。。。。。。

    因为第一种写法在COCO==0的时候就会直接跳过while语句。而第二种写法在COCO==0时,会一直等到COCO为1,这就是在等待外设。

    使用IAR还有一个技巧。IAR你的局部变量会在用完之后被清掉。这很烦人,因为有时候你想看它们的值。一个有效的办法,就是在你的断点之后,对该变量加一个打印语句,只要有这条语句存在,局部变量的值在执行到断点的时候就不会被清掉。

    最后贴一下AD采集到的数据:




  • 相关阅读:
    HTTP解析
    Linux(CentOS)常用命令
    Windows下虚拟Linux
    国内静态文件CDN服务介绍 国内js公共库
    吐槽一下csdn和博客园
    项目托管 网站 小记
    微软2013年校园实习生招聘笔试题及答案
    最近在折腾VPS(持续完善)
    spring MVC +freemarker + easyui 实现sql查询和执行小工具总结
    Hessian 接口使用示例总结
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3165736.html
Copyright © 2011-2022 走看看