从ISR

时间:2017-10-03 04:16:34

标签: avr pwm isr dithering

实现抖动功能以升级ATmega88的PWM分辨率及其控制的LED时,我几乎没有问题。 我的想法是,使用一种“种类”浮点数,由两个uint8_t组成“小数位”,以便例如“255.31”将由“0xff.0x1f”(BYTE_HIGH.BYTE_LOW)表示。

现在我希望OCR中的值在BYTE_HIGH和BYTE_HIGH + 1之间抖动,为此我需要第二个计数器(除了定时器本身)以生成重叠占空比(定时器的占空比必须在增加之后递增) (int)255-BYTE_LOW个循环)。但是在main()中管理这些东西会导致闪烁,所以我想在一个叫做定时器溢出的ISR中这样做。

我的avr以20 MHz运行并获得足够的抖动频率我不能使用高于8的预分频器。您认为,我可能会过于频繁地调用ISR吗?但是,ISR中没有太多代码。

我能想到的另一个问题是,ISR必须写入可能同时由定时器读取的OCR,但不是这种“线程保存”,因为定时器永远不会写入OCR ?

我没有找到任何与我的问题有关的内容,因此我希望得到一些提示。请参阅下面的代码

#include <avr/interrupt.h>
#include <avr/io.h>

#define compare_register OCR2B  //duty cycle

volatile uint8_t dither_count=0;
volatile uint8_t BYTE_HIGH=0;
volatile uint8_t BYTE_LOW=0;

void init_pwm(void){

//some standard pwm initializations
TCCR2A |= (1 << COM2A1);
TCCR2A |= (1 << COM2B1);
// non inverting, fast PWM mode and prescaler to
TCCR2A |= (0 << WGM21) | (1 << WGM20);
TCCR2B |= (1 << CS21);
// set desired pin as an output (not sure, if it's the correct pin, because I left out other pins in use)
DDRD = (1 << DDD3)|(1<<DDD4);

// enable interrupt on timer overflow
TIMSK2 |= (1<<TOIE2);

// enable global interrupts
  sei();
}

ISR(TIMER2_OVF_vect){
  dither_count++;
  if(dither_count<=BYTE_LOW){
    compare_register=BYTE_HIGH+1;
  }else{
    compare_register=BYTE_HIGH;
  }
}

int main(){
init_pwm();
//this or any function dimming the leds
  BYTE_HIGH=10;
  BYTE_LOW=1;
}

这在理论上应该有用,但遗憾的是它不能真正起作用。 ISR被调用,但没有按预期运行。我是否在ISR内正确调用变量? 如果有人看到我做的一个根本错误,我会很高兴,特别是因为我没有任何串口工作用于调试......

编辑:同时我发现,很明显ISR会卡住并阻止我在主函数中执行的任何代码......

1 个答案:

答案 0 :(得分:0)

我在Arduino Uno上试过你的程序。该板基于a ATmega328P,除了一些额外的内存,基本上是相同的 你的Mega88(相同的数据表)我首先添加了以下几行 结束main()

init_pwm();

// Blink the LED on PB5.
DDRB |= _BV(PB5);
for (;;) {
    PINB |= _BV(PB5);
    _delay_ms(400);
}

PWM显然需要第一行才能工作。 LED闪烁 只是一个测试,看看程序是否卡在ISR中。 结果是:它没有。 LED正常闪烁。 PWM 输出在范围上看起来也没问题。请注意,与之相反 代码中的注释表示,您正在阶段配置计时器 正确的 PWM模式,而不是快速PWM。然后定时器周期是2×255定时器 时钟周期而不是256。

我反汇编了二进制文件并尝试计算CPU周期数 需要服务中断。在-Os编译的程序 优化级别,我得到了大约50.鉴于中断每次都会触发 2×255×8 = 4080个周期,约占CPU功率的1.2% 用于服务中断。