本設計以Python為上位機制作的STM32示波器,實現了波形顯示、頻率計算、波形保存等功能,代碼均有完整中文注釋,供大家參考(如果有條件,使用OLED顯示屏當做上位機實現該設計,這樣有效的減少了上位機界面刷新的延遲)
文件包括上位機 下位機 測試數據等
上位機程序:
- import serial
- import threading
- import time
- import matplotlib.pyplot as plt
- from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
- import tkinter as tk
- from tkinter import ttk
- from tkinter import filedialog
- from PIL import Image, ImageTk
- import numpy as np
- class Oscilloscope:
- def __init__(self, master):
- self.master = master # 定義 master 變量
- self.master.title("簡易示波器") # 設置窗口標題
- self.master.geometry("1400x600") # 設置窗口大小
- self.master.resizable(False, False) # 設置窗口不可調整大小
- self.master.protocol("WM_DELETE_WINDOW", self.close_window) # 設置關閉窗口時調用的方法
- self.ser = None # 定義 ser 變量,初始值為 None
- self.baudrate = tk.StringVar(value="921600") # 定義波特率變量,初始值為 "921600"
- self.port = tk.StringVar(value="COM5") # 定義端口變量,初始值為 "COM11"
- self.size = tk.StringVar(value=50)
- self.MAXvar = tk.StringVar()
- self.MINvar = tk.StringVar()
- self.Fvar = tk.StringVar()
- self.Fsvar = tk.StringVar()
- self.pause = tk.BooleanVar(value=False) # 定義暫停變量,初始值為 False
- self.fig = plt.Figure(figsize=(6, 4), dpi=100) # 創建一個 Figure 對象
- self.ax = self.fig.add_subplot(111) # 在 Figure 對象中添加一個子圖
- self.canvas = FigureCanvasTkAgg(self.fig, master=self.master) # 創建一個畫布對象
- self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True) # 將畫布添加到窗口中
- self.toolbar = tk.Frame(master=self.master) # 創建一個工具欄對象
- self.toolbar.pack(side=tk.TOP, fill=tk.X) # 將工具欄添加到窗口中
- self.pause_button = ttk.Checkbutton(self.toolbar, text="暫停", variable=self.pause, command=self.pause_waveform, width=6) # 創建一個暫停按鈕
- self.pause_button.pack(side=tk.LEFT, padx=5) # 將暫停按鈕添加到工具欄中
- self.save_button = ttk.Button(self.toolbar, text="保存圖片", command=self.save_waveform, width=8) # 創建一個保存按鈕
- self.save_button.pack(side=tk.LEFT, padx=5) # 將保存按鈕添加到工具欄中
- self.port_label = ttk.Label(self.toolbar, text="端口:", width=6) # 創建一個端口標簽
- self.port_label.pack(side=tk.LEFT, padx=5) # 將端口標簽添加到工具欄中
- self.port_combobox = ttk.Combobox(self.toolbar, textvariable=self.port, values=["COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8","COM10"], width=6) # 創建一個端口下拉框
- self.port_combobox.pack(side=tk.LEFT, padx=5) # 將端口下拉框添加到工具欄中
- self.baudrate_label = ttk.Label(self.toolbar, text="波特率:", width=6) # 創建一個波特率標簽
- self.baudrate_label.pack(side=tk.LEFT, padx=5) # 將波特率標簽添加到工具欄中
- self.baudrate_combobox = ttk.Combobox(self.toolbar, textvariable=self.baudrate, values=["9600", "115200","921600"], width=6) # 創建一個波特率下拉框
- self.baudrate_combobox.pack(side=tk.LEFT, padx=5) # 將波特率下拉框添加到工具欄中
- self.baudrate_label = ttk.Label(self.toolbar, text="橫軸長度:", width=8) # 創建一個波特率標簽
- self.baudrate_label.pack(side=tk.LEFT, padx=5) # 將波特率標簽添加到工具欄中
- self.baudrate_combobox = ttk.Combobox(self.toolbar, textvariable=self.size, values=[50, 100, 200, 500, 1000], width=5) # 創建一個橫坐標尺寸下拉框
- self.baudrate_combobox.pack(side=tk.LEFT, padx=5) # 將波特率下拉框添加到工具欄中
- self.connect_button = ttk.Button(self.toolbar, text="連接", command=self.connect, width=6) # 創建一個連接按鈕
- self.connect_button.pack(side=tk.LEFT, padx=5) # 將連接按鈕添加到工具欄中
- self.disconnect_button = ttk.Button(self.toolbar, text="斷開連接", command=self.disconnect, width=8) # 創建一個斷開連接按鈕
- self.disconnect_button.pack(side=tk.LEFT, padx=5)
- self.disconnect_button = ttk.Button(self.toolbar, text="清除圖像", command=self.clear, width=8) # 創建一個斷開連接按鈕
- self.disconnect_button.pack(side=tk.LEFT, padx=5) # 將斷開連接按鈕添加到工具欄中
- ······
復制代碼 下位機主程序:
- /**********************************************************
- MCU接線說明
- 采樣接口:PA6
- 正弦波:PA4
- 三角波:PA5
- 增加采樣頻率:KEY0
- 降低采樣頻率:KEY1
- 基于正點原子精英板 MCU STM32F1Z8T6
- 時間:2023年5月12日
- ***********************************************************/
- #include "led.h"
- #include "delay.h"
- #include "sys.h"
- #include "usart.h"
- #include "lcd.h"
- #include "adc.h"
- #include "dma.h"
- #include "timer.h"
- #include "table_fft.h"
- #include "stm32_dsp.h"
- #include "math.h"
- #include "key.h"
- #include "BEEP.h"
- #include "dac.h"
- #include "exti.h"
- #define NPT 1024 //采樣次數
- #define PI2 6.28318530717959 //2*pi 用于正弦波生成
- void InitBufInArray(void); //正弦波輸出緩存
- void sinout(void); //正弦波輸出
- void GetPowerMag(void); //FFT變換,輸出頻率
- void sendData(void);
- int long fftin [NPT]; //FFT輸入 x[n]
- int long fftout[NPT]; //FFT輸出 X[k]
- u32 FFT_Mag[NPT/2]={0}; //幅頻特性
- u16 magout[NPT]; //模擬正弦波輸出緩存區
- u16 currentadc; //實時采樣數據
- u16 adcx[NPT]; //adc數值緩存
- u32 adcmax; //采樣最大值和最小值
- u32 adcmin;
- u8 adc_flag=0; //采樣結束標志
- u8 key_flag=0; //按鍵掃描標志
- u8 show_flag=1; //更新暫停標志
- u16 T=2000; //定時器2重載值,不能小于PWM的Pluse值
- u16 pre=36; //定時器2預分頻值
- u32 fre; //采樣頻率 Hz
- u16 F; //波形頻率
- u16 temp=0; //幅值最大的頻率成分
- u16 t=0;
- u16 key; //按鍵
- int main()
- {
- u16 i;
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
- MYDMA1_Config(DMA1_Channel1,(u32)&ADC1->DR,(u32)¤tadc,1);
- uart_init(921600);
- delay_init();
- LED_Init();
- EXTIX_Init();
- Adc_Init();
- InitBufInArray();
- TIM4_Int_Init(1,35); //三角波和噪聲頻率控制,
- TIM3_Int_Init(39,71); //72MHz/40/72=25kHz 25kHz/1024≈25Hz 正弦波頻率約為24.5Hz
- TIM2_PWM_Init(T-1,pre-1); //最大頻率72000000/1/2000=3.6KHz
- Dac1_Init();
- Dac2_Init();
-
- while(1)
- {
- //等待采樣完成
- while(adc_flag==0)
- {
- LED1=!LED1;
- sendData(); //發數據給上位機
- delay_ms(100);
-
- }
復制代碼 |