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.

[参考译文] TM4C1294NCPDT:ADC 测量中的噪声

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/979716/tm4c1294ncpdt-noise-in-adc-measurements

器件型号:TM4C1294NCPDT

尊敬的支持人员:

我已经申请了多项测量应用于 BLDC 电机(反电动势)的波形的操作。 我将使用带 RC 滤波器的分压器、并使用示波器读取这些值。

问题是、在电机的某些速度下、它似乎有很多噪声。 在这里、我展示了以64kHz 为单位测量的 ADC 输入。

我的 pwmInput 在7500至12500个任意单位之间变化、实际上、这会将输入占空比从 1ms 变为2ms。 在下表中、在第16000个采样之前、我测量的波形的频率为1、68kHz、在该波形的频率高于2、04kHz。 我还执行了中等平均滤波器(MAF)、样本数量为3个和10个、如下图所示:

1、68kHz 波:

2、04 kHz 波形:

我放弃了一些可能性:

  • 采样问题:我要测量的波形的最大频率为2kHz、因此64kHz 应该足够好。 我还尝试了16kHz 和100kHz、采集保持不变;
  • ADC 距离:一些人建议我缩短 ADC 和采集点之间的距离。 我做了一个屏蔽、它连接在 launchpad 的下方;
  • 分压器:我在文档中阅读过、为了实现阻抗匹配、测量点的电阻器应为1kOhm。 我使用的是10kOhm、更改为1kOhm、它没有显示 ADC 读数的太多差异。

我的想法太多了、因此、我非常感谢在这个问题上提供的帮助。

这是包含图形的.xlsx。 我还使用不同的 aquisitons 和原始.csv 文件制作了一个驱动器:  

e2e.ti.com/.../0217_5F00_Test2.xlsx

使用的代码(尽管与相关问题中的代码非常相似):

//
//库
//*********

#include 
#include 

#include "driverlib/adc.h"
#include "driverlib/pio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/pinmwm.h"
#include "driverlib/rom.h"
#include "driverlib/mnts.h"
#include "driverlib_mware.h"#include "drivers/intru.triggio.h"#include"#include "drivers.包含"drivers/driverlib#drivers.h.hw_sym.inc"#include"#drivers.intrintrintrintru.h"#include "drivers/drivers.hw_sym.intrinc/包含"#include "drivers.hw_sym.inc"#include"#include "drivers.hw.







//为计时
器#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_adc.h"
#include "inc/hw_timer.h"
#include "inc/hw_NVIC.h"
#include "inc/hw_sysctl.h"

#include "utils/uartdio.h


*
//信息
//*********
// uint32_t - 32位的无符号整数-范围为0到2^32 - 1

//***************
//变量声明
//*********

// ADC
uint32_t ui32adcValues[4]; //用于存储来自 ADC
volatile bool bDataReady 的值的变量= false; //指示 ADC 就绪的标志

// ADC 滤波
器 uint32_t adcSumFilterCounter = 1; //用于计数
器 uint32_t adc_sum_filter_samples_number = 1的变量; //总和滤波器
uint32_t analogValue_ADC3的大小= 0; //用于存储值的变量

//系统
uint32_t g_ui32SysClock; //系统时钟速率,单位为 Hz。
uint32_t system_clock = 60000000; // 64MHz

// PWM
浮点类比值= 0、类比平均= 0、pwmMaxFloat = 6000;

float adcToPwmRatio = 0; //使用的 PWM 值与 ADC 分辨率
间的比率 float pwmMin = 7500; // PWM 的最小值、零速时的电机
悬空 pwmMax = 14500; // PWM 的最大值、全速
浮动电机 analogValueFloat_ADC3; //滤波器后 ADC 的值以获取

uint32_t sumCounter = 0、iSamples = 1000、pwmValue = 0;
volatile uint32_t pwmInput = 1;
uint32_t pwmDutyCycle = 15000; // 500Hz

//计时
器易失性无符号长整型 g_ui32TimerIntCount = 0;
易失性无符号长整型 g_ui32SecondsOnTime = 0;
#define APP_TICKS_PER_SEC 100;
bStatebTimerDone = false;
uint32_t SampleFreq = 0;


//测量采集
uint8_t


测量机器
的时间= 0;volatile enum = 0;//测量机器测量计数器
空闲、
初始测量、
初始计算、
WAIT_TO_POS_CYCLE、
WAIT_TO_HALF_CYCLE、
Wait_for_full_cycle、
Update_measurements
}measState;


//速度循环状态机
易失性枚举{
SPEED1、
Speed2、
SPEED3、
SPEED4、
SPEED5、
SPEED6、
停止
}循环状态;


uint32_t iSpeedStateDelay = 0;
uint32_t pwmMeas = 0;


#define HYSTH_MIN_ADC 250 // ADC 识别电机处于运动
中的最小值#define INTRIAL_MEAS_NUMBER 50 //初始测量值

uint32_t sumADC3 = 0; //存储 ADC3
uint32_t iADCSum3=0的累积总和; // ADC3
uint32_t nCycl3完成的测量次数的初始计数器= 0; //由 ADC3

uint32_t avgADC3完成的测量次数的稳定计数器 = 0; // ADC3
uint32_t currentFreq3的平均值= 0; // ADC3
Long inV_deltaT 的电流频率 = 16000000; // ADC 采样频率- 16kHz

bool bStartRunning = 0;

//*********
//驱动程序库遇到错误时调用的错误例程。
//
#ifdef debug
void
__error__(char *dpcFilename、uint32_t ui32Line)
{

#endif

//*********
// ADC0序列 ISR - 19.01.2021
//*********
void
ADC0Sequence0ISR (void)
{

if (measureCounter = 1){
GPIOPinWrite (GPIO_PORTL_BASE、GPIO_PIN_3、0);
measureCounter = 2;
}

if (measureCounter = 0){
GPIOPinWrite (GPIO_PORTL_BASE、GPIO_PIN_3、GPIO_PIN_3);
measureCounter = 1;
}

if (measureCounter = 2){
measureCounter = 0;
}

ADCIntClear (ADC0_BASE、0);

ADCSequenceDataGet (ADC0_BASE、0、ui32adcValues);

如果(!bDataReady)
{
bDataReady = true;
}

}

//*********
// ADC 初始化- 19.01.2021
//*********
void
ConfigureADC (void)
{
SysCtlPeripheralReset (SYSCTL_Periph_GPIOE);
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOE);
SysCtlPeripheralReset (SYSCTL_Periph_ADC0);
SysCtlPeripheralEnable (SYSCTL_Periph_ADC0);
SysCtlDelay (10);

GPIOPinTypeADC (GPIO_Porte _BASE、GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0);

//
//将 ADC 配置为在 system_clock (96MHz)上使用 PLL 除以3以获得 ADC
// 32MHz 时钟,全速率采样。
//
ADCClockConfigSet (ADC0_BASE、ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL、50);

//
//等待时钟配置设置。
//
SysCtlDelay (10);

//选择序列发生器2并将其设置为最高优先级。
ADCSequenceConfigure (ADC0_BASE、0、ADC_TRIGGER_TIMER、0);
//ADCSequenceConfigure (ADC0_BASE、0、ADC_TRIGGER_AUSE_0);

ADCSequenceStepConfigure (ADC0_BASE、0、0、ADC_CTL_CH0);
ADCSequenceStepConfigure (ADC0_BASE、0、1、ADC_CTL_CH1);
ADCSequenceStepConfigure (ADC0_BASE、0、2、ADC_CTL_CH2);
ADCSequenceStepConfigure (ADC0_BASE、0、3、ADC_CTL_CH3 | ADC_CTL_IE | ADC_CTL_END);

ADCSequenceEnable (ADC0_BASE、0);
ADCIntClear (ADC0_BASE、0);
ADCIntEnable (ADC0_BASE、0);
IntEnable (INT_ADC0SS0);
}

//*********
// PWM 初始化- 13.09.2020
//*********
void Init_PWM (){

// 1.
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOF); //启用端口 F
while (!SysCtlPeripheralReady (SYSCTL_Periph_GPIOF));

// 2.
SysCtlPeripheralDisable (SYSCTL_Periph_PWM0);
SysCtlPeripheralReset (SYSCTL_Periph_PWM0);
SysCtlPeripheralEnable (SYSCTL_Periph_PWM0);
while (!(SysCtlPeripheralReady (SYSCTL_Periph_PWM0)));


// PWM0_BASE:0 -> 0来自 M_0_PWM1
// PWM_OUT_1和 PWM_OUT_1_BIT:1来自 M0PWM_1
// PWM_GEN_0:针对 PWM0和 PWM1的 GEN_0、针对 PWM2和 PWM3的 GEN_1……


PWMClockSet (PWM0_BASE、PWM_SYSCLK_DIV_8); // system_clock/32 = 3MHz

GPIOPinTypePWM (GPIO_PORTF_BASE、GPIO_PIN_1); //端口 F - PF1的引脚1
GPIOPinConfigure (GPIO_PF1_M0PWM1);
PWMGenConfigure (PWM0_BASE、PWM_GEN_0、PWM_GEN_MODE_DOWN | PWM_GEN_MODE_NO_SYNC);
PWMGenPeriodSet (PWM0_BASE、PWM_GEN_0、pwmDutyCycle); // 120MHz/pwmMax = pwmFreq
PWMPulseWidthSet (PWM0_BASE、PWM_OUT_1、1);
PWMGenEnable (PWM0_BASE、PWM_GEN_0);
PWMOutputState (PWM0_BASE、PWM_OUT_1_BIT、TRUE);

PWMIntEnable (PWM0_BASE、PWM_INT_GEN_0);
PWMGenIntTrigEnable (PWM0_BASE、PWM_GEN_0、PWM_TR_CNT_ZERO);
IntEnable (INT_PWM0_0);

}

//*********
// UART 初始化- 19.01.21
//*************
void
InitConsole (void){

SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA); //启用用于 UART0引脚的 GPIO 端口 A。

//
//为端口 A0和 A1上的 UART0功能配置引脚复用。
//如果您的器件不支持引脚复用、则无需执行此步骤。
//
GPIOPinConfigure (GPIO_PA0_U0RX);
GPIOPinConfigure (GPIO_PA1_U0TX);

SysCtlPeripheralEnable (SYSCTL_Periph_UART0); //启用 UART0以便我们可以配置时钟。

UARTClockSourceSet (UART0_BASE、UART_CLOCK _PIOSC);//使用内部16MHz 振荡器作为 UART 时钟源。

//
//为这些引脚选择替代(UART)功能。
//
GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1);

UARTStdioConfig (0、115200、16000000); //初始化控制台 I/O 的 UART
}


//
//计时器初始化- 26.01.2021
//*********
void
ConfigureTimer (void){

//
//启用此示例使用的外设。
//
SysCtlPeripheralEnable (SYSCTL_Periph_TIMER0);

//
//配置一个16位周期定时器。
//
TimerConfigure (TIMER0_BASE、TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODICASE);

//
//将 ADC 采样频率设置为16KHz,即每隔62.5uS。
//
TimerLoadSet (TIMER0_BASE、TIMER_A、(g_ui32SysClock/64000)- 1);

//
//启用 Timer A 的 ADC 触发输出
//
TimerControlTrigger (TIMER0_BASE、TIMER_A、TRUE);

//
//启用处理器中断。
//
IntMasterEnable();

//
//启用计时器0,它将启动整个应用程序进程。
//
TimerEnable (TIMER0_BASE、TIMER_A);
}


int
main (void){

G_ui32SysClock = MAP_SysCtlClockFreqSet ((SYSCTL_XTAL_25MHz |
SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
SYSCTL_CFG_VCO_480)、SYSTEM_CLOCK); //从 PLL 以 system_clock MHz 运行


InitConsole(); //设置用于显示消息的串行控制台
ConfigureTimer();//设置计时器
ConfigureADC(); //设置 ADC
init_pwm (); //设置 PWM

SysCtlPeripheralEnable (SYSCTL_Periph_GPION); //启用端口 N
while (!SysCtlPeripheralReady (SYSCTL_Periph_GPION));

GPIOPinTypeGPIOOutput (GPIO_PORTN_BASE、GPIO_PIN_1); //为 LED D1 (PN1)启用 GPIO 引脚。


SysCtlPeripheralEnable (SYSCTL_Periph_GPIOL); //启用端口 L
while (!SysCtlPeripheralReady (SYSCTL_Periph_GPIOL));

GPIOPinTypeGPIOOutput (GPIO_PORTL_base、GPIO_PIN_3); //为 PL3启用 GPIO 引脚


IntMasterEnable();

//相对于最大和最小 PWM 以及 ADC 读数的转换
adcToPwmRatio =(pwmMax - pwmMin)/4095.0; // 4095 = 2^12位
pwmInput = pwmMin; //从 pwmMin 值开始

UARTprintf ("pwmValue");
UARTprintf ("AIN0、");//\r 替换、\n 替换为新行
//UARTprintf ("AIN1、");
//UARTprintf ("AIN2");
UARTprintf ("AIN3\n");
//UARTprintf ("avgADC3");
//UARTprintf ("currentFreq3");

//空闲时启动 MeasState
MeasState = IDLE;


//无限循环
while (1){

if (bDataReady){

UARTprintf ("%3D"、pwmInput);
UARTprintf ("%4d、"、ui32adcValues[0]);//\r 要替换、\n 到新行
//UARTprintf ("%4d、"、ui32adcValues[1]);
//UARTprintf ("%4d、"、ui32adcValues[2]);
UARTprintf ("%4D\n"、ui32adcValues[3]);
//UARTprintf ("%4d、"、avgADC3);
//UARTprintf ("%8d\n"、currentFreq3);

bDataReady = false;
}


if (iSpeedStateDelay < 191000){
iSpeedStateDelay = iSpeedStateDelay + 1;
}

if (iSpeedStateDelay = 20000){
pwmInput = 7500;
}

if (iSpeedStateDelay = 40000){
pwmInput = 8500;
}

if (iSpeedStateDelay = 60000){
pwmInput = 9500;
}

if (iSpeedStateDelay = 80000){
pwmInput = 10500;
}

if (iSpeedStateDelay = 100000){
pwmInput = 11500;
}

if (iSpeedStateDelay = 120000){
pwmInput = 12500;
}

if (iSpeedStateDelay = 140000){
pwmInput = 12000;
}

if (iSpeedStateDelay = 160000){
pwmInput = 10000;
}

if (iSpeedStateDelay = 170000){
pwmInput = 8200;
}

if (iSpeedStateDelay = 180000){
pwmInput = 7750;
}

if (iSpeedStateDelay = 190000){
pwmInput = 7500;
}

}

此致、

Gustavo Wegher

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

    我看到的最常见问题是源阻抗和采样时间。 如果您的源阻抗对于采样时间来说太大、您转换的其他通道将影响您的结果。 可能的解决方案:  

    1.降低源阻抗

    2.增加采样时间

    3.添加一个外部采样电容器

    请参阅 :https://www.ti.com/lit/an/spna061/spna061.pdf

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

    您好 Gustavo、

    查看您的代码、我注意到您配置了4个 ADC 步长和1个 PWM 发生器。 请注意、具有上数/ dwn 计数的中心对齐同步 PWM 发生器是最典型的。 必须将 ADC 采样与 PWM 发生器同步 与使用发生器触发源相比、通过计时器触发的 ADC 模块可能需要延迟才能将采样窗口缓慢/同步到所需的信号采集点/s 尽管采样 窗口的奈奎斯特频率可能是奈奎斯特频率的两倍、但这并不意味着信号采集点或计数将保持甚至实现。

    BTW:如果您尝试创建一个正弦空间矢量调制方案、该方案可能是通过1294 MCU 类徒劳的尝试。 否则、很容易实现六步梯形波、但需要查找表以生成霍尔代码。