自制 示波器/頻譜顯示/dds


自制示波器/頻譜顯示/DDS。

基於ucos+ARMcortexM4+FPGA。

帶FIR,FFT,Kalman算法。

最高采樣率50M。存儲8K*2字節數據。每秒64次波形(VGA刷屏63次/秒,快了也顯示不出)

fpga:數據采集,DDS波形產生,提供VGA時序驅動屏幕。

ARMcortexM4:外設接口控制,數據處理。

 

FPGA與CPU通過8位並行總線通信。CPU給FPGA內置RAM寫 命令/數據

 

先上張圖

 

 

 

 

頻譜顯示功能演示(FFT)對着數字信號處理教材自己寫的,用遞歸和非遞歸兩種方式實現,和MATLAB對照確認計算無誤。

 

高通濾波器與低通濾波器功能演示(理想FIR濾波器+漢明窗)單獨開任務計算FIR參數。每輸入一次計算一次參數。

MATLAB仿真

 

卡爾曼濾波算法(kalman算法對於隨機噪聲為最優),一維卡爾曼算法,無轉置矩陣。

MATLAB仿真,不同參數的kalman算法

 

 

任務調度部分代碼。(#include fpga控制.h,數學算法.h,寄存器配置BSP.h)

#include <app.h>
#include  "ucos_ii.h"          //uC/OS-II系統函數頭文件
#include  "sysinit.h"          //系統配置


#include "task_header.h" //任務相關宏 結構體
#include "fpga_data.h"   //與FPGA通信部分
#include "bsp.h"       //ARM驅動


#include "character.h"   //字模
#include "dds_data.h"   //dds數據

#include "mcu_math.h"    //數學算法部分
//#include "arm_math.h" 
/********臨時定義變量******************/
void system_init_task(void *pdata) { //double cc; pdata = pdata; #if OS_CRITICAL_METHOD == 3 //關中斷的方法為3 OS_CPU_SR cpu_sr; #endif OS_ENTER_CRITICAL(); OS_CPU_SysTickInit(CPU_frequency/1000); //初始化OS節拍無比重要 port_init(); //設置所有IO為低電平&&輸出 //UART4_Init(115200); init_LED(); key_init(); //將四個IO配備成中斷 lcd_data_init(); //lcd 數據傳輸 PIT0_Init(CPU_frequency/64); //pit定時中斷,VGA刷屏速率約為63次/秒 //PIT0_Init(5000000); //初始化四個電位器AD AD_init(); OS_EXIT_CRITICAL(); //計算sin相關參數,尼瑪不要手動輸入。 read_data_init(); LED1(0); LED2(0); LED3(0); LED4(0); //狀態 trigger.state =0; kalman.state = 0; fft_wave.state =0; freq_selc.state =0; dds.state = 0; trigger_lock.state =0; //默認值 trigger.value =0; kalman.value = 0; fft_wave.value =0; freq_selc.value =0; dds.value = 0; trigger_lock.value =0; //光標 trigger.cursor =0; kalman.cursor = 0; fft_wave.cursor =0; freq_selc.cursor =0; dds.cursor = 0; trigger_lock.cursor =0; //雙向循環鏈表 fft_wave.next_menu = &trigger; trigger.last_menu = &fft_wave; fft_wave.value_num = 2; fft_wave.menu_num =1; trigger.next_menu = &kalman; kalman.last_menu = &trigger; trigger.value_num = 3;//上升 下降 雙向 trigger.menu_num =2; kalman.next_menu = &freq_selc; freq_selc.last_menu = &kalman; kalman.value_num =2; kalman.menu_num =3; freq_selc.next_menu = &trigger_lock; trigger_lock.last_menu = &freq_selc; freq_selc.value_num = 3;//開啟,關閉,確認輸入 freq_selc.menu_num =4; trigger_lock.next_menu = &dds; dds.last_menu = &trigger_lock; trigger_lock.value_num = 2;//鎖定,解鎖 trigger_lock.menu_num =5; dds.next_menu = &fft_wave; fft_wave.last_menu = &dds; dds.value_num = 4;//方波,正弦,合成波(濾波演示),干擾波(卡爾曼演示) dds.menu_num =6; menu_p = &fft_wave; menu_head = &fft_wave; //key事件標志 KeyFlag = OSFlagCreate(0,&err); Menu = OSFlagCreate(0,&err); Data_Process = OSFlagCreate(0,&err); //menu信號量,保護全局變量 MenuSem = OSSemCreate(1); FirParamSem = OSSemCreate(1); //這里換成互斥信號量,避免優先級反轉標記一下。 //LCDdataSem = OSSemCreate(1); LCDdataSem = OSMutexCreate(Mutex_prio,&err); //發送參數的郵箱 ParaMbox = OSMboxCreate((void*)0); FirMbox = OSMboxCreate((void*)0); OSFlagPost(Menu,(OS_FLAGS)0x01,OS_FLAG_SET,NULL); /*臨時測試add與clk信號是否能用*/ OSTimeDly(5); OSTaskDel(Init_task_prio); } void key_task(void *pdata) { pdata = pdata; while(1) { //等待置1 OSFlagPend(KeyFlag,(OS_FLAGS)0x0f,OS_FLAG_WAIT_SET_OR,0,&err); OSTimeDly(40); if(!((GPIOD_PDIR>>8)&0x01)) //確認鍵 { led_2 = !led_2; while(!((GPIOD_PDIR>>8)&0x01)) OSTimeDly(1); OSTimeDly(40); LED2(led_2); key_menu(1); OSFlagPost(KeyFlag,(OS_FLAGS)0x01,OS_FLAG_CLR,NULL); OSFlagPost(Menu,(OS_FLAGS)0x01,OS_FLAG_SET,NULL); OSFlagPost(FirFlag,(OS_FLAGS)0x01,OS_FLAG_SET,NULL); } else if(!((GPIOD_PDIR>>10)&0x01)) //退出鍵 { led_2 = !led_2; while(!((GPIOD_PDIR>>10)&0x01)) OSTimeDly(1); OSTimeDly(40); LED2(led_2); key_menu(2); OSFlagPost(KeyFlag,(OS_FLAGS)0x02,OS_FLAG_CLR,NULL); OSFlagPost(Menu,(OS_FLAGS)0x02,OS_FLAG_SET,NULL); } else if(!((GPIOD_PDIR>>12)&0x01)) // { led_2 = !led_2; while(!((GPIOD_PDIR>>12)&0x01)) OSTimeDly(1); OSTimeDly(20); LED2(led_2); key_menu(3); OSFlagPost(KeyFlag,(OS_FLAGS)0x04,OS_FLAG_CLR,NULL); OSFlagPost(Menu,(OS_FLAGS)0x04,OS_FLAG_SET,NULL); } else if(!((GPIOD_PDIR>>14)&0x01)) // { led_2 = !led_2; while(!((GPIOD_PDIR>>14)&0x01)) OSTimeDly(1); OSTimeDly(20); LED2(led_2); key_menu(4); OSFlagPost(KeyFlag,(OS_FLAGS)0x08,OS_FLAG_CLR,NULL); OSFlagPost(Menu,(OS_FLAGS)0x08,OS_FLAG_SET,NULL); } else OSFlagPost(KeyFlag,(OS_FLAGS)0x0f,OS_FLAG_CLR,NULL);//清按鍵數據 } } void uart4_task(void *pdata) { pdata = pdata; while(1) { /* LED1(0); Uart4_SendByte(97); OSTimeDly(100); LED1(1); OSTimeDly(100);*/ } } void menu_task(void * pdata) { //uint8 data; #if OS_CRITICAL_METHOD == 3 //關中斷的方法為3 OS_CPU_SR cpu_sr; #endif pdata = pdata; //cpu_sr = cpu_sr; while(1) { OSFlagPend(Menu,(OS_FLAGS)0x0f,OS_FLAG_WAIT_SET_OR+OS_FLAG_CONSUME,0,&err); //所有按鍵皆觸發該事件 //OSSemPend(LCDdataSem,0,&err); OSMutexPend(LCDdataSem,0,&err); show_menu(); //OSSemPost(LCDdataSem); OSMutexPost(LCDdataSem); OSFlagPost(Menu,(OS_FLAGS)0x01,OS_FLAG_CLR,NULL); } } void data_process_task(void * pdata) { #if OS_CRITICAL_METHOD == 3 //關中斷的方法為3 OS_CPU_SR cpu_sr; #endif uint16 i,j,trigger_add,add; uint8 data; int8 tem; uint8 wave_data[(LcdLength+FirLength-1)]; uint16 ReadLength; struct complex_num fft_result[FFT_CNT]; uint8 fft_out[FFT_CNT]; int32 FirTem; //uint8 wocao[4] = {0x01,0x04,0x02,0x03}; //uint8 sample_para,voltage_para,phase_para,show_para; uint8 Para[4]; //sample show phase vlotage //uint8 show_num,; pdata = pdata; while(1) { OSFlagPend(Data_Process,(OS_FLAGS)0x01,OS_FLAG_WAIT_SET_AND+OS_FLAG_CONSUME,0,&err); //cc = arm_sin_f32(1.6); if(!trigger_lock.value) //如果觸發 { //獲取AD信號,分頻 Para[0] = ADC_Getdata(sample_ctrl); Para[0] = sample_algorithms(Para[0]); debug2 = Para[0]; Set_fre_div(Para[0]);//1為2分頻,2為四分頻…… //開始采集 read_start(1); //尋找觸發源 trigger_add = trigger_seek(); } else { } Para[1] = (ADC_Getdata(show_ctrl)>>4)+1; debug = Para[1]; Para[2] = ADC_Getdata(phase_ctrl); Para[2] =(Para[2]>>2)<<2; debug1 = Para[2]; OSMboxPost(ParaMbox,&Para[0]); //phase_para = 0; //debug = phase_para; //發送消息 add = trigger_add+Para[2]*Para[1]; //讀取更多數據以完成FIR濾波 if(freq_selc.value) ReadLength = (LcdLength+FirLength-1); else ReadLength = LcdLength; for(i=0;i<ReadLength;i++) { //OS_ENTER_CRITICAL(); add += Para[1]; wave_data[i] = read_data(add); //OS_EXIT_CRITICAL(); } read_start(0); if(freq_selc.value==2) { for(i=0;i<LcdLength;i++) { FirTem=0; for(j=0;j<FirLength;j++) FirTem += wave_data[i+j]*FirParam[j]; wave_data[i]=FirTem>>10; } } else if(freq_selc.value==1) { for(i=0;i<LcdLength;i++) { FirTem=0; for(j=0;j<FirLength;j++) FirTem += wave_data[i+j]*FirParam[j]; wave_data[i]=(FirTem>>10)-100; } } else; if(kalman.value) KalmanFilter(&wave_data[0],KalmanInitX,KalmanInitP); else; if(fft_wave.value==1) { OS_ENTER_CRITICAL(); fft(&wave_data[0],&fft_result[0],FFT_LEN,FFT_CNT); absfft(&fft_result[0],&fft_out[0],FFT_CNT); OS_EXIT_CRITICAL(); //cc[0] = fft_out[0]; //cc[1] = fft_out[1]; //cc[2] = fft_out[2]; //cc[3] = fft_out[3]; OSMutexPend(LCDdataSem,0,&err); //命令切換 data = (menu_p->state)?(0x80+clr_data_cnt):clr_data_cnt; write_command(data); //寫波形數據 data = (menu_p->state)?(0x80+write_data_command):write_data_command; write_command(data); for(i=0;i<(FFT_CNT);i++) { tem = (fft_out[i+1]-fft_out[i])/3; write_data(fft_out[i]); write_data((fft_out[i]+tem)); write_data((fft_out[i]+tem+tem)); } for(i=0;i<96;i++) { write_data(0x00); } OSMutexPost(LCDdataSem); } else { OSMutexPend(LCDdataSem,0,&err); //命令切換 data = (menu_p->state)?(0x80+clr_data_cnt):clr_data_cnt; write_command(data); //寫波形數據 data = (menu_p->state)?(0x80+write_data_command):write_data_command; write_command(data); for(i=0;i<480;i++) { write_data(wave_data[i]); } OSMutexPost(LCDdataSem); } OSFlagPost(Data_Process,(OS_FLAGS)0x01,OS_FLAG_CLR,NULL); } } void dds_ctrl_task(void *pdata) { pdata = pdata; while(1) { OSFlagPend(Menu,(OS_FLAGS)0x01,OS_FLAG_WAIT_SET_AND+OS_FLAG_CONSUME,0,&err); //確認鍵觸發該事件 //OSFlagPend(Menu,(OS_FLAGS)0x01,OS_FLAG_WAIT_SET_AND,0,&err); //嘗試清除/不清除標志 if((menu_p ==&dds)&&(!menu_p->state)) //在DDS選項下按了確認 並且狀態非下拉 { OSMutexPend(LCDdataSem,0,&err); dds_data(dds.value); OSMutexPost(LCDdataSem); } else { //OSFlagPost(Menu,(OS_FLAGS)0x01,OS_FLAG_CLR,NULL); //標志不清除,留給menu事件用。 } } } void FirPara_task(void *pdata) { pdata = pdata; uint8 * ReceivePara; uint32 FirFre; while(1) { OSFlagPend(Menu,(OS_FLAGS)0x01,OS_FLAG_WAIT_SET_AND+OS_FLAG_CONSUME,0,&err); //確認鍵觸發該事件 if((menu_p ==&freq_selc)&&(!menu_p->state)) //計算fir參數 { ReceivePara = OSMboxPend(ParaMbox,0,&err); if(freq_selc.value==1) { FirFre = ReceivePara[1]*3*(ReceivePara[0]-1)/25; FirPara(255,FirFre,DataLength,&FirParam[0],FirLength); } else if(freq_selc.value==2) { FirFre = ReceivePara[1]*12*(ReceivePara[0]-1)/25; FirPara(FirFre,0,DataLength,&FirParam[0],FirLength); } else; } OSTimeDly(10); } //參數計算 參數 采樣頻率 分頻 DDS頻率 //FirPara(uint8 H,uint8 L, uint16 N,float * fir_c,FirLength) } void Paradata_task(void *pdata) { uint8 * ReceivePara; pdata =pdata; while(1) { ReceivePara = OSMboxPend(ParaMbox,0,&err); OSMutexPend(LCDdataSem,0,&err); show_para(ReceivePara); OSMutexPost(LCDdataSem); OSTimeDly(3); } }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM