如何使用EK-TM4C123GXL(ARM Cortex M4)从直流电池获得稳定的ADC读数?

问题描述 投票:0回答:1

我正在开发一个项目,使用 Texas Instruments EK-TM4C123GXL LaunchPad 来测量面包板电源模块 (hw-131) 的电压。我正在使用板载 ADC 模块读取电压,但遇到一些问题:

  1. 问题描述:
    • 我已将电源模块的3.3V端子连接到TM4C123GXL的ADC输入引脚(PE3/AIN0)。
    • ADC 转换是使用内部 3.3V 参考电压完成的。
    • 我已经用万用表确认,电源模块输入TM4C123GXL的电压稳定在2.8伏,波动不超过±0.5伏。
    • 在测试过程中,我注意到即使输入电压保持稳定,ADC 输出值也不稳定并且波动很大。
  2. 我尝试过的:
    • 我检查了 ADC 配置和时钟设置,并确保使用了适当的采样时间和分辨率。
    • 我还实现了多个样本的平均,但这并没有完全消除波动。
  3. 相关代码:
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"
#include "driverlib/sysctl.h"
#include "driverlib/adc.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"
#include "driverlib/pin_map.h"

#define NUM_SAMPLES 8

// Function to configure UART0 for communication
void ConfigureUART(void)
{
    // Enable UART0 and GPIOA peripherals
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    // Configure PA0 and PA1 as UART pins
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    // Initialize UART0 with a baud rate of 115200
    UARTStdioConfig(0, 115200, SysCtlClockGet());
}

// ADC0 interrupt handler
void ADC0IntHandler(void)
{
    // Clear the ADC interrupt flag
    ADCIntClear(ADC0_BASE, 0);

    uint32_t ui32ADC0Value[NUM_SAMPLES];
    uint32_t ui32Sum = 0;
    uint32_t i = 0;

    // Get the ADC sequence data
    ADCSequenceDataGet(ADC0_BASE, 0, ui32ADC0Value);

    // Sum the ADC values
    while(i < NUM_SAMPLES){
        ui32Sum += ui32ADC0Value[i];
        i++;
    }

    // Calculate the average ADC value
    uint32_t ui32Average = ui32Sum / NUM_SAMPLES;

    // Print the average ADC value to the UART
    UARTprintf("ADC Average Value: %d\n", ui32Average);

    // Calculate the input voltage in volts (assuming 3.3V reference voltage)
    float voltage = (ui32Average * 3.3) / 4096.0;
    uint32_t v_int_part = voltage; // Integer part of the voltage
    uint32_t v_frac_part = (voltage - v_int_part) * 1000; // Fractional part in millivolts

    // Print the calculated voltage to the UART
    UARTprintf("Input Voltage: %d.%03d V\n", v_int_part, v_frac_part);
}

int main(void)
{
    // Set the system clock to 50MHz (200MHz PLL / 4)
    SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);

    // Configure UART for debugging
    ConfigureUART();

    // Enable the ADC0 and GPIOE peripherals
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);

    // Wait for the peripherals to be ready
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_ADC0) || !SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOE))
    {
    }

    // Configure PE3 as ADC input
    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);

    // Set the ADC clock source and rate
    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PIOSC | ADC_CLOCK_RATE_FULL, 8);

    // Configure ADC sequence 0 to be triggered by the processor
    ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);

    // Configure all 8 steps in the sequence to sample from CH0 (PE3)
    ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH0);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH0);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH0);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH0);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH0);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 6, ADC_CTL_CH0);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 7, ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END); // Enable interrupt on last step

    // Enable ADC sequence 0
    ADCSequenceEnable(ADC0_BASE, 0);

    // Clear any pending ADC interrupts
    ADCIntClear(ADC0_BASE, 0);

    // Enable ADC interrupts
    ADCIntEnable(ADC0_BASE, 0);

    // Enable the ADC0 sequence 0 interrupt in the NVIC
    IntEnable(INT_ADC0SS0);

    // Set ADC0 sequence 0 interrupt priority to highest (0)
    IntPrioritySet(INT_ADC0SS0, 0x00);

    while(1)
    {
        // Trigger the ADC conversion
        ADCProcessorTrigger(ADC0_BASE, 0);

        // Delay to simulate some processing time
        SysCtlDelay(SysCtlClockGet() / 6);
    }
}

  1. 我的问题:
    • 是否有任何方法可以稳定这些读数,例如更好的软件技术?
    • 我需要进行特定的 ADC 配置来稳定输入信号吗?
    • 您会推荐哪些此类应用程序的最佳实践?
  2. 电路: my circuit
  3. 波动数据如图:
    • 当电源模块ON时 when the power supply module ON
    • 当电源模块OFF时] when the power supply module OFF

看来电源模块OFF时的波动比电源模块ON时的波动更显着。

任何建议或指导将不胜感激!谢谢!

c embedded signal-processing microcontroller adc
1个回答
0
投票

较大的波动是调试输出中的错误,而不是“真实的”。例如,当您的 ADC 值

9
对应于 (9 x 3.3) / 4096 = 0.007 伏特时,您的调试代码将输出 0.7 伏特。

© www.soinside.com 2019 - 2024. All rights reserved.