我正在使用 ATtiny85 进行一个基于 C 构建的简单红外项目(用于 DSLR 相机的红外遥控器)。我在 CTC 模式下使用定时器 0 生成了一个 38.4 kHz 方波信号,并设置输出在每次定时器达到最大值时切换 PB0
OCRA
。我想使用定时器 0 比较单元生成的中断来计算它生成的周期数,因为计数器达到最大值两次以生成 38.4 kHz 方波的完整周期,对两个中断进行计数应指示完整的循环。 问题:我注意到每次调用sei()
函数来启用全局中断时,生成的方波都会变形,并且永远不会调用关联的ISR。我使用示波器检查了 PB0 上生成的波形:
我实现了以下测试代码,如前所述配置定时器 0,并在每次检测到与定时器 0 的比较单元相关的中断时切换 PB1:
main.h
#ifndef MAIN_H
#define MAIN_H
#define __AVR_ATtiny85__
#define F_CPU 8000000UL
#endif
main.c
#include "main.h"
#include <avr/io.h>
#include <avr/interrupt.h>
int main(void)
{
cli();
DDRB |= _BV(PB0) | _BV(PB1);
PORTB &= ~_BV(PB1);
// Set general register to sync mode for configuration
GTCCR |= _BV(TSM) | _BV(PSR0);
// Default registers
TCCR0A = 0;
TCCR0B = 0;
TCNT0 = 0;
TCCR0A |= _BV(COM0A0) | _BV(WGM01); // Set toggle on match and CTC mode
TCCR0B |= _BV(CS00); // internal clock no-prescaling
OCR0A |= 12; // For app 38,8kHz
TIMSK |= _BV(OCIE0A);
// Enable timer
GTCCR &= ~_BV(TSM) & ~_BV(PSR0);
// Enable global interrupts
sei();
while(1);
}
// Demo interrupt service routine
ISR(TIMER0_COMPA_vect){
PORTB ^= _BV(PB1);
}
编译我使用的代码
avr-gcc
,如下所示:
avr-gcc main.c -o main.elf -Wall -Wextra
编译器没有发出任何警告。然后我使用
avr-objcopy
来获取十六进制文件:
avr-objcopy -O ihex -j .text -j .data main.elf main.hex
最后我使用avrdude对IC进行了编程:
avrdude -p t85 -c usbtiny -B 125kHz -U flash:w:main.hex
保险丝是:
avrdude: safemode: Fuses OK (E:FF, H:DF, L:62)
- 手动设置 SREG 寄存器:
将
sei()
行替换为:
SREG |= 1 << 7;
做了一些事情,但仍然不起作用。生成的方波看起来更好,但不符合预期,并且 ISR 没有对 PB1 执行任何操作。
- 替换 ISR 操作: 我虽然可能端口操作花费了很多时间,但是用
_NOP();
替换它对生成的方波的奇怪行为没有影响。
-尝试过其他 IC: 我有另一个 ATtiny85,并且表现相同。也许我有两个有缺陷的IC?
我不知道是否我配置错误,或者当我使用
sei()
启用中断时,IC 受到中断的轰炸而无法正常工作?
预先感谢您的任何提示或回复!
#define __AVR_ATtiny85__
不要摆弄工具链的内部宏。相反...
avr-gcc main.c -o main.elf -Wall -Wextra
...用
-mmcu=attiny85
进行编译和链接。如果缺少该选项,链接阶段将不会链接到启动代码crtattiny85.o
,并且设置一些宏也无法解决该问题。
此外,如果没有
-mmcu=
,编译器将使用错误的 AVR 架构:在 avr-gcc 中,ATtiny85 是 avr25
,而默认值(没有 -mmcu=
)是 avr2
。请参阅 avr-gcc 机器相关选项。
也可能是设备总是被watchdog定时器重置并从头开始的情况。因此,请检查 watchdock 是否正在服务或已停用(通过配置或熔断器)。