基于stm32f407的示波器+FFT频谱分析

1 设计思路
代码流程图

2 DMA传输ADC采样值
使用DMA直接将ADC->DR中的数据传输到ADC数据缓存区,节省cpu资源,高速AD采集,代码如下:

DMA_InitStructure.DMA_PeripheralBaseAddr=(u32)&ADC3->DR;//外设基地址 ADC3_DR
DMA_InitStructure.DMA_Memory0BaseAddr = mar;   //内存基地址

3 ADC定时器触发(可修改ADC采样率)
为了实现ADC采样率可调,我将AD的出发方式设置为定时器触发,使用TIM3来触发adc采集,首先初始化定时器,先预设几种初值存入数组内,初始化的时候根据需求修改定时器初值,修改adc采样率时直接调用adc初始化函数,装不同的初值,就能实现修改采样率的功能, 定时器代码如下(完整源码连接在文章末):

/********ADC TIM触发初始化********/
  TIM_Cmd(TIM3, DISABLE);
  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); //初始化定时器
  
  TIM_TimeBaseStructure.TIM_Period = 168000000/g_SampleFreqTable[TimeBaseId][0] - 1;//计数值42MHz*2/1000/168=500Hz  
  TIM_TimeBaseStructure.TIM_Prescaler = g_SampleFreqTable[TimeBaseId][1]-1;     //预分频器1000分频
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟输入1分频
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
  
  TIM_ARRPreloadConfig(TIM3, ENABLE); //允许TIM3定时重载
  TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update);  //选择TIM3的UPDATA事件更新为触发源

ADC初始化一定要选择外部触发源:
ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_T3_TRGO;//外部触发源 TIM3_TRGO

4 DSP库FFT运算
ADC采集完时域波形后,调用了ST官方DSP库(arm_cortexM4lf_math.lib),实现FFT运算将时域波形转为频域图形,调用其中做fft运算的函数接口,最后dis_fft_dat[]数组内就是计算出来的频域图形值,将该数组绘制在LCD屏上,简易的频谱显示就完成了,效果见文章末的效果图。

arm_cfft_radix4_init_f32(&scfft,FFTDorpLen,0,1); //初始化scfft结构体
arm_cfft_radix4_f32(&scfft,testInput_fft_256);	//FFT计算(基4)
arm_cmplx_mag_f32(testInput_fft_256,dis_fft_dat,FFTDorpLen);	//把运算结果复数求模得幅值

5 UCOS操作系统
为了实现多任务处理,代码中移植了ucos操作系统,在start任务内创建了4个任务,emwin绘图任务、按键任务、DSP任务、led闪烁任务,其中DSP任务主要负责adc数据采集和FFT运算,并且DSP任务的优先级必须最高,否则可能会出现波形失真。

void start_task(void *pdata)
{
	OS_CPU_SR cpu_sr;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC,ENABLE);	//开启CRC时钟				//在所有窗口上使用存储设备
	
	OSStatInit(); //初始化统计任务
	OS_ENTER_CRITICAL();  //进入临界区,关闭中断
	
	OSTaskCreate(emwin_maintask,(void*)0,(OS_STK*)&EMWINDEMO_TASK_STK[EMWINDEMO_STK_SIZE-1],EMWINDEMO_TASK_PRIO);//2D绘图任务
	OSTaskCreate(touch_task,(void*)0,(OS_STK*)&TOUCH_TASK_STK[TOUCH_STK_SIZE-1],TOUCH_TASK_PRIO); //按键任务
	OSTaskCreate(led0_task,(void*)0,(OS_STK*)&LED0_TASK_STK[LED0_STK_SIZE-1],LED0_TASK_PRIO); //LED0任务
	OSTaskCreate(dsp_task,(void*)0,(OS_STK*)&DSP_TASK_STK[DSP_STK_SIZE-1],DSP_TASK_PRIO); 		//DSP 任务
	
	OSTaskSuspend(OS_PRIO_SELF); //挂起start任务
	OS_EXIT_CRITICAL();  //退出临界区,开中断
}

6 Emwin绘制背景图
波形绘制和页面快速刷新显示使用了emwin图形库,为了快速刷新显示背景图,直接使用GUI_MEMDEV_CreateFixed,GUI_MEMDEV_Select函数接口将图像像素直接存入内存,
绘制背景图片代码

需要显示时调用GUI_MEMDEV_WriteAt(DrawTimeMem,Tx1,Tx2);函数接口将画面显示到Tx1,Tx2坐标开始的位置上,使用该方法背景图片刷新只需要10ms左右。
7 Emwin绘制波形图
绘制波形图直接调用GUI_DrawGraph函数,在Tx1Tx2坐标开始绘制长度为WindowDropLen的DIS_da波形。(DIS_da是一个256元素的数组)

GUI_SetColor(GUI_YELLOW);//设置颜色
GUI_DrawGraph(DIS_da,WindowDropLen,Tx1,Tx2+100);//绘制波形图

在stm32F407VET6 mini开发板上运行的效果
在这里插入图片描述
在这里插入图片描述
附源码连接(无需积分免费下载):https://download.csdn.net/download/weixin_40751800/85522977?spm=1001.2014.3001.5501

代码有不足的地方,多多评论交流

  • 26
    点赞
  • 165
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叒木森

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值