繁体   English   中英

16 位定时器 PWM LED 调光器

[英]16-bit Timer PWM LED Dimmer

我是 AVR C 编程的新手,我正在使用 Atmega328p 计数器/定时器上的 16 位定时器测试一个简单的 PWM,它假设充当 LED 的调光器。

我的代码:

#define F_CPU 16000000UL

void initTimer();

int x = 1;
int n = 1000;

int main(void)
{   

    initTimer();

    DDRB |= (1 << PB1)| (1 << PB2);

    while(1)
    {
        x++; 

        if(x > 65) {
            x = 1;
        }
    }
}

void initTimer() {

    TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); 
    TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); 
    // used for TOP, makes for 50 Hz PWM
    ICR1 = 40000; 
    OCR1A = n * x; 

} 

ISR(TIMER1_OVF_vect)
{
    OCR1A = n * x;  
}

问题是它不显示调光效果,对于我最初为 OCR1A (PB1) 输出引脚设置的任何值,LED 的亮度保持不变,它假设在中断发生时改变值,但它只是不这样做,这应该是简单的测试我做错了什么?

更新:

作为建议,我使用 TIMSK1 寄存器和 SEI() 启用中断,但是仍然存在相同的问题,无论 initTimer() 中指定的 OCR1A 的原始值如何,LED 亮度都保持不变。

int main(void)
{   
    initTimer();
    DDRB |= (1 << PB1)| (1 << PB2);

    while(1)
    {
        x++; 
        if(x > 65) {
            x = 1;
        }
    }
}

void initTimer() {

    ICR1 = 40000; 
    OCR1A = n * x; 
    TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); 
    TIMSK1 |= (1 << ICIE1);
    TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); 
    sei();
}

ISR (TIMER1_COMPA_vect)
{
    OCR1A = n * x;  
}

虽然我尝试了另一种方法,这给了我调光效果:

int main(void)
{   

    initTimer();

    DDRB |= (1 << PB1)| (1 << PB2);

    while(1)
    {
        _delay_ms(20);
        OCR1A = n * 4; 
        _delay_ms(20);
        OCR1A = n * 8;
        _delay_ms(20);
        OCR1A = n * 15; 
        _delay_ms(20);
        OCR1A = n * 25;
        _delay_ms(20);
        OCR1A = n * 1; 

    }
}

void initTimer() {

    ICR1 = 40000; 
    OCR1A = n * x; 
    TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11);   
    TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); 

} 

所以看起来问题出在中断上,因为 PWM 影响有效,但它只是不与中断处理程序一起工作。

我首先想到的是 x 和 n 应该是 volatile 。 您还应该在 TIMSK0 寄存器中启用中断。 还可以通过调用 sei 来启用中断。

如果我是你,我会从一些熟悉的示例代码开始。 我提到的页面有一个示例,它每 4 毫秒触发一次中断。 获取该代码并打开和关闭 LED。

另一个问题是你在改变 x 而不管 isr 是否被调用。 所以实际上你每次都会在 isr 中得到一个随机的 x。 这段代码很简单,可能会卡在一个简单的模式中。 而是将 x 的设置移动到您的 isr。

这是 avr 计时器的一个很好的介绍: https : //sites.google.com/site/qeewiki/books/avr-guide/timers-on-the-atmega328

ICR1 = 40000; 
OCR1A = n * x; 
TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11);   
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11);

这是错误的,需要在初始化ICR1和OCR1A之前配置TCCR1A和TCCR1B。 有关更多详细信息,请参阅此答案

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM