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文章来源:https://www.toymoban.com/news/detail-446307.html
代码有不足的地方,多多评论交流文章来源地址https://www.toymoban.com/news/detail-446307.html
到了这里,关于基于stm32f407的示波器+FFT频谱分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!