[MM32软件] 【灵动微电子MM32F5330测评】04 ADC+DMA

[复制链接]
1087|0
 楼主| 怀揣少年梦 发表于 2024-8-3 09:40 | 显示全部楼层 |阅读模式
本帖最后由 怀揣少年梦 于 2024-8-3 09:43 编辑

一、先来看一下MM32F5330的ADC功能介绍与特性
1、ADC介绍
ADC 是 12 位的逐次逼近型(SAR)模拟数字转换器,可以将模拟信号转换成数字信号。ADC 有可测量内部或外部信号源,其中 ADC1 有 19 路外部输入通道,ADC2 有 17 路外部输入通道和 2 路内部通道。这些 ADC 的通道可以单次、单周期和连续进行转换。根据不同的方式又可以选择普通通道转换、任意通道转换。ADC 的最大输入时钟为 48MHz,它是由 PLL2 和 APB2 时钟(PCLK2)分频产生。
2、特性
  • 高达 3Msps 转换速率;
  • 支持普通通道转换;
  • 单次转换模式:在指定通道完成一次转换;
  • 单周期扫描模式:对所有指定通道(从低序号通道到高序号通道,或从高序号通道到低序号通道)完成一个周期转换;
  • 连续扫描模式:连续执行单周期扫描模式直到软件停止 A/D 转换。若需要修改转换通道只能停止A/D 转换,等待完成寄存器配置再重新开启转换;
  • 支持任意通道转换;
  • 单次转换模式:在指定通道完成一次转换; 单周期扫描模式:在所有指定通道按照通道设置完成一个周期转换;连续扫描模式:连续执行单周期扫描模式直到软件停止 A/D 转换。若需要转换期间修改通道,用户不必停止转换,可配置相应通道寄存器,配置的新通道将在下一个扫描周期进行转换;
  • 注入通道转换自动注入:在任意通道转换方式下,完成任意通道转换后自动开始进行注入通道转换
  • 可编程通道采样时间 最高 12 位可编程分辨率 SAR 支持 DMA 传输 A/D 转换开始条件
  • 软件启动;
  • 触发启动,可配置触发延时。触发源包括:Timer 和 EXTI 模拟看门狗功能。转换结果与指定的阈值区间进行比较,当转换值超出设定的阈值区间时,如果ADC_ADCR.AWDIE 置位,则产生中断;
  • 支持自校准功能,输入时钟 1.5MHz 支持单端、差分、伪差分转换;这个还是很强大的。
  • 支持过采样


二、ADC+DMA编程
1、编写ADC代码
  1. void ADC_Configure(void)
  2. {
  3.     ADC_InitTypeDef  ADC_InitStruct;
  4.     DMA_InitTypeDef  DMA_InitStruct;
  5.     GPIO_InitTypeDef GPIO_InitStruct;
  6.     NVIC_InitTypeDef NVIC_InitStruct;

  7.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);// 使能GPIOA时钟

  8.     ADC_CalibrationConfig(ADC1, 0x1FE);//校准

  9.     ADC_StructInit(&ADC_InitStruct);
  10.     ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;//12bit模式
  11.     ADC_InitStruct.ADC_Prescaler  = ADC_Prescaler_16; //时钟分频
  12.     ADC_InitStruct.ADC_Mode       = ADC_Mode_Continue;//连续采样
  13.     ADC_InitStruct.ADC_DataAlign  = ADC_DataAlign_Right;
  14.     ADC_Init(ADC1, &ADC_InitStruct);

  15.     ADC_DMACmd(ADC1, ENABLE);//使能DMA

  16.     ADC_SampleTimeConfig(ADC1, ADC_Channel_1, ADC_SampleTime_79_5);//配置
  17.     ADC_SampleTimeConfig(ADC1, ADC_Channel_4, ADC_SampleTime_79_5);
  18.     ADC_SampleTimeConfig(ADC1, ADC_Channel_5, ADC_SampleTime_79_5);

  19.         //使能ADC通道 1 4 5
  20.     ADC_ChannelCmd(ADC1, ADC_Channel_1, ENABLE);
  21.     ADC_ChannelCmd(ADC1, ADC_Channel_4, ENABLE);
  22.     ADC_ChannelCmd(ADC1, ADC_Channel_5, ENABLE);

  23.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

  24.     /* PA1(RV1) PA4(RV2) PA5(RV3) */
  25.     GPIO_StructInit(&GPIO_InitStruct);
  26.     GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5; // 使能GPIOA时钟,配置为模拟输入模式

  27.     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
  28.     GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AIN;
  29.     GPIO_Init(GPIOA, &GPIO_InitStruct);
  30.         //使能ADC
  31.     ADC_Cmd(ADC1, ENABLE);

  32.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  33.         
  34.     DMA_DeInit(DMA1_Channel1);
  35.         //初始化DMA参数
  36.     DMA_StructInit(&DMA_InitStruct);
  37.     DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->ADDATA);
  38.     DMA_InitStruct.DMA_MemoryBaseAddr     = (uint32_t)ADC_Buffer;
  39.     DMA_InitStruct.DMA_DIR                = DMA_DIR_PeripheralSRC;
  40.     DMA_InitStruct.DMA_BufferSize         = 30;
  41.     DMA_InitStruct.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
  42.     DMA_InitStruct.DMA_MemoryInc          = DMA_MemoryInc_Enable;
  43.     DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  44.     DMA_InitStruct.DMA_MemoryDataSize     = DMA_MemoryDataSize_HalfWord;
  45.     DMA_InitStruct.DMA_Mode               = DMA_Mode_Circular;
  46.     DMA_InitStruct.DMA_Priority           = DMA_Priority_VeryHigh;
  47.     DMA_InitStruct.DMA_M2M                = DMA_M2M_Disable;
  48.     DMA_InitStruct.DMA_Auto_Reload        = DMA_Auto_Reload_Disable;
  49.     DMA_Init(DMA1_Channel1, &DMA_InitStruct);
  50.         //配置DMA中断
  51.     DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
  52.         //使能DMA通道1
  53.     DMA_Cmd(DMA1_Channel1, ENABLE);
  54.         //配置DMA中断
  55.     NVIC_InitStruct.NVIC_IRQChannel = DMA1_CH1_IRQn;
  56.     NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
  57.     NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
  58.     NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  59.     NVIC_Init(&NVIC_InitStruct);
  60. }

  61. void ADC_NormalChannel_ContinuousScan_DMA_Interrupt_Sample(void)
  62. {
  63.     uint8_t  i = 0, j = 0;
  64.     uint32_t RVxSum = 0;
  65.     float    RVxAverage[3], RVxVoltage[3];

  66.     printf("\r\nTest %s", __FUNCTION__);

  67.     ADC_Configure();

  68.     ADC_SoftwareStartConvCmd(ADC1, ENABLE);

  69.     while (1)
  70.     {
  71.         if (0 != ADC_DMA_InterruptFlag)
  72.         {
  73.             ADC_DMA_InterruptFlag = 0;

  74.             for (i = 0; i < 3; i++)
  75.             {
  76.                 RVxSum = 0;

  77.                 for (j = 0; j < 10; j++)
  78.                 {
  79.                     RVxSum += ADC_Buffer[i + j * 3];
  80.                 }

  81.                 RVxAverage[i] = (float)RVxSum / (float)10.0;
  82.             }

  83.             printf("\r\n");


  84.             RVxVoltage[0] = RVxAverage[0] * (float)3.3 / (float)4096.0;
  85.                         log_d("RV%d Voltage = %0.2f\t", 1, RVxVoltage[0]);
  86.             RVxVoltage[1] = RVxAverage[1] * (float)3.3 / (float)4096.0;
  87.                         log_i("RV%d Voltage = %0.2f\t", 2, RVxVoltage[1]);
  88.                         RVxVoltage[2] = RVxAverage[2] * (float)3.3 / (float)4096.0;
  89.                         log_w("RV%d Voltage = %0.2f\t", 3, RVxVoltage[2]);
  90.                         PLATFORM_DelayMS(500);
  91.         }
  92.     }
  93. }

2、验证
1)ADC三个通道的电压,如图所示。
PixPin_2024-08-03_09-07-51.png

2)旋转RV1的电位器,如图所示。
PixPin_2024-08-03_09-08-55.png

3)与万用表对比
使用UT39E+万用表对比测试。
万用表的精度如下图:
万用表.png
实测数据对比
            
万用表
(V)
ADC
(V)
差值(MV)
RV1
3.198
3.21
2
RV2
1.646
1.65
4
RV3
1.742
1.74
2
3.2.jpg 微信图片_20240803094249.jpg 1.742.jpg
总结:
1、检测10分钟,ADC数值没有变化,还是比较稳定。
2、与万用表对比,基本相差2-4mv;在要求不是特别高的情况,精度还是不错的。

您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:一切皆有可能

45

主题

473

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部