原先用STC8H8K64U,但是用于复杂运算性能实在是免为其难,没有成功。现在改用STC32G12K128后终于成功,程序也是在原先基础上稍微修改,做这个装置是为了接收叠加有较强噪音的单音CW信号,使声音更清晰。
制作出来的实物图如下:
电路原理图如下:
单片机源程序如下:
- /**
- * 单片机数字音频带通滤波器
- * ADC: 12位
- * 采样率: 8KHz
- * 输出: PWM
- * 功能: 带宽、中心频率可调
- */
- #include <STC32G.h>
- #include <intrins.h>
- //#include <stdint.h>
- #define uint8_t unsigned char
- #define uint16_t unsigned int
- #define uint32_t unsigned long
-
- unsigned char Table[]="0123456789";
- unsigned char freq_num[4];// 频率
- unsigned char bw_num[4];//带宽
- uint16_t center_bm=100;//默认带宽100hz
- uint16_t center_freq=1000;//默认频率1000HZ
- bit flag=1;
- //-------定义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
- // 按键定义
- 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;
- /* ==================== 配置参数 ==================== */
- #define SAMPLE_RATE 8000UL // 采样率 8KHz
- #define ADC_MAX 4095 // 12位ADC最大值
- #define PWM_MAX 255 // 8位PWM最大值
- /* ==================== 滤波器结构体 ==================== */
- typedef struct {
- // 滤波器系数
- float b0, b1, b2; // 分子系数
- float a1, a2; // 分母系数 (a0 = 1)
- // 延迟单元
- float x1, x2; // 输入延迟
- float y1, y2; // 输出延迟
- // 滤波器参数
- float center_freq; // 中心频率 (Hz)
- float bandwidth; // 带宽 (Hz)
- } BandpassFilter;
- /* 全局滤波器实例 */
- BandpassFilter g_filter;
- /* ==================== 数学工具函数 ==================== */
- /**
- * 简化的正弦近似 (适用于资源受限的单片机)
- * 使用泰勒级数展开
- */
- float sin_approx(float x) {
-
- float x2;
- // 将x归一化到 [-π, π]
- while (x > 3.14159265f) x -= 6.2831853f;
- while (x < -3.14159265f) x += 6.2831853f;
- // 泰勒级数: sin(x) ≈ x - x3/6 + x?/120
- x2 = x * x;
- return x * (1.0f - x2 / 6.0f * (1.0f - x2 / 20.0f));
- }
- /**
- * 余弦近似
- */
- float cos_approx(float x) {
- return sin_approx(x + 1.5707963f);
- }
- /**
- * 平方根近似 (牛顿迭代法)
- */
- float sqrt_approx(float x) {
-
- float guess;
- uint8_t i;
- if (x <= 0.0f) return 0.0f;
- guess = x * 0.5f;
- for (i = 0; i < 5; i++) {
- guess = (guess + x / guess) * 0.5f;
- }
- return guess;
- }
- /* ==================== 滤波器核心函数 ==================== */
- /**
- * 计算带通滤波器系数
- * 使用双二阶IIR滤波器 (Biquad)
- * @param filter: 滤波器实例指针
- * @param center_freq: 中心频率 (Hz)
- * @param bandwidth: 带宽 (Hz)
- */
- void BandpassFilter_UpdateCoeffs(BandpassFilter* filter, float center_freq, float bandwidth) {
-
- float omega;
- float sin_omega;
- float cos_omega;
- float alpha;
- float a0;
- float Q;
- // 参数边界检查
- if (center_freq < 20.0f) center_freq = 20.0f;
- if (center_freq > (SAMPLE_RATE / 2.5f)) center_freq = SAMPLE_RATE / 2.5f;
- if (bandwidth < 10.0f) bandwidth = 10.0f;
- if (bandwidth > center_freq) bandwidth = center_freq;
- filter->center_freq = center_freq;
- filter->bandwidth = bandwidth;
- // 角频率
- omega = 2.0f * 3.14159265f * center_freq / SAMPLE_RATE;
- sin_omega = sin_approx(omega);
- cos_omega = cos_approx(omega);
- // Q值计算: Q = center_freq / bandwidth
- Q = center_freq / bandwidth;
- if (Q > 20.0f) Q = 20.0f; // 限制Q值防止不稳定
- if (Q < 0.5f) Q = 0.5f;
- // 计算alpha
- alpha = sin_omega / (2.0f * Q);
- // 带通滤波器系数 (恒定0dB峰值增益)
- // b0 = alpha
- // b1 = 0
- // b2 = -alpha
- // a0 = 1 + alpha
- // a1 = -2*cos(omega)
- // a2 = 1 - alpha
- a0 = 1.0f + alpha;
- filter->b0 = alpha / a0;
- filter->b1 = 0.0f;
- filter->b2 = -alpha / a0;
- filter->a1 = -2.0f * cos_omega / a0;
- filter->a2 = (1.0f - alpha) / a0;
- }
- /**
- * 初始化滤波器
- */
- void BandpassFilter_Init(BandpassFilter* filter) {
- filter->x1 = 0.0f;
- filter->x2 = 0.0f;
- filter->y1 = 0.0f;
- filter->y2 = 0.0f;
- filter->center_freq = 1000.0f;
- filter->bandwidth = 200.0f;
- // 计算初始系数
- BandpassFilter_UpdateCoeffs(filter, filter->center_freq, filter->bandwidth);
- }
- /**
- * 滤波器处理 (Direct Form II Transposed)
- * @param filter: 滤波器实例指针
- * @param input: 输入样本 (归一化到 -1.0 ~ 1.0)
- * @return: 滤波后输出 (归一化)
- */
- float BandpassFilter_Process(BandpassFilter* filter, float input) {
- // Direct Form II Transposed 结构
- // y = b0*x + s1
- // s1 = b1*x - a1*y + s2
- // s2 = b2*x - a2*y
- float output = filter->b0 * input + filter->y1;
- filter->y1 = filter->b1 * input - filter->a1 * output + filter->y2;
- filter->y2 = filter->b2 * input - filter->a2 * output;
- return output;
- }
- /* ==================== 硬件抽象层 (需根据具体单片机修改) ==================== */
- /**
- * ADC初始化
- * 需要根据具体单片机修改
- */
- void ADC_Init(void) {
-
- ADCCFG = ADCCFG | 0X20;
- ADC_CONTR = 0X80;
- }
- /**
- * 读取ADC值
- * @return: 12位ADC值 (0-4095)
- */
- uint16_t ADC_Read(uint8_t ch) {//P1.0
-
- 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);
- }
- /**
- * PWM初始化
- * 需要根据具体单片机修改
- */
- void PWM_Init(void) {
-
- 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_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;
- }
- /**
- * 设置PWM占空比
- *
- */
- void PWM_SetDuty(uint16_t duty) {//P2.0
-
- P_SW2 |=0X80;
- PWMA_CCR1H = (uint8_t)(duty >> 8);
- PWMA_CCR1L = (uint8_t)(duty);
- P_SW2 &= 0X7F;
- }
- /**
- * 定时器初始化 (用于8KHz采样中断)
- */
- void Timer_Init(void) {
-
- AUXR |= 0x80; //定时器时钟1T模式
- TMOD &= 0xF0; //设置定时器模式
- TL0 = 0x48; //设置定时初始值125us/8khz@24mhz
- TH0 = 0xF4; //设置定时初始值
- TF0 = 0; //清除TF0标志
- TR0 = 1; //定时器0开始计时
- ET0 = 1; //使能定时器0中断
- }
- /* ==================== 主处理函数 ==================== */
- /**
- * 音频处理函数 (在8KHz定时器中断中调用)
- */
- void Audio_Process_ISR(void) {
-
- uint8_t pwm_duty;
- uint16_t adc_raw;
- float sample;
- float filtered;
- // 1. 读取ADC (12位: 0-4095)
- adc_raw = ADC_Read(0);//P1.0
-
- adc_raw = adc_raw << 4;
- // 2. 归一化到 -1.0 ~ 1.0 (去除直流偏置)
- sample = ((float)adc_raw - 2048.0f) / 2048.0f;
- // 3. 带通滤波
- filtered = BandpassFilter_Process(&g_filter, sample);
- // 4. 限幅保护
- if (filtered > 1.0f) filtered = 1.0f;
- if (filtered < -1.0f) filtered = -1.0f;
- // 5. 转换为PWM占空比 (0-255)
- // 将 -1~1 映射到 0~255
- pwm_duty = (uint8_t)((filtered + 1.0f) * 127.5f);
- // 6. PWM输出
- PWM_SetDuty(pwm_duty);
- }
- /* ==================== 用户接口函数 ==================== */
- /**
- * 设置中心频率
- * @param freq: 中心频率 (Hz)
- */
- void SetCenterFrequency(float freq) {
- BandpassFilter_UpdateCoeffs(&g_filter, freq, g_filter.bandwidth);
- }
- /**
- * 设置带宽
- * @param bw: 带宽 (Hz)
- */
- void SetBandwidth(float bw) {
- BandpassFilter_UpdateCoeffs(&g_filter, g_filter.center_freq, bw);
- }
- /**
- * 同时设置中心频率和带宽
- */
- void SetFilterParams(float center_freq, float bandwidth) {
- BandpassFilter_UpdateCoeffs(&g_filter, center_freq, bandwidth);
- }
- //-------------------1602--------------------------//
- void delay_5us(void)
- {
- unsigned char data i;
- _nop_();
- i = 11;
- while (--i);
- }
- //----------------------------------------------
- void delay_nus(uint8_t n)//N us延时函数
- {
- uint8_t i=0;
-
- for (i=0;i<n;i++){_nop_();_nop_();_nop_();}
- }
-
- void Delay1ms(void)
- {
- unsigned char data i, j;
- _nop_();
- _nop_();
- _nop_();
- i = 11;
- j = 190;
- do
- {
- while (--j);
- } while (--i);
- }
- //------------------------------
- void del_ms(uint8_t n)//ms延时函数
- {
- uint8_t j;
-
- for(j=0;j<n;j++){Delay1ms();}
- }
- //------------------------------
- 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(uint8_t 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( uint8_t x, uint8_t y )//写地址函数
- {
- uint8_t address;
- if (y == 0) address = 0x80 + x;
- else
- address = 0xc0 + x;
- RS=0;
- LCD_by(address);
- }
- //---------------------------------------------
- void LCD_write_str(uint8_t X,uint8_t Y,uint8_t *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 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]]);
- }
- }
- //------------------带宽-----------------------
- 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 KeyScan(void) {
- // 频率增加
- if(KEY_FREQ_UP == 0) {
- del_ms(50);
- center_freq=center_freq+50;
- 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-50;
- if(center_freq<=300)center_freq=300;
- while(KEY_FREQ_DOWN==0);
- flag=1;
- }
-
- // 带宽增加
- if(KEY_Q_UP == 0) {
- del_ms(50);
- center_bm=center_bm+50;
- if(center_bm>=3000)center_bm=3000;
- while(KEY_Q_UP==0);
- flag=1;
- }
- // 带宽减少
- else if(KEY_Q_DOWN == 0) {
- del_ms(50);
- center_bm=center_bm-50;
- if(center_bm<=50)center_bm=50;
- while(KEY_Q_DOWN == 0);
- flag=1;
- }
- }
- /*************** 状态显示 ***************/
- void DisplayStatus(void) {
-
- 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;
-
- 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)
- {
- SetCenterFrequency(center_freq);// 中心频率
- SetBandwidth(center_bm); // 带宽
-
- // 更新频率显示
- LCD_write_str(0,0,"Freq:");
- display_F(7,0);
- LCD_write_str(14,0,"Hz");
-
- // 更新带宽显示
- LCD_write_str(0,1,"Bw:");
- display_Bm(7,1);
- LCD_write_str(14,1,"Hz");
-
- flag=0;
- }
- }
- /* ==================== 主程序 ==================== */
- /**
- * 系统初始化
- */
- void System_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;
-
- EAXFR = 1;
- WTST = 0;
- CKCON = 0;
- // 初始化滤波器
- BandpassFilter_Init(&g_filter);
- // 初始化硬件
- ADC_Init();
- PWM_Init();
- Timer_Init();
- LCD_init();
- del_ms(100);
- EA=1;
- }
- /**
- * 主函数
- */
- void main(void) {
- // 系统初始化
- System_Init();
- // 设置初始滤波器参数 (示例: 中心频率1KHz, 带宽100Hz)
- SetFilterParams(1000.0f, 100.0f);
- // 主循环
- while (1) {
- KeyScan();
- DisplayStatus();
- P00=~P00;
- }
- }
- /* ==================== 中断服务程序示例 ==================== */
- /**
- * 定时器中断服务程序 (8KHz)
- * 需要根据具体单片机修改中断向量
- */
- void audio_isr(void) interrupt 1 {
- // 调用音频处理
- Audio_Process_ISR();
- }
复制代码 |