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.

[参考译文] TMS320F28379D:ADC 和模拟信号

Guru**** 1641220 points
Other Parts Discussed in Thread: LF353, TINA-TI
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1341300/tms320f28379d-adc-and-analog-signal

器件型号:TMS320F28379D
主题中讨论的其他器件:LF353TINA-TI

大家好!

我需要使用 C2000 Launchpad 的 ADC 获得辐射光谱仪。 ADC 配置已设置为以尽可能最快的速率采样。 我从示波器中确认、当使用 ISR 进行控制时、可以以600ns 的间隔进行采样。 来自 CZT 型半导体探测器的信号通过 Cremat 前置放大器放大。 示波器上的信号输出在300-600mV 之间变化、具体取决于辐射源。 前置放大器输出端信号的上升时间约为2微秒。 我认为以600ns 的间隔进行采样就足够了。 我确信 ADC 工作正常、因为我可以在1 MHz 处从信号发生器对正弦波和方波进行采样并捕获峰值点。 但是、出于某种原因、当我将前置放大器输出连接到 ADC 输入时、我可以读取零或接近零的值。 这可能是由于阻抗不匹配造成的? 如果不是、您建议哪些故障排除建议? 下面随附的代码。

#include "F28x_Project.h"     // Cihaz Başlık Dosyası ve Örnekler Dahil Dosyası

#define DATA_SIZE 128

float input_data[DATA_SIZE] = {0}; // ADC'den gelen veri dizisi
float filtered_data[DATA_SIZE] = {0}; // Filtrelenmiş veri dizisi
float Result = 0;
float peak_value;

// ADC verilerini okuyan ve filtreleyen fonksiyon
void ReadAndFilterADCData() {
    int i;

    // ADC'den veri oku ve input_data dizisine kaydet
    for(i = 0; i < DATA_SIZE; i++) {
        input_data[i] = AdcaResultRegs.ADCRESULT0;
        // Örneğin AdcaResultRegs.ADCRESULT0, ADC'nin sonuç kaydı
        // Bu, gerçek donanımınıza göre değişebilir
    }

    // Trapezoidal filtreleme işlemi
    for(i = 0; i < DATA_SIZE; i++) {
        // İlk iki ve son iki örneği doğrudan kopyala
        if(i < 2 || i >= DATA_SIZE - 2) {
            filtered_data[i] = input_data[i];
        } else {
            // Trapezoidal filtreleme
            filtered_data[i] = (input_data[i - 2] + 2 * input_data[i - 1] + 2 * input_data[i] + 2 * input_data[i + 1] + input_data[i + 2]) / 8.0;
        }
    }
}

// Tepe noktasını bulan fonksiyon
float FindPeak(float filtered_data[], int data_size) {
    float peak_value = filtered_data[0]; // Tepe noktasının başlangıç değeri, dizinin ilk elemanı olarak belirlenir

    // Tüm diziyi tarayarak tepe noktasını bul
    int i;
    for (i = 1; i < data_size; i++) {
        // Eğer mevcut eleman tepe değerinden büyükse, tepe değeri güncellenir
        if (filtered_data[i] > peak_value) {
            peak_value = filtered_data[i];
        }
    }
    // Bulunan tepe değeri döndürülür
    return peak_value;
}

interrupt void adcint1_isr(void) {
    Result = AdcaResultRegs.ADCRESULT0;
    //GpioDataRegs.GPBTOGGLE.bit.GPIO32 = 1;
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // Kesme bayrağını temizle
}
void main(void) {
    // Sistem Kontrolünü Başlat:
    // PLL, WatchDog, Periferik Saatleri etkinleştir

   InitSysCtrl();

    // Tüm kesmeleri temizleyin ve PIE vektör tablosunu başlatın:
    // CPU kesmelerini devre dışı bırak
    DINT;

    // PIE kontrol kayıtlarını varsayılan durumlarına başlatın.
    // Varsayılan durum, tüm PIE kesmelerinin devre dışı bırakılması ve bayrakların temizlenmesidir.
    InitPieCtrl();

    // CPU kesmelerini devre dışı bırakın ve tüm CPU kesme bayraklarını temizleyin:
    IER = 0x0000;
    IFR = 0x0000;

    // PIE vektör tablosunu kabuk Kesme Servis Rutinlerine (ISR) işaretçilerle başlatın.
    // Bu, kesme kullanılmıyor olsa bile tüm tabloyu doldurur.
    // Bu, hata ayıklama amaçları için yararlıdır.
    // Kabuk ISR rutinleri, F2837xD_DefaultIsr.c dosyasında bulunur.
    InitPieVectTable();

    // Global Kesmeleri ve daha yüksek öncelikli gerçek zamanlı hata ayıklama olaylarını etkinleştirin:
    //EINT;  // Global kesmeyi etkinleştir INTM
    //ERTM;  // Global gerçek zamanlı kesmeyi etkinleştir DBGM

    EALLOW;

    // GPIO34'ü Başlat:
    GpioCtrlRegs.GPBGMUX1.bit.GPIO32 = 0;
    GpioCtrlRegs.GPBMUX1.bit.GPIO32 = 0; // Pini GPIO olarak yapılandır
    GpioCtrlRegs.GPBDIR.bit.GPIO32 = 1; // GPIO34'ü çıkış olarak tanımla
    GpioDataRegs.GPBDAT.bit.GPIO32 = 1; // Çıkış kilitlenmesine 1 girin

    // Timer0 kesmesi için dönem değerini yükle
    CpuTimer0Regs.PRD.all = 30 - 1; // Varsayılan 2000
    CpuTimer0Regs.TPR.bit.TDDR = 0; // Zamanlayıcı için öncül değeri 1 olarak ayarla
    CpuTimer0Regs.TCR.bit.TSS = 1; // Zamanlayıcıyı durdur
    CpuTimer0Regs.TCR.bit.TRB = 1; // Zamanlayıcıyı yeniden yükle
    CpuTimer0Regs.TCR.bit.TIE = 1; // Zamanlayıcı0 kesmesini periferik seviyede etkinleştir
    CpuTimer0Regs.TCR.bit.TSS = 0; // Zamanlayıcıyı başlat

    // ADC için ayarları yap
    AdcaRegs.ADCCTL2.bit.PRESCALE = 6; // ADCCLK bölenini /4 olarak ayarla
    AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1; // ADC'yi etkinleştir
    AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 1; // Kesme darbesi pozisyonlarını geç ayarlara ayarla
    AdcaRegs.ADCCTL2.bit.RESOLUTION = 0; // 12-bit çözünürlük
    AdcaRegs.ADCCTL2.bit.SIGNALMODE = 0; // Tek bitişik (sadece 12-bit modu)

    // ADC kullanmadan önce en az 500 mikrosaniye gecikme olmalı
    DELAY_US(1000);

    // ADC'nin dönüştürme yapacağı pini belirle
    AdcaRegs.ADCSOC0CTL.bit.CHSEL = 1; // SOC0 pini ADCINA0'ı dönüştürecek
    AdcaRegs.ADCSOC0CTL.bit.ACQPS = 15 - 1; // Örnekleme penceresi 8000 SYSCLK döngüsü
    AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 0x01; // CPU Timer 0 ile tetikle

    // ADCINT1'in EOC0 bayrağını ayarla
    AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 0; // EOC0 INT1 bayrağını ayarlar
    AdcaRegs.ADCINTSEL1N2.bit.INT1CONT = 1; // Kesmeler oluşturulacak
    AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1; // INT1 bayrağını etkinleştir

    // ISR adresini yeniden yönlendir:
    PieVectTable.ADCA1_INT = &adcint1_isr;

    // PIE bloğunu etkinleştir
    PieCtrlRegs.PIECTRL.bit.ENPIE = 1;

    // PIE Grup 1 INT1 ADCA1'i etkinleştir
    PieCtrlRegs.PIEIER1.bit.INTx1 = 1;

    // CPU INT1'i etkinleştir (Xint1 dahil)
    IER |= M_INT1;

    // Global kesme maskesini etkinleştir (INTM)
    EINT;

    // Gerçek zamanlı kesme maskesini etkinleştir (DBGM)
    ERTM;

    EDIS;

    // Ana döngü
    while(1) {

        ReadAndFilterADCData();
        peak_value = FindPeak(filtered_data, DATA_SIZE);

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

    您好!

    示波器上显示的信号输出根据辐射源在300-600mV 之间变化。 前置放大器输出端信号的上升时间约为2微秒。 我认为以600ns 的间隔进行采样就足够了。 我确信 ADC 工作正常、因为我可以从信号发生器在1 MHz 处对正弦波和方波进行采样并捕获峰值点。

    您期望以何种方式在峰值采样? 您是否使用某种峰值检测电路?  

    此致、

    本·科利尔

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

    在我提到的 ADC 输入需要前置放大之前、没有前置电子元件(峰值检测等)。  基本上、我使用移动平均线或梯形滤波器来使信号平滑、并选择窗口大小来为阵列分配 ADC 输出、以便可以对我采样的信号的峰值进行排序和检测。  当然、它会导致信号延迟和逃逸、但在光谱仪中可以、因为它只会使测量时间更长。 另一方面、昨天我认识到、当信号发生器的正弦/方波设定为大约20V 时、ADC 的信号输入几乎为0V。 当我将信号发生器的振幅增加至23V 时、可以看到 ADC 输出为0-4096。 会出现电压降或类似情况、但我不知道会发生什么情况。 此外、我增加了放大器的增益、使检测器的信号振幅约为50V、但 ADC 输入中仍然没有信号。 这可能是阻抗不匹配导致的。 检测器和信号发生器具有不同的阻抗等级、这可能有没有原因。 在这两种情况下、我都确实需要解决这个问题。

    谢谢。

    哈利特

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

    Halit,

    我不确定我是否充分理解您的系统、以便解决这个问题、因为在 ADC 之外似乎出现了问题。

    只是想知道、您是否可以对 ADC 输入进行示波?  

    此致、

    本·科利尔

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

    是的 Benjamin、我可以通过示波器监控 ADC 输入。 根本没有问题。 但是、就 ADC 输出而言、我什么都看不到。 她对我很生气。  

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

    好的、我很想看看您通过示波器看到的内容。 我可以在这之后进一步评论。  

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

    为巨大的缺口感到抱歉、有一些文书工作要处理。 我有一张示波器图片、其中显示了信号的输出(运算放大器输出)。 出于在源端保持高阻抗的隔离目的、我采用了 LF353运算放大器、而振荡器属于运算放大器的输出(同相单位增益设置)。 我进行了交叉检查、以确保运算放大器的输入和输出与我的预期相同。 这是检测器侧、一切正常、符合预期。  在 C2000 ADC 端、我的采样频率大约为1.65MHz、正如我之前所提到的、几乎是600ns。 当我通过信号发生器向 LF353的输入提供高达1MHz 的正弦信号时、输出与 ADC 的输入相同、并按预期稳定。   还测试了0V 至3V 的不同振幅水平、这是可以的。 即使在高频下、ADC 也非常适合正弦波。 当我将检测器设置连接到 ADC 输入时、就开始了奇怪的事情。 ADC 读取持续的零、但在 ADC 的输出中我看到的几个非常小的信号除外。 我看了  C2000 ADC 的电荷共享驱动电路中的示例(使用 TINA-TI 仿真工具)(修订版 A) https://www.ti.com/lit/an/spracv0a/spracv0a.pdf?ts = 1711982105174&ref_url=https%253A%252F%252Fe2echina.ti.com%252Fsupport%252Fmachine-translation%252Fmt-c2000-microcontrollers%252Ff%252Fmt-c2000-microcontrollers-forum%252F345666%252Ftms320f28388d-16-adc 

    在第二个示例中、选择了非常类似的参数、因此昨天我决定测试其中的公式、以便根据我选择的采样率计算 RC 滤波器。  RC 的带宽约为150kHz、运算放大器的带宽也可以提高4倍。 根据公式,RC 参数 分别处理为5欧姆和220 nF。 但是、它也不起作用。  我的工作总结:

    1)检测器信号>前置放大器>整形器> LF353 (通过此处的振荡器检查输出、信号正常)> ADC (除几个非常小的信号外、输出为零)

    2) 检测器信号>前置放大器>整形器> LF353 > RC 低通滤波器(输出由振荡器检查、此处信号正常)> ADC (除几个非常小的信号外输出为零)

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

    您如何设置 ADC SOC? ADC 转换是如何触发的?  

    我将信号发生器的振幅提高至23V 后,可以看到 ADC 输出为0-4096。 会出现电压降或类似情况、但我不知道会发生什么情况。 此外、我增加了放大器的增益、使检测器的信号振幅约为50V、但 ADC 输入中仍然没有信号。 [/报价]

    我不得不说、这很奇怪、只能改变您的输入信号振幅、然后您会从看到满量程 ADC 范围而不看到任何内容。