切换到宽版
爱科技/爱创意/爱折腾/爱极致;技术知识分享平台,点击进入新版数码之家网站
  • 43105阅读
  • 152回复

[其他]LED点阵胸牌魔改为音乐频谱(附视频、源代码、原理讲解fft) [复制链接]

上一主题 下一主题
离线2545889167
 

发帖
13268
M币
20754
专家
302
粉丝
4860
只看楼主 倒序阅读 我要置顶 楼主  发表于: 2016-11-07
之前参加某宝商家的免单活动(其实就是shua dan了,活动早就没了,别问了)免费得了个LED点阵胸牌。到手后发现他配套的上位机非常非常难用,10次连接,1次不到的概率能连接到胸牌下载程序,而且内容编辑功能也巨难用。然而,转念也想,貌似作为一个胸牌我也用不到,还不如跟风改造个音乐频谱,于是就有了今天的帖子。
胸牌原装的芯片是GD32f150c6t6,这个芯片时国内MCU企业兆易创新推出的超值型单片机。然而这个东西不像pos机上的gd32f103,和stm32f03基本上是完全兼容的。这货的引脚和stm32f103c8不兼容,但是和stm32f030c8引脚兼容(如图),然而GD32f150c6t6的内核是cortex m3,stm32f030c8内核是cortex m0,也就是说,这两个在内核上也是不兼容的。

所以说了半天,是不是有点绕。但是综上所述就是,GD32f150这个芯片不是我熟悉使用的,而且貌似无论使用stlink还是jlink都不能选到合适的型号直接调试(即不支持),要使用gd link ,但是我没有。
可以使用串口做isp下载,但是这样不能做调试还要每次下载拉boot0很不爽的。在观察电路的时候,我甚至发现,这个板子上的BOOT0引脚是直接接地的。也就是说,这真心断了我在原装芯片上折腾的兴趣。
正好GD32f150c6t6和stm32f030c8的引脚是兼容的,我手上也有几片stm32f030c8,于是就开始了本帖的魔改心路例程
首先先放上魔改总体设计图

第一步当然是拆原装芯片
拆下来的gd32妥善保管,以防以后研究没有进展不想玩了的时候,还有后悔的机会,吧原来芯片换回去就满血复活了

因为这个pcb是黑色的,所以在跑走线的时候,真心是一边骂娘一边在放大镜下看
顺便拍下了空焊盘下的走线,方便以后备查

还有一张
同时经过测量,我也吧boot0接地的走线直接隔断了,也是为了方便以后操作

换上stm32f030(这个芯片不带USB,这是和gd32的一个区别)

因为是黑油,很难完整的排查出走线,所以使用了观察走线(查出哪些走线和led有关)+程序点亮排查+万用表点亮(确定行列逻辑)的综合手段来排查
最后大概花了两天的时间吧走线跑通并实现点亮。

首先,这个led是44(列)*11(行)的点阵,使用了23个io来驱动
其次,每两列是共阳的
接着,每一行是有2-3个io来共阴驱动的,驱动的时候,一组负责奇数,一组负责偶数(大致是这样的,实际更复杂,但是也有规律)
最后,吧行列线直接直连。
第23根线的作用类似于用来解决对角线引脚重复问题(大致是这样的,实际更复杂,但是也有规律)

上面这段貌似说了一大堆也没说明白,其实这东西,语言不好讲明白,画电路图很复杂,只能意会不好言传,哈哈。暂且认为你们听懂了,实在不懂的,可能去看下程序怎么实现的,就懂了。
如图是吧所以列的共阳拉高,拉低点亮其中一行的情况,看到了吧,这规律还是有点风骚的

行驱动在对角线位置会出行跳到下一行的动作,并且奇偶会发生变化。这样就是为毛我熬了两天才吧所有线序弄明白的原因。
设计者的这个设计真的太精妙也太复杂了

最后的测序结果如图,很佩服用23个io点亮了484个led的人

其实这个工程到这里就算是吧最难的坎过去了,后面要做啥都很简单了,只要扫描驱动就好
如图是我做的驱动和原装没改造过的显示亮度效果对比
为了追求亮度,貌似我设置的扫描速度要稍微慢了点,但是也只是局限于相机的效果,反正眼睛看,都一样,没区别


后面点亮了整个led就是开始改造频谱了。
主要是加了在PA3输入音频信号,剪了一个报废的耳机线接上,又焊接了一个座子供声音输出监听用的。
板子左边吧供电和调试用的swd都引出来了。
至于外观,请勿吐槽,处于实验阶段都是随便乱接线的,图的是方便,要美观的话肯定是要等到设计定性以后才考虑的

特写

然后开始编程。主要就是吧快速傅里叶变换(FFT)的东西弄好了,就可以玩了
快速傅里叶变换(FFT)的这个东西,不接触的时候,看着就感觉都难,实际上,如果吧他当作一个黑箱来用的时候,其实就不怎么难了。
具体详细原理可以看这两个帖子:
http://www.51hei.com/bbs/dpj-49593-1.html
http://www.amobbs.com/forum.php?mod=viewthread&tid=5574941
(我大致说下怎么用,说的不好大神勿喷)
也就是说,这个东西的作用就是吧一段采集到的的信号进行分析,从而得到这段信号里面频率的分布和对应的强度,也就是说吧时域信号转为频域信号。
而如果我们吧他看作一个黑箱,给他输入的信号是adc采样得到的信号,中间进行了一些换算,换算的结果是以复数的形式表现的,最后进行取模运算,就是这个频率点对于的模长(可以理解成强度)。

我用到的是进行128点的转换。首先使用定时器进行定时(我设置了24khz采样,也就是说,最高能捕捉12khz的信号),设置每次定时器溢出的时候自动触发一次ADC转换。转换完成后的数据由DMA自动搬运到内存指定位置,这个采样过程无需cpu干预,完全自动,处理器该干嘛干嘛去。在完成128次定频率的转换后,会触发一个完成中断,在中断里面将处理完成标志置为1。
然后我们定义一个数组,里面使用结构体,实部加虚部,
  1. struct compx {float real,imag;};  
这个数组长度为128。
当满足上一次换算完成和adc采样完成的两个条件时,将所有采样adc得到的数据搬运到上面定义的数组里面的实部里面,然后将所以虚部赋值为0.
这个数组完成赋值后,就可以吧他丢给FFT函数进行换算了,具体的换算过程,我们不用管他,当做黑箱来用,感兴趣的可以看看书。
完成换算以后,换算的结果是以复数的形式表现的,比如某个频率的信息以a+bi的形式表示,这里a是实部,b是虚部,最后进行取模运算,也就是取a和b的平方根,就是这个频率点对于的模长(可以理解成强度)。
将这个模长进行长度拉申或压缩(为了适应屏幕的显示高度),然后就可以吧这些内容显示到屏幕上了。
核心代码展示
其实真的很简单,不难
  1. #define FFT_N 128  
  2. extern uint16_t scan_frame_buffer[44];//led显示缓存
  3. extern uint8_t ADC_Sample_Complete;//ADC取样完成标志
  4. extern uint16_t RegularConvData_Tab[ADC_sam_dat_size];
  5. const uint16_t dat2display[12]={0x0000,0x0400,0x0600,0x0700,0x0780,0x07c0,0x07e0,0x07f0,0x07f8,0x07fc,0x07fe,0x07ff};//吧数据转换成显示的灯条长度
  6. struct compx {float real,imag;};  
  7. struct compx s[FFT_N]; //FFT输入和输出:从S[1]开始存放,根据大小自己定义
  8. void Show_Spectrum(void)
  9. {
  10.     uint16_t i;
  11.     uint8_t cache;
  12.     while(ADC_Sample_Complete==0);//等待adc转换完成
  13.     for(i=0;i<FFT_N;i++)
  14.     {
  15.         s[i].real=(float)RegularConvData_Tab[i];//实部为正弦波FFT_N点采样,赋值为ADC取样值
  16.         s[i].imag=0;   //虚部为0          
  17.     }
  18.     ADC_Sample_Complete=0;//删除标志位
  19.     Restart_DMA();//开始采样
  20.     FFT(s);//做傅里叶变换
  21.     for(i=0;i<FFT_N;i++)
  22.     {
  23.         s[i].real=sqrt(s[i].real*s[i].real+s[i].imag*s[i].imag);    //求变换后结果的模值,存入复数的实部部分
  24.     }
  25.     
  26.     for(i=0;i<44;i++)//吧计算结果写入显示缓存
  27.     {
  28.         cache=(uint8_t)(s[i+1].real/200);
  29.         if(cache>11)cache=11;
  30.         scan_frame_buffer[i]=dat2display[cache];
  31.     }        
  32. }

我现在做的转换所需耗时的参数和专业人士做的还是有很大的差距,不过也是在可视范围内完全完全够用了。
做128点FFT运算。处理器M0内核,速度48mhz。每次转换耗时约20ms的样子。也就是说每秒刷新50次已经完全超出视觉了,也是够用了。

而这次做下来,最花时间的首先是跑LED的走线和想办法驱动,第二花时间的是如何实现TIM+ADC+DMA的自动运行。因为我是第一次用STM32F030,之前用103的时候很多想法都有先人实践过,大部分抄过来改改就行了,然而030真心资料好少,调试这三样东西花了我好多的精力才调通。其中有两个坑要说的,默认的TIMER-TRGO事件是定时器复位而不是定时器updata溢出,也就是说,要配置成updata,才能在每次定时器溢出的时候触发adc 。第二出就是这个芯片的定时器15个人感觉有很大的问题。它定出来的时间是常规的128分频,然而我找了参考手册,没找到关于怎么调整这个分频为1分频的地方。参考时钟树,发觉同样是挂在APB2上的定时器16,确是一切正常,毫无半点问题,这也是百思不得其解。。。。之前我是用定时器15触发adc的,结果发觉频率老是不对,后来改到了定时器3触发,就一切正常了。  

最后说一点,对于USB和电池电压检测,因为换了030,都是不支持的,所以这方面我就没研究了。

使用软件单一频率的扫频部分图



最后是音乐播放的视频
其实如果这个点阵能宽度变成2倍的话,也就是44*22的话,那么显示效果真的能大大提升,现在这个矮矮的,频率条子太容易冲出去了。
里面有四首歌,(按顺序)分别是,这些歌里面除了第三首是看了坛友的视频跟风测试的以外,其他几首貌似都比较小众,个人感觉也很悦耳,算是安利一发吧,喜欢的可以下载听听
King of My Heart  
歌手:Love & the Outcome
Bonnie & Clyde
歌手:Sarah Connor/Henning Wehland
My Soul(忧伤还是快乐)  
歌手:昼夜
The Riot's Gone
歌手:Santigold

flash: http://player.youku.com/player.php/sid/XMTgwODU3NjkwMA==/v.swf

源代码在这里:链接:http://pan.baidu.com/s/1sk9jV1V 密码:tce9
或者可以下载附件


回帖都有m币哦


[ 此帖被2545889167在2016-11-12 12:16重新编辑 ]
本文内容包含图片或附件,获取更多资讯,请 登录 后查看;或者 注册 成为会员获得更多权限
本帖最近打赏记录:共2条打赏M币+40
hellodoraemo M币 +20 優秀文章 2019-01-17
皮卡丘の星空 M币 +20 - 2018-12-18
离线mousebat04

发帖
16458
M币
8980
专家
10
粉丝
92
只看该作者 1楼 发表于: 2016-11-07
请登录后查看
本帖最近打赏记录:共1条打赏M币+3
离线shi988

发帖
556
M币
1028
专家
2
粉丝
25
只看该作者 2楼 发表于: 2016-11-07
请登录后查看
本帖最近打赏记录:共2条打赏M币+6
离线2545889167

发帖
13268
M币
20754
专家
302
粉丝
4860
只看该作者 3楼 发表于: 2016-11-07
请登录后查看
[ 此帖被2545889167在2016-11-12 12:20重新编辑 ]
本帖最近打赏记录:共4条打赏M币+12
离线搅搅震

发帖
8831
M币
7012
专家
3
粉丝
43
只看该作者 4楼 发表于: 2016-11-07
请登录后查看
本帖最近打赏记录:共3条打赏M币+9
离线迷惘186

发帖
108
M币
316
专家
0
粉丝
4
只看该作者 5楼 发表于: 2016-11-07
请登录后查看
本帖最近打赏记录:共2条打赏M币+6
离线jpdd521

发帖
25693
M币
8005
专家
15
粉丝
350
只看该作者 6楼 发表于: 2016-11-07
请登录后查看
本帖最近打赏记录:共2条打赏M币+6
离线wangke2010

发帖
1147
M币
784
专家
5
粉丝
51
只看该作者 7楼 发表于: 2016-11-07
标题
请登录后查看
[ 此帖被wangke2010在2016-11-07 01:50重新编辑 ]
本帖最近打赏记录:共1条打赏M币+3
离线mousebat04

发帖
16458
M币
8980
专家
10
粉丝
92
只看该作者 8楼 发表于: 2016-11-07
请登录后查看
本帖最近打赏记录:共1条打赏M币+3

发帖
3521
M币
10795
专家
6
粉丝
55
只看该作者 9楼 发表于: 2016-11-07
请登录后查看
快速回复
限80 字节
如果您提交过一次失败了,可以用”恢复数据”来恢复帖子内容
 
上一个 下一个