打印
[资料分享与下载]

K60实现ADC四通道自动连续采集 无需CPU干预

[复制链接]
3010|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
小猫爱吃鱼|  楼主 | 2015-7-12 21:47 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
前有许多朋友询问如何使用K60的ADC实现多个通道的连续自动采集功能。其实就K60而言,他的ADC有ADC0和ADC1,每个ADCx又有A和B两组控制通道,因此最多可以实现4组ADC通道的连续自动采集,而且配合DMA和PDB,无需CPU对采集过程进行干预,我们可以直接读取内存中的转换结果!本例程同样是基于LPLD的OSKinetis固件库开发的,代码中全部使用库函数进行开发,开发过程无需涉及任何寄存器操作。每步我们都写了详细注释,相信不了解原理的童鞋也能看个大概!下面我还是简单叙述下实现原理:Step 1.配置ADC模块,配置A组和B组控制通道均为硬件触发,使能DMA请求。并使能相关输入通道。Step 2.配置DMA模块,分别用2个DMA通道来控制ADC0和ADC1的DMA传输,并配置DMA源地址为ADC结果寄存器,配置主循环计数2次,因为要分别传输R[A]和R[B]结果寄存器的值。Step 3.配置PDB模块,使用软件触发或其他外设触发均可,例程中位软件触发。关键步骤是要配置PDB的ADC预触发模式,使能通道0和通道1的预触发,并配置为Back to Back模式,这样才能让ADC的COCO转换完成标志自动触发下一个AD转换!Step 4.触发PDB工作,坐享其成!

//**********************************************
//Step 1.配置ADC0和ADC1的参数
//ADC0-A
adc0_init_struct.ADC_Adcx = ADC0;
adc0_init_struct.ADC_BitMode = SE_12BIT;      //12位精度
adc0_init_struct.ADC_CalEnable = TRUE;        //使能初始化校验
adc0_init_struct.ADC_HwAvgSel = HW_4AVG;      //使能4次硬件校准
adc0_init_struct.ADC_HwTrgCfg = HW_TRGA;      //配置A组为硬件触发
adc0_init_struct.ADC_DmaEnable = TRUE;        //使能DMA请求
LPLD_ADC_Init(adc0_init_struct);      //初始化ADC0-A组通道
//ADC0-B,只需配置不同参数的成员变量
adc0_init_struct.ADC_HwTrgCfg = HW_TRGB;      //配置B组为硬件触发
LPLD_ADC_Init(adc0_init_struct);      //初始化ADC0-B组通道
//使能ADC0的通道DAD1、AD14的引脚复用功能
LPLD_ADC_Chn_Enable(ADC0, DAD1);
LPLD_ADC_Chn_Enable(ADC0, AD14);
//使能ADC0的相关转换通道
LPLD_ADC_EnableConversion(ADC0, DAD1, 0, FALSE);
LPLD_ADC_EnableConversion(ADC0, AD14, 1, FALSE);

//ADC1A
adc1_init_struct.ADC_Adcx = ADC1;
adc1_init_struct.ADC_BitMode = SE_12BIT;
adc1_init_struct.ADC_CalEnable = TRUE;
adc1_init_struct.ADC_HwAvgSel = HW_4AVG;
adc1_init_struct.ADC_HwTrgCfg = HW_TRGA;
adc1_init_struct.ADC_DmaEnable = TRUE;
LPLD_ADC_Init(adc1_init_struct);
//ADC1B
adc1_init_struct.ADC_HwTrgCfg = HW_TRGB;
LPLD_ADC_Init(adc1_init_struct);
LPLD_ADC_Chn_Enable(ADC1, AD10);
LPLD_ADC_Chn_Enable(ADC1, AD11);
LPLD_ADC_EnableConversion(ADC1, AD10, 0, FALSE);
LPLD_ADC_EnableConversion(ADC1, AD11, 1, FALSE);
   
//**********************************************
//Step 2.配置DMA CH0和DMA CH1,分别处理ADC0和ADC1的DMA请求
//DMA CH0
dma0_init_struct.DMA_CHx = DMA_CH0;           //使用Ch0通道
dma0_init_struct.DMA_Req = ADC0_DMAREQ;       //DMA请求源为ADC0
dma0_init_struct.DMA_MajorLoopCnt = 2;        //主循环计数2次,因为要循环ADC0的AB两组通道
dma0_init_struct.DMA_MinorByteCnt = 2;        //次循环传输字节计数(由于ADC采样为12位,因此传输2字节)
dma0_init_struct.DMA_SourceAddr = (uint32)&(ADC0->R[0]);       //源地址:ADC0结果寄存器A地址
dma0_init_struct.DMA_SourceDataSize = DMA_SRC_16BIT;   //源地址传输数据宽度16位
dma0_init_struct.DMA_SourceAddrOffset = 4;    //源地址偏移为4个字节,因为ADC0->R寄存为32位宽,A组传输完成后移动到B组
dma0_init_struct.DMA_LastSourceAddrAdj = -8;  //主循环最后调节地址为-8个字节,因为主循环为2次计数,因此地址偏移了8个字节
dma0_init_struct.DMA_DestAddr = (uint32)&Result;       //目的地址,即定义的结果保存数组头地址
dma0_init_struct.DMA_DestDataSize = DMA_DST_16BIT;     //目的地址传输数据宽度16位
dma0_init_struct.DMA_DestAddrOffset = 2;      //目的地址偏移为2个字节,因为Result为16位变量
dma0_init_struct.DMA_LastDestAddrAdj = -4;    //目的地址最后调节地址为-4个字节
dma0_init_struct.DMA_AutoDisableReq = FALSE;   //禁用自动禁用请求,即不受主循环计数计数限制
//初始化DMA
LPLD_DMA_Init(dma0_init_struct);
//使能DMA请求
LPLD_DMA_EnableReq(DMA_CH0);

//DMA CH1,配置基本相同
dma1_init_struct.DMA_CHx = DMA_CH1;   
dma1_init_struct.DMA_Req = ADC1_DMAREQ;      
dma1_init_struct.DMA_MajorLoopCnt = 2;        
dma1_init_struct.DMA_MinorByteCnt = 2;
dma1_init_struct.DMA_SourceAddr = (uint32)&(ADC1->R[0]);      
dma1_init_struct.DMA_SourceDataSize = DMA_SRC_16BIT;  
dma1_init_struct.DMA_SourceAddrOffset = 4;
dma1_init_struct.DMA_LastSourceAddrAdj = -8;
dma1_init_struct.DMA_DestAddr = (uint32)&Result+4;       //目的地址,由于数组中头2个元素存ADC0的结果,因此要偏移4个字节取第3个元素的地址
dma1_init_struct.DMA_DestDataSize = DMA_DST_16BIT;  
dma1_init_struct.DMA_DestAddrOffset = 2;
dma1_init_struct.DMA_LastDestAddrAdj = -4;
dma1_init_struct.DMA_AutoDisableReq = FALSE;   
//初始化DMA
LPLD_DMA_Init(dma1_init_struct);
//使能DMA请求
LPLD_DMA_EnableReq(DMA_CH1);
   
//**********************************************
//Step 3.配置PDB,用于触发ADC
pdb_init_struct.PDB_CounterPeriodMs = 100;    //PDB计数器周期,这个决定了4个通道每采集一次的间隔
pdb_init_struct.PDB_LoadModeSel = LOADMODE_0;
pdb_init_struct.PDB_ContinuousModeEnable = TRUE;      //使能连续工作模式,即只需要开始触发一次,以后PDB就会连续工作
pdb_init_struct.PDB_TriggerInputSourceSel = TRIGGER_SOFTWARE; //软件触发模式,即不需要用其他模块触发PDB工作
//初始化PDB
LPLD_PDB_Init(pdb_init_struct);
//配置PDB预触发功能
//使能ADC0-A组的预触发功能
LPLD_PDB_AdcTriggerCfg(ADC0, PRETRIG_EN_A|PRETRIG_DLY_A, 0);  
//使能ADC0-B组的预触发功能,并使用Back to Back模式
LPLD_PDB_AdcTriggerCfg(ADC0, PRETRIG_BB_B|PRETRIG_EN_B|PRETRIG_DLY_B, 0);
//使能ADC1-A组的预触发功能,并使用Back to Back模式
LPLD_PDB_AdcTriggerCfg(ADC1, PRETRIG_BB_A|PRETRIG_EN_A|PRETRIG_DLY_A, 0);
//使能ADC1-B组的预触发功能,并使用Back to Back模式
LPLD_PDB_AdcTriggerCfg(ADC1, PRETRIG_BB_B|PRETRIG_EN_B|PRETRIG_DLY_B, 0);
//软件触发PDB开始工作
LPLD_PDB_SoftwareTrigger();

while(1)
{
  delay();
  printf("ADC0_RA=%d\r\n", Result[0]);
  printf("  ADC0_RB=%d\r\n", Result[1]);
  printf("    ADC1_RA=%d\r\n", Result[2]);
  printf("      ADC1_RB=%d\r\n", Result[3]);
}


相关帖子

沙发
奥德赛| | 2015-7-13 09:41 | 只看该作者
谢谢楼主分享这么好的资料,很有用

使用特权

评论回复
板凳
@曲终人散@| | 2015-7-16 14:57 | 只看该作者
看不懂

使用特权

评论回复
地板
Luis德华| | 2015-7-16 15:43 | 只看该作者
配置ADC模块,配置A组和B组控制通道均为硬件触发,使能DMA请求。并使能相关输入通道。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

33

主题

294

帖子

2

粉丝