【WB32库开发】第14章 (中) ADC电压采集——多通道采集

上节课学习的ADC电压采集仅使用了16个ADC通道中的其中一个来采集电压,效率相对来说较慢。

本节将结合上一章学习的DMA来进行多通道的ADC电压采集,使用这种方法可以提高ADC采集的效率。

本节以固件库例程ADC中的ADC_DMA为例,讲解如何配置ADC与DMA,使之完成多通道采集的实验(注意,本例程中只给出单通道采集,我们,我们先对比上一节中断读取来学习,具体的多通道采集请看下一节内容)。

14.5 ADC DMA读取

本节例程有四个需要注意的点:
1)初始化ADC GPIO(同时配置DMA的时钟);
2)初始化ADC工作参数;
3)配置DMA工作参数;
4)读取ADC采集的数据。

代码中某些配置不再细讲,如果不理解的请阅读以往的教程。

14.5.1 初始化ADC GPIO

  /* 使能 DMAC1, ADC, GPIOA 时钟 */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMAC1Bridge, ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_BMX1 |RCC_APB1Periph_DMAC1 |RCC_APB1Periph_ADC |RCC_APB1Periph_GPIOA, ENABLE);

  /* 配置 PA3(ADC Channel3) 为模拟模式 */
  GPIO_Init(GPIOA, GPIO_Pin_3 , GPIO_MODE_ANA);

这里需要注意通道的英文Channel,很多人在编写代码时容易将ADC Channel3看成ADC通道13。

14.5.2 初始化ADC工作参数

这部分着重观察DMA读取与中断读取配置的不同之处。

  PWR_UnlockANA();
  ANCTL_SARADCCmd(ENABLE);
  PWR_LockANA();
  
  /* ADC结构体成员配置 */
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;                            //ADC扫描模式选择,单通道为DISABLE,多通道为ENABLE
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;                      //ADC单次转换或者连续转换选择,这里ENABLE配置为连续转换
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfChannel = 1;                                 //根据实际使用通道数填写,本例使用到1个通道用来转换。
  ADC_Init(&ADC_InitStructure);

  /* ADC规则通道设置。 */
  /* 配置通道3,转换顺序为1,此采样时间为7.5个时钟周期  */
  ADC_RegularChannelConfig(ADC_Channel_3, 1, ADC_SampleTime_7Cycles5);

  /* 使能ADC的DMA */
  ADC_DMACmd(ENABLE);

  ADC_ExternalTrigConvCmd(ENABLE);

  ADC_Cmd(ENABLE);

  /* 初始化ADC校准寄存器并重启 */
  ADC_StartCalibration();
  while(ADC_GetCalibrationStatus());
  ADC_ResetCalibration();
  while(ADC_GetResetCalibrationStatus());

  /* 没有使用外部触发,故使用软件触发ADC转换 */
  ADC_SoftwareStartConvCmd(ENABLE);

因为本例讲解DMA方式,因此少了中断相关配置,而增加了使能ADC的DMA的函数语句。

14.5.3 配置DMA工作参数

DMA可配置参数相对较多,务必仔细观察学习:

  /* DMAC channel0 configuration ---------------------------------------------*/
  DMAC_DeInit(DMAC1);

  /* ADC->DR 为ADC读取到的‘电压值’的存放地址 */
  DMAC_Channel_InitStruct.DMAC_SourceBaseAddr = (uint32_t)&ADC->DR;
  
  /* ADCConvertedValue为用户自己申请的变量,由于需要对应传输地址,故在前加上‘&’符号 */
  /* __IO uint16_t ADCConvertedValue; */
  DMAC_Channel_InitStruct.DMAC_DestinationBaseAddr = (uint32_t)&ADCConvertedValue; 
  
  DMAC_Channel_InitStruct.DMAC_Interrupt = DMAC_Interrupt_Disable;
  DMAC_Channel_InitStruct.DMAC_SourceTransferWidth = DMAC_SourceTransferWidth_16b;
  DMAC_Channel_InitStruct.DMAC_DestinationTransferWidth = DMAC_DestinationTransferWidth_16b;
  
  /* 注意以下两行代码,由于本节例程是从外设传输到存储器,故外设地址不变,存储器内存地址设置为自增模式 */
  DMAC_Channel_InitStruct.DMAC_SourceAddrInc = DMAC_SourceAddrInc_NoChange;
  DMAC_Channel_InitStruct.DMAC_DestinationAddrInc = DMAC_DestinationAddrInc_Increment;
  
  DMAC_Channel_InitStruct.DMAC_SourceTransactionLength = DMAC_SourceTransactionLength_1;
  DMAC_Channel_InitStruct.DMAC_DestinationTransactionLength = DMAC_DestinationTransactionLength_1; 

  /* 传输方向为外设到存储器 */
  DMAC_Channel_InitStruct.DMAC_TransferTypeAndFlowControl = DMAC_TransferTypeAndFlowControl_PeripheralToMemory_DMAC;
  
  DMAC_Channel_InitStruct.DMAC_SourceMasterInterface = DMAC_SourceMasterInterface_APB;
  DMAC_Channel_InitStruct.DMAC_DestinationMasterInterface = DMAC_DestinationMasterInterface_AHB;
  DMAC_Channel_InitStruct.DMAC_BlockTransferSize = 1;
  DMAC_Channel_InitStruct.DMAC_SourceHandshakingInterfaceSelect = DMAC_SourceHandshakingInterfaceSelect_Hardware;
  DMAC_Channel_InitStruct.DMAC_DestinationHandshakingInterfaceSelect = DMAC_DestinationHandshakingInterfaceSelect_Hardware;
  DMAC_Channel_InitStruct.DMAC_SourceHandshakingInterfacePolarity = DMAC_SourceHandshakingInterfacePolarity_High;
  DMAC_Channel_InitStruct.DMAC_DestinationHandshakingInterfacePolarity = DMAC_DestinationHandshakingInterfacePolarity_High;
  DMAC_Channel_InitStruct.DMAC_AutomaticSourceReload = DMAC_AutomaticSourceReload_Disable;

  /* 使能存储器重装载功能 */
  DMAC_Channel_InitStruct.DMAC_AutomaticDestinationReload = DMAC_AutomaticDestinationReload_Enable;
  
  DMAC_Channel_InitStruct.DMAC_FlowControlMode = DMAC_FlowControlMode_0;
  DMAC_Channel_InitStruct.DMAC_FIFOMode = DMAC_FIFOMode_0;
  DMAC_Channel_InitStruct.DMAC_ChannelPriority = 0;
  DMAC_Channel_InitStruct.DMAC_ProtectionControl = 0x1;
  DMAC_Channel_InitStruct.DMAC_SourceHardwareHandshakingInterfaceAssign = DMAC_HardwareHandshakingInterface_ADC_Regular;
  DMAC_Channel_InitStruct.DMAC_DestinationHardwareHandshakingInterfaceAssign = 0;
  DMAC_Channel_InitStruct.DMAC_MaximumAMBABurstLength = 0;
  DMAC_Channel_Init(DMAC1, DMAC_Channel_0, &DMAC_Channel_InitStruct);

  DMAC_Cmd(DMAC1,ENABLE);
  DMAC_ChannelCmd(DMAC1, DMAC_Channel_0, ENABLE);

没有进行注释的代码不需要太在意,我们先从固定模式学习,再学习如何变通;

可以注意到这与以往的DMA设置无太大不同,只是对应使用方式有一些不同的参数设置。

注意:
1)结构体成员DMAC_DestinationBaseAddr应填入我们在WB32中申请的变量的地址(__IO uint16_t ADCConvertedValue),其中“__IO”很多人都是初次见到:

__IO 一般宏定义为volatile,表示可读可写 volatile 就是为了禁止编译器对其优化。
这个_IO 是指静态, volatile uint16_t 是指16位的无符号整形变量uint16_t 是指16位的无符号整形变量。
_t后缀一般表明这是个系统内的数据型。 __IO uint16_t 等价于 volatile unsigned short int。

14.5.4 读取ADC采集的数据

  while (1)
  {
    //判断DMAC1通道0是否传输完成
    while(DMAC_GetRawITStatus(DMAC1, DMAC_Channel_0, DMAC_IT_BLOCK) == RESET); 
    //若完成则清除该中断标识符
    DMAC_ClearITPendingBit(DMAC1, DMAC_Channel_0, DMAC_IT_BLOCK);               
    //打印存放在ADCConvertedValue中被ADC_GetADValue()函数转换过的值
    printf("\rADC Channel 3: %-5d", ADC_GetADValue(ADCConvertedValue));			
  }

这一次我们将读取值的代码写在while(1)中,意味着上电后其中的代码会不断地执行,待会儿在实验现象中可以看到。

14.6 实验现象

代码编译烧录后,使用CH340将开发板与电脑连接好,打开串口调试器,先将PA3(ADC通道3)浮空或接GND,可看到:
在这里插入图片描述
如我们在14.5.4节中所说,会不断读取ADC的值。

此时将PA3与板载3.3V连接,可看到:
在这里插入图片描述
可以看到ADC读取到了最大量程4093(约为4096,此部分不懂的请看上节中断读取部分)。

14.7 小结

本次实验成功,但还没有实现多通道读取,在代码编写上也有些杂乱;因此,在本节课程和代码的基础上,笔者给出综合实验例程供下载,望读者提前阅读代码,并跟随下节课程学习。

给出的代码解压后直接复制到固件库ADC例程中即可:
在这里插入图片描述

ADC电压采集DMA多通道读取例程代码下载地址:

链接:https://pan.baidu.com/s/121fkYzd23fRTy4yoAX-rAA
提取码:CSDN

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值