• stm32f103c6t6制作音乐频谱分析仪


    前言

    这个学期学习数字信号处理,需要制作一个音乐频谱分析仪,但是本人比较菜,所以只能复刻别人做好的。

    参考来自: stm32f103+FFT+OLED的音乐频谱制作(只需三步即可)

    原文使用的是stm32f103c8t6,我用的是stm32f103c6t6,两个大部分引脚是通用的。我将OLED换成了四针的IIC接口。
    在这里插入图片描述
    stm32f103c6t6是自己做的最小系统板,接了一个扩展版,把oled接口和ADC采集接口引到了右边。

    所有硬件软件开源地址(点这里!!!

    硬件

    电路使用LM358进行放大,采用电源5V直流供电。由于单片机的ADC不能采集到负值,所以我们把信号加上了1/2Vcc的直流偏置,50倍增益可调。
    在这里插入图片描述
    本来打算做成贴片,可测试信号放大很差,信号干扰特别强,学识有限,搞不明白为什么,最后就做成插件了。
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    软件

    stm32f103c6t6最小系统板是自己画的,包含了RTC的外部低速时钟,如果下载中No target connected或者Internal command error的问题,需要按住复位键再下载,下载的时候再松开复位键。

    详细操作参考:自制stm32F103c6t6出现No target connected或者Internal command error的原因猜测和解决方法

    oled引脚接口可以通过OLED.h修改
    在这里插入图片描述
    程序框架采用HAL库的形式建立,如果没学过可能有点蒙圈。使用的是PA0接口进行ADC采集。

    参考链接:ADC采样的HAL配置以及程序参考

    代码中主要涉及到了GUI的移植:(利用类似如下函数画柱状图)

    /****************************************************************************
    * 名称:GUI_LineWith()
    * 功能:画任意两点之间的直线,并且可设置线的宽度。
    * 入口参数: x0		直线起点的x坐标值
    *           y0		直线起点的y坐标值
    *           x1      直线终点的x坐标值
    *           y1      直线终点的y坐标值
    *           with    线宽(0-50)
    *           color	显示颜色
    * 出口参数:无
    * 说明:操作失败原因是指定地址超出有效范围。
    ****************************************************************************/
    void  GUI_LineWith(uint32 x0, uint32 y0, uint32 x1, uint32 y1, uint8 with, TCOLOR color)
    {  int32   dx;						// 直线x轴差值变量
       int32   dy;          			// 直线y轴差值变量
       int8    dx_sym;					// x轴增长方向,为-1时减值方向,为1时增值方向
       int8    dy_sym;					// y轴增长方向,为-1时减值方向,为1时增值方向
       int32   dx_x2;					// dx*2值变量,用于加快运算速度
       int32   dy_x2;					// dy*2值变量,用于加快运算速度
       int32   di;						// 决策变量
       
       int32   wx, wy;					// 线宽变量
       int32   draw_a, draw_b;
       
       /* 参数过滤 */
       if(with==0) return;
       if(with>50) with = 50;
       
       dx = x1-x0;						// 求取两点之间的差值
       dy = y1-y0;
       
       wx = with/2;
       wy = with-wx-1;
       
       /* 判断增长方向,或是否为水平线、垂直线、点 */
       if(dx>0)							// 判断x轴方向
       {  dx_sym = 1;					// dx>0,设置dx_sym=1
       }
       else
       {  if(dx<0)
          {  dx_sym = -1;				// dx<0,设置dx_sym=-1
          }
          else
          {  /* dx==0,画垂直线,或一点 */
             wx = x0-wx;
             if(wx<0) wx = 0;
             wy = x0+wy;
             
             while(1)
             {  x0 = wx;
                GUI_RLine(x0, y0, y1, color);
                if(wx>=wy) break;
                wx++;
             }
             
          	 return;
          }
       }
       
       if(dy>0)							// 判断y轴方向
       {  dy_sym = 1;					// dy>0,设置dy_sym=1
       }
       else
       {  if(dy<0)
          {  dy_sym = -1;				// dy<0,设置dy_sym=-1
          }
          else
          {  /* dy==0,画水平线,或一点 */
             wx = y0-wx;
             if(wx<0) wx = 0;
             wy = y0+wy;
             
             while(1)
             {  y0 = wx;
                GUI_HLine(x0, y0, x1, color);
                if(wx>=wy) break;
                wx++;
             }
          	 return;
          }
       }
        
       /* 将dx、dy取绝对值 */
       dx = dx_sym * dx;
       dy = dy_sym * dy;
     
       /* 计算2倍的dx及dy值 */
       dx_x2 = dx*2;
       dy_x2 = dy*2;
       
       /* 使用Bresenham法进行画直线 */
       if(dx>=dy)						// 对于dx>=dy,则使用x轴为基准
       {  di = dy_x2 - dx;
          while(x0!=x1)
          {  /* x轴向增长,则宽度在y方向,即画垂直线 */
             draw_a = y0-wx;
             if(draw_a<0) draw_a = 0;
             draw_b = y0+wy;
             GUI_RLine(x0, draw_a, draw_b, color);
             
             x0 += dx_sym;				
             if(di<0)
             {  di += dy_x2;			// 计算出下一步的决策值
             }
             else
             {  di += dy_x2 - dx_x2;
                y0 += dy_sym;
             }
          }
          draw_a = y0-wx;
          if(draw_a<0) draw_a = 0;
          draw_b = y0+wy;
          GUI_RLine(x0, draw_a, draw_b, color);
       }
       else								// 对于dx
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141

    在ADC的采集中断里进行FFT计算

    //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
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    软件也都开源在前言那里。

    总结

    感谢大佬的开源,让我能复刻出来,难点主要在软件,这是我头一次接触GUI移植,同时也发现GUI的强大。同时,我也发现FFT软件复现对我挺难的,只是利用现成的库,还需要加强理论学习。最后就是贴片的信号放大不明白为什么。不知道是芯片选型的问题还是电路的问题。

  • 相关阅读:
    专业图像处理软件DxO PhotoLab 7 mac中文特点和功能
    深度学习之基于Yolov5人体姿态摔倒识别分析报警系统(GUI界面)
    SpringSecurity框架【详解】
    OceanBase 社区版 Docker 镜像存在的必要性
    2022年数模国赛冲刺之模型复习2
    STM32 EtherCAT 总线型(1 拖 4)步进电机解决方案
    十四天学会C++之第一天(入门和基本语法)
    linux使用docker实现redis主从复制和哨兵模式
    【C语言进阶】动态内存管理常见错误
    java某百货店POS积分管理系统积分点更新生成以及通票回收处理源代码+LW
  • 原文地址:https://blog.csdn.net/zerokingwang/article/details/126517208