This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TM4C123GH6PM:使用两个 ADC 进行仿真采样期间出现问题

Guru**** 2609895 points
Other Parts Discussed in Thread: TM4C123GH6PM

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/754599/tm4c123gh6pm-problem-during-simulatenously-sampling-using-both-the-adcs

器件型号:TM4C123GH6PM

大家好、我尝试使用电路板上的两个 ADC 来对两个输入信号进行采样。 根据我使用单个 ADC 进行采样的经验、我能够构建的逻辑是、我使用相同的中断来触发两个 ADC 并开始同步转换。 在单个 while 环路中、我将对一个信号进行采样、获取另一个信号、并对其进行采样并结束转换。 我想我将面临的问题是抖动、因为在取和采样的指令周期中、可能会产生一些不准确的情况。 如何减少这种情况? 我是否也可以获得有关代码的指导?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    配置每个 ADC 并让它们使用相同的触发源、例如计时器。 使用 CPU 触发 ADC 将导致抖动和偏差。

    我可以回答有关如何使用 TivaWare 驱动程序的技术问题、但我不会为您执行代码审阅或调试软件。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    主席先生、我如何使用 TivaWare 驱动程序(或如果有任何其他方法)同时触发两个 ADC 而不产生任何抖动?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    器件型号:TM4C123GH6PM

    我打算使用电路板中的两个 ADC 对两个传入输入信号进行采样。 我想在没有任何抖动的情况下同时对这两个器件进行采样。 是否有任何有效的方法? 如果是、您能给我一些建议并提供某种参考代码吗?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Soummyadeb、

    如果您使用计时器、则可以设置 ADC 以相同的间隔进行采样、然后必须在采样完成后读取这些值。

    请注意、计时器是该用例的硬性要求、因为这是一个单核 MCU、您必须依赖计时器来允许多个外设并排运行。

    我们有一个项目可以让您参与其中、它只执行一个通道、并且还使用 DMA、您可以对其进行调整以更好地满足您的项目要求: e2e.ti.com/.../2084.ADCwDMA.zip

    此外、还将始终存在一些抖动、MCU ADC 对于大多数应用而言是实用的、但其精度或速度不是专门设计的外部 ADC。 您需要确定结果上存在的抖动是否过大。

    如果这确实是您的一个大问题、我建议您查看 TI 的 ADC 产品系列、并查找可满足您严格抖动要求的器件: www.ti.com/.../overview.html

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    不存在此类示例、但您可以查看使用 ADC_TRIGGER_WAIT 和 ADC_TRIGGER_SIGNAL 的情况。 请参见下面的。 在 ADC0中、为第一个信号配置采样序列发生器、并使用 ADC_TRIGGER_WAIT 标志由处理器触发。 在 ADC1中、为第二个信号配置采样序列发生器、并使用 ADC_TRIGGER_SIGNAL 标志通过处理器触发。 尝试一下、看看它是否起作用、并与社区分享您的工作代码。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Charles、

    实际上找到了我现在添加到上一帖子的示例代码! 此外、还修改了我对顺序与同步的评论、以考虑将计时器触发器用作进行顺序采样的另一种方法。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    主席先生、是否最好使用 ADC 中断而不是计时器中断来提高效率?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    如果目的是同时转换两个值、则 ADC 中断不起作用。 您在转换完成后获得中断。 您有两个选项。
    选项1:如果您需要定期转换、例如您将执行 FFT。 在这种情况下、使用启动两个转换的计时器。 这样您就具有固定的采样率。 请注意、ADC 不是由中断启动的、而是由计时器的硬件标志启动的。
    选项2:如果您只需要单点中断或随机点中断。 在这种情况下、您可以通过软件请求启动两个 ADC。 在启动第一个 ADC 时使用 ADC_TRIGGER_WAIT 选项。 通过这种方式、它等待第二个 ADC、两个 ADC 一起启动。

    您当然可以使用 ADC 中断来触发对结果的读取。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    谢谢先生!
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    但 UDMA 一次可用于单个 ADC、对吧? 如果我打算同时使用这两个采样器、我认为 UDMA 将不会有什么帮助。 那么、如何使用计时器来启动两个 cconversions 呢?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    UDMA 可在两个 ADC 上使用。 它用于读取结果。 要实现同步转换、您需要同时启动两个 ADC、但无需同时读取结果。 UDMA 将按顺序读取结果。

    Ralph 之前发布了一个使用计时器触发 ADC 并使用 UDMA 读取结果的示例。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    //
    //
    // project0.c -演示最小 TivaWare 设置的示例
    //
    //版权所有(c) 2012-2017 Texas Instruments Incorporated。 保留所有权利。
    //软件许可协议
    //
    //德州仪器(TI)提供此软件仅供
    和//仅供 TI 的微控制器产品使用。 软件归
    // TI 和/或其供应商所有,并受适用的版权
    //法律保护。 您不能将此软件与"病毒"开源
    //软件组合在一起以形成更大的程序。
    //
    //此软件按“原样”提供,且存在所有故障。
    //对于
    
    本软件,不作任何明示、暗示或法定的保证,包括但不限于对适销性和适用性的暗示保证//特定用途。 在任何
    //情况下、TI 不对任何
    原因造成的特殊、意外或必然//损害负责。
    //
    //这是 EK-TM4C123GXL 固件包版本2.1.4.178的一部分。
    ////
    *****************
    
    #include 
    #include 
    include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_adc.h"
    #include "inc/hw_types.h"
    #include "inc/hw_udma.h"
    #include "driverlib/driverlib"
    #driverlib/driver.h"
    #include "driverlib/driver.h"#driverlib#driverlib.driverlib.driver.h"#include "driverlib#driverlib/driverlib"#driverlib.driver.h"#include "driverlib.driver.h"#driverlib#driverlib.driverlib#driverlib.driver.h"#include "driverlib.driverlib.driverlib.driver.h"#include "driverlib.driverlib.driverlib.driver.h"#include "drivers.driverlib.driverlib.driverlib#driver.h"#include "drivers.driverlib#driverlib#driverlib.driver.h"#include "driver.h"#drivers.
    
    
    
    
    
    
    
    
    
    
    
    //
    //定义引脚到 LED 颜色映射。
    ////
    *****************
    
    //
    //
    //! \addtogroup example_list
    //! 

    Project Zero (项目0)

    //! //! 此示例演示了如何使用 TivaWare 设置时钟和 //! 切换 GPIO 引脚以使 LED 闪烁。 这是一个很好的开始 //开始的地方! 了解您的 LaunchPad 以及可用于对其进行编程的工具。 //// ***************** // // //如果驱动程序库遇到错误,则调用的错误例程。 //// ***************** #ifdef debug void __error__(char *dpcFilename、uint32_t ui32Line) { #endif //********* // ////主"C"语言入口点。 使用 TivaWare 切换 LED。 //// ***************** uint32_t adcbuffer[1000]; uint32_t adcdata1[1000]; uint32_t adcdata2[1000]; uint32_t i、timebase、triglvl、xpos、res0、res1; void main (){ SysCtlClockSet (SYSCTL_SYSDIV_10 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHz);//20MHz 时钟 SysCtlPeripheralEnable (SYSCTL_Periph_ADC0); SysCtlPeripheralEnable (SYSCTL_Periph_ADC1); SysCtlPeripheralEnable (SYSCTL_Periph_GPIOE); SysCtlPeripheralEnable (SYSCTL_Periph_GPIOF); GPIOPinTypeADC (GPIO_Porte _BASE、GPIO_PIN_3); GPIOPinTypeADC (GPIO_Porte _BASE、GPIO_PIN_2); GPIOPinTypeGPIOOutput (GPIO_PORTF_BASE、GPIO_PIN_1); GPIOPinTypeGPIOOutput (GPIO_PORTF_BASE、GPIO_PIN_4); ADCSequenceDisable (ADC0_BASE、3); //定时器配置 SysCtlPeripheralEnable (SYSCTL_Periph_TIMER0); TimerConfigure (TIMER0_BASE、TIMER_CFG_PERIODICASE); TimerLoadSet (TIMER0_BASE、TIMER_A、12); //将计时器设置为 fs=2ksps 加载值 //如果计时器加载值=5000;fs=1ksps // sysclock=20MHz,因此 TSYs=1/22000000sec;获得1ms 延迟 //我们需要加载1ms/0.5us 的计时器 TimerEnable (TIMER0_BASE、TIMER_A); // ADCSequenceDisable (ADC0_BASE、3); // ADCClockConfigSet (ADC0_BASE、ADC_CClock_SRC_PLL | ADC_CClock_RATE_FULL、266); ADCSequenceConfigure (ADC0_BASE、3、ADC_TRIGGER_PROCESSOR、0); ADCSequenceConfigure (ADC1_base、3、ADC_TRIGGER_PROCESSOR, 0); ADCSequenceStepConfigure (ADC0_BASE、3、0、ADC_CTL_CH7 | ADC_CTL_IE | ADC_CTL_END); ADCSequenceStepConfigure (ADC1_base、3、0、ADC_CTL_CH6 | ADC_CTL_IE | ADC_CTL_END); ADCSequenceStepConfigure (ADC1_base、3、0、ADC_CTL_CH5 | ADC_CTL_IE | ADC_CTL_END); ADCSequenceStepConfigure (ADC1_base、3、0、ADC_CTL_CH4 | ADC_CTL_IE | ADC_CTL_END); ADCSequenceStepConfigure (ADC0_BASE、3、0、ADC_CTL_CH3 | ADC_CTL_IE | ADC_CTL_END); ADCSequenceEnable (ADC0_BASE、3); ADCSequenceEnable (ADC1_BASE、3); ADCIntClear (ADC0_BASE、3); while (1) { ADCSequenceStepConfigure (ADC1_base、3、0、ADC_CTL_CH5 | ADC_CTL_IE | ADC_CTL_END); ADCIntClear (ADC1_BASE、3); ADCProcessorTrigger (ADC1_base、3); //触发 ADC 转换。 while (!ADCIntStatus (ADC1_base、3、false)){} //等待转换完成。 ADCIntClear (ADC1_BASE、3); //清除 ADC 中断标志。 ADCSequenceDataGet (ADC1_base、3、adcbuffer); //读取 ADC 值。 时基= adcbuffer[0]; ADCSequenceStepConfigure (ADC1_base、3、0、ADC_CTL_CH4 | ADC_CTL_IE | ADC_CTL_END); ADCIntClear (ADC1_BASE、3); ADCProcessorTrigger (ADC1_base、3); //触发 ADC 转换。 while (!ADCIntStatus (ADC1_base、3、false)){} //等待转换完成。 ADCIntClear (ADC1_BASE、3); //清除 ADC 中断标志。 ADCSequenceDataGet (ADC1_base、3、adcbuffer); //读取 ADC 值。 triglvl = adcbuffer[0]; ADCSequenceStepConfigure (ADC0_BASE、3、0、ADC_CTL_CH3 | ADC_CTL_IE | ADC_CTL_END); ADCIntClear (ADC0_BASE、3); ADCProcessorTrigger (ADC0_BASE、3); //触发 ADC 转换。 while (!ADCIntStatus (ADC0_BASE、3、false)){} //等待转换完成。 ADCIntClear (ADC0_BASE、3); //清除 ADC 中断标志。 ADCSequenceDataGet (ADC0_BASE、3、adcbuffer); //读取 ADC 值。 xpos = adcbuffer[0]; 对于(i=0;i<=1000;i++) { ADCSequenceStepConfigure (ADC0_BASE、3、0、ADC_CTL_CH7 | ADC_CTL_IE | ADC_CTL_END); ADCIntClear (ADC0_BASE、3); ADCProcessorTrigger (ADC0_BASE、3); //触发 ADC 转换。 while (!ADCIntStatus (ADC0_BASE、3、false)){} //等待转换完成。 ADCIntClear (ADC0_BASE、3); //清除 ADC 中断标志。 ADCSequenceDataGet (ADC0_BASE、3、adcbuffer); //读取 ADC 值。 adcdata1[i]= adcbuffer[0]; res0=adcddata1[i]; // GPIOPinWrite (GPIO_PORTF_BASE、GPIO_PIN_1、RES0); ADCSequenceStepConfigure (ADC1_base、3、0、ADC_CTL_CH6 | ADC_CTL_IE | ADC_CTL_END); ADCIntClear (ADC1_BASE、3); ADCProcessorTrigger (ADC1_base、3); //触发 ADC 转换。 while (!ADCIntStatus (ADC1_base、3、false)){} //等待转换完成。 ADCIntClear (ADC1_BASE、3); //清除 ADC 中断标志。 ADCSequenceDataGet (ADC1_base、3、adcbuffer); //读取 ADC 值。 adcddata2[i]= adcbuffer[0]; res1=adcddata2[i]; //GPIOPinWrite (GPIO_PORTF_BASE、GPIO_PIN_4、RES1); } }


















    谢谢主席先生。 我能够使用这两个 ADC 进行采样。 这是我的当前代码。 但是、我观察到采样信号中的失真、无法弄清原因。 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    更新了:先生、我能够获得一个近似的重构信号、但我在 ADC 的两个输出之间得到了延迟。 是否有任何方法可以最大限度地减小两个输出之间的延迟? 因为目前我在这两者之间得到了显著的延迟。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您设置了计时器、但随后在循环中使用了"ADCProcessorTrigger()"、而未使用"ADC_TRIGGER_WAIT"。 对于同步转换的简单 CPU 触发、序列更像这样:

    ADCProcessorTrigger (ADC0_BASE、3 | ADC_TRIGGER_WAIT);//设置触发器但等待。
    ADCProcessorTrigger (ADC1_base、3); //触发两个 ADC
    while (!ADCIntStatus (ADC0_BASE、3、false)){} //等待转换完成。
    ADCSequenceDataGet (ADC0_BASE、3、&adcddata1[i]); //读取 ADC 值。
    while (!ADCIntStatus (ADC1_base、3、false)){} //等待转换完成。
    ADCSequenceDataGet (ADC1_base、3、&adcdata2[i]); //读取 ADC 值。
    

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。


    主席先生、我在 for 循环中使用过这种方法、但存储了值
    在 adcddata1和 adcddata2中、现在变为零。
    我无法看到任何转换。

     
    ADCSequenceStepConfigure (ADC0_BASE、3、0、ADC_CTL_CH7 | ADC_CTL_IE | ADC_CTL_END);
    ADCSequenceStepConfigure (ADC1_base、3、0、ADC_CTL_CH6 | ADC_CTL_IE | ADC_CTL_END);
    ADCIntClear (ADC0_BASE、3);
    ADCIntClear (ADC1_BASE、3);
    ADCProcessorTrigger (ADC0_BASE、3 | ADC_TRIGGER_WAIT);//设置触发器但等待。
    ADCProcessorTrigger (ADC1_base、3); //触发两个 ADC
    while (!ADCIntStatus (ADC0_BASE、3、false)){} //等待转换完成。
    ADCSequenceDataGet (ADC0_BASE、3、&adcddata1[i]); //读取 ADC 值。
    adcdata1[i]= adcbuffer[0];
    while (!ADCIntStatus (ADC1_base、3、false)){} //等待转换完成。
    ADCSequenceDataGet (ADC1_base、3、&adcdata2[i]); //读取 ADC 值。
    adcddata2[i]= adcbuffer[0];
    
    
    
    
    
    
    
    

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    为什么要用 adcbuffer[0]的初始值覆盖数组中的值? 您需要对代码的运行情况有基本的了解。 语句"ADCSequenceDataGet (ADC0_BASE、3、&adcddata1[i]);"用值填充数组 adcddata1。 然后用"adcbuffer[0]"覆盖该值、该值看起来未初始化、因此为0。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    主席先生、即使我不覆盖该值、我仍会将其设置为零。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    实际上、您应该卡在 while 环路中等待 ADC0。 您需要将"ADC_TRIGGER_SIGNAL "添加到"ADCProcessorTrigger (ADC1_base、3);"语句。 我附加了一个示例.zip 项目、该项目对通道 AIN0和 AIN1进行5个同步转换。 使用 code composer "File""Import"函数将此项目添加到您的工作区。

    /cfs-file/__key/communityserver-discussions-components-files/908/SimultaneousADC.zip

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    主席先生,我一直在使用代码,因为它只是用来测试功能,但当我调试它时,它会被重定向到 exit.c,进入异常程序终止,我无法确定其原因。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    更新了:我能够进行同步采样。 但是、当我使用3.3V 作为基准电压(DC)时、理论上、我希望在成像中有大约4100的直线、但我看到的是大约500的直线。 我无法确定问题所在。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    检查您的连接。 我得到了预期的4095。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    非常感谢先生! 我能够实现我尝试的目标。 但主席先生、我会得到大约100ms 的抖动、这会导致我的应用出现问题。 是否有办法解决这个问题? 还是应该使用外部 ADC?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    100mS 的抖动是什么意思? 两个 ADC 将同时进行采样和转换。 如果您的意思是不是以精确的频率采集样本、这是因为您使用的是软件触发器。 要使样本处于精确的间隔、您需要使用计时器来触发两个 ADC。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    感谢您的支持我的问题得到了解决!!!
    非常感谢!