基于STM32开源:磁流体蓝牙音箱(包含源码+PCB) 您所在的位置:网站首页 带功放蓝牙模块的音箱有哪些 基于STM32开源:磁流体蓝牙音箱(包含源码+PCB)

基于STM32开源:磁流体蓝牙音箱(包含源码+PCB)

2024-07-10 20:33| 来源: 网络整理| 查看: 265

目录 日常·唠嗑一、视频效果二、硬件设计三、程序设计四、工程获取五、专利

日常·唠嗑

      21年6月的时候,那会刚开始创业,跟着合伙人园丁(笔名)在创业的道路上,瞎灯黑火乱摸索,基本上是能跟开发有关合法赚钱的方式(嘿嘿,我这人比较庸俗,就想着赚钱),我们都思考过。为了一个看不见的投资,也是跟着另外三个小伙伴,去外面搞应酬(不过这个经历,也是我们人生中,一个不过珍贵的回忆,即使没拿到第一个投资,但那是我们以一个创业人为自己事业打拼的一件事)。       这创业的过程,我们也像大多数出来创业的年轻技术人员那样去接单子做(俗称接外包赚外快),这个磁流体项目就是我们那会接的单子,21年磁流体音箱项目网上还没有这么多       呸呸呸。尽讲些没用的,直接上视频,看效果进入正文。

一、视频效果

21年6月做的,后面因为找不到投资人,所以没有再进行外包装优化,当时我们还给这个作品起了个中二的名字:毒液音箱(嘿嘿)

STM32:磁流体蓝牙音箱项目开源(源码+PCB)

二、硬件设计

      主控器,我们是自己画的最小系统板,板子上有:控制电路+电磁铁电路+电源电路       控制电路:STM32F103C8T6最小系统       电源电路:AMS117电路       电磁铁电路:一个大功率的MOS管做开关电路     除了自己设计的最小系统板外,还需要到某宝买一个蓝牙音箱+一个36V可调电源,这两个东西都可以自己做,但是没必要,网上便宜,性能还稳定,毕竟别人做了这么多年这东西了,还是可以的。     在电磁铁电路,开始,我们相过用大功率三极管做,但是电流实在太大了,工作不到一会,就会严重发烫。后来我三师兄给我介绍了MOS电路,发现就好了。 在这里插入图片描述 在这里插入图片描述

      这个PCB跟原理图,我等会会跟源码放在一起,打包放在文末,有兴趣的,自己下载。

三、程序设计

      其实这东西做起来没那么难,有些基础的人都可以做,主要用到FFT算法,我讲一下算法思路:这里我不会讲FFT算法的内容,网上讲解很多,感兴趣的自己去搜。我讲一下,大致原理,在第二大点的硬件设计中,我们用到了一个大功率MOS管做开关电路,其实就是让电磁铁把磁流体吸起来(给电就有磁力就吸起来了,没电没磁力就又掉下去),那么如何做到磁流体随着音乐跳动呢?       其实很简单,就是我们把单片的一个端口,根据音乐的跳动(FFT频率)不断输出PWM信号去控制这个MOS管的开关。(注意:因为电磁铁的电流是很大的,必须很单片机直接做隔绝,所以你可以看到,我设计的板子是有一些大电容跟小三极管做隔绝的)。

主程序: 代码已经做了注释,相信有基础的人都能看懂,没基础的,建议把基础打好,再来搞这项目

/* 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 1024//256 #define PI2 6.28318530717959 #define K1 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_4) #define K2 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_11) #define K3 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_12) //采样率计算 //分辨率:Fs/NPT //#define Fs 10000 #define Fs 25600 //取9984能出来整数的分辨率 9984/256 = 39Hz #define DCT_0 HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9, GPIO_PIN_RESET); #define DCT_1 HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9, GPIO_PIN_SET); /* 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}; uint8_t DCT_QD_flag; uint16_t DCT_QD_flag1; uint32_t error2; //差值 long lBufInArray[NPT]; long error1[NPT/2]={0}; //差值 long lBufOutArray[NPT/2]; long lBufMagArray[NPT/2];//当前幅值 long lastSpectrum[NPT/2];//上一次幅值 差值处理使用 uint8_t ucmagarry[37]; #define SPECTRUM_WND_SIZE 10 //窗口数 #define THRESHOLD_WINDOW_SIZE 10 //均值窗口数 #define MULTIPLIER 1.0f //增益系数 uint16_t wndNum = 0; uint16_t spectralFlux[SPECTRUM_WND_SIZE]; //前后差值 uint16_t threshold[SPECTRUM_WND_SIZE]; //均值阈值 uint16_t peakSpectrum[SPECTRUM_WND_SIZE]; //节拍值 long DCT_error_max; //电磁铁差值最大值 uint8_t DCT_flag=0; //电磁铁工作标志位0开启 1关闭 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 DCT_0; if (DCT_flag == 0)//开启电磁铁 { DCT_1; HAL_Delay(120); DCT_flag =1; DCT_0; } else { DCT_0; } HAL_Delay(10); } else { DCT_1; } } } /** 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 signed short lX,lY; float X,Y,Mag; unsigned short i; for(i=0; i uint16_t i = 0; uint8_t x = 0; uint8_t y = 0; /*******************显示*******************/ GUI_ClearSCR(); for(i = 0; i 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 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 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 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,m=0; uint32_t flux = 0; int start,end,j; float mean; static uint16_t num = 0; // printf("adc dma interrupt \r\n"); HAL_ADC_Stop_DMA(&hadc1); //完成一次测量 关闭DMA传输 //填充数组 for(i=0;i error2=adc_buf[i+1]; } } if(error2>992)//说明音乐启动 { DCT_QD_flag=1;//有音乐 } else { DCT_QD_flag1++; if(DCT_QD_flag1>25) { DCT_QD_flag1=0; DCT_QD_flag=0; } } // if(error2>500)//说明音乐启动 // { // DCT_QD_flag=1;//有音乐 // } // else // { // DCT_QD_flag=0; // } cr4_fft_1024_stm32(lBufOutArray, lBufInArray, NPT); //FFT变换 // cr4_fft_256_stm32(lBufOutArray, lBufInArray, NPT); GetPowerMag(); //取直流分量对应的AD值 // DCT_flag=1; //关闭电磁铁 /***********求差值******************/ for(i=0;i lBufMagArray[i]=0; } } for(i=0;i error1[i]=0; } // printf("i:%3d, f:%.2f, Power:%10d\r\n", i, (float)i*Fs/NPT, error1[i]); } for(i=0;i if (error1[i+1]>error1[i]) { DCT_error_max=error1[i+1]; } else { DCT_error_max=0; } } /************************判断是否开启电磁铁************************************/ if (DCT_error_max>=5) { DCT_flag=0; //开启电磁铁 } else { DCT_flag=1; //关闭电磁铁 } //自动显示 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); } 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; display_num --; } } } } /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @param None * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler */ /* User can add his own implementation to report the HAL error return state */ while(1) { } /* USER CODE END Error_Handler */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t* file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

ADC程序:

/* Includes ------------------------------------------------------------------*/ #include "adc.h" #include "gpio.h" #include "dma.h" /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ ADC_HandleTypeDef hadc1; DMA_HandleTypeDef hdma_adc1; /* ADC1 init function */ void MX_ADC1_Init(void) { ADC_ChannelConfTypeDef sConfig; /**Common config */ hadc1.Instance = ADC1; hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE; hadc1.Init.ContinuousConvMode = DISABLE; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T3_TRGO; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 1; if (HAL_ADC_Init(&hadc1) != HAL_OK) { Error_Handler(); } /**Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_1; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } } void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle) { GPIO_InitTypeDef GPIO_InitStruct; if(adcHandle->Instance==ADC1) { /* USER CODE BEGIN ADC1_MspInit 0 */ /* USER CODE END ADC1_MspInit 0 */ /* Peripheral clock enable */ __HAL_RCC_ADC1_CLK_ENABLE(); /**ADC1 GPIO Configuration PA0-WKUP ------> ADC1_IN0 */ GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* Peripheral DMA init*/ hdma_adc1.Instance = DMA1_Channel1; hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE; hdma_adc1.Init.MemInc = DMA_MINC_ENABLE; hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; hdma_adc1.Init.Mode = DMA_CIRCULAR; hdma_adc1.Init.Priority = DMA_PRIORITY_LOW; if (HAL_DMA_Init(&hdma_adc1) != HAL_OK) { Error_Handler(); } __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1); /* USER CODE BEGIN ADC1_MspInit 1 */ /* USER CODE END ADC1_MspInit 1 */ } } void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle) { if(adcHandle->Instance==ADC1) { /* USER CODE BEGIN ADC1_MspDeInit 0 */ /* USER CODE END ADC1_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_ADC1_CLK_DISABLE(); /**ADC1 GPIO Configuration PA0-WKUP ------> ADC1_IN0 */ HAL_GPIO_DeInit(GPIOA, GPIO_PIN_0); /* Peripheral DMA DeInit*/ HAL_DMA_DeInit(adcHandle->DMA_Handle); } /* USER CODE BEGIN ADC1_MspDeInit 1 */ /* USER CODE END ADC1_MspDeInit 1 */ } /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 四、工程获取

1、直接在平台下载: 基于STM32:磁流体蓝牙音箱(源码工程+PCB+原理图)

在这里插入图片描述

五、专利

关于磁流体蓝牙音箱,本团队已经申请了专利(已授权下证),本团队有成熟的技术,有兴趣的朋友私信我们可以合作。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有