这次是我第一次尝试在“原创”的后面又加了经典俩字,至于为啥(俺的东北话又情不自禁冒出来了,呵呵),一个是自己一时兴起(今天心情相比于前段时间稍好些),二个是我自认为本篇**是俺的一篇得意之作而且对广大Kinetis用户也是非常有用的一篇技术博文(对俺来说担当的起“经典”俩字),所以为了避免自己有沽名钓誉之嫌有必要在这里解释一下,呵呵。当然了,不能说俺之前的**不经典啦(那岂不是在打自己的脸,哈哈),只是相对来说,我觉着这篇**对一些应用场合更有实际的意义。咳咳,好吧,自己不小心又唠叨了这么多,发现自打写博客之后我都快成为话唠了,用那句经典的广告语来说就是“根本停不下来”啊,呵呵~
好了,言归正传,我之前不止在一篇博客里面提到过飞思卡尔Kinetis独有的片内16位高精度ADC(其他家大多都是12位的),这个16位分辨率的ADC,虽然其不可能精度达到全16位,但是其最高13/14位的精度也不是其他12位ADC能比的(而且其还支持单端和差分输入,自带PGA和硬件平均功能),所以Kinetis在一些比如温度、重量和电池电压监控等测量方面的应用有其独特的优势。但是让人又爱又恨的是,这个16位ADC不支持通道自动扫描的功能,也就是说每次转换一个通道都需要软件或硬件触发一次(估计上这是一种成本上的妥协和折衷吧),这个问题对上面所提到的温度和重量等大滞环系统没有影响(他们本身对你时间没有太高的要求,一个个慢慢转换就是了),但是在一些对信号的采样率和实时性要求比较高的场合,如果使用查询等待的方式会干耗掉CPU的资源,而使用中断方式的话又会有太多的中断响应。那有没有一种比较优化的方式实现来满足这种对采样率和实时性要求较高的需求呢,咳咳,有点废话了,没有的话我写这篇**干嘛,呵呵,所以本篇的主要目的就是通过使用ADC+DMA+定时器来灵活实现Kinetis内部ADC自动通道扫描的方法,下面开整,走着:
测试平台:YL_KL26(优龙做的基于KL26的开发板,与FSL官方的FRDM-KL26很相近)
开发环境:IARv7.3
测试代码:基于FRDM-KL26Z_SC\FRDM-KL26Z_SC_Rev_1.0\klxx-sc-baremetal\build\iar\hello_world代码修改
功能描述:以100ksps的采样率对ADC的Channel0(接到YL-KL26板载的变阻器)和Channel26(KL26内部温度传感器)以DMA方式扫描采样,对一个Buffer存满10次采样数据后切换到另一个Buffer继续存,而对之前的Buffer进行处理(数组的偶数元素存的是Channel0的数据,奇数元素存的是Channel26的数据),从而实现双缓存。
(1)首先定义需要用到的变量和宏,如下所示,其中BUFFER_SIZE定义了Buffer的存储深度(为了测试,我先只定义了10个数组,其中5个for Channel0的数据,5个for Channel26的数据),pCounter用来做双缓存的切换计数,ADC_Channel数组为要采样的Channel list(至于本来是2个通道,为什么定义成4个数组,这是由于DMA的Circular Buffer模数计数最小为16个字节构成循环,一个Channel占用4个字节,所以最少定义4个元素,凑足16个字节),而剩下的Result_Buffer和Buffer_Address则为数据缓存和缓存的首地址,用来做DMA目的地址;
#define BUFFER_SIZE 10
unsigned char pCounter=0; // Counter used for Dual buffer switch
uint32 ADC_Channel[4]={0, 26, 0, 26}; //Channel list for Channel0 and Channel 26
uint8 Result_Buffer1[BUFFER_SIZE]={0}; //Buffer1
uint8 Result_Buffer2[BUFFER_SIZE]={0}; //Buffer2
uint32 Buffer_Address[2]={(uint32)&Result_Buffer1, (uint32)&Result_Buffer2}; //Buffer list |