我有一些小问题,实现抖动功能,以升级我的ATmega88和它控制的leds的PWM分辨率。我的想法是,使用一个“某种”浮点数,包括两个uint8_t作为“十进制位”,以便例如"255.31“将由"0xff.0x1f”(BYTE_HIGH.BYTE_LOW)表示。
现在,我希望OCR中的值在BYTE_HIGH和BYTE_HIGH+1之间抖动,为此,我需要第二个计数器(除了计时器本身)来生成一个覆盖的任务周期(计时器的占空周期必须在(int) 255字节_LOW循环之后增加)。但是在main()中管理这些东西会导致闪烁,所以我想在一个叫做计时器溢出的ISR中这样做。
我的avr运行在20 MHz,为了获得足够的抖动频率,我不能使用高于8的预分频器。你认为我可能打得太频繁了吗?但是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会卡住并阻止在我的主要函数中执行的任何代码.
发布于 2017-10-04 20:52:20
我在Arduino Uno上试过你的程序。这个板基于一个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 cycles,这大约是用于服务中断的CPU功率的1.2%。
https://stackoverflow.com/questions/46537133
复制相似问题