找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5936|回复: 16
打印 上一主题 下一主题
收起左侧

STM32+定时ADC+DMA+FFT源码

  [复制链接]
跳转到指定楼层
楼主
ID:352663 发表于 2018-7-21 18:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
  1. #include "sys.h"
  2. #include "delay.h"
  3. #include "usart.h"
  4. #include "led.h"
  5. #include "pwm.h"
  6. #include "adc.h"
  7. #include "dma.h"
  8. #include "lcd.h"
  9. #include "math.h"
  10. #include "arm_math.h"



  11. float CalMax_FREQ(float *Data, u16 DataSize);

  12. #define SEND_BUFF_SIZE 4096
  13. #define SAMPLE_FREQ    6000
  14. #define INIT_FREQ             400
  15. #define MAX_FREQ           3000
  16. #define INC_FREQ       25
  17. u16 ADCDMA_DATA[SEND_BUFF_SIZE];
  18. float fft_inputbuf[SEND_BUFF_SIZE*2];        //FFT输入数组
  19. float fft_outputbuf[SEND_BUFF_SIZE];        //FFT输出数组
  20. float  FundamentalFreq;
  21. u16 ExsistingFreq;


  22. int main(void)
  23. {
  24.         u16 led0pwmval=1000000/SAMPLE_FREQ;
  25.         float temp;
  26.         u16 adcx;
  27.         u16 i = 0,j=0,k=0;
  28.         u16 ExsistingPwmCount;
  29.         u8 INC_FREQ_Flag = 0;
  30.         arm_cfft_radix4_instance_f32 scfft;
  31.         FundamentalFreq = 0;
  32.         ExsistingFreq = INIT_FREQ;
  33. //        u8 dir=1;
  34.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
  35.         delay_init(168);  //初始化延时函数
  36.         uart_init(115200);//初始化串口波特率为115200
  37.         LED_Init();
  38.         LCD_Init();
  39.          
  40.         Adc_Init();
  41.         MYDMA_Config(DMA2_Stream0,DMA_Channel_0,(u32)&ADC1->DR,(u32)ADCDMA_DATA,SEND_BUFF_SIZE);
  42.         TIM3_PWM_Init(led0pwmval-1,84-1);        //84M/84=1Mhz的计数频率,重装载值500,所以PWM频率为 1M/500=2Khz.
  43.     TIM_SetCompare1(TIM3,led0pwmval/2);        //修改比较值,修改占空比
  44.         
  45. //        ExsistingFreq = 814;
  46. //        ExsistingFreq = INIT_FREQ;
  47. //        ExsistingPwmCount = 100000/ExsistingFreq;
  48. //        TIM14_PWM_Init(ExsistingPwmCount-1,840-1);        //84M/840=100Khz的计数频率,重装载值25,所以PWM频率为 100K/ExsistingFreq=5KHz.
  49. //    TIM_SetCompare1(TIM14,ExsistingPwmCount/2);        //修改比较值,修改占空比
  50.         
  51.         arm_cfft_radix4_init_f32(&scfft,SEND_BUFF_SIZE,0,1);//初始化scfft结构体,设定FFT相关参数
  52.         POINT_COLOR=RED;
  53.         LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");        
  54.         LCD_ShowString(30,70,200,16,16,"ADC TEST");        
  55.         LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
  56.         LCD_ShowString(30,110,200,16,16,"2014/5/6");         
  57.         POINT_COLOR=BLUE;//设置字体为蓝色
  58.         LCD_ShowString(30,130,200,16,16,"ADC1_CH5_VAL:");              
  59.         LCD_ShowString(30,150,200,16,16,"ADC1_CH5_VOL:0.000V");        //先在固定位置显示小数点  
  60.         
  61. //        //初始化扫频
  62. //        for(i=0;i<(MAX_FREQ-INIT_FREQ)/INC_FREQ;i++)
  63. //        {
  64. //                ExsistingFreq = INIT_FREQ+i*INC_FREQ;
  65. //                ExsistingPwmCount = 100000/ExsistingFreq;
  66. //                TIM14_PWM_Init(ExsistingPwmCount-1,840-1);        
  67. //                TIM_SetCompare1(TIM14,ExsistingPwmCount/2);
  68. //                TIM_Cmd(TIM14, ENABLE);
  69. //                delay_ms(10);
  70. //                TIM_Cmd(TIM14, DISABLE);
  71. //        }
  72. //        delay_ms(100);
  73. //        printf("The %d times:\r\n",j);
  74. //                //开始采样
  75. //        ADC_Cmd(ADC1,ENABLE);
  76. //        //等待采样完成
  77. //        while(DMA_GetFlagStatus(DMA2_Stream0,DMA_FLAG_TCIF0)==RESET);
  78. //        //DMA传输完成,清除标志位,等待下次DMA传输
  79. //        DMA_ClearFlag(DMA2_Stream0,DMA_FLAG_TCIF0);//清除DMA2_Steam7传输完成标志
  80. //        //禁止ADC转换,计算传感器频率
  81. //        ADC_Cmd(ADC1,DISABLE);
  82. //        LED0 = !LED0;
  83. //        for(k=0;k<SEND_BUFF_SIZE;k++)
  84. //        {
  85. //                fft_inputbuf[2*k] =(float)(ADCDMA_DATA[k]*(3.3/4096));
  86. //                fft_inputbuf[2*k+1] = 0;
  87. //        }
  88. //        //计算频率,傅里叶变换
  89. //        arm_cfft_radix4_f32(&scfft,fft_inputbuf);        //FFT计算(基4)        
  90. //        arm_cmplx_mag_f32(fft_inputbuf,fft_outputbuf,SEND_BUFF_SIZE);        //把运算结果复数求模得幅值
  91. //        //计算基频
  92. //        FundamentalFreq = CalMax_FREQ(fft_outputbuf,SEND_BUFF_SIZE/2);
  93. //        //得到初始频率
  94. //        ExsistingFreq = FundamentalFreq;
  95. //        printf("FFT Result:\r\n");
  96. //        printf("The Calculate Fundamental Frequency: %f\r\n",FundamentalFreq);
  97. //        
  98. //        k=0;
  99.         
  100.     while(1) //实现比较值从0-300递增,到300后从300-0递减,循环
  101.         {
  102.                         
  103.                 adcx = ADCDMA_DATA[SEND_BUFF_SIZE-1];
  104.                 LCD_ShowxNum(134,130,adcx,4,16,0);    //显示ADCC采样后的原始值
  105.                 temp=(float)adcx*(3.3/4096);          //获取计算后的带小数的实际电压值,比如3.1111
  106.                 adcx=temp;                            //赋值整数部分给adcx变量,因为adcx为u16整形
  107.                 LCD_ShowxNum(134,150,adcx,1,16,0);    //显示电压值的整数部分,3.1111的话,这里就是显示3
  108.                 temp-=adcx;                           //把已经显示的整数部分去掉,留下小数部分,比如3.1111-3=0.1111
  109.                 temp*=1000;                           //小数部分乘以1000,例如:0.1111就转换为111.1,相当于保留三位小数。
  110.                 LCD_ShowxNum(150,150,temp,3,16,0X80); //显示小数部分(前面转换为了整形显示),这里显示的就是111.

  111. //                //激励
  112. ////                ExsistingFreq = 810;
  113. //                ExsistingPwmCount = 100000/ExsistingFreq;
  114. //                TIM14_PWM_Init(ExsistingPwmCount-1,840-1);        
  115. //                TIM_SetCompare1(TIM14,ExsistingPwmCount/2);
  116. //                TIM_Cmd(TIM14, ENABLE);  //使能TIM14
  117. //                //激励50ms
  118. //                delay_ms(50);
  119. //                //停止激励
  120. ////                TIM_Cmd(TIM14, DISABLE);  
  121. //                //延时200ms采样,去除波形不稳定时波形对采样结果影响
  122. //                delay_ms(100);
  123. //                //开始采样
  124. //                ADC_Cmd(ADC1,ENABLE);
  125. //                //等待采样完成
  126. //                while(DMA_GetFlagStatus(DMA2_Stream0,DMA_FLAG_TCIF0)==RESET);
  127. //                //DMA传输完成,清除标志位,等待下次DMA传输
  128. //                DMA_ClearFlag(DMA2_Stream0,DMA_FLAG_TCIF0);//清除DMA2_Steam7传输完成标志
  129. //                //禁止ADC转换,计算传感器频率
  130. //                ADC_Cmd(ADC1,DISABLE);
  131. //                LED0 = !LED0;
  132. //                for(i=0;i<SEND_BUFF_SIZE;i++)
  133. //                {
  134. //                        fft_inputbuf[2*i] =(float)(ADCDMA_DATA[i]*(3.3/4096));
  135. //                        fft_inputbuf[2*i+1] = 0;
  136. //                }
  137. //                //计算频率,傅里叶变换
  138. //                arm_cfft_radix4_f32(&scfft,fft_inputbuf);        //FFT计算(基4)        
  139. //                arm_cmplx_mag_f32(fft_inputbuf,fft_outputbuf,SEND_BUFF_SIZE);        //把运算结果复数求模得幅值
  140. //                //计算基频
  141. //                FundamentalFreq = CalMax_FREQ(fft_outputbuf,SEND_BUFF_SIZE/2);
  142. //                printf("FFT Result:\r\n");
  143. //                printf("The Calculate Fundamental Frequency: %f\r\n",FundamentalFreq);
  144. //               
  145. //                //判断是否起振
  146. //                if(FundamentalFreq>(ExsistingFreq-INC_FREQ/2)&&FundamentalFreq<(ExsistingFreq+INC_FREQ/2))
  147. //                {
  148. //                        //起振成功,保留起振频率
  149. //                        ExsistingFreq = (u16)FundamentalFreq;
  150. //                        printf("FFT Result:\r\n");
  151. //                        printf("The ExsistingFreq Frequency: %d\r\n",ExsistingFreq);
  152. //                }
  153. //                else
  154. //                {        
  155.                         if((FundamentalFreq>ExsistingFreq-INC_FREQ/2)&&(FundamentalFreq<ExsistingFreq+INC_FREQ/2))
  156.                         {
  157.                                 printf("Frequency is correct: \r\n");
  158.                                 k=0;
  159.                         }
  160.                         else
  161.                         {
  162.                                 k=1;
  163.                         }
  164.                         //起振失败,扫频
  165.                         //初始化扫频
  166.                         if(k==1)
  167.                         {
  168.                                 printf("Initial Scan Frequency:\r\n");
  169.                                 for(i=0;i<(MAX_FREQ-INIT_FREQ)/INC_FREQ;i++)
  170.                                 {
  171.                                         ExsistingFreq = INIT_FREQ+i*INC_FREQ;
  172.                                         ExsistingPwmCount = 100000/ExsistingFreq;
  173.                                         TIM14_PWM_Init(ExsistingPwmCount-1,840-1);        
  174.                                         TIM_SetCompare1(TIM14,ExsistingPwmCount/2);
  175.                                         TIM_Cmd(TIM14, ENABLE);
  176.                                         delay_ms(10);
  177.                                         TIM_Cmd(TIM14, DISABLE);
  178.                                 }
  179. //                        delay_ms(100);
  180. //                        printf("The %d times:\r\n",j);
  181. //                                //开始采样
  182. //                        ADC_Cmd(ADC1,ENABLE);
  183. //                        //等待采样完成
  184. //                        while(DMA_GetFlagStatus(DMA2_Stream0,DMA_FLAG_TCIF0)==RESET);
  185. //                        //DMA传输完成,清除标志位,等待下次DMA传输
  186. //                        DMA_ClearFlag(DMA2_Stream0,DMA_FLAG_TCIF0);//清除DMA2_Steam7传输完成标志
  187. //                        //禁止ADC转换,计算传感器频率
  188. //                        ADC_Cmd(ADC1,DISABLE);
  189. //                        LED0 = !LED0;
  190. //                        for(k=0;k<SEND_BUFF_SIZE;k++)
  191. //                        {
  192. //                                fft_inputbuf[2*k] =(float)(ADCDMA_DATA[k]*(3.3/4096));
  193. //                                fft_inputbuf[2*k+1] = 0;
  194. //                        }
  195. //                        //计算频率,傅里叶变换
  196. //                        arm_cfft_radix4_f32(&scfft,fft_inputbuf);        //FFT计算(基4)        
  197. //                        arm_cmplx_mag_f32(fft_inputbuf,fft_outputbuf,SEND_BUFF_SIZE);        //把运算结果复数求模得幅值
  198. //                        //计算基频
  199. //                        FundamentalFreq = CalMax_FREQ(fft_outputbuf,SEND_BUFF_SIZE/2);
  200. //                        //得到初始频率
  201. //                        ExsistingFreq = (u16)FundamentalFreq;
  202. //                        printf("FFT Result:\r\n");
  203. //                        printf("The ExsistingFreq Frequency: %d\r\n",ExsistingFreq);
  204.                 }
  205.                 else      //正常激励
  206.                 {
  207. //                        ExsistingFreq = FundamentalFreq;
  208.                         ExsistingPwmCount = 100000/ExsistingFreq;
  209.                         TIM14_PWM_Init(ExsistingPwmCount-1,840-1);        
  210.                         TIM_SetCompare1(TIM14,ExsistingPwmCount/2);
  211.                         TIM_Cmd(TIM14, ENABLE);
  212.                         delay_ms(100);
  213.                         TIM_Cmd(TIM14, DISABLE);
  214. //                        delay_ms(100);
  215. //                        printf("The %d times:\r\n",j);
  216. //                                //开始采样
  217. //                        ADC_Cmd(ADC1,ENABLE);
  218. //                        //等待采样完成
  219. //                        while(DMA_GetFlagStatus(DMA2_Stream0,DMA_FLAG_TCIF0)==RESET);
  220. //                        //DMA传输完成,清除标志位,等待下次DMA传输
  221. //                        DMA_ClearFlag(DMA2_Stream0,DMA_FLAG_TCIF0);//清除DMA2_Steam7传输完成标志
  222. //                        //禁止ADC转换,计算传感器频率
  223. //                        ADC_Cmd(ADC1,DISABLE);
  224. //                        LED0 = !LED0;
  225. //                        for(k=0;k<SEND_BUFF_SIZE;k++)
  226. //                        {
  227. //                                fft_inputbuf[2*k] =(float)(ADCDMA_DATA[k]*(3.3/4096));
  228. //                                fft_inputbuf[2*k+1] = 0;
  229. //                        }
  230. //                        //计算频率,傅里叶变换
  231. //                        arm_cfft_radix4_f32(&scfft,fft_inputbuf);        //FFT计算(基4)        
  232. //                        arm_cmplx_mag_f32(fft_inputbuf,fft_outputbuf,SEND_BUFF_SIZE);        //把运算结果复数求模得幅值
  233. //                        //计算基频
  234. //                        FundamentalFreq = CalMax_FREQ(fft_outputbuf,SEND_BUFF_SIZE/2);
  235. //                        //得到初始频率
  236. //                        ExsistingFreq = (u16)FundamentalFreq;
  237. //                        printf("FFT Result:\r\n");
  238. //                        printf("The ExsistingFreq Frequency: %d\r\n",ExsistingFreq);
  239.                 }
  240. //                }
  241.                 delay_ms(100);
  242.                         printf("The %d times:\r\n",j);
  243.                                 //开始采样
  244.                         ADC_Cmd(ADC1,ENABLE);
  245.                         //等待采样完成
  246.                         while(DMA_GetFlagStatus(DMA2_Stream0,DMA_FLAG_TCIF0)==RESET);
  247.                         //DMA传输完成,清除标志位,等待下次DMA传输
  248.                         DMA_ClearFlag(DMA2_Stream0,DMA_FLAG_TCIF0);//清除DMA2_Steam7传输完成标志
  249.                         //禁止ADC转换,计算传感器频率
  250.                         ADC_Cmd(ADC1,DISABLE);
  251.                         LED0 = !LED0;
  252.                         for(k=0;k<SEND_BUFF_SIZE;k++)
  253.                         {
  254.                                 fft_inputbuf[2*k] =(float)(ADCDMA_DATA[k]*(3.3/4096));
  255.                                 fft_inputbuf[2*k+1] = 0;
  256.                         }
  257.                         //计算频率,傅里叶变换
  258.                         arm_cfft_radix4_f32(&scfft,fft_inputbuf);        //FFT计算(基4)        
  259.                         arm_cmplx_mag_f32(fft_inputbuf,fft_outputbuf,SEND_BUFF_SIZE);        //把运算结果复数求模得幅值
  260.                         //计算基频
  261.                         FundamentalFreq = CalMax_FREQ(fft_outputbuf,SEND_BUFF_SIZE/2);
  262.                         for(i=0;i<10;i++)
  263.                         {
  264.                                 if(fft_inputbuf[2*i])
  265.                                 {
  266.                                         INC_FREQ_Flag = 0;
  267.                                 }
  268.                                 else
  269.                                 {
  270.                                         INC_FREQ_Flag = 1;
  271.                                 }        
  272.                         }
  273.                         if(0 == INC_FREQ_Flag)
  274.                         {
  275.                                 //更新激励频率
  276.                                 ExsistingFreq = (u16)FundamentalFreq;
  277.                         }
  278. //                        //得到初始频率
  279. //                        ExsistingFreq = (u16)FundamentalFreq;
  280.                         printf("FFT Result:\r\n");
  281.                         printf("The ExsistingFreq Frequency: %d\r\n",ExsistingFreq);
  282.                 //串口打印频率
  283.                 printf("FFT Result:\r\n");
  284.                 printf("The Fundamental Frequency: %f\r\n",FundamentalFreq);
  285.                
  286.                 delay_ms(1000);
  287.                 //使能激励信号
  288. //                TIM_Cmd(TIM14, ENABLE);  //使能TIM14
  289. //                delay_ms(50);        
  290.                
  291.         }
  292. }


  293. float CalMax_FREQ(float *Data, u16 DataSize)
  294. {
  295.         u16 i;
  296.         u16 MaxIndex = 1;
  297.         float CalFreq = 0;
  298.         for(i=1;i<DataSize;i++)
  299.         {
  300. //                printf("%f\r\n",Data[i]);
  301.                 if(Data[i]>Data[MaxIndex])
  302.                 {
  303.                         MaxIndex = i;
  304.                 }
  305.         }
  306.         CalFreq =  (float)MaxIndex* SAMPLE_FREQ/SEND_BUFF_SIZE;
  307.         return CalFreq;
  308. }

复制代码

全部资料51hei下载地址:

定时ADC+DMA +FFT-0118.rar (1.12 MB, 下载次数: 245)


评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏6 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:354404 发表于 2018-8-5 12:42 | 只看该作者
这个能把能不能采集到频率啊!!!!!
回复

使用道具 举报

板凳
ID:267330 发表于 2018-9-20 13:35 | 只看该作者
这个能把能不能采集到频率啊!!!!!
回复

使用道具 举报

地板
ID:267330 发表于 2018-9-20 13:35 | 只看该作者
很想学习啊
回复

使用道具 举报

5#
ID:476548 发表于 2019-4-29 17:06 | 只看该作者
希望有用
回复

使用道具 举报

6#
ID:317574 发表于 2019-5-5 09:44 | 只看该作者
非常感谢楼主的分享,现在正在学习
回复

使用道具 举报

7#
ID:465802 发表于 2019-5-14 09:29 | 只看该作者
这个是F4系列的板子呀。。我的是F1的。。
回复

使用道具 举报

8#
ID:68875 发表于 2019-5-16 23:07 | 只看该作者
很想学习啊
回复

使用道具 举报

9#
ID:68875 发表于 2019-5-18 21:57 | 只看该作者
good job
回复

使用道具 举报

10#
ID:68875 发表于 2019-5-18 21:58 | 只看该作者
很想学习
回复

使用道具 举报

11#
ID:68875 发表于 2019-5-21 22:23 | 只看该作者

希望有用
回复

使用道具 举报

12#
ID:403626 发表于 2019-7-3 11:08 | 只看该作者
感谢分享
回复

使用道具 举报

13#
ID:416106 发表于 2019-7-17 16:59 | 只看该作者
感谢分享!!
回复

使用道具 举报

14#
ID:652775 发表于 2019-12-4 17:05 | 只看该作者
资料不错,做个记号
回复

使用道具 举报

15#
ID:652775 发表于 2019-12-13 08:19 | 只看该作者
资料不错,感谢楼主分享
回复

使用道具 举报

16#
ID:447147 发表于 2019-12-23 14:26 | 只看该作者
很想学习啊
回复

使用道具 举报

17#
ID:658039 发表于 2019-12-24 19:30 | 只看该作者
本人对傅里叶一窍不通,希望能有所 了解,学习了。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表