標題:
求助3264雙色點陣音樂頻譜的問題
[打印本頁]
作者:
1qaz2wsx77
時間:
2025-4-19 16:01
標題:
求助3264雙色點陣音樂頻譜的問題
偶得一塊3264雙色的點陣屏,想用STC15的單片機做一個音樂頻譜,頻率24M。可整了幾天也整不出來,煩請老師幫忙看一下問題出在哪?該如何改?代碼中:ADC讀取部分移植于12864音樂頻譜顯示,好用,顯示部分就簡單了?傻揭黄鹁筒缓糜昧恕V詻]有用定時器控制顯示,是不會計算ADC的時序,怕程序出現(xiàn)問題。
另:本論壇中也有音樂頻譜的相關資料,可沒有一個上機能用的,為此我還專門買了STC12的單片機,不知問題出在哪。
#include<math.h>
#include <STC15.h>
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
#define ADC_POWER 0x80
#define ADC_FLAG 0x10
#define ADC_START 0x08
#define ADC_SPEEDLL 0x00
#define ADC_SPEEDL 0x20
#define ADC_SPEEDH 0x40
#define ADC_SPEEDHH 0x60
struct compx
{
float real;
float imag;
};
xdata struct compx s[ 64 ];
struct compx EE(struct compx,struct compx);
void FFT(struct compx xin[],int N);
sbit R1=P3^6;
sbit R2=P3^7;
sbit G1=P2^4;
sbit G2=P2^5;
sbit STB=P2^6;
sbit SCK=P2^7;
sbit OE=P3^5;
sbit IA=P2^0;
sbit IB=P2^1;
sbit IC=P2^2;
sbit ID=P2^3;
uchar data row;
void xianshi();
void hang();
void InitADC()
{
P1ASF =0x01;
P1M0 = 0x01;
P1M1 = 0x01;
ADC_RES = 0;
ADC_RESL = 0;
ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
}
unsigned int GetADCResult(unsigned char ch)
{
ADC_CONTR = ADC_POWER | ADC_SPEEDHH | ch | ADC_START;
_nop_();
_nop_();
_nop_();
_nop_();
while (!(ADC_CONTR & ADC_FLAG));
ADC_CONTR &= ~ADC_FLAG;
return (ADC_RES<<2+ADC_RESL);
}
struct compx EE(struct compx a1,struct compx b2)
{
struct compx b3;
b3.real=a1.real*b2.real-a1.imag*b2.imag;
b3.imag=a1.real*b2.imag+a1.imag*b2.real;
return(b3);
}
void FFT(struct compx xin[],int N)
{
int f,m,nv2,nm1,i,k,j=1,l;
struct compx v,w,t;
nv2=N/2;
f=N;
for(m=1;(f=f/2)!=1;m++){;}
nm1=N-1;
for(i=0;i<nm1;i++)
{
if(i<j)
{
t=xin[j];
xin[j]=xin[i];
xin[i]=t;
}
k=nv2;
while(k<j)
{
j=j-k;
k=k/2;
}
j=j+k;
}
{
int le,lei,ip;
float pi;
for(l=1;l<=m;l++)
{
le=pow(2,l);
lei=le/2;
pi=3.14159265;
v.real=1.0;
v.imag=0.0;
w.real=cos(pi/lei);
w.imag=-sin(pi/lei);
for(j=1;j<=lei;j++)
{
for(i=j-1;i<N;i=i+le)
{
ip=i+lei;
t=EE(xin[ ip ],v);
xin[ ip ].real=xin[ i ].real-t.real;
xin[ ip ].imag=xin[ i ].imag-t.imag;
xin[ i ].real=xin[ i ].real+t.real;
xin[ i ].imag=xin[ i ].imag+t.imag;
}
v=EE(v,w);
}
}
}
}
void main (void)
{
int N=64,i;
float offset;
P1M0=0x00;
P1M1=0x00;
P3M0=0x00;
P3M1=0x00;
P2M0=0x00;
P2M1=0x00;
InitADC();
offset=GetADCResult(0);
while (1)
{
for(i=0;i<N;i++)
{
ADC_CONTR=0xC8;
while(!(ADC_CONTR&0x10));
s[i].real=((float)ADC_RES*4+(float)(ADC_RESL%0x04)-offset)/4;
s[i].imag=0;
}
FFT(s,N);
xianshi();
}
}
void hang(unsigned char Value)
{
switch(Value)
{
case 0: {IA=0;IB=0;IC=0;ID=0;}break;
case 1: {IA=1;IB=0;IC=0;ID=0;}break;
case 2: {IA=0;IB=1;IC=0;ID=0;}break;
case 3: {IA=1;IB=1;IC=0;ID=0;}break;
case 4: {IA=0;IB=0;IC=1;ID=0;}break;
case 5: {IA=1;IB=0;IC=1;ID=0;}break;
case 6: {IA=0;IB=1;IC=1;ID=0;}break;
case 7: {IA=1;IB=1;IC=1;ID=0;}break;
case 8: {IA=0;IB=0;IC=0;ID=1;}break;
case 9: {IA=1;IB=0;IC=0;ID=1;}break;
case 10: {IA=0;IB=1;IC=0;ID=1;}break;
case 11: {IA=1;IB=1;IC=0;ID=1;}break;
case 12: {IA=0;IB=0;IC=1;ID=1;}break;
case 13: {IA=1;IB=0;IC=1;ID=1;}break;
case 14: {IA=0;IB=1;IC=1;ID=1;}break;
case 15: {IA=1;IB=1;IC=1;ID=1;}break;
}
}
void xianshi()
{
unsigned char i,j;
unsigned char dis_rdata[16];
for(i=0;i<16;i++)
{
float t0=0;
t0=sqrt(pow((s[i ].real+s[i+1].real),2)+pow((s[i ].imag+s[i+1].imag),2))/2;
dis_rdata[i]=(unsigned char)t0;
}
for(j=0;j<64;j++)
{
SCK=0;
SCK=1;
if(dis_rdata[j]<=row+16) R1=1;
else R1=0;
if(dis_rdata[j]<=row) R2=1;
else R2=0;
}
STB=1;
STB=0;
row++;
if(row>15)row=0;
OE=1;
hang(row);
OE=0;
}
復制代碼
作者:
622323wjl
時間:
2025-4-19 22:31
### 代碼問題分析
1. **頭文件包含與編譯器兼容性**
- 代碼中包含了`STC15.h`頭文件,該頭文件用于STC15系列單片機,對寄存器等進行定義。確保該頭文件與所使用的編譯器版本兼容,不同編譯器對頭文件的支持和解析可能存在差異。如果編譯器對某些寄存器定義識別有誤,可能導致程序運行異常。
- 雖然包含了`math.h`用于運算(如在`FFT`函數(shù)中使用`pow`、`cos`、`sin`等函數(shù)),但在單片機開發(fā)中,`math.h`庫函數(shù)的實現(xiàn)可能會消耗較多資源(如代碼空間和運行時間)。對于資源有限的單片機(如STC15 ),可能需要考慮使用簡化的運算替代方案,或者優(yōu)化庫函數(shù)的使用。
2. **ADC部分**
- 在`InitADC`函數(shù)中,對`P1ASF`、`P1M0`、`P1M1`進行設置,用于配置ADC相關引腳的功能。確保這些設置與實際硬件連接匹配,例如所選的ADC通道引腳是否正確配置為模擬輸入功能。
- 在`GetADCResult`函數(shù)中,通過設置`ADC_CONTR`寄存器啟動ADC轉(zhuǎn)換,并等待轉(zhuǎn)換完成標志位。這里存在一個潛在問題,在等待轉(zhuǎn)換完成標志位時,只是簡單地循環(huán)檢測,沒有添加超時機制。如果ADC轉(zhuǎn)換出現(xiàn)異常,可能導致程序進入死循環(huán)?梢蕴砑右粋計數(shù)器,在一定次數(shù)檢測后跳出循環(huán)并進行錯誤處理。
3. **FFT(快速傅里葉變換)部分**
- `FFT`函數(shù)實現(xiàn)較為復雜,在計算過程中涉及到大量的復數(shù)運算(通過`EE`函數(shù)實現(xiàn)復數(shù)乘法 )。需要仔細檢查復數(shù)運算邏輯是否正確,例如`EE`函數(shù)中復數(shù)乘法的計算是否符合數(shù)學定義,確保在運算過程中不會出現(xiàn)精度丟失或計算錯誤,影響FFT結(jié)果的準確性。
- 在`FFT`函數(shù)中,一些變量的初始化和計算邏輯可能存在問題。例如`for(m = 1;(f = f/2) != 1;m++){;}`這部分代碼用于計算FFT的級數(shù),要確保計算結(jié)果正確,否則后續(xù)的蝶形運算可能會出現(xiàn)錯誤。
4. **顯示部分**
- 在`xianshi`函數(shù)中,計算頻譜數(shù)據(jù)并控制點陣屏顯示。這里計算頻譜數(shù)據(jù)的方式是根據(jù)FFT結(jié)果進行簡單處理,需要確認這種處理方式是否能準確反映音樂頻譜。例如,計算平方根等操作是否符合實際頻譜顯示需求。
- 點陣屏的顯示控制邏輯較為簡單,通過`SCK`、`STB`、`OE`等引腳控制數(shù)據(jù)傳輸和顯示。需要檢查這些引腳的時序是否與點陣屏的硬件要求嚴格匹配。如果時序出現(xiàn)偏差,可能導致顯示異常,如顯示亂碼、部分區(qū)域不顯示等問題。同時,在控制`R1`、`R2`等引腳時,判斷條件和邏輯可能需要進一步優(yōu)化,以實現(xiàn)更準確的頻譜顯示效果。
5. **整體時序與資源管理**
- 由于沒有使用定時器控制顯示,而是在主循環(huán)中不斷進行ADC讀取、FFT計算和顯示操作,可能導致各部分操作的時序混亂。例如,ADC讀取頻率可能與FFT計算和顯示頻率不匹配,影響最終的頻譜顯示效果。建議使用定時器來精確控制各部分操作的時間間隔,確保程序運行的穩(wěn)定性和準確性。
- STC15單片機資源有限,在進行ADC讀取、FFT計算和點陣屏顯示等操作時,要注意資源管理。例如,代碼中定義了較多的變量(如`xdata struct compx s[64]` ),需要確保這些變量的存儲不會超出單片機的內(nèi)存限制。同時,F(xiàn)FT計算等操作可能會占用較多的計算資源和時間,要合理優(yōu)化算法,避免程序運行過于緩慢或出現(xiàn)死機現(xiàn)象。
### 改進建議
1. **ADC部分改進**
- 在`GetADCResult`函數(shù)中添加超時機制。例如:
```c
unsigned int GetADCResult(unsigned char ch)
{
int timeout = 100; // 設置超時次數(shù)
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`函數(shù)中的變量初始化和計算邏輯進行詳細驗證?梢酝ㄟ^打印中間變量的值等方式,檢查每一步計算是否正確。例如,在計算級數(shù)的部分:
```c
for(m = 1;(f = f/2) != 1;m++){;}
// 可以添加打印語句,查看m和f的值是否符合預期
// 如:printf("m = %d, f = %d\n", m, f);
```
- 優(yōu)化復數(shù)運算部分的代碼,提高計算精度和效率。可以參考一些成熟的FFT算法實現(xiàn),對比檢查代碼中的運算邏輯是否正確。
3. **顯示部分改進**
- 重新評估頻譜數(shù)據(jù)的計算方式,可以參考相關的音樂頻譜顯示算法資料,確保計算出的數(shù)據(jù)能準確反映音樂頻譜。
- 使用示波器等工具測量點陣屏控制引腳的時序,與點陣屏的硬件手冊進行對比,精確調(diào)整時序邏輯。例如,確保`SCK`、`STB`等信號的脈沖寬度、上升沿和下降沿時間等符合要求。
4. **整體時序與資源管理改進**
- 使用定時器來控制程序的運行時序。例如,設置一個定時器中斷,每隔一定時間(如根據(jù)音樂信號的頻率和采樣要求確定 )觸發(fā)一次ADC讀取操作,然后進行FFT計算和顯示操作。在STC15單片機中,可以通過配置定時器相關寄存器來實現(xiàn)。
- 對代碼中的變量進行優(yōu)化,合理分配內(nèi)存資源。如果內(nèi)存緊張,可以考慮減少不必要的變量定義,或者對一些變量進行復用。同時,對FFT等復雜算法進行優(yōu)化,減少計算資源的消耗。例如,可以使用定點運算替代部分浮點運算,以提高運算速度和減少資源占用。
作者:
1qaz2wsx77
時間:
2025-4-20 07:57
622323wjl 發(fā)表于 2025-4-19 22:31
### 代碼問題分析
1. **頭文件包含與編譯器兼容性**
- 代碼中包含了`STC15.h`頭文件,該頭文件用于ST ...
感謝!謝謝你的指導,分析的很有道理。比DeepSeek分析的還好。
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1