冰楓論壇

 找回密碼
 立即註冊
搜索
查看: 605|回覆: 0
打印 上一主題 下一主題

[討論] PIC18LF25K50-I/ML 示波器

[複製鏈接]

2609

主題

0

好友

994

積分

高級會員

Rank: 4

UID
373967
帖子
8822
主題
2609
精華
0
積分
994
楓幣
0
威望
971
存款
34510
贊助金額
0
推廣
0
GP
1205
閱讀權限
50
在線時間
452 小時
註冊時間
2023-1-12
最後登入
2024-11-12

2023端午節紀念勳章 2023中秋節紀念勳章 2023聖誕節紀念勳章

跳轉到指定樓層
1
發表於 2023-4-10 05:52:28 |只看該作者 |正序瀏覽


要製作一個基於 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[ADC_BUFFER_SIZE];
unsigned int sample_buffer[SAMPLE_BUFFER_SIZE];
unsigned int fft_buffer[FFT_BUFFER_SIZE];
unsigned char fft_window[FFT_WINDOW_SIZE];

// 定義相關的函數
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[i] = 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[i];
}
unsigned int average = sum / SAMPLE_BUFFER_SIZE;

// 將樣本緩存中的數據減去平均值,並將其存儲到 FFT 緩存中
for (i = 0; i < SAMPLE_BUFFER_SIZE; i++) {
    fft_buffer[i] = sample_buffer[i] - 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[i] > max_value) {
max_value = fft_buffer[i];
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[i] = data[i] * window[i];
}

// 執行快速傅里葉變換
j = 0;
n2 = n / 2;
for (i = 0; i < n - 1; i++) {
    if (i < j) {
        xt = data[j];
        data[j] = data[i];
        data[i] = 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[id]) - mul_fixed_point(c2, data[id + 1]);
            yt = mul_fixed_point(c2, data[id]) + mul_fixed_point(c1, data[id + 1]);
            data[id] = data[k] - xt;
            data[id + 1] = data[k + 1] - yt;
            data[k] = data[k] + xt;
            data[k + 1] = data[k + 1] + 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[index];
unsigned int y2 = sine_table[index + 1];
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 楓幣 幸運榜 / 衰神榜
收藏收藏0 推0 噓0


把本文推薦給朋友或其他網站上,每次被點擊增加您在本站積分: 1彩票
複製連結並發給好友,以賺取推廣點數
簡單兩步驟,註冊、分享網址,即可獲得獎勵! 一起推廣文章換商品、賺$$
高級模式
B Color Image Link Quote Code Smilies |上傳

廣告刊登意見回饋關於我們管群招募本站規範DMCA隱私權政策

Copyright © 2011-2024 冰楓論壇, All rights reserved

免責聲明:本網站是以即時上載留言的方式運作,本站對所有留言的真實性、完整性及立場等,不負任何法律責任。

而一切留言之言論只代表留言者個人意見,並非本網站之立場,用戶不應信賴內容,並應自行判斷內容之真實性。

小黑屋|手機版|冰楓論壇

GMT+8, 2024-11-12 16:21

回頂部