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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 9999|回復(fù): 7
收起左側(cè)

STM32+咪頭+OLED12864音樂LED頻譜制作 附程序

  [復(fù)制鏈接]
ID:575440 發(fā)表于 2019-7-1 10:29 | 顯示全部樓層 |閱讀模式
制作過程:
1.準(zhǔn)備材料:
stm32f103核心板 1塊
OLED12864顯示屏 1塊(SPI接口)
聲音檢測傳感器 1塊 (咪頭+放大電路 可以網(wǎng)上買現(xiàn)成的模塊,也可根據(jù)后文提供的原理圖自己做)
2.硬件連接:
(1)OLED連接:
OLED_SCLK   ————  PB7
OLED_SDIN    ————  PB6
OLED_RST     ————  PB5
OLED_RS       ————  PB4
(2)聲音檢測傳感器連接:
直接將模塊的輸出接到單片機(jī)的PA0即可。
OK硬件連接完成!就這么簡單!
3.程序下載
接下來將程序下載到單片機(jī)即可,音樂頻譜就完成了!(別告訴我你連下載程序都不會 滑稽)
程序燒錄文件 鏈接:https://pan.baidu.com/s/1EjKPvBFbTmYzzh6fSn0U5A 密碼:o6uu
程序源碼:https://download.csdn.net/download/mc_li/10601743
ps:以上就是簡單的音樂頻譜制作過程,下面是較為詳細(xì)的制作過程,提供源碼和原理圖,有興趣的同志們可以看看。

單片機(jī)源程序如下:
  1. /* Includes ------------------------------------------------------------------*/
  2. #include "main.h"
  3. #include "stm32f1xx_hal.h"
  4. #include "adc.h"
  5. #include "dma.h"
  6. #include "tim.h"
  7. #include "usart.h"
  8. #include "gpio.h"

  9. /* USER CODE BEGIN Includes */
  10. #include "stm32_dsp.h"
  11. #include "table_fft.h"
  12. #include "math.h"
  13. #include "oled.h"
  14. #include "config.h"
  15. #include "bg.h"
  16. /* USER CODE END Includes */

  17. /* Private variables ---------------------------------------------------------*/

  18. /* USER CODE BEGIN PV */
  19. /* Private variables ---------------------------------------------------------*/
  20. #define NPT 256
  21. #define PI2 6.28318530717959
  22. //采樣率計算
  23. //分辨率:Fs/NPT
  24. //#define Fs        10000
  25. #define Fs        9984
  26. //取9984能出來整數(shù)的分辨率 9984/256 = 39Hz

  27. /* USER CODE END PV */

  28. /* Private function prototypes -----------------------------------------------*/
  29. void SystemClock_Config(void);
  30. void Error_Handler(void);

  31. /* USER CODE BEGIN PFP */
  32. /* Private function prototypes -----------------------------------------------*/
  33. void Creat_Single(void);
  34. void GetPowerMag(void);
  35. void Single_Get(void);
  36. void display1(void);
  37. void display2(void);
  38. void Key_Scan(void);
  39. /* USER CODE END PFP */

  40. /* USER CODE BEGIN 0 */
  41. uint32_t adc_buf[NPT]={0};

  42. long lBufInArray[NPT];
  43. long lBufOutArray[NPT/2];
  44. long lBufMagArray[NPT/2];


  45. uint8_t prt = 10;        //量化顯示的比例
  46. #define SHOW_NUM 4                                //顯示函數(shù)的個數(shù)
  47. uint8_t display_num = 1;        //控制顯示方式的
  48. uint8_t auto_display_flag = 0;        //自動切換顯示標(biāo)志 1:自動切換 0:手動

  49. uint8_t fall_pot[128];        //記錄下落點(diǎn)的坐標(biāo)

  50. /* USER CODE END 0 */

  51. int main(void)
  52. {

  53.   /* USER CODE BEGIN 1 */
  54.         uint16_t i = 0;
  55.   /* USER CODE END 1 */

  56.   /* MCU Configuration----------------------------------------------------------*/

  57.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  58.   HAL_Init();

  59.   /* Configure the system clock */
  60.   SystemClock_Config();

  61.   /* Initialize all configured peripherals */
  62.   MX_GPIO_Init();
  63.   MX_DMA_Init();
  64.   MX_USART1_UART_Init();
  65.   MX_ADC1_Init();
  66.   MX_TIM3_Init();

  67.   /* USER CODE BEGIN 2 */
  68.         printf("uart test! \r\n");
  69.        
  70.         /*初始化顯示*/
  71.         GUI_Initialize();
  72.         /*設(shè)置前景色和背景色 這里用1和0代替*/
  73.         GUI_SetColor(1,0);
  74.         GUI_LoadPic(0,0,(uint8_t *)&gImage_bg,128,64);
  75.         GUI_Exec();
  76.         HAL_Delay(3000);
  77.        
  78.         //初始化下落點(diǎn) 把下落的點(diǎn) 初始化為最底部顯示
  79.         for(i=0;i<128;i++)
  80.                 fall_pot[i] = 63;
  81.        
  82.         /*啟動ADC的DMA傳輸 配合下面定時器來觸發(fā)ADC轉(zhuǎn)換*/
  83.         HAL_ADC_Start_DMA(&hadc1, adc_buf, NPT);
  84.         /*開啟定時器 用溢出事件來觸發(fā)ADC轉(zhuǎn)換*/
  85.         HAL_TIM_Base_Start(&htim3);

  86.   /* USER CODE END 2 */

  87.   /* Infinite loop */
  88.   /* USER CODE BEGIN WHILE */
  89.   while (1)
  90.   {
  91.   /* USER CODE END WHILE */

  92.   /* USER CODE BEGIN 3 */
  93.                 Key_Scan();
  94.   }
  95.   /* USER CODE END 3 */

  96. }

  97. /** System Clock Configuration
  98. */
  99. void SystemClock_Config(void)
  100. {

  101.   RCC_OscInitTypeDef RCC_OscInitStruct;
  102.   RCC_ClkInitTypeDef RCC_ClkInitStruct;
  103.   RCC_PeriphCLKInitTypeDef PeriphClkInit;

  104.     /**Initializes the CPU, AHB and APB busses clocks
  105.     */
  106.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  107.   RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  108.   RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  109.   RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  110.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  111.   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  112.   RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  113.   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  114.   {
  115.     Error_Handler();
  116.   }

  117.     /**Initializes the CPU, AHB and APB busses clocks
  118.     */
  119.   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  120.                               |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  121.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  122.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  123.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  124.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  125.   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  126.   {
  127.     Error_Handler();
  128.   }

  129.   PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
  130.   PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
  131.   if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  132.   {
  133.     Error_Handler();
  134.   }

  135.     /**Configure the Systick interrupt time
  136.     */
  137.   HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

  138.     /**Configure the Systick
  139.     */
  140.   HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  141.   /* SysTick_IRQn interrupt configuration */
  142.   HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
  143. }

  144. /* USER CODE BEGIN 4 */
  145. /************FFT相關(guān)*****************/
  146. //測試用 生成一個信號
  147. void Creat_Single(void)
  148. {
  149.         u16 i = 0;
  150.         float fx=0.0;
  151.        
  152.         for(i=0; i<NPT; i++)
  153.         {
  154.                 fx = 2048+2048*sin(PI2 * i * 200.0 / Fs)+
  155.                                  3100*sin(PI2 * i * 502.0 / Fs)+
  156.                                  1300*sin(PI2 * i * 990.0 / Fs);
  157.                 lBufInArray[i] = ((signed short)fx) << 16;               
  158.         }
  159. }
  160. //獲取FFT后的直流分量
  161. void GetPowerMag(void)
  162. {
  163.     signed short lX,lY;
  164.     float X,Y,Mag;
  165.     unsigned short i;
  166.     for(i=0; i<NPT/2; i++)
  167.     {
  168.         lX  = (lBufOutArray[i] << 16) >> 16;
  169.         lY  = (lBufOutArray[i] >> 16);
  170.                        
  171.                                 //除以32768再乘65536是為了符合浮點(diǎn)數(shù)計算規(guī)律
  172.         X = NPT * ((float)lX) / 32768;
  173.         Y = NPT * ((float)lY) / 32768;
  174.         Mag = sqrt(X * X + Y * Y)*1.0/ NPT;
  175.         if(i == 0)       
  176.             lBufMagArray[i] = (unsigned long)(Mag * 32768);
  177.         else
  178.             lBufMagArray[i] = (unsigned long)(Mag * 65536);
  179.     }
  180. }
  181. /*柱狀顯示*/
  182. void display1(void)
  183. {
  184.         uint16_t i = 0;
  185.         uint8_t x = 0;
  186.         uint8_t y = 0;
  187.        
  188.         /*******************顯示*******************/
  189.         GUI_ClearSCR();
  190.         for(i = 0; i < 32; i++)        //間隔的取32個頻率出來顯示
  191.         {
  192.                 x = (i<<2);        //i*4
  193.                 y = 63-(lBufMagArray[x+1]/prt)-2;        //加1是為了丟掉第一個直流分量
  194.                 if(y>63) y = 63;
  195.                
  196.                 GUI_LineWith(x,y,x,63,3,1);
  197.                
  198.                 //畫下落的點(diǎn)
  199.                 if(fall_pot[i]>y) fall_pot[i] = y;
  200.                 else
  201.                 {
  202.                                 if(fall_pot[i]>63) fall_pot[i]=63;
  203.                                 GUI_LineWith(x,fall_pot[i],x,fall_pot[i]+3,3,1);
  204.                                 fall_pot[i] += 2 ;
  205.                 }
  206.         }
  207.         GUI_Exec();
  208. }
  209. /*單柱狀顯示*/
  210. void display2(void)
  211. {
  212.         uint16_t i = 0;
  213.         uint8_t y = 0;
  214.        
  215.         /*******************顯示*******************/
  216.         GUI_ClearSCR();
  217.         for(i = 1; i < 128; i++)       
  218.         {
  219.                 y = 63-(lBufMagArray[i]/prt)-2;
  220.                 if(y>63) y = 63;
  221.                
  222.                 GUI_RLine(i,y,63,1);               
  223.                 //畫下落的點(diǎn)
  224.                 if(fall_pot[i]>y) fall_pot[i] = y;
  225.                 else
  226.                 {
  227.                                 if(fall_pot[i]>63) fall_pot[i]=63;
  228.                                 GUI_RLine(i,fall_pot[i],fall_pot[i]+1,1);
  229.                                 fall_pot[i] += 2 ;
  230.                 }
  231.         }
  232.         GUI_Exec();
  233. }
  234. /*柱狀顯示 中間對稱*/
  235. void display3(void)
  236. {
  237.         uint16_t i = 0;
  238.         uint8_t y = 0;
  239.        
  240.         /*******************顯示*******************/
  241.         GUI_ClearSCR();
  242.         for(i = 0; i < 127; i++)       
  243.         {
  244.                 y = 31-(lBufMagArray[i+1]/prt)-2;        //加1是為了丟掉第一個直流分量
  245.                 if(y>31) y = 31;
  246.                
  247.                 GUI_RLine(i,32,y,1);
  248.                 GUI_RLine(i,32,63-y,1);
  249.                
  250.                 //畫下落的點(diǎn)
  251.                 if(fall_pot[i]>y) fall_pot[i] = y;
  252.                 else
  253.                 {
  254.                                 if(fall_pot[i]>30) fall_pot[i]=30;
  255.                                 GUI_RLine(i,fall_pot[i],fall_pot[i]+1,1);
  256.                                 GUI_RLine(i,63-fall_pot[i],63-(fall_pot[i]+1),1);
  257.                                 fall_pot[i] += 2 ;
  258.                 }
  259.         }
  260.         GUI_Exec();
  261. }
  262. /*單柱狀顯示 中間對稱*/
  263. void display4(void)
  264. {
  265.         uint16_t i = 0;
  266.         uint8_t x = 0;
  267.         uint8_t y = 0;
  268.        
  269.         /*******************顯示*******************/
  270.         GUI_ClearSCR();
  271.         for(i = 0; i < 32; i++)        //間隔的取32個頻率出來顯示
  272.         {
  273.                 x = (i<<2);        //i*4
  274.                 y = 31-(lBufMagArray[x+1]/prt)-2;        //加1是為了丟掉第一個直流分量
  275.                 if(y>31) y = 31;
  276.                
  277.                 GUI_LineWith(x,y,x,32,3,1);
  278.                 GUI_LineWith(x,63-y,x,32,3,1);
  279.                
  280.                 //畫下落的點(diǎn)
  281.                 if(fall_pot[i]>y) fall_pot[i] = y;
  282.                 else
  283.                 {
  284.                                 if(fall_pot[i]>31) fall_pot[i]=31;
  285.                                 GUI_LineWith(x,fall_pot[i],x,fall_pot[i]+3,3,1);
  286.                                 GUI_LineWith(x,63 - fall_pot[i],x,63 - fall_pot[i]-3,3,1);
  287.                                 fall_pot[i] += 2 ;
  288.                 }
  289.         }
  290.         GUI_Exec();
  291. }


  292. //ADC DMA傳輸中斷
  293. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
  294. {
  295.         uint16_t i = 0;
  296.         static uint16_t num = 0;       
  297. //        printf("adc dma interrupt \r\n");
  298.         HAL_ADC_Stop_DMA(&hadc1);                                                        //完成一次測量 關(guān)閉DMA傳輸
  299.        
  300.         //填充數(shù)組
  301.         for(i=0;i<NPT;i++)
  302.                 lBufInArray[i] = ((signed short)(adc_buf[i]-2048)) << 16;                //這里因?yàn)閱纹瑱C(jī)的ADC只能測正的電壓 所以需要前級加直流偏執(zhí)
  303.                                                                                                                                                                                                                                                                         //加入直流偏執(zhí)后 軟件上減去2048即一半 達(dá)到負(fù)半周期測量的目的
  304.         //cr4_fft_1024_stm32(lBufOutArray, lBufInArray, NPT);                                                        //FFT變換
  305.         cr4_fft_256_stm32(lBufOutArray, lBufInArray, NPT);
  306.         GetPowerMag();                                                                                                                                                                                                        //取直流分量對應(yīng)的AD值
  307. //        //打印出來測試
  308. //        for(i=0;i<NPT/2;i++)
  309. //                printf("i:%3d, f:%.2f, Power:%10d\r\n", i, (float)i*Fs/NPT, lBufMagArray[i]);
  310.        
  311.         //自動顯示
  312.         if(auto_display_flag == 1)
  313.         {
  314.                 if(num>300)
  315.                 {
  316.                         num = 0;
  317.                         display_num ++;
  318.                         if(display_num>SHOW_NUM) display_num = 1;
  319.                 }
  320.         }
  321.         num++;
  322.         //顯示
  323.         switch(display_num)
  324.         {
  325.                 case 1:
  326.                         display1();
  327.                         break;
  328.                 case 2:
  329.                         display2();
  330.                         break;
  331.                 case 3:
  332.                         display3();
  333.                         break;
  334.                 case 4:
  335.                         display4();
  336.                         break;
  337.                 default:
  338.                         display3();
  339.                         break;
  340.         }
  341.         HAL_ADC_Start_DMA(&hadc1, adc_buf, NPT);
  342. }

  343. #define K1 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_3)
  344. #define K2 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_4)
  345. #define K3 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)

  346. void Key_Scan(void)
  347. {
  348.         static uint8_t mode_num = 0;
  349.         if(K1 == RESET)
  350.         {
  351.                 HAL_Delay(10);
  352.                 if(K1 == RESET)
  353.                 {
  354.                         while(!K1);
  355.                         mode_num=!mode_num;
  356.                         if(mode_num == 1) //自動顯示模式
  357.                         {
  358.                                 auto_display_flag = 1;
  359.                                 GUI_PutString(0,0,"Auto");
  360.                                 GUI_Exec();
  361.                         }
  362.                         else                                                        //正常顯示模式 手動切換效果
  363.                         {
  364.                                 auto_display_flag = 0;
  365.                                 GUI_PutString(0,0,"Manual");
  366.                                 GUI_Exec();
  367.                         }
  368.                 }
  369.         }
  370.         if(K2 == RESET)
  371.         {
  372.                 HAL_Delay(10);
  373.                 if(K2 == RESET)
  374.                 {
  375.                         while(!K2);
  376.                         if(mode_num == 0)        //手動模式
  377.                         {
  378.                                 display_num ++;
  379.                                 if(display_num > SHOW_NUM) display_num = 1;
  380.                         }
  381.                 }
  382.         }
  383.         if(K3 == RESET)
  384.         {
  385.                 HAL_Delay(10);
  386.                 if(K3 == RESET)
  387.                 {
  388.                         while(!K3);
  389.                         if(mode_num == 0)        //手動模式
  390.                         {
  391.                                 if(display_num == 1) display_num = SHOW_NUM+1;
  392. ……………………

  393. …………限于本文篇幅 余下代碼請從51黑下載附件…………
復(fù)制代碼

程序51hei提供下載:
FFT V2.0.7z (620.44 KB, 下載次數(shù): 273)

評分

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

查看全部評分

回復(fù)

使用道具 舉報

ID:537401 發(fā)表于 2019-7-2 21:26 | 顯示全部樓層
樓主高大。
回復(fù)

使用道具 舉報

ID:562991 發(fā)表于 2019-7-30 15:52 | 顯示全部樓層
支持謝謝!
回復(fù)

使用道具 舉報

ID:4572 發(fā)表于 2020-4-2 23:24 | 顯示全部樓層
支持謝謝!
回復(fù)

使用道具 舉報

ID:745514 發(fā)表于 2020-6-3 11:06 來自手機(jī) | 顯示全部樓層
原理圖樓主能分享一下嗎
回復(fù)

使用道具 舉報

ID:434962 發(fā)表于 2021-4-22 15:14 | 顯示全部樓層
效果怎么樣,有沒有人調(diào)試過?
估計失真較大
回復(fù)

使用道具 舉報

ID:480779 發(fā)表于 2021-5-30 22:16 | 顯示全部樓層
這是OLED音樂頻譜吧,你的標(biāo)題對不對啊?
回復(fù)

使用道具 舉報

ID:796531 發(fā)表于 2022-4-19 16:39 | 顯示全部樓層
好東西,網(wǎng)上找了半天都要money下載,總算在這里下到了
回復(fù)

使用道具 舉報

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

本版積分規(guī)則

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

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 久久综合一区 | 激情一区二区三区 | 日韩淫片免费看 | 婷婷99| 久久久久国产精品 | re久久 | 亚洲精品日韩在线 | 久久亚洲一区二区三区四区 | 欧美精品久久久久久 | 亚洲一区二区在线播放 | 日韩另类视频 | 久久精品一区 | 成人免费看电影 | 日韩亚洲一区二区 | 日韩av成人 | 欧美日韩18| 精品福利在线 | 成人国产精品色哟哟 | 成人自拍视频网站 | 午夜精品一区二区三区在线观看 | 91九色porny首页最多播放 | 国产98色在线 | 日韩 | 色妹子综合网 | 视频国产一区 | 欧美一级二级三级视频 | 亚洲国产精品成人无久久精品 | 中文字幕av网址 | 搞av.com| 久久久久久久久综合 | 亚洲一区国产 | 国产日韩久久 | 欧美精品在线播放 | 日韩毛片免费看 | 欧美视频在线播放 | 黄色毛片视频 | 一级日批片 | 亚洲成人免费网址 | 美女久久视频 | 秋霞在线一区 | 久久高清 | 久精品久久 |