久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费
標題:
STM32+咪頭+OLED12864音樂LED頻譜制作 附程序
[打印本頁]
作者:
一紙青衫丶
時間:
2019-7-1 10:29
標題:
STM32+咪頭+OLED12864音樂LED頻譜制作 附程序
制作過程:
1.準備材料:
stm32f103核心板 1塊
OLED12864顯示屏 1塊(SPI接口)
聲音檢測傳感器 1塊 (咪頭+放大電路 可以網上買現成的模塊,也可根據后文提供的原理圖自己做)
2.硬件連接:
(1)OLED連接:
OLED_SCLK ———— PB7
OLED_SDIN ———— PB6
OLED_RST ———— PB5
OLED_RS ———— PB4
(2)聲音檢測傳感器連接:
直接將模塊的輸出接到單片機的PA0即可。
OK硬件連接完成!就這么簡單!
3.程序下載
接下來將程序下載到單片機即可,音樂頻譜就完成了!(別告訴我你連下載程序都不會 滑稽)
程序燒錄文件 鏈接:
https://pan.baidu.com/s/1EjKPvBFbTmYzzh6fSn0U5A
密碼:o6uu
程序源碼:
https://download.csdn.net/download/mc_li/10601743
ps:以上就是簡單的音樂頻譜制作過程,下面是較為詳細的制作過程,提供源碼和原理圖,有興趣的同志們可以看看。
單片機源程序如下:
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f1xx_hal.h"
#include "adc.h"
#include "dma.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* USER CODE BEGIN Includes */
#include "stm32_dsp.h"
#include "table_fft.h"
#include "math.h"
#include "oled.h"
#include "config.h"
#include "bg.h"
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
#define NPT 256
#define PI2 6.28318530717959
//采樣率計算
//分辨率:Fs/NPT
//#define Fs 10000
#define Fs 9984
//取9984能出來整數的分辨率 9984/256 = 39Hz
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void Error_Handler(void);
/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
void Creat_Single(void);
void GetPowerMag(void);
void Single_Get(void);
void display1(void);
void display2(void);
void Key_Scan(void);
/* USER CODE END PFP */
/* USER CODE BEGIN 0 */
uint32_t adc_buf[NPT]={0};
long lBufInArray[NPT];
long lBufOutArray[NPT/2];
long lBufMagArray[NPT/2];
uint8_t prt = 10; //量化顯示的比例
#define SHOW_NUM 4 //顯示函數的個數
uint8_t display_num = 1; //控制顯示方式的
uint8_t auto_display_flag = 0; //自動切換顯示標志 1:自動切換 0:手動
uint8_t fall_pot[128]; //記錄下落點的坐標
/* USER CODE END 0 */
int main(void)
{
/* USER CODE BEGIN 1 */
uint16_t i = 0;
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
MX_ADC1_Init();
MX_TIM3_Init();
/* USER CODE BEGIN 2 */
printf("uart test! \r\n");
/*初始化顯示*/
GUI_Initialize();
/*設置前景色和背景色 這里用1和0代替*/
GUI_SetColor(1,0);
GUI_LoadPic(0,0,(uint8_t *)&gImage_bg,128,64);
GUI_Exec();
HAL_Delay(3000);
//初始化下落點 把下落的點 初始化為最底部顯示
for(i=0;i<128;i++)
fall_pot[i] = 63;
/*啟動ADC的DMA傳輸 配合下面定時器來觸發ADC轉換*/
HAL_ADC_Start_DMA(&hadc1, adc_buf, NPT);
/*開啟定時器 用溢出事件來觸發ADC轉換*/
HAL_TIM_Base_Start(&htim3);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
Key_Scan();
}
/* USER CODE END 3 */
}
/** System Clock Configuration
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInit;
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
/**Configure the Systick interrupt time
*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
/**Configure the Systick
*/
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/* USER CODE BEGIN 4 */
/************FFT相關*****************/
//測試用 生成一個信號
void Creat_Single(void)
{
u16 i = 0;
float fx=0.0;
for(i=0; i<NPT; i++)
{
fx = 2048+2048*sin(PI2 * i * 200.0 / Fs)+
3100*sin(PI2 * i * 502.0 / Fs)+
1300*sin(PI2 * i * 990.0 / Fs);
lBufInArray[i] = ((signed short)fx) << 16;
}
}
//獲取FFT后的直流分量
void GetPowerMag(void)
{
signed short lX,lY;
float X,Y,Mag;
unsigned short i;
for(i=0; i<NPT/2; i++)
{
lX = (lBufOutArray[i] << 16) >> 16;
lY = (lBufOutArray[i] >> 16);
//除以32768再乘65536是為了符合浮點數計算規律
X = NPT * ((float)lX) / 32768;
Y = NPT * ((float)lY) / 32768;
Mag = sqrt(X * X + Y * Y)*1.0/ NPT;
if(i == 0)
lBufMagArray[i] = (unsigned long)(Mag * 32768);
else
lBufMagArray[i] = (unsigned long)(Mag * 65536);
}
}
/*柱狀顯示*/
void display1(void)
{
uint16_t i = 0;
uint8_t x = 0;
uint8_t y = 0;
/*******************顯示*******************/
GUI_ClearSCR();
for(i = 0; i < 32; i++) //間隔的取32個頻率出來顯示
{
x = (i<<2); //i*4
y = 63-(lBufMagArray[x+1]/prt)-2; //加1是為了丟掉第一個直流分量
if(y>63) y = 63;
GUI_LineWith(x,y,x,63,3,1);
//畫下落的點
if(fall_pot[i]>y) fall_pot[i] = y;
else
{
if(fall_pot[i]>63) fall_pot[i]=63;
GUI_LineWith(x,fall_pot[i],x,fall_pot[i]+3,3,1);
fall_pot[i] += 2 ;
}
}
GUI_Exec();
}
/*單柱狀顯示*/
void display2(void)
{
uint16_t i = 0;
uint8_t y = 0;
/*******************顯示*******************/
GUI_ClearSCR();
for(i = 1; i < 128; i++)
{
y = 63-(lBufMagArray[i]/prt)-2;
if(y>63) y = 63;
GUI_RLine(i,y,63,1);
//畫下落的點
if(fall_pot[i]>y) fall_pot[i] = y;
else
{
if(fall_pot[i]>63) fall_pot[i]=63;
GUI_RLine(i,fall_pot[i],fall_pot[i]+1,1);
fall_pot[i] += 2 ;
}
}
GUI_Exec();
}
/*柱狀顯示 中間對稱*/
void display3(void)
{
uint16_t i = 0;
uint8_t y = 0;
/*******************顯示*******************/
GUI_ClearSCR();
for(i = 0; i < 127; i++)
{
y = 31-(lBufMagArray[i+1]/prt)-2; //加1是為了丟掉第一個直流分量
if(y>31) y = 31;
GUI_RLine(i,32,y,1);
GUI_RLine(i,32,63-y,1);
//畫下落的點
if(fall_pot[i]>y) fall_pot[i] = y;
else
{
if(fall_pot[i]>30) fall_pot[i]=30;
GUI_RLine(i,fall_pot[i],fall_pot[i]+1,1);
GUI_RLine(i,63-fall_pot[i],63-(fall_pot[i]+1),1);
fall_pot[i] += 2 ;
}
}
GUI_Exec();
}
/*單柱狀顯示 中間對稱*/
void display4(void)
{
uint16_t i = 0;
uint8_t x = 0;
uint8_t y = 0;
/*******************顯示*******************/
GUI_ClearSCR();
for(i = 0; i < 32; i++) //間隔的取32個頻率出來顯示
{
x = (i<<2); //i*4
y = 31-(lBufMagArray[x+1]/prt)-2; //加1是為了丟掉第一個直流分量
if(y>31) y = 31;
GUI_LineWith(x,y,x,32,3,1);
GUI_LineWith(x,63-y,x,32,3,1);
//畫下落的點
if(fall_pot[i]>y) fall_pot[i] = y;
else
{
if(fall_pot[i]>31) fall_pot[i]=31;
GUI_LineWith(x,fall_pot[i],x,fall_pot[i]+3,3,1);
GUI_LineWith(x,63 - fall_pot[i],x,63 - fall_pot[i]-3,3,1);
fall_pot[i] += 2 ;
}
}
GUI_Exec();
}
//ADC DMA傳輸中斷
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
uint16_t i = 0;
static uint16_t num = 0;
// printf("adc dma interrupt \r\n");
HAL_ADC_Stop_DMA(&hadc1); //完成一次測量 關閉DMA傳輸
//填充數組
for(i=0;i<NPT;i++)
lBufInArray[i] = ((signed short)(adc_buf[i]-2048)) << 16; //這里因為單片機的ADC只能測正的電壓 所以需要前級加直流偏執
//加入直流偏執后 軟件上減去2048即一半 達到負半周期測量的目的
//cr4_fft_1024_stm32(lBufOutArray, lBufInArray, NPT); //FFT變換
cr4_fft_256_stm32(lBufOutArray, lBufInArray, NPT);
GetPowerMag(); //取直流分量對應的AD值
// //打印出來測試
// for(i=0;i<NPT/2;i++)
// printf("i:%3d, f:%.2f, Power:%10d\r\n", i, (float)i*Fs/NPT, lBufMagArray[i]);
//自動顯示
if(auto_display_flag == 1)
{
if(num>300)
{
num = 0;
display_num ++;
if(display_num>SHOW_NUM) display_num = 1;
}
}
num++;
//顯示
switch(display_num)
{
case 1:
display1();
break;
case 2:
display2();
break;
case 3:
display3();
break;
case 4:
display4();
break;
default:
display3();
break;
}
HAL_ADC_Start_DMA(&hadc1, adc_buf, NPT);
}
#define K1 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_3)
#define K2 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_4)
#define K3 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)
void Key_Scan(void)
{
static uint8_t mode_num = 0;
if(K1 == RESET)
{
HAL_Delay(10);
if(K1 == RESET)
{
while(!K1);
mode_num=!mode_num;
if(mode_num == 1) //自動顯示模式
{
auto_display_flag = 1;
GUI_PutString(0,0,"Auto");
GUI_Exec();
}
else //正常顯示模式 手動切換效果
{
auto_display_flag = 0;
GUI_PutString(0,0,"Manual");
GUI_Exec();
}
}
}
if(K2 == RESET)
{
HAL_Delay(10);
if(K2 == RESET)
{
while(!K2);
if(mode_num == 0) //手動模式
{
display_num ++;
if(display_num > SHOW_NUM) display_num = 1;
}
}
}
if(K3 == RESET)
{
HAL_Delay(10);
if(K3 == RESET)
{
while(!K3);
if(mode_num == 0) //手動模式
{
if(display_num == 1) display_num = SHOW_NUM+1;
……………………
…………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
程序51hei提供下載:
FFT V2.0.7z
(620.44 KB, 下載次數: 273)
2019-7-1 17:55 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
作者:
林中小蟲
時間:
2019-7-2 21:26
樓主高大。
作者:
cheng_5230
時間:
2019-7-30 15:52
支持謝謝!
作者:
chensiyu
時間:
2020-4-2 23:24
支持謝謝!
作者:
單片機真好玩呀
時間:
2020-6-3 11:06
原理圖樓主能分享一下嗎
作者:
asong356
時間:
2021-4-22 15:14
效果怎么樣,有沒有人調試過?
估計失真較大
作者:
lpxok
時間:
2021-5-30 22:16
這是OLED音樂頻譜吧,你的標題對不對啊?
作者:
paladina
時間:
2022-4-19 16:39
好東西,網上找了半天都要money下載,總算在這里下到了
歡迎光臨 (http://www.zg4o1577.cn/bbs/)
Powered by Discuz! X3.1
主站蜘蛛池模板:
久久精品亚洲一区
|
国产在视频一区二区三区吞精
|
国产精品免费一区二区三区
|
免费成人国产
|
亚洲人成人一区二区在线观看
|
日韩视频一区二区在线
|
久久久久国产精品一区
|
精品欧美一区二区三区久久久小说
|
久草日韩
|
亚洲高清在线视频
|
亚洲一区二区三区四区五区午夜
|
国产日韩久久久久69影院
|
大象视频一区二区
|
波多野结衣在线观看一区二区三区
|
欧美一二区
|
精品久久久久久亚洲综合网
|
北条麻妃国产九九九精品小说
|
日日操天天射
|
国产成人精品福利
|
中文字幕视频在线观看
|
精品视频一区二区三区
|
成人精品一区二区三区中文字幕
|
免费一区二区在线观看
|
中文字幕久久精品
|
色婷婷综合在线观看
|
午夜欧美
|
天堂视频一区
|
伊人网站在线观看
|
91视频网
|
91av在线免费观看
|
亚洲精品视频免费观看
|
正在播放国产精品
|
美国一级毛片a
|
亚洲综合一区二区三区
|
婷婷福利
|
国产精品福利视频
|
欧美日韩高清免费
|
超碰免费在线
|
一区二区三区亚洲视频
|
蜜桃在线播放
|
精品国产欧美一区二区三区成人
|