- UID
- 373967
- 帖子
- 8822
- 主題
- 2609
- 精華
- 0
- 積分
- 994
- 楓幣
- 0
- 威望
- 971
- 存款
- 34510
- 贊助金額
- 0
- 推廣
- 0
- GP
- 1205
- 閱讀權限
- 50
- 在線時間
- 452 小時
- 註冊時間
- 2023-1-12
- 最後登入
- 2024-11-12
|
要製作一個基於 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 輸入控制頻率。 |
|