382|0

36

帖子

2

TA的资源

一粒金砂(中级)

楼主
 

【极海APM32M3514电机通用评估板】基于DMA的多通道ADC转换测试 [复制链接]

 

由于该MCU和开发板主要针对电机,所以ADC的数据采集也是针对电机的数据进行采集,针对BLDC电机驱动,需要我们实时采集各项电流,电压,并对电流的过流,电压的欠压,过压进行判断,同时还需要电源电压,电机调速电位器等模拟量进行采集。

1.电机通用评估板的ADC采样电路如下:

1.1.电机三相IV,IU,IW电压采集电路,通过电阻分压,并使用稳压管进行I/O过压保护。

 

1.2.电机三相电流和总电流采集电路,通过APM32M3514自带的运算放大器进行放大,该示例中选用外部放大电阻。并通过一个运算放大器提供1.65V的参考电压。

 

1.3.输入电压和电阻可调旋钮的采集电路,

2.APM32M3514 MCU使用的ADC硬件电路使用通道介绍

2.1.电机三相电压采集ADC引脚,使用通道ADC_IN13,ADC_IN14,ADC_IN15,分别采集V,U,W三相。

 

1.2.PA0是采集参考电压,目前未使用,PA4,PB0和PB10分别采集IV相电流,IU相电流和ISUM总电流,

  2.3.PA6用于采集输入电压,PA7用于采集可变电阻调节旋钮阻值变化

 

3.代码展示和讲解

3.1.ADC的IO及通道初始化

void Drv_Adc_Init(void)
{
    ADC_Config_T   ADC_InitStructure;

//ADC DMA Initial
    DMA_Config_T   DMA_InitStructure;
    DMA_InitStructure.peripheralAddress  = (uint32_t)&(ADC->DATA);//ADC地址
    DMA_InitStructure.memoryAddress      = (uint32_t)&ADC_ConvertedValue[0]; //内存地址
    DMA_InitStructure.direction          = DMA_DIR_PERIPHERAL; //方向(从外设到内存)
    DMA_InitStructure.bufferSize         = TOTAL_CHANNEL;//TOTAL_CHANNEL; //传输内容的大小---传输次数
    DMA_InitStructure.peripheralInc      = DMA_PERIPHERAL_INC_DISABLE; //外设地址固定
    DMA_InitStructure.memoryInc          = DMA_MEMORY_INC_ENABLE;//DMA_MEMORY_INC_ENABLE; //内存地址固定  
    DMA_InitStructure.peripheralDataSize = DMA_PERIPHERAL_DATASIZE_HALFWORD ; //外设数据单位
    DMA_InitStructure.memoryDataSize     = DMA_MEMORY_DATASIZE_HALFWORD ;    //内存数据单位
    DMA_InitStructure.circular           = DMA_CIRCULAR_ENABLE  ; //DMA模式:循环传输
    DMA_InitStructure.priority           = DMA_PRIORITY_LEVEL_VERYHIGH ; //优先级:高
    DMA_InitStructure.memoryTomemory     = DMA_M2M_DISABLE;   //禁止内存到内存的传输
    ADC_Reset();
    DMA_Config(DMA_CHANNEL_1, &DMA_InitStructure);  //配置DMA的1通道
    DMA_Enable(DMA_CHANNEL_1);
    ADC_ClockMode(ADC_CLOCK_MODE_ASYNCLK);//48M/4=12mADC_CLOCK_MODE_SYNCLKDIV4   
        /* Enable ADC clock */
    // RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC);
    ADC_ConfigStructInit(&ADC_InitStructure);
    ADC_InitStructure.convMode    = ADC_CONVERSION_SINGLE;
    ADC_InitStructure.scanDir     = ADC_SCAN_DIR_UPWARD;
    ADC_InitStructure.extTrigConv1 = ADC_EXT_TRIG_CONV_TRG1;  //  timer1 CC4
    ADC_InitStructure.extTrigEdge1 = ADC_EXT_TRIG_EDGE_RISING;
    ADC_InitStructure.dataAlign   = ADC_DATA_ALIGN_RIGHT;
    ADC_InitStructure.resolution  = ADC_RESOLUTION_12B;    
    ADC_Config(&ADC_InitStructure);
    ADC_ConfigChannel(ADC_CHANNEL_2 | ADC_CHANNEL_8 | ADC_CHANNEL_6 | ADC_CHANNEL_7| ADC_CHANNEL_12| ADC_CHANNEL_13| ADC_CHANNEL_14| ADC_CHANNEL_15 ,ADC_SAMPLE_TIME_1_5);
    ADC->CFG1_B.OVRMAG = 1;    
    ADC_EnableInterrupt(ADC_INT_CS);
//=========================ADC中断使用=================================================
    NVIC_EnableIRQ(ADC_COMP_IRQn);//
    NVIC_SetPriority(ADC_COMP_IRQn,0);  
    ADC_DMARequestMode(ADC_DMA_MODE_CIRCULAR);
    ADC_EnableDMA();
    ADC_Enable();  
    ADC_StartConversion();//必需要启动一下


    /*  Config ADC Channel GPIO   */
    GPIO_Config_T   GPIO_InitStructure; 

    GPIO_InitStructure.pin      =   GPIO_Pin_ADC_VDC;//pin
    GPIO_InitStructure.speed    =   GPIO_SPEED_50MHz;//GPIO speed
    GPIO_InitStructure.mode     =   GPIO_MODE_AN;//GPIO configured as analog input
    GPIO_InitStructure.pupd     =   GPIO_PUPD_NO;//no pull-up and pull-down
    GPIO_Config(GPIO_ADC_VDC, &GPIO_InitStructure);
    
    GPIO_InitStructure.pin      =   GPIO_Pin_ADC_Handle;
    GPIO_InitStructure.speed    =   GPIO_SPEED_50MHz;
    GPIO_InitStructure.mode     =   GPIO_MODE_AN;
    GPIO_InitStructure.pupd     =   GPIO_PUPD_NO;
    GPIO_Config(GPIO_ADC_Handle, &GPIO_InitStructure);
    
    GPIO_InitStructure.pin      =   GPIO_Pin_ADC_IU;
    GPIO_InitStructure.speed    =   GPIO_SPEED_50MHz;
    GPIO_InitStructure.mode     =   GPIO_MODE_AN;
    GPIO_InitStructure.pupd     =   GPIO_PUPD_NO;
    GPIO_Config(GPIO_ADC_IU, &GPIO_InitStructure);
    
    GPIO_InitStructure.pin      =   GPIO_Pin_ADC_IV;
    GPIO_InitStructure.speed    =   GPIO_SPEED_50MHz;
    GPIO_InitStructure.mode     =   GPIO_MODE_AN;
    GPIO_InitStructure.pupd     =   GPIO_PUPD_NO;
    GPIO_Config(GPIO_ADC_IV, &GPIO_InitStructure);
    
    GPIO_InitStructure.pin      =   GPIO_Pin_ADC_IBUS;
    GPIO_InitStructure.speed    =   GPIO_SPEED_50MHz;
    GPIO_InitStructure.mode     =   GPIO_MODE_AN;
    GPIO_InitStructure.pupd     =   GPIO_PUPD_NO;
    GPIO_Config(GPIO_ADC_IBUS, &GPIO_InitStructure);

    GPIO_InitStructure.pin      =   GPIO_Pin_ADC_UV;
    GPIO_InitStructure.speed    =   GPIO_SPEED_50MHz;
    GPIO_InitStructure.mode     =   GPIO_MODE_AN;
    GPIO_InitStructure.pupd     =   GPIO_PUPD_NO;
    GPIO_Config(GPIO_ADC_UV, &GPIO_InitStructure);    

    GPIO_InitStructure.pin      =   GPIO_Pin_ADC_VV;
    GPIO_InitStructure.speed    =   GPIO_SPEED_50MHz;
    GPIO_InitStructure.mode     =   GPIO_MODE_AN;
    GPIO_InitStructure.pupd     =   GPIO_PUPD_NO;
    GPIO_Config(GPIO_ADC_VV, &GPIO_InitStructure);

    GPIO_InitStructure.pin      =   GPIO_Pin_ADC_WV;
    GPIO_InitStructure.speed    =   GPIO_SPEED_50MHz;
    GPIO_InitStructure.mode     =   GPIO_MODE_AN;
    GPIO_InitStructure.pupd     =   GPIO_PUPD_NO;
    GPIO_Config(GPIO_ADC_WV, &GPIO_InitStructure);   
}
3.2.启动ADC转换

/* Wait until ADC is ready 等待ADC准备好*/

    while (!ADC_ReadStatusFlag(ADC_FLAG_ADRDY));

    ADC_StartConversion();//开启ADC转换

    __enable_irq();                             //Enable all interrupts

3.3.ADC中断

当产生中断时,读取ADC的转换结果,并将之保存,注意转换结果是按通道顺序排列。

uint16_t chnlvcur[50] = {0};

uint16_t chnlucur[50] = {0};

uint16_t chnlibus[50] = {0};

uint16_t chnluvol[50] = {0};

uint16_t chnlvvol[50] = {0};

uint16_t chnlwvol[50] = {0};

uint16_t chnlsvol[50] = {0};

uint16_t chnlinvol[50] = {0};

uint16_t i = 0;

void ADC_COMP_IRQHandler(void)

{  

        chnlvcur = (int16_t)ADC_GetValue(CURR_CHANNEL_V);

        chnlucur = (int16_t)ADC_GetValue(CURR_CHANNEL_U);

        chnlibus = (int16_t)ADC_GetValue(IBUS_CHANNEL);

        chnlsvol = (int16_t)ADC_GetValue(Handle_CHANNEL);

        chnlinvol = (int16_t)ADC_GetValue(VDC_CHANNEL);

        chnluvol = (int16_t)ADC_GetValue(VOL_CHANNEL_U);

        chnlvvol = (int16_t)ADC_GetValue(VOL_CHANNEL_V);

        chnlwvol = (int16_t)ADC_GetValue(VOL_CHANNEL_W);

        i++;

        if(i>= 50)

        {

          i = 0;

        }

    }

}

4.代码运行结果查看

  6.测试情况及数据

以下表电机工作时和不工作时,ADC采集的电压值作为比较,发现电机不工作时,这时电流波动较小,电压采集结果稳定,误差小。而在电机工作时,发现偶尔会出现电压值偏差很大,并且是正偏或负偏很大的值都偶尔出现,通过该测试可以发现,我们ADC在面对电流变化复杂的情况,不仅软件需要做滤波,硬件也需要处理好电源的突然变化。针对该评估板对动态输入电压对ADC的影响,可以每十组数据,去掉最大值和最小值,进行均值滤波,就可以将这种现象带来的误差减小到最小。

序号 输入电压(电机工作) 输入电压(电机不工作)
0 1360 1358
1 1352 1359
2 1362 1361
3 1361 1358
4 1361 1358
5 1361 1358
6 1355 1358
7 1359 1358
8 1360 1358
9 1361 1358
10 1361 1359
11 1360 1358
12 1525 1359
13 1348 1358
14 1367 1359
15 1358 1358
16 1371 1359
17 1752 1358
18 1328 1358
19 1361 1359
20 1360 1359
21 1361 1359
22 1361 1358
23 1359 1358
24 1399 1359
25 1361 1358
26 1361 1358
27 1361 1358
28 1360 1359
29 1360 1359
30 1361 1358
31 1361 1358
32 1361 1358
33 1361 1358
34 1120 1359
35 1359 1358
36 1356 1358
37 1363 1358
38 1347 1358
39 1247 1358
40 1715 1359
41 1198 1359
42 1361 1359
43 1361 1358
44 1361 1358
45 1361 1359
46 1357 1358
47 1362 1358
48 1361 1358
49 1361 1359

 

7.综合评价

  通过这次测试,可以看出该芯片的ADC精度高,采样时间和采集值都表现不错。

点赞 关注
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表