我是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;
}
问题是它没有显示调光效果,LED的亮度对于我最初为OCR1A(PB1)输出引脚设置的值保持不变,它假设在中断发生时改变值但是它不是这样做,这是简单的测试我做错了什么?
更新
作为建议我使用TIMSK1寄存器和SEI()启用中断,但是仍然存在相同的问题,LED亮度与initTimer()中指定的OCR1A的原始值保持不变。
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影响有效,但它只是不使用中断处理程序。
答案 0 :(得分:1)
向我跳出的第一件事是x和n应该是不稳定的。您还应该在TIMSK0寄存器中启用中断。也可以通过调用sei来启用中断。
如果我是你,我会从一些熟悉的示例代码开始。我提到的页面有一个示例,每隔4ms触发一次中断。获取该代码并打开和关闭LED。
另一个问题是你正在改变x,而不管是否调用了isr。所以实际上你每次都会在isr中得到一个随机的x。这段代码很简单,可能会卡在一个简单的模式中。而是将x的设置移动到您的isr。
以下是avr计时器的简介:https://sites.google.com/site/qeewiki/books/avr-guide/timers-on-the-atmega328
答案 1 :(得分:0)
ICR1 = 40000;
OCR1A = n * x;
TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11);
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11);
这是错误的,您需要在初始化ICR1和OCR1A之前配置TCCR1A和TCCR1B。有关更多详细信息,请参见this answer。