4 7
您的位置: 电子制作DIY -> 单片机 -> 51单片机 -> 用单片机ATMEGA324PA自制音乐频谱-附C程序源... 
本帖共有684个阅读者
发表帖子 发表投票 回复主题
用单片机ATMEGA324PA自制音乐频谱-附C程序源代码
尊贵身份标志
灰色小精灵(VIP会员)
灰色小精灵
头衔:版面管理
帮派:无帮无派
帖数:26
金钱:346
积分:77
注册时间:2020/12/28
楼主信息 | 留言 | Email | 主页 | 编辑 | 管理 | 离线
用单片机ATMEGA324PA自制音乐频谱-附C程序源代码
看到论坛上有很多朋友做了音乐频谱,感觉很炫,于是也模仿着做了一个。在制作过程中,从网上查了很多资料,得到很多帮助。我要非常感谢那些辛勤付出的网友们,是你们无私的付出让我们可以站在更高的起点奔跑。诗经有云:投我以木桃,报之以琼瑶。如果一味的索取,泉源也会枯竭。故将我制作的所有资料传上来,以作为对那些帮助过我的网友的答谢,也希望看到此贴的人能将此一做法传承下去,
为论坛贡献自己的一份力量。效果图:

这个作品的制作可以分为三个过程:1、焊接LED点阵;2、设计控制电路;3、编程所谓音乐频谱就是将音乐的各个频率分量显示出来,LED点阵的水平轴代表各个频率,竖直轴代表强度。从下面的图中可以看出,该点阵大小为16*30(本来要做16*32,限于万用板大小只能容下30列)。每两列为一组,共15组,由于是阴极接在一起,姑且称之为共阴极组;同理,每一行的阳极接在一起,称为共阳极组,共16组。
点阵接线图:
正面:

(围成圆圈的灯是七彩快闪LED,只要接上电源,其颜色自动变换。)
背面:

从图中可以看到,所有的阴极线(15根)、阳极线(16根) 都用排针引出来,再用杜邦线就可以和控制板相连。
控制电路图:

单片机用的是ATMEGA324PA(内部晶振,8MHZ),只用到通用IO功能,移植到其他单片机上也很方便。基本控制思路:扫描。每一时刻只让一个共阴极组接地,其它接高电平,从左至右依次选通每个共阴极组。每次选中共阴极组后,需要对其阳极写入数据,由于有16行,需要写入两个字节。假如以上方为高字节,我想让选中的共阴极组下面的9行灯亮,则应往阳极段写入的两个字节为:0x01,0xff。控制电路采用了4个锁存器74HC573,2个ULN2803(八路达林顿管,其实是一个8路反向器,可以承受大电流

。左边两个573用来对阳极写入数据,右边两个573和2803接在一起,用来选通共阴极组。4个573的数据输入端都连到一起,接在单片机的PB口。573还有一个选通端LE,当其为高电平时,可以对其写入数据,低电平时输出锁存。将其作为片选(SS0,SS1,SS2,SS3)依次接单片机PA0,PA1,PA2,PA3。每次只让一个片选为1,就可以对每个573分开写入数据了。最后说说编程。用了一个声音模块采集声音,声音模块
原理为:麦克接收声音,OUT端输出声音信号波形。OUT端接在单片机的PA7(AD转换端口)上。程序的循环中,先进行32次AD采样,得到32(必须是2的n次方)个采样值,做快速傅里叶变换,得到32个频率的强度,由于是前后对称的,只取其前15个频率的强度,经过幅值调整(调为0~16),在15个共阴极组上依次显示出来。


「该帖子被 灰色小精灵 在 2021/1/6 13:41:47 编辑过」

我的地盘我做主
等级:VIP会员 参考IP地址:*.*.*.*
2021/1/6 13:36:51
尊贵身份标志
灰色小精灵(VIP会员)
灰色小精灵
头衔:版面管理
帮派:无帮无派
帖数:26
金钱:346
积分:77
注册时间:2020/12/28
1信息 | 留言 | Email | 主页 | 编辑 | 管理 | 离线
1、<main.c>
主函数(AD转换,FFT变换)
  1. #define   F_CPU  8  //可定义为你所用的晶振频率(单位Mhz)
  2. #include <ioavr.h>
  3. #include "delay.h"
  4. #include "data.h"
  5. #include "display.h"
  6. #define DATA PORTB
  7. #define SS0 PORTA_Bit0
  8. #define SS1 PORTA_Bit1
  9. #define SS2 PORTA_Bit2
  10. #define SS3 PORTA_Bit3
  11. #define pi 3.141592654
  12. #include<math.h>//要调入数学(和谐)运算的头文件
  13. //定义复数结构
  14. struct compx
  15. {
  16.   float real;
  17.   float imag;
  18. };
  19. //定义复数乘法
  20. struct compx EE(struct compx a,struct compx b)
  21. {
  22.   struct compx c;
  23.   c.real=a.real*b.real-a.imag*b.imag;
  24.   c.imag=a.real*b.imag+a.imag*b.real;
  25.   return(c);
  26. }
  27. //定义复数求模
  28. float cmplxabs(struct compx a)
  29. {
  30.   float b;
  31.   b=sqrt(a.real*a.real+a.imag*a.imag);
  32.   return(b);
  33. }
  34. //FFT子程序
  35. //入口:复数数组指针和点数。
  36. //出口:原复数数组,取模后为强度,可用于频谱。
  37. void FFT(struct compx *xin,unsigned int N)
  38. {
  39.   int f,m,nv2,nm1,i,k,j=1,l;
  40.   int le,lei,ip;
  41.   struct compx v,w,t;
  42.   nv2=N/2;
  43.   f=N;
  44.   for(m=1;(f=f/2)!=1;m++);
  45.   nm1=N-1;
  46.   for(i=1;i<=nm1;i++)
  47.   {
  48.     if(i<j)
  49.       {
  50.         t=xin[j-1];
  51.         xin[j-1]=xin[i-1];
  52.         xin[i-1]=t;
  53.       }
  54.     k=nv2;
  55.     while(k<j){j=j-k;k=k/2;}
  56.     j=j+k;
  57.   }
  58.   /* FFT*/
  59.   for(l=1;l<m;l++)
  60.   {
  61.     le=(int)pow(2.0,l);
  62.     lei=le/2;
  63.     v.real=1.0;v.imag=0.0;
  64.     w.real=cos(pi/lei);w.imag=-sin(pi/lei);
  65.     for(j=1;j<=lei;j++)
  66.     {
  67.       for(i=j;i<=N;i+=le)
  68.       {
  69.         ip=i+lei;
  70.         t=EE(xin[ip-1],v);
  71.         xin[ip-1].real=xin[i-1].real-t.real;
  72.         xin[ip-1].imag=xin[i-1].imag-t.imag;
  73.         xin[i-1].real=xin[i-1].real+t.real;
  74.         xin[i-1].imag=xin[i-1].imag+t.imag;
  75.       }
  76.       v=EE(v,w);
  77.     }
  78.   }
  79. }
  80. void ADC_Init()
  81. {
  82.   ADCSRA=0xE3;//ADC使能,开始转换,自动触发转换,中断bit3,8分频
  83.   ADCSRB=0x00;//自由转换模式
  84.   ADMUX=0x47;//基准电压Internal 1.1V Voltage,通道0 4n通道n
  85. }
  86. char s[15][2]={0};
  87. void start()
  88. {
  89.   flash2(1);
  90.   flash4(1);
  91.   flash5(5);
  92. }
  93. void end()
  94. {
  95.   scroll(67,word,1);
  96.   flash2(1);
  97.   while(1)xiaolian(5);
  98. }
  99. char counter=0;
  100. #pragma vector=TIMER1_OVF_vect
  101. __interrupt void TIMER1_OVF_ISR()
  102. {
  103.   TCNT1=0;//8.4s
  104.     counter++;
  105.   if(counter==28)
  106.     end();
  107. }
  108. void TIMER1_INIT()//TIMER1 16位定时器
  109. {
  110.   TCNT1=0;
  111.   TIMSK1=0x01;//T1溢出中断使能
  112.   SREG=0x80;//总中断使能
  113.   TCCR1A=0x00;
  114.   TCCR1B=0x05;//1024分频,开始计数
  115. }
  116. struct compx ss[32];
  117. char w=0,bar[15]={0};
  118. unsigned int t,tL,tH;
  119. void main()
  120. {
  121.   PORTA=0x00;
  122.   DDRA=0x0f;  
  123.   PORTB=0x00;
  124.   DDRB=0xFF;
  125.   ADC_Init();
  126.   start();
  127.   TIMER1_INIT();
  128.   while(1)
  129.   {  
  130.     tL=ADCL;
  131.     tH=ADCH<<8;
  132.     t=tH+tL;
  133.     ss[w].real=(float)t;//采样结果送实部,注意数据类型转换
  134.     ss[w].imag=0;
  135.     w++;
  136.     for(char i=1;i<10;i++)refresh(bar);
  137.     if(w==32)
  138.     {
  139.       w=0;
  140.       clear();
  141.       FFT(ss,32);
  142.       unsigned int sum;
  143.       for(char i=1;i<=15;i++)sum+=cmplxabs(ss);
  144.       sum/=15;//平均值
  145.       for(char i=0;i<=14;i++)
  146.       {
  147.         char temp=(char)(cmplxabs(ss[i+1])/250);
  148.         if(temp>16)temp=16;
  149.         if(bar>temp)
  150.           bar-=1;
  151.         else
  152.         {
  153.           bar=temp;
  154.         }
  155.       }
  156.     }
  157.   }
  158. }
限于篇幅现将源程序打包:
   2021161444875.rar [ 4.25 KB ]


「该帖子被 灰色小精灵 在 2021/1/6 14:05:23 编辑过」

我的地盘我做主
等级:VIP会员 参考IP地址:*.*.*.*
2021/1/6 13:43:03
Copyright © 2011 电子制作DIY. All rights reserved.电子制作DIY8066 Call, 1 Queries, Processed in 401.856 millisecond(2),