[经验分享] 单片机AD采样,然后FFT变换程序

[复制链接]
3351|50
 楼主| ulystronglll 发表于 2023-8-26 19:44 | 显示全部楼层 |阅读模式
用单片机对模拟信号进行转换,转换后做FFT快速傅里叶变换。
  1. #include<math.h>

  2. #define SYSCLK 11000000
  3. #define  PI 3.1415926536
  4. #define  size_x  1024

  5. sfr16 ADC0 = 0xbe;

  6. typedef struct{
  7.      float real;
  8.      float img;
  9. }complex;

  10. complex W[512];
  11. complex xdata x[1024];
  12. float p=0;                                                           //总功率
  13. unsigned int h;

  14. void SYSCLK_Init (void)
  15. {
  16.    int i;                              // delay counter
  17.    OSCXCN = 0x67;                      // start external oscillator with
  18.                                        // 11MHz crystal
  19.    for (i=0; i < 256; i++) ;           // Wait for osc. to start up
  20.    while (!(OSCXCN & 0x80)) ;          // Wait for crystal osc. to settle
  21.    OSCICN = 0x88;                      // select external oscillator as SYSCLK
  22.                                        // source and enable missing clock
  23.                                        // detector
  24. //        OSCICN = 0x07;   //interal 16MHZ
  25. }
  26. void WDT_Init()
  27. {
  28. WDTCN = 0xde;
  29. WDTCN = 0xad;
  30. }
  31. void T3_Init()                                                      //定时48.8us
  32. {
  33. TMR3CN=0x02;
  34. TMR3RLL=(65536-540)%256;
  35. TMR3RLH=(65536-540)/256;
  36. TMR3L=(65536-540)%256;
  37. TMR3H=(65536-540)/256;
  38. TMR3CN|=0X04;                                                          //启动定时器
  39. }
  40. void ADC_Init()
  41. {
  42. AMX0CF=0X00;                                                          //通道0
  43. AMX0SL=0X00;
  44. ADC0CF = (SYSCLK/2500000) << 3;               //SAR时钟为2.5mhz
  45. ADC0CN = 0x84;                                                          //定时器3方式启动
  46. REF0CN = 0x03;
  47. EA=1;
  48. EIE2|=0X02;                    
  49. EIE1&= ~0x04;
  50. }
  51. void ADC0_ISR() interrupt 15
  52. {
  53. ADC0CN&=0xdf;
  54. x[h].real=ADC0;
  55. h++;
  56. }
  57. void add(complex a,complex b,complex *c)
  58. {
  59.      c->real=a.real+b.real;
  60.      c->img=a.img+b.img;
  61. }
  62. void mul(complex a,complex b,complex *c)
  63. {
  64.      c->real=a.real*b.real - a.img*b.img;
  65.      c->img=a.real*b.img + a.img*b.real;
  66. }
  67. void sub(complex a,complex b,complex *c)
  68. {
  69.      c->real=a.real-b.real;
  70.      c->img=a.img-b.img;
  71. }
  72. void change()                                                                                                  //倒位序
  73. {
  74.   unsigned int i=0,j=0,k=0,t;
  75.   complex temp;
  76.   for(i=0;i<size_x;i++)
  77.   {
  78.     k=i;j=0;
  79.         t=(unsigned) (log(size_x)/log(2));
  80.     while(t--)
  81.         {
  82.        j=j<<1;
  83.        j|=(k & 1);                                                                                         
  84.        k=k>>1;
  85.     }
  86.     if(j>i)
  87.         {
  88.        temp=x[i];
  89.        x[i]=x[j];
  90.        x[j]=temp;
  91.     }
  92.   }                                                                                          
  93. }                                                                                                                         //计算旋转因子
  94. void init_W()                                                                                
  95. {
  96. int i;
  97. for(i=0;i<(size_x/2);i++)
  98. {
  99.    W[i].real=cos(2*PI/size_x*i);
  100.    W[i].img=-1*sin(2*PI/size_x*i);
  101.                   
  102. }
  103. }
  104. void FFT()
  105. {
  106.      unsigned int i=0,j=0,k=0,l=0;
  107.      complex up,down;
  108.      change();                                                                                                                          //倒位序
  109.          init_W();                                                                                                                          //计算旋转因子
  110.      for(i=0;i<(int)( log(size_x)/log(2) );i++)                                                          //一级蝶形运算
  111.          {                     
  112.            l=( 1<<i );                                                                                                         
  113.            for(j=0;j<size_x;j+=(1<<(i+1)))                                                                  //一组蝶形运算
  114.                    {                              
  115.                  for(k=0;k<l;k++)
  116.                                  {                                                                                                                  //一个蝶形运算
  117.                                                                      
  118.                         mul(x[j+k+l],W[size_x*k/2/l],&up);
  119.                         add(x[j+k],up,&up);
  120.                         mul(x[j+k+l],W[size_x*k/2/l],&down);
  121.                         sub(x[j+k],down,&down);
  122.                         x[j+k]=up;
  123.                         x[j+k+l]=down;
  124.                  }
  125.            }
  126.      }
  127. }
  128. void PSD()                                                                                             //功率谱
  129. {
  130. unsigned int i;
  131. for(i=0;i<size_x;i++)
  132. {                        
  133.   x[i].real=(1/1024.0)*(x[i].real*x[i].real+x[i].img*x[i].img);
  134.   x[i].img=0;
  135. }
  136. }
  137. void ZP()                                                                                           //总功率
  138. {
  139.   int i;
  140.   for(i=0;i<size_x;i++)
  141. {p+=x[i].real*x[i].real;}
  142.   p=(1/1024.0)*p;
  143. }                                                                                                           //转电压
  144. void ZDY()
  145. {
  146. unsigned int i;
  147. for(i=0;i<1024;i++)
  148. {
  149.   x[i].real=(1/4096.0)*x[i].real*2.4;
  150. }
  151. }
  152. void main()
  153. {
  154.   WDT_Init();
  155.   SYSCLK_Init();
  156.   ADC_Init();
  157.   T3_Init();
  158.   while(h==1024)
  159.   {
  160.    TMR3CN&=0xfb;
  161.    ZDY();
  162.    ZP();
  163.    FFT();
  164.    PSD();
  165.    h=0;
  166.    TMR3CN|=0x04;
  167.   }
  168. }


modesty3jonah 发表于 2023-9-12 16:01 | 显示全部楼层
采样频率应足够高以捕获所需的信号频率成分,而采样深度决定了采样精度。确保选择的参数在单片机硬件支持的范围内。
hearstnorman323 发表于 2023-9-12 17:11 | 显示全部楼层
需要选择合适的FFT变换算法,例如快速傅里叶变换(FFT)或离散傅里叶变换(DFT)。
febgxu 发表于 2023-9-12 19:27 | 显示全部楼层
FFT变换是一种快速傅里叶变换算法,可以对数字信号进行频域分析和滤波。
sdCAD 发表于 2023-9-13 10:49 | 显示全部楼层
在进行AD采样时,需要注意采样速率、采样位数和采样范围等参数,以确保采样结果的准确性。
youtome 发表于 2023-9-13 11:09 | 显示全部楼层
对于模拟信号,需要使用模拟信号数据类型;对于数字信号,需要使用数字信号数据类型。
juliestephen 发表于 2023-9-13 11:58 | 显示全部楼层
选择合适的FFT算法以满足性能和资源要求。常见的FFT算法包括快速傅里叶变换(FFT)和快速**玛变换(FHT)。根据单片机的处理能力和存储空间,选择适当的算法和优化策略。
deliahouse887 发表于 2023-9-13 12:26 | 显示全部楼层
在使用ADC时,需要注意不要超出芯片的测量范围和存储容量;在使用FFT算法时,需要注意不要超出芯片的计算能力。
lzmm 发表于 2023-9-13 14:10 | 显示全部楼层
单片机系统中的电源稳定性和噪声抑制也是关键因素。
ingramward 发表于 2023-9-13 16:36 | 显示全部楼层
采样数据可以是实数或复数形式,根据需要选择合适的数据格式。在进行FFT变换之前,可能需要进行预处理
geraldbetty 发表于 2023-9-13 17:20 | 显示全部楼层
考虑到可能出现的错误和异常情况,设计适当的错误处理机制,以确保系统的稳定性和可靠性。
biechedan 发表于 2023-9-13 18:04 | 显示全部楼层
可能需要采取一些措施来减少干扰,比如使用屏蔽材料,或者在电路板设计时考虑到电磁兼容性
olivem55arlowe 发表于 2023-9-13 18:12 | 显示全部楼层
对FFT变换结果进行处理,例如进行数据滤波、数据压缩等。
ccook11 发表于 2023-9-13 18:28 | 显示全部楼层
考虑噪声源、信号处理和滤波技术,以提高信噪比和减小噪声对FFT结果的影响。
janewood 发表于 2023-9-13 18:44 | 显示全部楼层
选择合适的FFT变换数据类型,例如浮点数或定点数。
wengh2016 发表于 2023-9-13 19:04 | 显示全部楼层
在进行FFT变换之前,通常需要对采样数据进行预处理,如去直流分量、滤波等。这可以帮助提高FFT的准确性和性能。
lzmm 发表于 2023-9-13 21:07 | 显示全部楼层
在进行FFT变换时,需要注意输入信号的格式和大小,以确保变换结果的准确性。
10299823 发表于 2023-9-13 21:16 | 显示全部楼层
选择适用于你的单片机平台的FFT库或实现FFT算法
modesty3jonah 发表于 2023-9-13 21:24 | 显示全部楼层
应该使用一个抗混叠滤波器来过滤掉高于采样率一半的频率成分。
everyrobin 发表于 2023-9-13 22:57 | 显示全部楼层
FFT变换后的结果通常是频谱图或功率谱密度图。根据需要,可以对结果进行幅度谱、相位谱、频率分析等进一步处理和显示。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

21

主题

1468

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部