知方号

知方号

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

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

1 设计思路

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

DMA_InitStructure.DMA_PeripheralBaseAddr=(u32)&ADC3->DR;//外设基地址 ADC3_DRDMA_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

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至lizi9903@foxmail.com举报,一经查实,本站将立刻删除。