找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 181|回复: 2
打印 上一主题 下一主题
收起左侧

求助3264双色点阵音乐频谱的问题

[复制链接]
跳转到指定楼层
楼主
ID:86421 发表于 2025-4-19 16:01 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
偶得一块3264双色的点阵屏,想用STC15的单片机做一个音乐频谱,频率24M。可整了几天也整不出来,烦请老师帮忙看一下问题出在哪?该如何改?代码中:ADC读取部分移植于12864音乐频谱显示,好用,显示部分就简单了。可到一起就不好用了。之所以没有用定时器控制显示,是不会计算ADC的时序,怕程序出现问题。另:本论坛中也有音乐频谱的相关资料,可没有一个上机能用的,为此我还专门买了STC12的单片机,不知问题出在哪。
  1. #include<math.h>

  2. #include <STC15.h>

  3. #include "intrins.h"
  4. #define uchar unsigned char
  5. #define uint unsigned int



  6. #define ADC_POWER   0x80     
  7. #define ADC_FLAG    0x10     
  8. #define ADC_START   0x08     
  9. #define ADC_SPEEDLL 0x00     
  10. #define ADC_SPEEDL  0x20     
  11. #define ADC_SPEEDH  0x40     
  12. #define ADC_SPEEDHH 0x60     

  13. struct compx                                                                           
  14. {
  15.         float real;
  16.         float imag;
  17. };

  18. xdata struct compx s[ 64 ];                                                      
  19. struct compx EE(struct compx,struct compx);   
  20. void FFT(struct compx xin[],int N);                                    


  21. sbit  R1=P3^6;   
  22. sbit  R2=P3^7;   
  23. sbit  G1=P2^4;   
  24. sbit  G2=P2^5;   

  25. sbit  STB=P2^6;   
  26. sbit  SCK=P2^7;   
  27. sbit  OE=P3^5;         

  28. sbit  IA=P2^0;   
  29. sbit  IB=P2^1;   
  30. sbit  IC=P2^2;   
  31. sbit  ID=P2^3;   


  32. uchar data row;                        


  33. void xianshi();      
  34. void hang();         


  35. void InitADC()
  36. {
  37.           P1ASF =0x01;              
  38.           P1M0 = 0x01;                    
  39.           P1M1 = 0x01;              
  40.     ADC_RES = 0;               
  41.           ADC_RESL = 0;                  
  42.     ADC_CONTR = ADC_POWER | ADC_SPEEDLL;         
  43. }


  44. unsigned int  GetADCResult(unsigned char  ch)
  45. {
  46.     ADC_CONTR = ADC_POWER | ADC_SPEEDHH | ch | ADC_START;
  47.     _nop_();                        
  48.     _nop_();
  49.     _nop_();
  50.     _nop_();
  51.     while (!(ADC_CONTR & ADC_FLAG));
  52.     ADC_CONTR &= ~ADC_FLAG;         
  53.     return (ADC_RES<<2+ADC_RESL);               
  54. }


  55. struct compx EE(struct compx a1,struct compx b2)        
  56. {
  57.         struct compx b3;
  58.         b3.real=a1.real*b2.real-a1.imag*b2.imag;
  59.         b3.imag=a1.real*b2.imag+a1.imag*b2.real;
  60.         return(b3);
  61. }

  62. void FFT(struct compx xin[],int N)                                 
  63. {
  64.         int f,m,nv2,nm1,i,k,j=1,l;
  65.         struct compx v,w,t;
  66.         nv2=N/2;
  67.         f=N;
  68.         for(m=1;(f=f/2)!=1;m++){;}
  69.         nm1=N-1;
  70.         for(i=0;i<nm1;i++)                                          
  71.         {
  72.                 if(i<j)
  73.                 {
  74.                         t=xin[j];
  75.                         xin[j]=xin[i];
  76.                         xin[i]=t;
  77.                 }
  78.                 k=nv2;                                                      
  79.                 while(k<j)
  80.                 {
  81.                         j=j-k;
  82.                         k=k/2;
  83.                 }
  84.                 j=j+k;
  85.         }
  86.         {
  87.                 int le,lei,ip;
  88.                   float pi;
  89.                   for(l=1;l<=m;l++)
  90.                    {
  91.                 le=pow(2,l);                                                
  92.                     lei=le/2;
  93.                     pi=3.14159265;
  94.                     v.real=1.0;
  95.                 v.imag=0.0;  
  96.                    w.real=cos(pi/lei);                                          
  97.                     w.imag=-sin(pi/lei);
  98.                   
  99.                 for(j=1;j<=lei;j++)                                          
  100.                      {
  101.                         for(i=j-1;i<N;i=i+le)                                         
  102.                               {
  103.                                     ip=i+lei;
  104.                                        t=EE(xin[ ip ],v);
  105.                                        xin[ ip ].real=xin[ i ].real-t.real;   
  106.                                        xin[ ip ].imag=xin[ i ].imag-t.imag;
  107.                                        xin[ i ].real=xin[ i ].real+t.real;
  108.                                        xin[ i ].imag=xin[ i ].imag+t.imag;
  109.                               }
  110.                               v=EE(v,w);   
  111.                       }     
  112.                    }
  113.           }
  114. }


  115. void main (void)
  116. {

  117.         int N=64,i;                                                            
  118.         float offset;

  119.         P1M0=0x00;
  120.   P1M1=0x00;
  121.   P3M0=0x00;
  122.   P3M1=0x00;
  123.   P2M0=0x00;
  124.   P2M1=0x00;

  125.   InitADC();         
  126.         offset=GetADCResult(0);
  127.       
  128.         while (1)         
  129.         {
  130.                         for(i=0;i<N;i++)                                      
  131.                   {
  132.                                 ADC_CONTR=0xC8;                                         

  133.                                 while(!(ADC_CONTR&0x10));
  134.                                    s[i].real=((float)ADC_RES*4+(float)(ADC_RESL%0x04)-offset)/4;  
  135.                                    s[i].imag=0;
  136.                   }
  137.                        
  138.                           FFT(s,N);        
  139.                     xianshi();
  140.         }
  141. }



  142. void hang(unsigned char Value)
  143. {
  144.         switch(Value)
  145.         {
  146.                                         case  0: {IA=0;IB=0;IC=0;ID=0;}break;
  147.                       case  1: {IA=1;IB=0;IC=0;ID=0;}break;
  148.                       case  2: {IA=0;IB=1;IC=0;ID=0;}break;
  149.                       case  3: {IA=1;IB=1;IC=0;ID=0;}break;
  150.           case  4: {IA=0;IB=0;IC=1;ID=0;}break;
  151.                       case  5: {IA=1;IB=0;IC=1;ID=0;}break;
  152.                       case  6: {IA=0;IB=1;IC=1;ID=0;}break;
  153.                       case  7: {IA=1;IB=1;IC=1;ID=0;}break;
  154.           case  8: {IA=0;IB=0;IC=0;ID=1;}break;
  155.                       case  9: {IA=1;IB=0;IC=0;ID=1;}break;
  156.                       case 10: {IA=0;IB=1;IC=0;ID=1;}break;
  157.                       case 11: {IA=1;IB=1;IC=0;ID=1;}break;
  158.           case 12: {IA=0;IB=0;IC=1;ID=1;}break;
  159.                       case 13: {IA=1;IB=0;IC=1;ID=1;}break;
  160.                        case 14: {IA=0;IB=1;IC=1;ID=1;}break;
  161.                 case 15: {IA=1;IB=1;IC=1;ID=1;}break;
  162.         }
  163.                                        
  164. }


  165. void xianshi()
  166. {
  167.   unsigned char i,j;
  168.         unsigned char dis_rdata[16];

  169.         for(i=0;i<16;i++)         
  170.         {
  171.                 float t0=0;
  172.                 t0=sqrt(pow((s[i  ].real+s[i+1].real),2)+pow((s[i  ].imag+s[i+1].imag),2))/2;
  173.                 dis_rdata[i]=(unsigned char)t0;
  174.         }

  175.                          for(j=0;j<64;j++)           
  176.                         {                                       
  177.                                 SCK=0;
  178.                                 SCK=1;

  179.                                 if(dis_rdata[j]<=row+16) R1=1;
  180.                                 else R1=0;
  181.                                 if(dis_rdata[j]<=row) R2=1;
  182.                                 else R2=0;
  183.                         }

  184.                 STB=1;
  185.                 STB=0;                                

  186.                 row++;
  187.                         if(row>15)row=0;
  188.                         OE=1;
  189.                 hang(row);                        
  190.                 OE=0;
  191. }
复制代码


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:1137639 发表于 2025-4-19 22:31 | 只看该作者
### 代码问题分析
1. **头文件包含与编译器兼容性**
    - 代码中包含了`STC15.h`头文件,该头文件用于STC15系列单片机,对寄存器等进行定义。确保该头文件与所使用的编译器版本兼容,不同编译器对头文件的支持和解析可能存在差异。如果编译器对某些寄存器定义识别有误,可能导致程序运行异常。
    - 虽然包含了`math.h`用于运算(如在`FFT`函数中使用`pow`、`cos`、`sin`等函数),但在单片机开发中,`math.h`库函数的实现可能会消耗较多资源(如代码空间和运行时间)。对于资源有限的单片机(如STC15 ),可能需要考虑使用简化的运算替代方案,或者优化库函数的使用。
2. **ADC部分**
    - 在`InitADC`函数中,对`P1ASF`、`P1M0`、`P1M1`进行设置,用于配置ADC相关引脚的功能。确保这些设置与实际硬件连接匹配,例如所选的ADC通道引脚是否正确配置为模拟输入功能。
    - 在`GetADCResult`函数中,通过设置`ADC_CONTR`寄存器启动ADC转换,并等待转换完成标志位。这里存在一个潜在问题,在等待转换完成标志位时,只是简单地循环检测,没有添加超时机制。如果ADC转换出现异常,可能导致程序进入死循环。可以添加一个计数器,在一定次数检测后跳出循环并进行错误处理。
3. **FFT(快速傅里叶变换)部分**
    - `FFT`函数实现较为复杂,在计算过程中涉及到大量的复数运算(通过`EE`函数实现复数乘法 )。需要仔细检查复数运算逻辑是否正确,例如`EE`函数中复数乘法的计算是否符合数学定义,确保在运算过程中不会出现精度丢失或计算错误,影响FFT结果的准确性。
    - 在`FFT`函数中,一些变量的初始化和计算逻辑可能存在问题。例如`for(m = 1;(f = f/2) != 1;m++){;}`这部分代码用于计算FFT的级数,要确保计算结果正确,否则后续的蝶形运算可能会出现错误。
4. **显示部分**
    - 在`xianshi`函数中,计算频谱数据并控制点阵屏显示。这里计算频谱数据的方式是根据FFT结果进行简单处理,需要确认这种处理方式是否能准确反映音乐频谱。例如,计算平方根等操作是否符合实际频谱显示需求。
    - 点阵屏的显示控制逻辑较为简单,通过`SCK`、`STB`、`OE`等引脚控制数据传输和显示。需要检查这些引脚的时序是否与点阵屏的硬件要求严格匹配。如果时序出现偏差,可能导致显示异常,如显示乱码、部分区域不显示等问题。同时,在控制`R1`、`R2`等引脚时,判断条件和逻辑可能需要进一步优化,以实现更准确的频谱显示效果。
5. **整体时序与资源管理**
    - 由于没有使用定时器控制显示,而是在主循环中不断进行ADC读取、FFT计算和显示操作,可能导致各部分操作的时序混乱。例如,ADC读取频率可能与FFT计算和显示频率不匹配,影响最终的频谱显示效果。建议使用定时器来精确控制各部分操作的时间间隔,确保程序运行的稳定性和准确性。
    - STC15单片机资源有限,在进行ADC读取、FFT计算和点阵屏显示等操作时,要注意资源管理。例如,代码中定义了较多的变量(如`xdata struct compx s[64]` ),需要确保这些变量的存储不会超出单片机的内存限制。同时,FFT计算等操作可能会占用较多的计算资源和时间,要合理优化算法,避免程序运行过于缓慢或出现死机现象。

### 改进建议
1. **ADC部分改进**
    - 在`GetADCResult`函数中添加超时机制。例如:
```c
unsigned int GetADCResult(unsigned char ch)
{
    int timeout = 100; // 设置超时次数
    ADC_CONTR = ADC_POWER | ADC_SPEEDHH | ch | ADC_START;
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    while (!(ADC_CONTR & ADC_FLAG) && timeout > 0) {
        timeout--;
    }
    if (timeout == 0) {
        // 处理超时错误,例如返回一个错误值
        return 0xFFFF;
    }
    ADC_CONTR &= ~ADC_FLAG;
    return (ADC_RES<<2+ADC_RESL);
}
```
2. **FFT部分改进**
    - 对`FFT`函数中的变量初始化和计算逻辑进行详细验证。可以通过打印中间变量的值等方式,检查每一步计算是否正确。例如,在计算级数的部分:
```c
for(m = 1;(f = f/2) != 1;m++){;}
// 可以添加打印语句,查看m和f的值是否符合预期
// 如:printf("m = %d, f = %d\n", m, f);
```
    - 优化复数运算部分的代码,提高计算精度和效率。可以参考一些成熟的FFT算法实现,对比检查代码中的运算逻辑是否正确。
3. **显示部分改进**
    - 重新评估频谱数据的计算方式,可以参考相关的音乐频谱显示算法资料,确保计算出的数据能准确反映音乐频谱。
    - 使用示波器等工具测量点阵屏控制引脚的时序,与点阵屏的硬件手册进行对比,精确调整时序逻辑。例如,确保`SCK`、`STB`等信号的脉冲宽度、上升沿和下降沿时间等符合要求。
4. **整体时序与资源管理改进**
    - 使用定时器来控制程序的运行时序。例如,设置一个定时器中断,每隔一定时间(如根据音乐信号的频率和采样要求确定 )触发一次ADC读取操作,然后进行FFT计算和显示操作。在STC15单片机中,可以通过配置定时器相关寄存器来实现。
    - 对代码中的变量进行优化,合理分配内存资源。如果内存紧张,可以考虑减少不必要的变量定义,或者对一些变量进行复用。同时,对FFT等复杂算法进行优化,减少计算资源的消耗。例如,可以使用定点运算替代部分浮点运算,以提高运算速度和减少资源占用。
回复

使用道具 举报

板凳
ID:86421 发表于 2025-4-20 07:57 | 只看该作者
622323wjl 发表于 2025-4-19 22:31
### 代码问题分析
1. **头文件包含与编译器兼容性**
    - 代码中包含了`STC15.h`头文件,该头文件用于ST ...

感谢!谢谢你的指导,分析的很有道理。比DeepSeek分析的还好。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表