【灵动微电子MM32F5330测评】04 ADC+DMA

一、先来看一下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代码

复制
void ADC_Configure(void)

{

    ADC_InitTypeDef  ADC_InitStruct;

    DMA_InitTypeDef  DMA_InitStruct;

    GPIO_InitTypeDef GPIO_InitStruct;

    NVIC_InitTypeDef NVIC_InitStruct;



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



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



    ADC_StructInit(&ADC_InitStruct);

    ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;//12bit模式

    ADC_InitStruct.ADC_Prescaler  = ADC_Prescaler_16; //时钟分频

    ADC_InitStruct.ADC_Mode       = ADC_Mode_Continue;//连续采样

    ADC_InitStruct.ADC_DataAlign  = ADC_DataAlign_Right;

    ADC_Init(ADC1, &ADC_InitStruct);



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



    ADC_SampleTimeConfig(ADC1, ADC_Channel_1, ADC_SampleTime_79_5);//配置

    ADC_SampleTimeConfig(ADC1, ADC_Channel_4, ADC_SampleTime_79_5);

    ADC_SampleTimeConfig(ADC1, ADC_Channel_5, ADC_SampleTime_79_5);



        //使能ADC通道 1 4 5 

    ADC_ChannelCmd(ADC1, ADC_Channel_1, ENABLE);

    ADC_ChannelCmd(ADC1, ADC_Channel_4, ENABLE);

    ADC_ChannelCmd(ADC1, ADC_Channel_5, ENABLE);



    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);



    /* PA1(RV1) PA4(RV2) PA5(RV3) */

    GPIO_StructInit(&GPIO_InitStruct);

    GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5; // 使能GPIOA时钟,配置为模拟输入模式



    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;

    GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AIN;

    GPIO_Init(GPIOA, &GPIO_InitStruct);

        //使能ADC

    ADC_Cmd(ADC1, ENABLE);



    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

        

    DMA_DeInit(DMA1_Channel1);

        //初始化DMA参数

    DMA_StructInit(&DMA_InitStruct);

    DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->ADDATA);

    DMA_InitStruct.DMA_MemoryBaseAddr     = (uint32_t)ADC_Buffer;

    DMA_InitStruct.DMA_DIR                = DMA_DIR_PeripheralSRC;

    DMA_InitStruct.DMA_BufferSize         = 30;

    DMA_InitStruct.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;

    DMA_InitStruct.DMA_MemoryInc          = DMA_MemoryInc_Enable;

    DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

    DMA_InitStruct.DMA_MemoryDataSize     = DMA_MemoryDataSize_HalfWord;

    DMA_InitStruct.DMA_Mode               = DMA_Mode_Circular;

    DMA_InitStruct.DMA_Priority           = DMA_Priority_VeryHigh;

    DMA_InitStruct.DMA_M2M                = DMA_M2M_Disable;

    DMA_InitStruct.DMA_Auto_Reload        = DMA_Auto_Reload_Disable;

    DMA_Init(DMA1_Channel1, &DMA_InitStruct);

        //配置DMA中断

    DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);

        //使能DMA通道1

    DMA_Cmd(DMA1_Channel1, ENABLE);

        //配置DMA中断

    NVIC_InitStruct.NVIC_IRQChannel = DMA1_CH1_IRQn;

    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;

    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;

    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStruct);

}



void ADC_NormalChannel_ContinuousScan_DMA_Interrupt_Sample(void)

{

    uint8_t  i = 0, j = 0;

    uint32_t RVxSum = 0;

    float    RVxAverage[3], RVxVoltage[3];



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



    ADC_Configure();



    ADC_SoftwareStartConvCmd(ADC1, ENABLE);



    while (1)

    {

        if (0 != ADC_DMA_InterruptFlag)

        {

            ADC_DMA_InterruptFlag = 0;



            for (i = 0; i < 3; i++)

            {

                RVxSum = 0;



                for (j = 0; j < 10; j++)

                {

                    RVxSum += ADC_Buffer[i + j * 3];

                }



                RVxAverage[i] = (float)RVxSum / (float)10.0;

            }



            printf("\r\n");





            RVxVoltage[0] = RVxAverage[0] * (float)3.3 / (float)4096.0;

                        log_d("RV%d Voltage = %0.2f\t", 1, RVxVoltage[0]);

            RVxVoltage[1] = RVxAverage[1] * (float)3.3 / (float)4096.0;

                        log_i("RV%d Voltage = %0.2f\t", 2, RVxVoltage[1]);

                        RVxVoltage[2] = RVxAverage[2] * (float)3.3 / (float)4096.0;

                        log_w("RV%d Voltage = %0.2f\t", 3, RVxVoltage[2]);

                        PLATFORM_DelayMS(500);

        }

    }

}


2、验证
1)ADC三个通道的电压,如图所示。
 



2)旋转RV1的电位器,如图所示。
 



3)与万用表对比
使用UT39E+万用表对比测试。
万用表的精度如下图:
 


实测数据对比
            

万用表
(V)
ADC
(V)
差值(MV)
RV13.1983.212
RV21.6461.654
RV31.7421.742

 

 

微信图片_20240803094249.jpg (162.3 KB )

下载附件

2024-8-3 09:43 上传


总结:
1、检测10分钟,ADC数值没有变化,还是比较稳定。
2、与万用表对比,基本相差2-4mv;在要求不是特别高的情况,精度还是不错的。
---------------------
作者:怀揣少年梦
链接:https://bbs.21ic.com/icview-3394084-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值