本帖最后由 后会无期1 于 2015-4-17 21:43 编辑
这次是我第一次尝试在“原创”的后面又加了经典俩字,至于为啥(俺的东北话又情不自禁冒出来了,呵呵),一个是自己一时兴起(今天心情相比于前段时间稍好些),二个是我自认为本篇**是俺的一篇得意之作而且对广大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目的地址;
(2)其次初始化ADC模块(为了方便我定义成8位分辨率),禁止ADC转换完成中断,使能ADC转换完成触发DMA,同时使能单次软件触发模式(即每次写入ADC0_SC1的通道号触发一次ADC转换)。需要注意的是ADC的输入时钟源要小于18MHz;
(3)然后初始化TPM定时器模块,该模块配置成自由计数模式,溢出中断触发DMA,其中MOD寄存器即溢出时间决定ADC的采样率,本例程配置成每100kHz的频率溢出一次;
(4)这部分是DMA的初始化,本例程的核心部分,本例程的实现需要使用两个Channel的DMA,其中一个channel的DMA与TPM定时器配合实现周期性触发ADC转换,即每次TPM定时器溢出触发一次DMA将Channellist的通道号写到ADC_SC1寄存器从而触发一次ADC转换,然后ADC转换完成触发另一个DMA Channel将ADC的结果传到其中一个Buffer,具体配置俺就不多说了,看下面的程序注释就行了,至于TPM和ADC在DMA中的触发源可以在KL16的参考手册中找到,如下图,其中ADC0的触发源为40,TPM1溢出触发源为55;
|