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_TRGO4 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
代码有不足的地方,多多评论交流