【dsPIC33】多路ADC同时采样

本文详细介绍了在微控制器中如何使用ADC进行同步采样,特别是针对dsPIC33E芯片,讲解了如何配置ADC寄存器实现不使用DMA的8通道同时采样。内容包括端口初始化、控制寄存器设置、输入通道配置以及交错采样的概念,以满足电机电流采样的需求。同时,提供了具体的代码示例来说明配置过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

上篇文章讲到使用PWM来触发ADC,进而控制ADC采样的时刻,这在电机控制中是非常重要的一步,但上篇文章没有细讲多路ADC的同时采样,本文就单独把这一部分拉出来进行分析。

读取ADC值有两种方式,一种使用DMA,另一种不使用DMA。

使用DMA:

翻译过来就是:使能DMA模块(ADDMAEN = 1)时,每个ADC外设ADC模块仅具有1个ADC结果缓冲器(即ADC1BUF0),并且在下一次ADC转换之前,必须由CPU或DMA控制器读取ADC转换结果。 可以避免覆盖先前的值。

不使用DMA:

翻译过来就是:禁用DMA模块时(ADDMAEN = 0),ADC具有16个结果缓冲区.ADC转换结果按顺序存储在ADC1BUF0-ADC1BUFF中,无论使用哪个模拟输入取决于SMPIx位和1c中描述的条件 以上。 被测ANx输入与转换结果将放置在哪个ADC缓冲器(ADC1BUF0-ADC1BUFF)之间没有关系。

也就是ADxCON4寄存器中的ADDMAEN位为DMA使能位,如果使用了DMA,则数据都会存储在ADC1BUF0,需要在下次采样之前取出数据,避免数据覆盖掉之前的值。

那么结合我们实际的情况,对于电机电流采样,每次采样就那几个数据采集一个就行,因此不使用DMA会更方便一些,可以直接读取相应的存储寄存器即可。

大多数应用,使用分时采样,或者叫顺序采样即可,但是在一些特殊场合,比如需要同步采样来消除模拟信号之间的相位差时,就必须有多个采样电路同时工作,dsPIC内部的10位AD转换器前端一共有4个可以同时工作的采样保持电路。可以通过ADCON2中的CHPS位来配置:

看一下我的原理图:

由于项目中有6个模拟信号,而且不使用DMA,因此可以参照手册中的 “使用同时采样对8个输入进行采样(不使用DMA)” 章节:

由上图可知,需要使能同时采样:

AD1CON1bits.SIMSAM = 1;  //同步采样

由上图可知,8通道同时采样实际是分为两部分,因为每个ADC只有4个通道,CH0-CH3,但是可以选择这四个通道连通的是哪四个输入引脚,第一个一个触发信号到来时,会使配置的MUXA的CH0-CH3同时采样,然后顺序转换,之后下一个触发信号到来时,会使配置的MUXB的CH0-CH3同时采样,然后顺序转换,依次存储在内存中。也就是说8通道同时采样是有两组,一组是MUXA,另一组是MUXB,虽说是8通道,但每个触发信号只能同时采样4个引脚,也就是交替采样这个概念。手册中的配置如图:

手册中的配置是4次采样后产生中断,也就是说,4个触发信号之后会产生一个ADC中断,也就是说,8个模拟输入,每个都采样了两遍,因为ADC的缓存空间有16个,因此可以存储两遍。而我在实际项目中,不需要每个通道采集两遍,因此通过配置SMPI位更改,而BUFM位也一样配置为0:

显然我是希望总是从起始地址开始填充缓冲区的。
按照手册上的配置,存储空间的示意图如下:

之后,我们可以参照手册上的配置来配置自己的,这时,需要再细看输入通道寄存器,dsPIC33E芯片中是有两个输入通道寄存器的,一个是ADxCHS0,用来进行CH0通道的配置;另一个是ADxCHS123,用来进行CH1,2,3的配置,CH1,2,3是同时配置的,由此可见对于CH0通道的使用是更加灵活的。

由上面的寄存器介绍可知:CH0通道可以配置为任意的AD引脚。


而CH1,2,3则稍微有些固定,不过也还算是灵活,也可以满足需要。

接下来就要理解交替采样的概念,手册上有一句话说的比较清楚:

就是说,第一个触发信号使用配置的MUXA通道进行采样,第二个触发信号使用配置的MUXB通道进行采样。之后再循环。

而我使用的是SVPWM,因此,只有触发时间点比PWM周期值小,便会在每个周期都会有两个触发信号:

到这里,便可以看我的实际电路图,来进行配置了。

我有6个通道,可以将MUXA的CH1,2,3通道配置为AN0,1,2,然后将MUXB的CH1,2,3通道配置为AD3,4,5,至于两个CH0,便可以随便指定。(注:这里我测试如果MUXA与MUXB的CH0通道都配置为同一个引脚的话,采集会有问题,因此避免两个CH0采集同一个通道)当然,在配置ADC之前,不要忘记将引脚配置为输入模式。

配置如下:

void sensor_SensorAdc_Init (void)
{   
    AD1CON1bits.DONE = 0;    //确保没有任何正在进行的转换
    /@@*端口初始化*/
    ANSELA = 0;
    ANSELB = 0;
    ANSELAbits.ANSA0 = 1;    // U相电流采样
    ANSELAbits.ANSA1 = 1;    // V相电流采样
    ANSELBbits.ANSB0 = 1;    // 总电流采样
    ANSELBbits.ANSB1 = 1;   // 电位器
    ANSELBbits.ANSB2 = 1;   // 偏移电压1.65V采样
    ANSELBbits.ANSB3 = 1;   // 总线电压采样
    TRISAbits.TRISA0 = 1;   //配置为输入
    TRISAbits.TRISA1 = 1;   
    TRISBbits.TRISB0 = 1;
    TRISBbits.TRISB1 = 1;
    TRISBbits.TRISB2 = 1;
    TRISBbits.TRISB3 = 1;
    /@@*控制寄存器配置*/
    AD1CON1 = 0x0000;        //清零
    AD1CON1bits.ADON = 0;    //ADC关闭
    AD1CON1bits.ADSIDL = 0;  //在空闲模式下模块继续工作
    AD1CON1bits.AD12B = 0;   //10位,4通道ADC工作
    AD1CON1bits.FORM = 0;    //输出整数(0000 00dd dddd dddd)
    AD1CON1bits.SSRC = 0x00; //当SSRCG=1时 SSRC=0即为由PWM发生器1主触发比较结束采样并启动转换
    AD1CON1bits.SSRCG = 1;
    AD1CON1bits.SAMP = 1;    //同时采样 CH0,CH1,CH2,CH3
    AD1CON1bits.ASAM = 1;    //上一次转换后立即开始采样,即SAMP位自动置1
    AD1CON1bits.SIMSAM = 1;  //同步采样
    AD1CON2 = 0x0000; //清零
    AD1CON2bits.CHPS = 0x03;  //多通道采样 CH0 - CH3
    AD1CON2bits.VCFG = 0x00;     //参考电压选择AVdd与AVss
    AD1CON2bits.CSCNA = 0;    //不扫描输入
    AD1CON2bits.SMPI = 0x01;  //每完成2次采样/转换操作后产生ADC中断a
    AD1CON2bits.ALTS = 1;     //MUXA与MUXB交替采样
    AD1CON2bits.BUFM = 0;     //总是从起始地址开始填充缓冲区
    AD1CON3 = 0x0000;  //清零
    /@@*短暂延时,让寄存器有充分时间写入*/
    Nop();
    /@@*不使用DMA*/
    AD1CON4 = 0x0000;
    /@@**************************MUXA输入选择****************************/
    /@@*输入CH0选择寄存器配置*/
    AD1CHS0bits.CH0SA = 4;       //CH0同向输入端选择 AN4 (偏移电压采集)
    AD1CHS0bits.CH0NA = 0;       //CH0反向输入端选择 Vrefl
    /@@*输入CH1,CH2,CH3选择寄存器配置*/
    AD1CHS123bits.CH123SA = 0;   //CH1,2,3同向输入端对应 AN0,1,2
    AD1CHS123bits.CH123NA = 0;   //CH1,2,3反向输入端都为 Vrefl
    /@@**************************MUXB输入选择***************************/
    /@@*输入CH0选择寄存器配置*/
    AD1CHS0bits.CH0SB = 5;        //CH0同向输入端选择 AN3 (电源电压采集)
    AD1CHS0bits.CH0NB = 0;        //CH0反向输入端选择 Vrefl
    /@@*输入CH1,CH2,CH3选择寄存器配置*/
    AD1CHS123bits.CH123SB = 1;    //CH1,2,3同向输入端对应 AN3,4,5
    AD1CHS123bits.CH123NB = 0;    //CH1,2,3反向输入端都为 Vrefl    
//    AD1CSSL = 0x001f;    //输入扫描时跳过ANx
    IFS0bits.AD1IF = 0;        //清楚ADC中断标志
    IEC0bits.AD1IE = 1;        //使能中断
    IPC3bits.AD1IP = 0x01;   //ADC中断优先级设置为1
    AD1CON1bits.ADON = 1;    //使能ADC    
}
void sensor_UpdateSensor (SENSOR_DATA *pSensor)
{
 /@@*****************************************************************************************************************************************
 *                                  ADC采集程序
 ****************************************************************************************************************************************/
    pSensor->i16_speedVol = ADC1BUF5;
    pSensor->i16_current_U = ADC1BUF1;
    pSensor->i16_current_V = ADC1BUF2;
    pSensor->i16_current_All = ADC1BUF3;
    pSensor->i16_offsetV = ADC1BUF0;
    pSensor->i16_vin = ADC1BUF4;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙猫略略略

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值