自制 示波器/频谱显示/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); } }
原文地址:https://www.cnblogs.com/hebaichuanyeah/p/4121798.html