洪嵐峰 發表於 2023-4-10 05:52:28

PIC18LF25K50-I/ML 示波器



要製作一個基於 PIC18LF25K50-I/ML 微控制器的示波器,需要以下零件:

PIC18LF25K50-I/ML 微控制器
晶振和相關電容:用於提供微控制器的時鐘信號。
電源電路:用於提供微控制器和其他電路的電源。
模擬前級電路:用於擷取模擬信號並轉換為微控制器可以讀取的數字信號。
數字信號處理電路:用於處理擷取到的信號數據,包括濾波、緩存、FFT等處理方式。
顯示器:用於顯示處理後的信號波形。
以下是 PIC18LF25K50-I/ML 微控制器的 QFN-28 封裝的連接腳位:


          VSS      1    28     VDD
          RA0      2    27     RA7
          RA1      3    26     RA6
          RA2      4    25     RA5
          RA3      5    24     RA4
          RC0      6    23     RC5
          RC1      7    22     RC4
          RC2      8    21     RC3
          OSC1     9    20     OSC2
          VUSB    10    19     RB4
          VBG     11    18     RB5
          AN11    12    17     RB6
          AN9     13    16     RB7
          VPP     14    15     PGD
以下是示波器的主要程式碼,該程式碼使用 PIC18LF25K50-I/ML

微控制器和相關電路來擷取和顯示模擬信號的波形。


#include <xc.h>

// 定義相關的輸入/輸出引腳和緩存
#define ADC_BUFFER_SIZE 512
#define ADC_INPUT_PIN RA0
#define ADC_OUTPUT_BUFFER PIR1bits.ADIF
#define ADC_OUTPUT_VALUE ADRESH

// 定義相關的示波器參數
#define TRIGGER_LEVEL 128
#define TRIGGER_MODE 0 // 0 = 自動觸發,1 = 正緣觸發,2 = 負緣觸發
#define TRIGGER_EDGE 0 // 0 = 上升沿觸發,1 = 下降沿觸發

// 定義相關的數字信號處理參數
#define SAMPLES_PER_SECOND 1000
#define SAMPLE_BUFFER_SIZE 512
#define FFT_BUFFER_SIZE 512
#define FFT_WINDOW_SIZE 512

// 相關的變量和數組
unsigned char adc_buffer;
unsigned int sample_buffer;
unsigned int fft_buffer;
unsigned char fft_window;

// 定義相關的函數
void setup_adc(void);
void start_adc(void);
void process_samples(void);
void display_waveform(void);

void main(void) {
// 初始化相關的硬件和變量
setup_adc();
setup_display();
setup_fft();

// 循環擷取和顯示信號波形
while (1) {
    // 開始擷取模擬信號
    start_adc();

    // 等待 ADC 轉換完成
    while (!ADC_OUTPUT_BUFFER);

    // 處理擷取到的數據
    process_samples();

    // 顯示處理後的信號波形
    display_waveform();
}
}

void setup_adc(void) {
// 設置 ADC 輸入引腳為模擬輸入模式
ADCON1bits.PCFG = 0b1110;
TRISA = 0b00000001;

// 設置 ADC 轉換速度和時鐘
ADCON2bits.ADCS = 0b110;
ADCON2bits.ACQT = 0b101;
ADCON2bits.ADFM = 1;

// 啟用 ADC 和中斷
ADCON0bits.ADON = 1;
PIE1bits.ADIE = 1;
}

void start_adc(void) {
// 啟動 ADC 轉換
ADCON0bits.GO = 1;
}

void process_samples(void) {
// 循環讀取 ADC 緩存中的數據,存儲到樣本緩存中
unsigned int i;
for (i = 0; i < SAMPLE_BUFFER_SIZE; i++) {
// 等待 ADC 轉換完成
while (!ADC_OUTPUT_BUFFER);

    // 讀取 ADC 緩存中的數據
    sample_buffer = ADC_OUTPUT_VALUE;

    // 重新啟動 ADC 轉換
    ADC_OUTPUT_BUFFER = 0;
    ADCON0bits.GO = 1;
}

// 計算樣本緩存中的平均值
unsigned long sum = 0;
for (i = 0; i < SAMPLE_BUFFER_SIZE; i++) {
    sum += sample_buffer;
}
unsigned int average = sum / SAMPLE_BUFFER_SIZE;

// 將樣本緩存中的數據減去平均值,並將其存儲到 FFT 緩存中
for (i = 0; i < SAMPLE_BUFFER_SIZE; i++) {
    fft_buffer = sample_buffer - average;
}
}

void display_waveform(void) {
// 計算 FFT 結果
fft(fft_buffer, FFT_BUFFER_SIZE, fft_window);

// 獲取 FFT 結果中的最大值和位置
unsigned int max_value =0;
unsigned int max_index = 0;
unsigned int i;
for (i = 0; i < FFT_BUFFER_SIZE / 2; i++) {
if (fft_buffer > max_value) {
max_value = fft_buffer;
max_index = i;
}
}


// 計算 FFT 結果中的頻率
float frequency = (float)max_index * ADC_SAMPLE_RATE / FFT_BUFFER_SIZE;

// 將 FFT 結果繪製到屏幕上
clear_display();
draw_text(0, 0, "Frequency:");
draw_float(0, 1, frequency, 2, 6);
draw_graph(0, 3, fft_buffer, FFT_BUFFER_SIZE / 2, GRAPH_TYPE_LINE, GRAPH_DIRECTION_LEFT_TO_RIGHT);
show_display();
}

// FFT 函數的實現
void fft(unsigned int *data, unsigned int n, unsigned char *window) {
unsigned int i;
unsigned char j, k, m;
unsigned int n1, n2;
unsigned int t1, t2;
unsigned int c1, c2;
unsigned int xt, yt, xp, yp;
unsigned int id, id1, id2;
unsigned int rad;
unsigned int tr, ti;


// 對數據應用漢明窗
for (i = 0; i < n; i++) {
    data = data * window;
}

// 執行快速傅里葉變換
j = 0;
n2 = n / 2;
for (i = 0; i < n - 1; i++) {
    if (i < j) {
        xt = data;
        data = data;
        data = xt;
    }
    k = n2;
    while (k <= j) {
        j -= k;
        k /= 2;
    }
    j += k;
}
n1 = 0;
n2 = 1;
for (i = 0; i < log(n) / log(2); i++) {
    n1 = n2;
    n2 = n2 * 2;
    rad = 0x4000 / n1;
    for (j = 0; j < n1; j++) {
        c1 = cos_fixed_point(rad * j);
        c2 = sin_fixed_point(rad * j);
        for (k = j; k < n; k += n2) {
            id = k + n1;
            xt = mul_fixed_point(c1, data) - mul_fixed_point(c2, data);
            yt = mul_fixed_point(c2, data) + mul_fixed_point(c1, data);
            data = data - xt;
            data = data - yt;
            data = data + xt;
            data = data + yt;
        }
    }
}
}

// 固定小數點乘法的實現
unsigned int mul_fixed_point(unsigned int a, unsigned int b) {
unsigned long c = (unsigned long)a * b;
return (unsigned int)(c >> 15);
}

弦函數的實現
unsigned int sin_fixed_point(unsigned int angle) {
static const unsigned int sine_table[] = {
0, 402, 804, 1206, 1608, 2010, 2412, 2814, 3215, 3616,
4017, 4418, 4818, 5218, 5617, 6016, 6414, 6812, 7209, 7606,
8002, 8397, 8792, 9185, 9578, 9969, 10360, 10749, 11137, 11523,
11908, 12292, 12674, 13054, 13433, 13810, 14186, 14559, 14930, 15300,
15668, 16033, 16396, 16757, 17115, 17471, 17824, 18175, 18523, 18868,
19211, 19550, 19887, 20220, 20551, 20878, 21202, 21522, 21839, 22153,
22462, 22768, 23070, 23368, 23662, 23952, 24238, 24519, 24797, 25070,
25338, 25601, 25860, 26115, 26364, 26609, 26848, 27083, 27312, 27536,
27754, 27967, 28175, 28377, 28574, 28765, 28950, 29129, 29303, 29470,
29632, 29787, 29937, 30080, 30218, 30349, 30474, 30593, 30705, 30812,
30912, 31006, 31093, 31174, 31248, 31316, 31377, 31432, 31480, 31521,
31555, 31583, 31603, 31617, 31624, 31624
};
unsigned int index = angle >> 7;
unsigned int frac = angle & 0x7F;
unsigned int y1 = sine_table;
unsigned int y2 = sine_table;
return y1 + mul_fixed_point((y2 - y1), frac);
}

// 固定小數點餘弦函數的實現
unsigned int cos_fixed_point(unsigned int angle) {
return sin_fixed_point(angle + 0x4000);
}

// 輸出波形到 DAC
void output_waveform(unsigned int waveform) {
unsigned int dac_value = 0;
switch (waveform) {
case WAVEFORM_SINE:
dac_value = sin_fixed_point(phase_accumulator);
break;
case WAVEFORM_TRIANGLE:
if (phase_accumulator < 0x4000) {
dac_value = mul_fixed_point(phase_accumulator, 0x100);
} else {
dac_value = mul_fixed_point(0x4000 - (phase_accumulator - 0x4000), 0x100);
}
break;
case WAVEFORM_SAWTOOTH:
dac_value = mul_fixed_point(phase_accumulator, 0x100);
break;
case WAVEFORM_SQUARE:
if (phase_accumulator < 0x8000) {
dac_value = 0x7FFF;
} else {
dac_value = 0;
}
break;
}
// 將 DAC 值輸出到 MCP4921
// ...
}

// 主函數
int main(void) {
// 初始化 Timer1,設置為自由運行模式,預分頻器為 1
T1CONbits.TMR1CS = 0; // 使用內部時鐘源
T1CONbits.T1CKPS = 0; // 預分頻器為 1
T1CONbits.T1SYNC = 0; // 不同步外部時鐘源
T1CONbits.TMR1ON = 1; // 啟動 Timer1

// 初始化 DAC,使用 MCP4921
// ...

// 初始化 GPIO,將 DAC 輸出引腳設置為輸出
// ...

// 循環運行
while (1) {
    // 讀取 ADC 輸入值,轉換為相位增量,更新相位累加器
    unsigned int adc_value = read_adc();
    phase_increment = mul_fixed_point(adc_value, MAX_PHASE_INCREMENT / ADC_MAX_VALUE);
    phase_accumulator += phase_increment;
    if (phase_accumulator >= MAX_PHASE) {
        phase_accumulator -= MAX_PHASE;
    }

    // 根據選擇的波形輸出波形到 DAC
    output_waveform(selected_waveform);

    // 等待一段時間,以控制波形的頻率
    __delay_ms(10);
}

return 0;
}




在以上程式碼中,需要根據實際電路配置和需求進行修改,包括初始化 ADC、DAC 和 GPIO 的程式碼,以及波形選擇和輸出部分的細節。

以下是一些可能需要注意的細節:

ADC 的初始化需要根據具體的電路設置和需求進行,包括通道選擇、參考電壓、取樣時間等參數的設置。

在本範例中,我們假設使用單通道且參考電壓為 5V。

DAC 的初始化需要根據具體的電路設置和需求進行,包括 SPI 通訊模式、輸出電壓範圍等參數的設置。

在本範例中,我們假設使用 MCP4921 這款 DAC,且輸出電壓範圍為 0V 至 5V。

GPIO 的初始化需要根據具體的電路設置和需求進行,包括輸入輸出模式、極性、上下拉等參數的設置。

在本範例中,我們假設使用 RB0 腳位作為 DAC 輸出。

波形選擇和輸出部分的細節需要根據具體的需求進行,包括波形種類、振幅、相位等參數的設置。在本範例中,我們實現了正弦波和方波兩種波形,且可通過 ADC 輸入控制頻率。
頁: [1]
查看完整版本: PIC18LF25K50-I/ML 示波器