|
本帖最后由 洋葱圈 于 2013-11-4 20:45 编辑
本节课我们来学习一下ADC模块在OSKinetis固件库中的使用方法。在例程包中已经有了关于ADC的单端和差分采集例程,相信大家已经运行过了。在使用过程中,只要进行简单的配置,就可以随意控制转换时间以及转换精度。虽然配置容易,但是具体到每次采集需要消耗多少时间在固件库中并不能表示出来,如果你的应用“没有时间概念”,那么大可不必关心本节课,如果你的应用比较在意模数转换的时间,那么请仔细看看本节课的内容。
与前几课不同,这次我们首先讲解例程,然后说说例程中的采集时间是具体怎么计算的,还有一些ADC模块中比较难懂的概念,我们也会给大家讲讲,比如:AD采样频率和AD时钟、硬件触发、AB组寄存器的区分、PGA可编程增益等等。如果你已经通过自学,可以熟练的使用ADC库函数了,那么可以直接看例程讲解后面的章节。
ADC例程讲解
本节课我们先讲解两个简单的ADC例程,也就是软件触发模式下的单端和差分采集。在后续的课程中我们会详细讲解硬件触发、DMA传输等高级例程。
单端采集-LPLD_AnalogSampleSE
如果你使用RUSH Kinetis开发板,那么可以直接将本例程下载到芯片中,通过旋转母板上的可变电阻器观察结果输出。无论你怎么旋转旋钮,输出结果总是0~4095之间。这说明单端输入的电压量总是、也只能是正电压,旋钮的位置以及相应的原理图如下图所示:
可以从原理图得知,K60的ADC输入引脚ADC0_DP1永远是R7分压得到的,电压值在0~3.3V之间变化。
接下来看代码,找到应用中的ADC初始化函数adc_init(),代码如下:
1 | adc_init_struct.ADC_Adcx = ADC0; | 2 | adc_init_struct.ADC_DiffMode = ADC_SE; //单端采集 | 3 | adc_init_struct.ADC_BitMode = SE_12BIT; //单端12位精度 | 4 | adc_init_struct.ADC_SampleTimeCfg = SAMTIME_SHORT; //短采样时间 | 5 | adc_init_struct.ADC_HwAvgSel = HW_4AVG; //4次硬件平均 | 6 | adc_init_struct.ADC_CalEnable = TRUE; //使能初始化校验 | 7 | LPLD_ADC_Init(adc_init_struct); | 8 | LPLD_ADC_Chn_Enable(ADC0, DAD1); |
Line 1:ADC_Adcx成员变量用于配置ADCx的模块号,MK60D系列单片机有ADC0和ADC1两个模块。哦对了,adc_init_struct是在之前定义的ADC初始化结构体变量。
Line 2:ADC_DiffMode用于配置采集模式,分为单端采集和差分采集,这里配置为单端采集。
Line 3:ADC_BitMode用于配置当前ADCx模块的采集精度,这里配置为单端12位精度。需要注意的是,每个ADCx模块只能配置为一种采集精度,也就是说如果ADC0配置为12位精度,那么它包含的所有输入通道均为12位精度。
Line 4:ADC_SampleTimeCfg用于选择长、短采样时间模式,这里配置为段采样时间模式。如果配置为长采样时间模式,还要配置额外需要的时间,这个成员变量是ADC_LongSampleTimeSel。
Line 5:配置ADC_HwAvgSel成员变量来使能硬件平均,同时指定为4次平均。ADC可以配置4、8、16、32次平均,如果不配置此参数,就不使能硬件平均功能。
Line 6:ADC_CalEnable用于使能校验功能,使能校验只会增加初始化的时间,建议使能。
Line 7:调用初始化函数,初始化ADC0模块。
Line 8:调用通道使能函数,使能单端通道DAD1的AD采集复用功能。该函数不是必须调用的,如果该通道对应的引脚没有被配置为其他功能,则不必调用该函数。这里的DAD1通道对应就是上面原理图中的ADC0_DP1引脚。
关于初始化结构体ADC_InitTypeDef成员变量的取值定义,请大家参考在线手册定义(ADC_InitTypeDef)。
初始化完毕后,就可以直接使用AD采集函数获取转换结果了,代码如下:
1 | result = LPLD_ADC_Get(ADC0, DAD1); | Line 1:使用LPLD_ADC_Get()函数可以通过软件触发的模式获取相应ADCx模块不同通道的采集结果。该函数内部首先选择相应输入通道,然后通过判断标志位等待转换结束,也就是说如果转换为结束,该函数不会返回值。如果你采用硬件触发方式或中断方式获取采集数据,那么可以通过LPLD_ADC_GetResult()函数直接读取寄存器的转换结果,使用方法我们后续课程会提及。
差分采集-LPLD_AnalogSampleDIFF
该例程同样用RUSH Kinetis开发板上的旋钮进行试验,不同的是,该例程的运行结果会随着旋钮的转动,输出-2047~2048之间的数。因为在电路中,通过R8和R9的分压,将1.15V的电压输入到了ADC0_DM1引脚,该引脚是DAD1差分通道的负输入端。而正输入端是又R7滑动变阻器进行分压的,因此DAD1差分通道的电压输入是在-1.15~1.15V之间变化的。
接下来看初始化函数代码:
1 | adc_init_struct.ADC_Adcx = ADC0; | 2 | adc_init_struct.ADC_DiffMode = ADC_DIFF; //差分采集 | 3 | adc_init_struct.ADC_BitMode = DIFF_13BIT; //差分13位精度 | 4 | adc_init_struct.ADC_SampleTimeCfg = SAMTIME_SHORT; //短采样时间 | 5 | adc_init_struct.ADC_HwAvgSel = HW_4AVG; //4次硬件平均 | 6 | adc_init_struct.ADC_CalEnable = TRUE; //使能初始化校验 | 7 | LPLD_ADC_Init(adc_init_struct); | 8 | LPLD_ADC_Chn_Enable(ADC0, DAD1); |
从代码中只能看到两处与上一个例程不同,分别是Line 2和Line 3,我们只要把采集模式改为差分(ADC_DIFF)、精度模式改为差分13位精度(DIFF_13BIT)即可。
初始化完毕后,同样适用LPLD_ADC_Get()函数采集通道ADC转换数据,不同的是我们需要把转换结果强制转换为有符号类型数字,因为这里的转换结果是差分数据,正负端输入的值可能是个负值,如下所示:
1 | result = (int16)LPLD_ADC_Get(ADC0, DAD1); |
当然,变量result也必须是有符号整形才可以。
ADC转换时间
所谓转换时间,就是从使能AD转换通道开始到转换完成标志置位的这段时间,其中使能AD转换通道的动作可以是软件触发也可以是硬件触发。曾经有人说库函数的AD转换函数太慢,有几ms之久,其实那是旧版本库出于稳定考虑采用了最长的转换时间。最新的OSKinetis V3固件库则可以通过配置ADC_SampleTimeCfg(长短采样)、ADC_LongSampleTimeSel(长采样时间选择)、ADC_HwAvgSel(硬件平均)等参数来使用不同的转换时间方案。你只要使用我们编写的ADC转换时间计算工具,就可以轻松得到不同配置模式下的AD转换时间!
转换时间公式解析
首先我们看看K60技术文档中K60P144M100SF2RM.pdf关于ADC转换时间是怎样定义的(如果你不想了解,也不影响固件库的使用),请看该技术文档的Page.838,图表34-95,该公式就是K60的ADC转换时间计算公式:
转换时间 = SFCAdder + 平均次数 * (BCT + LSTAdder + HSCAdder)
SFCAdder-代表单次或首次连续转换时间的累加值,该值由这样几个寄存器位决定:ADLSMP(采样时间配置)、ADACKEN(AD异步时钟输出使能)、ADICLK(输入时钟选择)。具体对应值见技术文档的表34-107。例如:采样时间配置为长时间采样(ADLSMP=1)、使能异步时钟输出(ADACKEN=1)、选择异步时钟(ADICLK=11),那么SFCAdder的值就是5个ADCK周期+5个总线周期。
ADCK-代表AD时钟,他由ADICLK决定,可以是总线时钟、总线时钟/2、备用时钟(ALTCLK)、异步时钟ADACK。
平均次数-代表硬件平均次数,如果仅用硬件平均就是1。
BCT-代表基础转换时间,它由你设定的转换精度决定,具体见技术文档的表34-109。例如选择单端8位精度,那么时间就是17个ADCK周期。
LSTAdder-代表长采样时间模式的时间累加值,如果选择为短采样模式则为0,如果选择为长采样时间模式,则根据ADLSTS(长采样时间选择)寄存器位的值决定,具体见技术文档的表34-110。
HSCAdder-高速转换时间累加值。当ADHSC=0,不采用高速转换时间时该值为0,如果为1,值为2个ADCK周期。
计算固件库中配置的AD转换时间
不知道大家有没有被上面的公式弄糊涂,如果没明白也没关系,因为下面有更方便的方法来知道AD转换时间到底是多少。不过首先你要下载一个“OSKinetis小工具(http://www.znczz.com/thread-210411-1-1.html)”,打开后选择“ADC Time”选项,根据例程LPLD_AnalogSampleSE中的ADC初始化配置设置相关选项,点击“Calculate”后便会在界面中显示出当前ADC模块的转换时间以及频率,如下图所示:
这个软件中的所有选项名称都是ADC初始化结构体中的成员变量,所有选项都是成员变量的取值,因此你也可以先用此工具配置好各个参数,计算出合适的时间后再去修改代码。该软件计算出来的时间是理论上ADC的转换时间,当然在使用固件库的过程中,会有部分时间损耗在函数的其他代码运行上,转换时间要多出几个us。如果你配置的转换时间越长,计算出来的时间和实际测试时间约近似!
如果你想测试下ADC的转换时间实际是多少,可以用IO口的高低电平变化来测试,例如在调用LPLD_ADC_Get()函数前置某个IO口为1,在调用之后再置IO口0,用示波器观察高电平的时序时间就是ADC的转换时间,当然会比理论计算长一点。
ADC模块解惑
AD采样频率和ADC模块时钟
虽然在使用固件库的时候,不会涉及到AD采样频率和ADC模块时钟这两个概念,但是为了更深入的学习Kinetis,知道总比不知道好。AD采样频率就是AD采样时间的倒数,这个时间的计算方法我们在上面一节已经说了,从公式以及公式各项中我们可以看到ADCK这个名词。ADCK就是ADC模块的时钟,而这个时钟是可以选择的且可以分频的,可以是模块内部生成的异步时钟,也可以是总线时钟、总线时钟/2、或者备用时钟。如下图所示,该图是ADC模块内部框图的一部分,全图可见技术文档的Page.805。
图中红框表示可选的时钟源,绿框表示通过ADICLK这个寄存器位来选择时钟源,蓝框表示经过ADIV分频后输出ADCK时钟。采样频率域ADC时钟最直接的关系,可以理解为一个AD采样时间内,包含n个ADCK,ADCK的频率越快,AD的采样频率也就越快!
ADC的硬件触发
ADC最重要的功能就是硬件触发,通过使用硬件触发模式,可以指定特定事件来触发ADC进行采集作业,而不需要人工用软件去控制ADC何时进行采集,配合DMA的使用,完全可以做到CPU无干预进行AD采集。在Kinetis中,能够触发ADC进行采集的方法除了软件触发之外就仅有PDB模块可以触发AD采集。那么又由什么来触发PDB工作呢,原来PDB还可以再由其他模块进行触发,例如PIT、FTM、软件触发等等。因此倒推回来,ADC就可以间接由PIT、FTM等内部模块进行触发了,例如可以设定PIT模块定时产生请求,触发ADC进行采集。那么你可能又要问了,既然可以用PIT间接触发ADC,那为什么不直接触发还要进过PDB呢,其实PDB并不是一个桥梁那么简单,他可以在接收到内部触发后,延时一段时间再触发AD采集,也可以触发一连串AD采集,具体的我们就不说了,讲到PDB的时候自然会提及。
A、B组寄存器区别
ADC模块的AB组寄存器概念仅涉及它的状态控制寄存器SC1,SC1A可以配置ADC为软件或硬件触发,SC1B只能配置ADC为硬件触发。很多学习ADC寄存器编写的同学对于这两组寄存器到底怎么用存在很大的疑惑,总是和ADC的通道概念相混淆。但是真相只有一个,就是SC1A和SC1B只有一个能暂时去控制ADC进行采集。很多人会问了,那我要俩SC干嘛,只有一个干活。但是你没发现,一个SC干活的话他只能去控制一个通道,如果2个SC轮流干活的话他们就可以同时采集2个通道的数据了!这个就是技术文档中写的,很多人不明白的“ping-pong”控制模式。而且这种高级的控制模式光用ADC一个模块实现不了,还必须配合PDB去控制。
当然具体到固件库的使用,我们已经大大的简化了编写步骤,本节只是给大家一个感性认识。
PGA可编程增益运放
ADC模块有个别通道不仅可以做普通的AD输入使用,还可以把输入的信号做内部放大。然后这个放大不是只是简单的把采集数据进行乘法运算,而是从硬件上进行信号增益。这就为那些成本敏感和空间有限的设计带来了便利!在固件库的使用过程中,可以直接在初始化时配置增益倍数,用ADC_PgaGain这个成员变量,在获取采集结果的时候,要使用正确的具有PGA功能的通道才能获取增益后的数据。对于MK60D单片机来说他只有DAD2通道可以进行可编程增益AD采集。
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
|