单片机/MCU论坛
直播中

叶伯特

未满1年用户 8经验值
擅长:可编程逻辑
私信 关注
[问答]

请问如何消除变频器所产生的抖动

我所编写的变频器程序在调整频率后,使用示波器来观察频率时,发现波形有抖动的现象,请问如何才能解决这个问题,单片机的型号是STC89C51。ヽ(*。>Д<)o

#include <REGX52.H>

sbit WAVE_OUT = P1^0;

volatile unsigned int count;   
volatile unsigned int count1;  
volatile unsigned int freq = 1000;      
volatile unsigned short high_count;      
volatile unsigned short low_count;       
volatile bit wave_state = 0;             

#define SYS_CLK         11059200UL       
#define INTERRUPT_DELAY 3               
#define MIN_FREQ        50               
#define MAX_FREQ        10000            



void calculate_timer_counts() {
    unsigned long period_us; 
    unsigned long high_us;    
    unsigned long low_us;     
	
    period_us = 1000000UL / freq;
    
    high_us = period_us / 2;
    low_us = period_us - high_us; 
    
   
    high_count = (unsigned short)( (high_us * SYS_CLK) / 12000000UL );
    low_count = (unsigned short)( (low_us * SYS_CLK) / 12000000UL );
    
    
    if (high_count > INTERRUPT_DELAY)
        high_count -= INTERRUPT_DELAY;
    else
        high_count = 1;
        
    if (low_count > INTERRUPT_DELAY)
        low_count -= INTERRUPT_DELAY;
    else
        low_count = 1;
}



void timer0_init() {
    TMOD &= 0xF0; 
    TMOD |= 0x01;  
    ET0 = 1;       
    EA = 1;       
}



void timer0_isr() interrupt 1 {
    if (wave_state) {
        
        WAVE_OUT = 0;
       
        TH0 = (65536 - low_count) >> 8;
        TL0 = (65536 - low_count) & 0xFF;
        count++;  
    } else {
        
        WAVE_OUT = 1;
        
        TH0 = (65536 - high_count) >> 8;
        TL0 = (65536- high_count) & 0xFF;
        count1++;  
    }
    wave_state = !wave_state;  
}



void set_frequency(unsigned int freq_val) {
    EA = 0;  
    
    if (freq_val < MIN_FREQ)
        freq_val = MIN_FREQ;
    if (freq_val > MAX_FREQ)
        freq_val = MAX_FREQ;
    
    freq = freq_val;
    calculate_timer_counts(); 
    

    if (wave_state) {
        TH0 = (65536 - low_count) >> 8;
        TL0 = (65536 - low_count) & 0xFF;
    } else {
        TH0 = (65536 - high_count) >> 8;
        TL0 = (65536 - high_count) & 0xFF;
    }
    
    EA = 1; 
}


void main() {
    timer0_init();
    set_frequency(9000);  
    TR0 = 1;          
    
    while(1) 
   {
     P2_0 = WAVE_OUT;     
    }
}

微信图片_20250927164301_4_2.jpg
微信图片_20250927164902_5_2.jpg

已退回20积分

回帖(1)

jf_87481316

2025-10-28 15:46:26
定时器中断服务程序中,每次中断都会切换波形状态,并重新设置定时器的重载值。但是,由于中断响应和代码执行的时间,可能会造成一定的误差。另外,在设置频率时,关闭了中断,然后重新设置定时器值,这可能会引起波形的不连续。
此外,使用的STC89C51是12T的8051单片机,每个机器周期由12个时钟周期组成。因此,定时器每12个时钟周期计数一次。在计算定时器计数时,我们已经考虑了这一点(除以12)。
但是,在计算high_count和low_count时,使用了公式:
high_count = (high_us * SYS_CLK) / 12000000UL;
这是因为:high_us * SYS_CLK 得到的是时钟周期数,而定时器每12个时钟周期计数一次,所以除以12,即12000000UL实际上是12*1000000。
另外,减去了一个INTERRUPT_DELAY(3)来补偿中断响应时间。但是,这个值可能需要根据实际情况调整。
可能的问题:
1. 中断响应时间补偿不准确。
2. 在设置新频率时,关闭中断可能会造成波形抖动。
3. 定时器重载值的计算可能因为整数除法的舍入而产生误差。
试下
#include

sbit WAVE_OUT = P1^0;

volatile unsigned int freq = 1000;      
volatile unsigned short high_count;      
volatile unsigned short low_count;      
volatile bit wave_state = 0;            

#define SYS_CLK         11059200UL      
#define MIN_FREQ        50               
#define MAX_FREQ        10000            
#define INTERRUPT_OVERHEAD 8            

void calculate_timer_counts() {
    unsigned long half_period_ticks;
   
    // 精确计算半周期定时器计数
    half_period_ticks = (SYS_CLK / 12UL) / freq / 2;
   
    // 范围保护
    if (half_period_ticks > 65535) half_period_ticks = 65535;
    if (half_period_ticks < 10) half_period_ticks = 10;
   
    // 补偿中断延迟
    if (half_period_ticks > INTERRUPT_OVERHEAD) {
        high_count = half_period_ticks - INTERRUPT_OVERHEAD;
        low_count = half_period_ticks - INTERRUPT_OVERHEAD;
    } else {
        high_count = 1;
        low_count = 1;
    }
}

void timer0_init() {
    TMOD &= 0xF0;
    TMOD |= 0x01;  // 定时器0,模式1,16位定时器
    ET0 = 1;       // 允许定时器0中断
    EA = 1;        // 开总中断
}

void timer0_isr() interrupt 1 {
    if (wave_state) {
        WAVE_OUT = 0;
        TH0 = (0x10000 - low_count) >> 8;
        TL0 = (0x10000 - low_count) & 0xFF;
    } else {
        WAVE_OUT = 1;
        TH0 = (0x10000 - high_count) >> 8;
        TL0 = (0x10000 - high_count) & 0xFF;
    }
    wave_state = !wave_state;
}

void set_frequency(unsigned int freq_val) {
    EA = 0;  // 关中断保护
   
    if (freq_val < MIN_FREQ) freq_val = MIN_FREQ;
    if (freq_val > MAX_FREQ) freq_val = MAX_FREQ;
   
    freq = freq_val;
    calculate_timer_counts();
   
    // 立即更新定时器
    TR0 = 0;  // 暂停定时器
    if (wave_state) {
        TH0 = (0x10000 - low_count) >> 8;
        TL0 = (0x10000 - low_count) & 0xFF;
    } else {
        TH0 = (0x10000 - high_count) >> 8;
        TL0 = (0x10000 - high_count) & 0xFF;
    }
    TR0 = 1;  // 重启定时器
   
    EA = 1;   // 开中断
}

void main() {
    timer0_init();
    set_frequency(1000);  // 初始频率1kHz
    TR0 = 1;              // 启动定时器0
   
    while(1) {
        // 可以在这里添加频率调整逻辑
        // set_frequency(新的频率值);
    }
}
1 举报
  • 叶伯特: 好的,谢谢,非常感谢你的帮助。

更多回帖

发帖
×
20
完善资料,
赚取积分