久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 11342|回復: 14
收起左側

C51單片機FFT OLED顯示程序

  [復制鏈接]
ID:460753 發表于 2020-4-8 11:07 | 顯示全部樓層 |閱讀模式
經過10幾天的努力,參考http://www.zg4o1577.cn/bbs/dpj-122556-1.html貼子,終于完成OLED C51頻譜顯示,實際測試頻譜范圍約500Hz-20KHz,64個點約150ms。
制作出來的實物圖如下:
fft1.png

fft2.png Time.png
單片機源程序如下:
  1. /*
  2. 0.芯片為STC15W4K58S4
  3. 1.使用的為IIC OLED,端口為OLED_SDA=P0^1;OLED_SCL=P0^0;
  4. 2.AD輸入為P1^6;
  5. 3.晶振選擇為內置,24M;
  6. */

  7. #include <math.h>
  8. #include "OLED.h"
  9. #define FFT_N 64                                                   //定義福利葉變換的點數
  10. #define PI 3.1415926535897932384626433832795028841971               //定義圓周率值
  11. #define Process_sensitivity        0                                                                                //修改Process_sensitivity的數值個調整頻譜變化幅度,不建議超過4
  12. unsigned char tmrcnt=0;
  13. float ADC_OutBuf[FFT_N/4];
  14. struct compx ADC_InBuf[FFT_N];                                      //FFT輸入和輸出:從S[0]開始存放,根據大小自己定義
  15. float SIN_TAB[FFT_N/4+1];                                           //定義正弦表的存放空間
  16. struct compx {float real,imag;};

  17. struct compx EE(struct compx a,struct compx b)      
  18. {
  19. struct compx c;
  20. c.real=a.real*b.real-a.imag*b.imag;
  21. c.imag=a.real*b.imag+a.imag*b.real;
  22. return(c);
  23. }

  24. void create_sin_tab(float *sin_t)                     
  25. {
  26.   int i;
  27.   for(i=0;i<=FFT_N/4;i++)
  28.   sin_t[i]=sin(2*PI*i/FFT_N);
  29. }

  30. float sin_tab(float pi)
  31. {
  32.   int n;
  33.   float a=0;
  34.    n=(int)(pi*FFT_N/2/PI);
  35.    
  36.   if(n>=0&&n<=FFT_N/4)
  37.     a=SIN_TAB[n];
  38.   else if(n>FFT_N/4&&n<FFT_N/2)
  39.     {
  40.      n-=FFT_N/4;
  41.      a=SIN_TAB[FFT_N/4-n];
  42.     }
  43.   else if(n>=FFT_N/2&&n<3*FFT_N/4)
  44.     {
  45.      n-=FFT_N/2;
  46.      a=-SIN_TAB[n];
  47.    }
  48.   else if(n>=3*FFT_N/4&&n<3*FFT_N)
  49.     {
  50.      n=FFT_N-n;
  51.      a=-SIN_TAB[n];
  52.    }
  53.   
  54.   return a;
  55. }

  56. float cos_tab(float pi)
  57. {
  58.    float a,pi2;
  59.    pi2=pi+PI/2;
  60.    if(pi2>2*PI)
  61.      pi2-=2*PI;
  62.    a=sin_tab(pi2);
  63.    return a;
  64. }

  65. void FFT(struct compx *xin)
  66. {
  67.   register int f,m,nv2,nm1,i,k,l,j=0;
  68.   struct compx u,w,t;
  69.    
  70.    nv2=FFT_N/2;                  //變址運算,即把自然順序變成倒位序,采用雷德算法
  71.    nm1=FFT_N-1;  
  72.    for(i=0;i<nm1;i++)        
  73.    {
  74.     if(i<j)                    //如果i<j,即進行變址
  75.      {
  76.       t=xin[j];           
  77.       xin[j]=xin[i];
  78.       xin[i]=t;
  79.      }
  80.     k=nv2;                    //求j的下一個倒位序
  81.     while(k<=j)               //如果k<=j,表示j的最高位為1   
  82.      {           
  83.       j=j-k;                 //把最高位變成0
  84.       k=k/2;                 //k/2,比較次高位,依次類推,逐個比較,直到某個位為0
  85.      }
  86.    j=j+k;                   //把0改為1
  87.   }
  88.                         
  89.   {
  90.    int le,lei,ip;                            //FFT運算核,使用蝶形運算完成FFT運算
  91.     f=FFT_N;
  92.    for(l=1;(f=f/2)!=1;l++)                  //計算l的值,即計算蝶形級數
  93.            ;
  94.   for(m=1;m<=l;m++)                         // 控制蝶形結級數
  95.    {                                        //m表示第m級蝶形,l為蝶形級總數l=log(2)N
  96.     le=2<<(m-1);                            //le蝶形結距離,即第m級蝶形的蝶形結相距le點
  97.     lei=le/2;                               //同一蝶形結中參加運算的兩點的距離
  98.     u.real=1.0;                             //u為蝶形結運算系數,初始值為1
  99.     u.imag=0.0;
  100.     w.real=cos_tab(PI/lei);                //w為系數商,即當前系數與前一個系數的商
  101.     w.imag=-sin_tab(PI/lei);
  102.     for(j=0;j<=lei-1;j++)                  //控制計算不同種蝶形結,即計算系數不同的蝶形結
  103.      {
  104.       for(i=j;i<=FFT_N-1;i=i+le)           //控制同一蝶形結運算,即計算系數相同蝶形結
  105.        {
  106.         ip=i+lei;                          //i,ip分別表示參加蝶形運算的兩個節點
  107.         t=EE(xin[ip],u);                   //蝶形運算,詳見公式
  108.         xin[ip].real=xin[i].real-t.real;
  109.         xin[ip].imag=xin[i].imag-t.imag;
  110.         xin[i].real=xin[i].real+t.real;
  111.         xin[i].imag=xin[i].imag+t.imag;
  112.        }
  113.       u=EE(u,w);                          //改變系數,進行下一個蝶形運算
  114.      }
  115.    }
  116.   }
  117.   
  118. }
  119. void Timer0Init(void)                //1毫秒@24.000MHz
  120. {
  121.         AUXR |= 0x80;                //定時器時鐘1T模式
  122.         TMOD &= 0xF0;                //設置定時器模式
  123.         TL0 = 0x40;                //設置定時初值
  124.         TH0 = 0xA2;                //設置定時初值
  125.         TF0 = 0;                //清除TF0標志
  126.         TR0 = 1;                //定時器0開始計時
  127.         ET0 = 1;
  128. }
  129. void Delay(unsigned short n)
  130. {
  131.     unsigned short x;

  132.     while (n--)
  133.     {
  134.         x = 5000;
  135.         while (x--);
  136.     }
  137. }
  138. void InitADC()
  139. {
  140.     P1ASF = 0xff;                   //設置P1口為AD口
  141.     ADC_CONTR =0x80|0x60;
  142.     Delay(2);                       //ADC上電并延時
  143. }
  144. unsigned short GetADCResult(unsigned char ch)//ch為輸入端口
  145. {
  146.         ADC_RES = 0;
  147.         ADC_RESL = 0;
  148.     ADC_CONTR =0x80|0x60|ch|0x08;
  149.     _nop_();                        
  150.     _nop_();
  151.     _nop_();
  152.     _nop_();
  153.     while (!(ADC_CONTR & 0x10));
  154.     ADC_CONTR &= ~0x10;         
  155.     return ((unsigned short)(ADC_RES<<2)+ADC_RESL);
  156. }
  157. void processfft(void)
  158. {
  159.         unsigned char data pt=0,i,high,x,temp,p,j;
  160.         for(pt=0;pt<(FFT_N);pt++)
  161.         {
  162.                 ADC_InBuf[pt].imag=0;
  163.         }

  164.         FFT(ADC_InBuf);

  165.         for(pt=2,i=0;pt<(FFT_N/2+1);pt+=2)
  166.         {
  167.                 ADC_OutBuf[i++] = sqrt(ADC_InBuf[pt].real*ADC_InBuf[pt].real+ADC_InBuf[pt].imag*ADC_InBuf[pt].imag);
  168.         }

  169.         for(i=0;i<(FFT_N/4);i++)
  170.         {
  171.                 high=(((unsigned char)ADC_OutBuf[i])>>Process_sensitivity);//修改Process_sensitivity的數值個調整頻譜變化幅度,不建議超過4
  172.                 for(x=0;x<8;x++)
  173.                 {
  174.                         OLED_SetPos(i*8,7-x);
  175.                         temp=0x00;
  176.                         for(j=0;j<8;j++)
  177.                         {
  178.                                 OLED_WriteData(temp);
  179.                         }
  180.                 }
  181.                 if(high>64)high=64;
  182.                 if(high==0)high=1;
  183.                 p=high/8;
  184.                 for(x=0;x<p;x++)
  185.                 {
  186.                         OLED_SetPos(i*8,7-x);
  187.                         temp=0xff;
  188.                         for(j=0;j<7;j++)
  189.                         {
  190.                                 OLED_WriteData(temp);
  191.                         }
  192.                 }
  193.                 OLED_SetPos(i*8,7-(high/8));
  194.                 temp=~0xff>>(high%8);
  195.                 for(j=0;j<7;j++)
  196.                 {
  197.                         OLED_WriteData(temp);
  198.                 }
  199.         }
  200. }
  201. void main()
  202. {
  203.         unsigned char i;
  204.         P0M1=0x00;
  205.         P0M0=0x00;
  206.         P1M1=0xc0; //設定AD輸入為P16/P17,實際只用了P16
  207.         P1M0=0x00;
  208.         EA=1;
  209.         Oled_Init();
  210.         Timer0Init();
  211.         InitADC();
  212.         create_sin_tab(SIN_TAB);
  213.         while(1)
  214.         {
  215.                 if(tmrcnt>=70)
  216.                 {
  217.                         P55=1;
  218.                         for(i=0;i<(FFT_N);i++)
  219.                         {  
  220.                                 ADC_InBuf[i].real=((GetADCResult(6))<<Process_sensitivity);//修改Process_sensitivity的數值個調整頻譜變化幅度,不建議超過4
  221.                         }
  222.                         
  223.                         processfft();
  224.                         P55=0;
  225.                         tmrcnt=0;
  226.                 }
  227.         }
  228. }
  229. void Time0() interrupt 1
  230. {
  231.         tmrcnt++;
  232. }
復制代碼
fft5.png
fft4.png
fft3.png

code.rar

65.44 KB, 下載次數: 224, 下載積分: 黑幣 -5

評分

參與人數 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

回復

使用道具 舉報

ID:582255 發表于 2020-4-17 22:23 | 顯示全部樓層
樓主有仿真不
回復

使用道具 舉報

ID:169891 發表于 2021-7-27 09:40 | 顯示全部樓層
正需要用到FFT,謝謝樓主
回復

使用道具 舉報

ID:206695 發表于 2021-8-1 14:50 | 顯示全部樓層
樓主能說說怎么用嗎
回復

使用道具 舉報

ID:422023 發表于 2021-9-23 21:59 | 顯示全部樓層
可否注釋下processfft()里的每是怎么來的。得出的結果又是什么?
回復

使用道具 舉報

ID:156220 發表于 2022-7-2 09:32 | 顯示全部樓層
參考參考,謝謝樓主的分享
回復

使用道具 舉報

ID:962396 發表于 2022-7-2 11:29 | 顯示全部樓層

學習,謝謝樓主無私的分享
回復

使用道具 舉報

ID:164385 發表于 2022-7-3 12:05 | 顯示全部樓層
親,半年報把那兩個工具也共享一下?謝謝!
回復

使用道具 舉報

ID:1063066 發表于 2023-2-14 22:37 | 顯示全部樓層
不錯 可以參考一下
回復

使用道具 舉報

ID:1063621 發表于 2023-7-15 17:42 | 顯示全部樓層
你好,這個代碼怎樣設置頻率,我想把顯示的頻率做更低一些60Hz-20K
回復

使用道具 舉報

ID:285069 發表于 2023-7-16 09:38 | 顯示全部樓層
謝謝樓主無私的分享
回復

使用道具 舉報

ID:460753 發表于 2023-7-18 08:03 | 顯示全部樓層
7631001 發表于 2022-7-3 12:05
親,半年報把那兩個工具也共享一下?謝謝!

兩個工具,一個是音頻信號發生器,一個是邏輯分析儀。上傳了信號發生器,邏輯分析議我用的是金沙灘的,百度一下即可。

WaveGen3.8.rar

109.63 KB, 下載次數: 13, 下載積分: 黑幣 -5

回復

使用道具 舉報

ID:582109 發表于 2023-7-22 22:28 | 顯示全部樓層
有時間研究一下
回復

使用道具 舉報

ID:1017706 發表于 2023-9-15 17:13 | 顯示全部樓層
剛好可以來測試一下,謝謝分享
回復

使用道具 舉報

ID:1098277 發表于 2023-11-2 22:36 | 顯示全部樓層
STC15W4K58S4 支持float 類型嗎?
是否可以直接在不支持float上跑
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 毛片免费在线 | 国产精品一码二码三码在线 | 九九伦理片 | 国产精品视频在线观看 | 欧美高清视频一区 | 国产欧美日韩一区二区三区在线 | 国产亚洲一级 | 亚洲视频二区 | 久久久久久久久久久久久久久久久久久久 | 中文字幕日本一区二区 | 亚洲精品久久视频 | 亚洲一区免费视频 | 日韩视频成人 | 在线成人一区 | 日本亚洲欧美 | 国产精品污www一区二区三区 | 亚洲成人中文字幕 | 欧美精品黄 | 天天拍天天操 | caoporn国产 | 欧美视频在线看 | 精品一区二区三区在线视频 | 久久精品二区 | 国产成人精品一区二区三区四区 | 97国产成人 | 国产精品视频导航 | 亚洲成色777777在线观看影院 | 日韩国产免费观看 | 久久国产精品精品 | 久久9999久久| 日韩在线观看中文字幕 | 久久久人成影片一区二区三区 | 成人免费小视频 | 男人天堂国产 | 中文字幕亚洲区一区二 | www.亚洲精品 | 无码日韩精品一区二区免费 | 久久久久久亚洲 | 91社区在线观看 | 成人h动漫精品一区二区器材 | 久久免费视频在线 |