亚洲春色中文字幕久久久-三上亚,一吻二脱三床四吻胸,国产真实伦对白视频全集,在线毛片观看,精品成品入口黄网,国产毛aⅴ片久久久,亚洲AV色香蕉一区二区三区老师,萧皇后A级艳片,色情日本视频更新,99久久亚洲精品日本无码

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 514|回復: 5
打印 上一主題 下一主題
收起左側

實驗8位單片機STC8H8K64U數字音頻帶通濾波器

[復制鏈接]
跳轉到指定樓層
樓主
ID:1136941 發表于 2026-5-25 16:42 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
主體程序及算法由AI生成,我加入了PWM音頻輸出及按鍵調節,LCD1602顯示。DIY了實際電路,經實驗輸入夾雜噪音的音頻信號,調節Q值(帶寬同步變化)變化明顯,但是調節中心頻率變化不正常,不知道是不是8位單片機性能太低的結果,請有經驗的老師指點一下。
/***************************************************
* 8位單片機數字音頻帶通濾波器 - 可調版本
* 采樣率:8kHz (125us中斷)
* 功能:實時修改中心頻率(500Hz-3kHz)和帶寬(Q值1-10)
* 控制:按鍵+LCD顯示
***************************************************/
#include <STC8H.H>
#include <intrins.h>

// 類型定義
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
typedef signed int s16;
typedef signed long s32;

#define uchar unsigned char
#define uint unsigned int
       
typedef signed int q15;     // Q15定點數格式
typedef signed long q31;    // Q31定點數格式
//------------------------------------------
// 雙二階濾波器結構體
typedef struct {
    // 延遲線
    q15 x1, x2;     // 輸入延遲:x[n-1], x[n-2]
    q15 y1, y2;     // 輸出延遲:y[n-1], y[n-2]

    // 濾波器系數(Q15格式)
    q15 b0, b1, b2; // 前向系數
    q15 a1, a2;     // 反饋系數(實際存儲 -a1, -a2)
} BiquadFilter;

// 濾波器參數結構體
typedef struct {
    float fc;       // 中心頻率 (Hz)
    float q;        // 品質因數
    float fs;       // 采樣率 (Hz)

    // 計算出的系數
    float b0, b1, b2;
    float a0, a1, a2;
} FilterParams;
//-------定義PWM輸出引腳------------
#define PWM1_0 0X00  //P:P1.0,N:P1.1
#define PWM1_1 0X01  //P:P2.0,N:P2.1
#define PWM1_2 0X02  //P:P6.0,N:P6.1

#define PWM2_0 0X00  //P:P1.2/P5.4,N:P1.3
#define PWM2_1 0X04  //P:P2.2,N:P2.3
#define PWM2_2 0X08  //P:P6.2,N:P6.3

#define PWM3_0 0X00  //P:P1.4,N:P1.5
#define PWM3_1 0X10  //P:P2.4,N:P2.5
#define PWM3_2 0X20  //P:P6.4,N:P6.5

#define PWM4_0 0X00  //P:P1.6,N:P1.7
#define PWM4_1 0X40  //P:P2.6,N:P2.7
#define PWM4_2 0X80  //P:P6.6,N:P6.7
#define PWM4_3 0XC0  //P:P3.4,N:P3.3

#define ENO1P 0X01
#define ENO1N 0X02
#define ENO2P 0X04
#define ENO2N 0X08
#define ENO3P 0X10
#define ENO3N 0X20
#define ENO4P 0X40
#define ENO4N 0X80

/***************全局變量 ***************/
static BiquadFilter bandpass;           // 帶通濾波器
static FilterParams params;             // 濾波器參數
static unsigned char need_update = 0;   //0 系數更新標志
static q15 volume = 32767;  //16384 音量系數 0.5 (范圍0-32767)

unsigned char Table[]="0123456789";
unsigned char freq_num[4];// 頻率  
unsigned char q_num[2] ;//  Q值
unsigned char  bw_num[4];//帶寬

u16 center_freq=1000;//默認1000HZ
u16 center_q=1;//默認Q值1
bit flag=1;
//-------------------------------------------
// 按鍵定義
sbit KEY_FREQ_UP = P3^0;   // 頻率增加
sbit KEY_FREQ_DOWN = P3^1; // 頻率減少
sbit KEY_Q_UP = P3^2;      // Q值增加
sbit KEY_Q_DOWN = P3^3;    // Q值減少

sbit RS=P2^5; //定義rs端口
              // RW 接地
sbit EN=P2^3; //定義en端口
sbit LCD_D4=P4^2;
sbit LCD_D5=P4^1;
sbit LCD_D6=P3^7;
sbit LCD_D7=P3^6;

//-------------函數聲明------------------------
void gpio_init(void);
void Timer0_Init(void);
void ADC_Init(void);
u16 ADC_Read(u8 ch);
//----------------------
void audio_setup(void);
void Filter_ResetFloat(void);
float Filter_ProcessFloat(float input);
q15 Filter_Process(q15 input);
void Filter_ApplyUpdate(void);
void Filter_SetQ(float q_value);
void Filter_SetFrequency(float freq_hz);
void Filter_Init(float sample_rate);
static void Filter_ClearDelay(BiquadFilter *f);
static void Filter_UpdateCoefficients(BiquadFilter *f, FilterParams *p);
void Filter_CalculateCoefficients(FilterParams *p);
static q15 q15_add(q15 a, q15 b);
static q15 q15_mul(q15 a, q15 b);
float cosf(float x);
static float cosf_optimized_positive_range(float x);
float sinf(float x);
//----------------------
void KeyScan(void);
void DisplayStatus(void);
void pwm_init();
void pwm_out(u16 PWM1_Duty);
//--------------------------
void display_Bm(unsigned char x, unsigned char y);
void display_F(unsigned char x, unsigned char y);
void display_Q(unsigned char x, unsigned char y);
void LCD_en_write(void);
void LCD_by(uchar abc);
void LCD_set_xy( uchar x, uchar y );
void LCD_write_str(uchar X,uchar Y,uchar *s);
void LCD_init(void);
void delay_nus(uint n);
void delay_5us(void);
void del_ms(uint n);
void Delay1ms(void);
//--------------------------------------------------
float sinf(float x) {
    // 快速角度歸一化
    const float two_pi = 6.28318530717958647692f;
    const float inv_two_pi = 0.15915494309189533576f;
    int sign;
          float x2;
          float result;
    // 獲取倍數
    int n = (int)(x * inv_two_pi);
    x = x - n * two_pi;

    // 保持在 [-π, π] 范圍內
    if (x > 3.14159265358979323846f) x -= two_pi;
    if (x < -3.14159265358979323846f) x += two_pi;

    // 使用奇偶對稱性減少計算范圍到 [0, π/2]
    sign = 1;
    if (x < 0) {
        x = -x;
        sign = -1;
    }
    if (x > 1.57079632679489661923f) {  // x > π/2
        x = 3.14159265358979323846f - x;
    }

    // 泰勒級數計算,重新計算符號
    x2 = x * x;
    result = x * (1.0f - x2 / 6.0f * (1.0f - x2 / 20.0f * (1.0f - x2 / 42.0f)));

    return sign * result;
}

// 內部輔助函數,只處理 [0, π/2] 范圍
static float cosf_optimized_positive_range(float x) {
    float x2 = x * x;
    // 使用霍納法則優化多項式計算
    // cos(x) ≈ 1 - x2/2! + x?/4! - x?/6! + x?/8!
    return 1.0f + x2 * (-0.5f + x2 * (0.041666666666666664f +
              x2 * (-0.001388888888888889f + x2 * 0.0000248015873015873f)));
}

float cosf(float x) {
    // 快速角度歸一化
    const float two_pi = 6.28318530717958647692f;
    const float inv_two_pi = 0.15915494309189533576f;

    // 獲取倍數并歸一化到 [-π, π]
    int n = (int)(x * inv_two_pi);
    x = x - n * two_pi;

    if (x > 3.14159265358979323846f) x -= two_pi;
    if (x < -3.14159265358979323846f) x += two_pi;

    // 利用 cos(-x) = cos(x),將 x 轉為正值
    if (x < 0) x = -x;

    // 利用 cos(π-x) = -cos(x) 減少計算范圍
    if (x > 1.57079632679489661923f) {  // x > π/2
        x = 3.14159265358979323846f - x;
        return -cosf_optimized_positive_range(x);
    }

    return cosf_optimized_positive_range(x);
}

// Q15乘法:a * b,返回Q15格式(帶飽和)
static q15 q15_mul(q15 a, q15 b) {
    q31 result = (q31)a * (q31)b;
    result = result >> 15;

    // 飽和處理
    if (result > 32767) result = 32767;
    if (result < -32768) result = -32768;
    return (q15)result;
}

// Q15加法(帶飽和)
static q15 q15_add(q15 a, q15 b) {
    q31 sum = (q31)a + (q31)b;
    if (sum > 32767) return 32767;
    if (sum < -32768) return -32768;
    return (q15)sum;
}

// 計算雙二階帶通濾波器系數
// 公式來源:RBJ音頻均衡器濾波器設計
void Filter_CalculateCoefficients(FilterParams *p) {
    float w0 = 2.0f * 3.14159265359f * p->fc / p->fs;
    float cos_w0 = cosf(w0);
    float sin_w0 = sinf(w0);
    float alpha = sin_w0 / (2.0f * p->q);

    // 帶通濾波器系數
    p->b0 = alpha;
    p->b1 = 0.0f;
    p->b2 = -alpha;
    p->a0 = 1.0f + alpha;
    p->a1 = -2.0f * cos_w0;
    p->a2 = 1.0f - alpha;

    // 歸一化(除以a0)
    p->b0 /= p->a0;
    p->b1 /= p->a0;
    p->b2 /= p->a0;
    p->a1 /= p->a0;
    p->a2 /= p->a0;
}

// 將浮點系數轉換為Q15定點格式并更新濾波器
static void Filter_UpdateCoefficients(BiquadFilter *f, FilterParams *p) {
    // 浮點轉Q15(范圍-1到1映射到-32768到32767)
    f->b0 = (q15)(p->b0 * 32767.0f);
    f->b1 = (q15)(p->b1 * 32767.0f);
    f->b2 = (q15)(p->b2 * 32767.0f);

    // 注意:差分方程使用 y[n] = b0*x[n] + ... - a1*y[n-1] - a2*y[n-2]
    // 所以這里存儲的是 -a1 和 -a2
    f->a1 = (q15)((-p->a1) * 32767.0f);
    f->a2 = (q15)((-p->a2) * 32767.0f);
}

// 清空濾波器延遲線(切換頻率時防止爆音)
static void Filter_ClearDelay(BiquadFilter *f) {
    f->x1 = 0;
    f->x2 = 0;
    f->y1 = 0;
    f->y2 = 0;
}

// 初始化濾波器
void Filter_Init(float sample_rate) {
    params.fs = sample_rate;
    params.fc = 1000.0f;    // 默認1kHz
    params.q = 1.0f;        // 默認Q=1

    // 計算初始系數
    Filter_CalculateCoefficients(&params);
    Filter_UpdateCoefficients(&bandpass, &params);
    Filter_ClearDelay(&bandpass);
       
    need_update = 0;
}

// 設置中心頻率(Hz)
void Filter_SetFrequency(float freq_hz) {
    if (freq_hz < 20.0f) freq_hz = 20.0f;
    if (freq_hz > params.fs / 2.0f) freq_hz = params.fs / 2.0f;

    if (params.fc != freq_hz) {
        params.fc = freq_hz;
        need_update = 1;
    }
}

// 設置Q值
void Filter_SetQ(float q_value) {
    if (q_value < 0.5f) q_value = 0.5f;
    if (q_value > 20.0f) q_value = 20.0f;

    if (params.q != q_value) {
        params.q = q_value;
        need_update = 1;
    }
}

// 執行濾波器系數更新(主循環調用)
void Filter_ApplyUpdate(void) {
    if (need_update) {
        Filter_CalculateCoefficients(&params);
        Filter_UpdateCoefficients(&bandpass, &params);
        Filter_ClearDelay(&bandpass);  // 清空延遲防爆音
        need_update = 0;
    }
}

// 處理一個采樣點(定點Q15版本)
q15 Filter_Process(q15 input) {
    q15 output;

    // 直接II型雙二階濾波器
    // y[n] = b0*x[n] + b1*x[n-1] + b2*x[n-2] + a1*y[n-1] + a2*y[n-2]
    output = q15_mul(bandpass.b0, input);
    output = q15_add(output, q15_mul(bandpass.b1, bandpass.x1));
    output = q15_add(output, q15_mul(bandpass.b2, bandpass.x2));
    output = q15_add(output, q15_mul(bandpass.a1, bandpass.y1));
    output = q15_add(output, q15_mul(bandpass.a2, bandpass.y2));

    // 更新延遲線
    bandpass.x2 = bandpass.x1;
    bandpass.x1 = input;
    bandpass.y2 = bandpass.y1;
    bandpass.y1 = output;

    return output;
}

// 浮點版本處理函數(精度高但速度慢)
float Filter_ProcessFloat(float input) {
    static float x1 = 0, x2 = 0, y1 = 0, y2 = 0;
    float output;

    output = params.b0 * input + params.b1 * x1 + params.b2 * x2
           - params.a1 * y1 - params.a2 * y2;

    x2 = x1;
    x1 = input;
    y2 = y1;
    y1 = output;

    return output;
}

// 重置浮點版本狀態
void Filter_ResetFloat(void) {
    static float x1 = 0, x2 = 0, y1 = 0, y2 = 0;
    x1 = x2 = y1 = y2 = 0;
}
//----------------------------------
// 音頻處理循環(中斷服務函數)
void audio_isr(void) interrupt 1 {
       
    unsigned int adc_raw;
    q15 input, output;
    u16 temp;

    // 讀取ADC
    adc_raw = ADC_Read(0);//端口P1^0

    // ADC轉Q15
    input = ((q15)adc_raw - 2048) << 8;

    // 濾波
    output = Filter_Process(input);

    // 應用音量控制
    temp = ((q31)output * volume) >> 14;
       
    output = (q15)temp;

    // 輸出
    temp = (u16)output + 32768;
                       
    temp = temp >> 8;
          
    pwm_out((u8)temp);
               
}
//----------------------------------
// 初始化
void audio_setup(void) {
    Filter_Init(8000.0f);      // 采樣率8kHz
//    Filter_SetFrequency(1000);  // 中心頻率1kHz
//    Filter_SetQ(2.0f);          // Q=2
}
//----------------------------------
void gpio_init(void){
       
          P0M0 = 0x00; P0M1 = 0x00;
    P1M0 = 0x00; P1M1 = 0x01;
    P2M0 = 0x01; P2M1 = 0x00;  
    P3M0 = 0x00; P3M1 = 0x00;
          P4M0 = 0x00; P4M1 = 0x00;
    P5M0 = 0x00; P5M1 = 0x00;       
}
//----------------頻率------------------------
void display_F(unsigned char x, unsigned char y)
{
  unsigned char i;
  LCD_set_xy( x, y );
  RS=1;         
  for(i=0;i<4;i++)
  {
          LCD_by(Table[freq_num[i]]);
  }
}
//-----------------Q值----------------------------
void display_Q(unsigned char x, unsigned char y)
{
  unsigned char i;
  LCD_set_xy( x, y );
  RS=1;        
  for(i=0;i<2;i++)
  {
          LCD_by(Table[q_num[i]]);
  }
}
//------------------帶寬-----------------------
void display_Bm(unsigned char x, unsigned char y)
{
  unsigned char i;
  LCD_set_xy( x, y );
  RS=1;        
  for(i=0;i<4;i++)
  {
          LCD_by(Table[bw_num[i]]);
  }
}
//---------------------------------------------
void LCD_en_write(void) //液晶使能
{
     delay_5us();
           delay_5us();
           delay_5us();
           delay_5us();
           delay_5us();
           delay_5us();
           delay_5us();
           delay_5us();
     EN=1;        
     delay_5us();
           delay_5us();
           delay_5us();
           delay_5us();
           delay_5us();
           delay_5us();
           delay_5us();
           delay_5us();
     EN=0;        
}
//---------------------------------------
void LCD_by(uchar abc)//寫字節
{
    delay_nus(1000);
    if(((abc<<0)&0x80)==0)     
     LCD_D7=0;            
     else LCD_D7=1;         
    if(((abc<<1)&0x80)==0)     
     LCD_D6=0;              
     else LCD_D6=1;        
    if(((abc<<2)&0x80)==0)     
     LCD_D5=0;              
     else LCD_D5=1;        
    if(((abc<<3)&0x80)==0)     
     LCD_D4=0;              
     else LCD_D4=1;        
    LCD_en_write();

    if(((abc<<4)&0x80)==0)     
     LCD_D7=0;              
     else LCD_D7=1;         
    if(((abc<<5)&0x80)==0)     
     LCD_D6=0;              
     else LCD_D6=1;         
    if(((abc<<6)&0x80)==0)     
     LCD_D5=0;              
     else LCD_D5=1;         
    if(((abc<<7)&0x80)==0)     
     LCD_D4=0;              
     else LCD_D4=1;         
    LCD_en_write();
}
//----------------------------------------------
void LCD_set_xy( uchar x, uchar y )//寫地址函數
  {
    uchar address;
    if (y == 0) address = 0x80 + x;
    else
    address = 0xc0 + x;
    RS=0;           
    LCD_by(address);
  }
//---------------------------------------------
void LCD_write_str(uchar X,uchar Y,uchar *s)//寫字符串
  {
    LCD_set_xy(X,Y);
    RS=1;
    while(*s)
    {
       LCD_by(*s);
       s++;
    }
  }
//------------------------------------
void LCD_init(void)     //液晶初始化
{
    RS=0;            
    del_ms(500);

    LCD_by(0x30);
    del_ms(60);
    LCD_by(0x30);
    del_ms(10);
    LCD_by(0x30);
    del_ms(10);
    LCD_by(0x02);
    del_ms(10);
    LCD_by(0x28);//4bit test顯示模式設置(不檢測忙信號)
    del_ms(10);
    LCD_by(0x08);// 顯示關閉
    del_ms(10);
    LCD_by(0x01);// 顯示清屏
    del_ms(10);
    LCD_by(0x06);// 顯示光標不移動設置//移動0x04
    del_ms(10);
    LCD_by(0x0C);// 顯示開及光標設置
    del_ms(100);
}
//----------------------------------------------
void delay_nus(uint n)//N us延時函數
  {
   uint i=0;
               
   for (i=0;i<n;i++){_nop_();_nop_();_nop_();}
  }
//------------------------------
void delay_5us(void)
{
        unsigned char data i;

        _nop_();
        i = 11;
        while (--i);
}
//------------------------------
void Delay1ms(void)       
{
        unsigned char data i, j;

        _nop_();
        _nop_();
        _nop_();
        i = 11;
        j = 190;
        do
        {
                while (--j);
        } while (--i);
}

//------------------------------
void del_ms(uint n)//ms延時函數
{
        uint j;
       
  for(j=0;j<n;j++){Delay1ms();}
}
//------------------------------------
void pwm_init()
{
  P_SW2 |=0X80;
        PWMA_CCER1 = 0X00;
  PWMA_CCER2 = 0X00;
  PWMA_CCMR1 = 0X60;
  PWMA_CCMR2 = 0X60;
  PWMA_CCMR3 = 0X60;
  PWMA_CCMR4 = 0X60;
  PWMA_CCER1 = 0X55;
  PWMA_CCER2 = 0X55;
//  PWMA_ARRH = 0X02; //設置周期24000000hz/32000-1=749
//  PWMA_ARRL = 0XED; //749/32KHZ
  PWMA_ARRH = 0X04;   //設置周期40000000hz/32000-1=1249
  PWMA_ARRL = 0XE1;   //1249/32KHZ
  PWMA_ENO = 0X00;   
  PWMA_ENO |= ENO1P;  //使能輸出
//  PWMA_ENO |= ENO2P;  //使能輸出
  PWMA_PS = 0X00;     //PWM通道輸出引腳選擇位
  PWMA_PS |= PWM1_1;  //選擇PWM1_1通道/P2.0
//  PWMA_PS |= PWM2_1;  //選擇PWM2_1通道/P2.2
        PWMA_BKR = 0X80;    //使能主輸出
        PWMA_CR1 |= 0X01;   //開始計時
        P_SW2 &= 0X7F;
}
//---------------------------------
void pwm_out(u16 PWM1_Duty)//端口P2^0
{
        P_SW2 |=0X80;
        PWMA_CCR1H = (u8)(PWM1_Duty >> 8);
        PWMA_CCR1L = (u8)(PWM1_Duty);
        P_SW2 &= 0X7F;
}

/******************************/
void ADC_Init(void) {
    ADCCFG = ADCCFG | 0X20;
          ADC_CONTR = 0X80;
}

u16 ADC_Read(u8 ch) {
          ADC_RES = 0;
          ADC_RESL = 0;
          ADC_CONTR = (ADC_CONTR & 0XE0) | 0X40 | ch;
          _nop_();
          _nop_();
    _nop_();
    _nop_();
          while((ADC_CONTR & 0X20) == 0);
          ADC_CONTR &= ~0X20;
          return (((unsigned int)ADC_RES<<8) | ADC_RESL);
}

/*************** 按鍵掃描 ***************/
void KeyScan(void) {

    // 頻率增加
    if(KEY_FREQ_UP == 0) {
       del_ms(50);
                         center_freq=center_freq+100;
                         if(center_freq>=3000)center_freq=3000;
                         while(KEY_FREQ_UP==0);
                         flag=1;
    }
    // 頻率減少
    else if(KEY_FREQ_DOWN == 0) {
       del_ms(50);
                         center_freq=center_freq-100;
                         if(center_freq<=500)center_freq=500;
                         while(KEY_FREQ_DOWN==0);
                         flag=1;
    }
                       
    // Q值增加
    if(KEY_Q_UP == 0) {
       del_ms(50);
                         center_q=center_q+1;
                         if(center_q>=10)center_q=10;
                         while(KEY_Q_UP==0);
                         flag=1;
    }
    // Q值減少
    else if(KEY_Q_DOWN == 0) {
       del_ms(50);
                         center_q=center_q-1;
                         if(center_q<=1)center_q=1;
                         while(KEY_Q_DOWN == 0);
                         flag=1;
    }
}

/*************** 狀態顯示 ***************/
void DisplayStatus(void) {       
          
            u16 center_bm=0;
            
                  freq_num[0] = center_freq%10000/1000;
            freq_num[1] = center_freq%1000/100;
            freq_num[2] = center_freq%100/10;
            freq_num[3] = center_freq%10;
            
            q_num[0] = center_q%100/10;
            q_num[1] = center_q%10;
       
            center_bm = center_freq/center_q;//頻率/Q=帶寬
            bw_num[0] = center_bm%10000/1000;
            bw_num[1] = center_bm%1000/100;
            bw_num[2] = center_bm%100/10;
            bw_num[3] = center_bm%10;
       
          if(flag==1)
                {
            Filter_SetFrequency(center_freq);// 中心頻率
      Filter_SetQ(center_q);          // Q
                       
                        Filter_ApplyUpdate();
               
        // 更新頻率顯示
                  LCD_write_str(0,0,"Freq:");
      display_F(7,0);
      LCD_write_str(14,0,"Hz");

        // 更新Q值顯示
      LCD_write_str(0,1,"Q:");
      display_Q(2,1);
                       
                          // 更新帶寬顯示
                        LCD_write_str(6,1,"Bw:");
      display_Bm(9,1);
                        LCD_write_str(14,1,"Hz");
                               
                        flag=0;
    }
}

/************************************/

void Timer0_Init(void) {  
        AUXR |= 0x80;                        //定時器時鐘1T模式
        TMOD &= 0xF0;                        //設置定時器模式
        TL0 = 0x78;                                //設置定時初始值125us/8khz@40mhz
        TH0 = 0xEC;                                //設置定時初始值
//        TL0 = 0x48;                                //設置定時初始值125us/8khz@24mhz
//        TH0 = 0xF4;                                //設置定時初始值
        TF0 = 0;                                //清除TF0標志
        TR0 = 1;                                //定時器0開始計時
        ET0 = 1;                                //使能定時器0中斷
}

/*************** 主函數 ***************/
void main(void) {
       
          gpio_init();
          pwm_init();
    ADC_Init();
    Timer0_Init();
    LCD_init();
          del_ms(500);
          
          audio_setup();
       
          EA=1;

    while(1) {
                       
                          KeyScan();
        DisplayStatus();

                    P00=~P00;
    }
}

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏2 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:1172039 發表于 2026-5-26 22:12 | 只看該作者
ADC 轉 Q15 溢出了:
input = ((q15)adc_raw - 2048) << 8;
12 位 ADC 左移 8 位會超過 int16 范圍,建議改成:

input = (q15)(((q31)adc_raw - 2048) << 4);
濾波器系數 a1 不能用 Q15 存。
帶通二階濾波器的反饋系數經常會超過 1.0,但 Q15 只能表示到接近 ±1。所以中心頻率一調,系數就錯了,濾波結果自然不正常。

建議把系數改成 Q14,或者用 32 位定點保存系數,乘加時用 32 位累加。

另外:

temp = ((q31)output * volume) >> 14;
應改成:

temp = ((q31)output * volume) >> 15;
不然滿音量時等于放大接近 2 倍,容易失真。
回復

使用道具 舉報

板凳
ID:69038 發表于 2026-5-26 22:48 | 只看該作者
弱弱問一下樓主,這個代碼能擴展成3段(高中低)音調控制電路的應用嗎?采樣率提高到44.1K或48K,MCU換為M4(st32f405RG)?
回復

使用道具 舉報

地板
ID:1136941 發表于 2026-5-27 09:26 | 只看該作者
zhuls 發表于 2026-5-26 22:48
弱弱問一下樓主,這個代碼能擴展成3段(高中低)音調控制電路的應用嗎?采樣率提高到44.1K或48K,MCU換為M4 ...

我的8位的還沒有成功
回復

使用道具 舉報

5#
ID:1136941 發表于 2026-5-27 09:26 | 只看該作者
sharktony 發表于 2026-5-26 22:12
ADC 轉 Q15 溢出了:
input = ((q15)adc_raw - 2048)  14;
應改成:

謝謝指點,我試下
回復

使用道具 舉報

6#
ID:1034262 發表于 2026-5-27 09:48 | 只看該作者
如果要用STC的MCU做音頻處理,推薦STC32G系列、AI8051U這樣的32位內核MCU,計算速度比8位快幾倍,做數字濾波還是不錯的,做32KHz采樣256點計算FFT可以連續實時的。
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表