Arduino Timer4自定义PWM问题

时间:2019-02-21 19:35:44

标签: arduino avr atmega atmel

我编写了一个不错的代码,可以生成占空比为50%的快速PWM,并且可以使用电位计来更改频率。它输出带有一些停滞时间的直通道和倒通道。我正在使用Arduino Micro aka ATmega32U4。该代码实际上是“ Atmel”代码。在关闭然后再次打开Arduino Micro的电源之前,代码工作正常。

我已经对代码和寄存器进行了编程,以使频率可以从10kHz更改为100kHz。但是在打开/关闭电源后,频率从5kHz变为50kHz。发生这种情况后,我必须再次使用Arduino IDE对该板进行编程,以使其正常工作。再次打开/关闭电源后,它已更改。我非常确定其中一个寄存器会被“ Arduino硬件抽象层”覆盖,但是我们应该命名它。我尚未读出所有寄存器,所以我不知道哪个寄存器被覆盖。我想这是预分频器。 如何防止这种情况发生?我应该在其他地方写寄存器内容吗?还是我应该写几次以确保? 无论如何还是为什么?

代码如下:

#define OSC1  5
#define OSC2  13

uint8_t read_reg1;
uint8_t read_reg2;
int pot, freq; 

void setup() {
  pinMode(OSC1, OUTPUT); 
  pinMode(OSC2, OUTPUT); 
  Serial.begin(9600);

  cli();  // disable global interrupts

  TCCR4A=0; // clear register
  TCCR4B=0x06; // configure prescaler to 64 (CK = CLK / 64 = 1.5 MHz)
  TCCR4C=0;
  TCCR4D=0; // select Fast PWM operation (0 << WGM41)|(0 << WGM40)
  PLLFRQ=(PLLFRQ&0xCF)|0x30; // select clock source and frequency
  OCR4C=150; // select PWM frequency
  OCR4A=150/2; // set duty cycle
  DT4 = 0x55; // set dead times. DT = (1 / 48Mhz) * 0...15

  // enable interrupt on timer4 overflow
  TIMSK4|=(1 << TOIE4);

  // This register write has to be after others. Otherwise the PWM generation will not work. I do not know why. 
  TCCR4A=0x42; // COM4A1..0 = 01, OC4A and !OC4A connected. PWM4A = 1 (activate channel A PWM output)

  sei(); // enable global interrupts
}

void loop() {
  //cli();
  pot = analogRead(A0);
  freq = map(pot, 0, 1023, 14, 166);
  //sei();
  /*
  Serial.print("Pot value: ");
  Serial.print(pot);
  Serial.print("\tFreq value: ");  
  Serial.println(1500000/freq);
  */

}

ISR(TIMER4_OVF_vect){
  OCR4C = freq;
  OCR4A = freq / 2; 
}

1 个答案:

答案 0 :(得分:0)

我不确定到底为什么在编程后会出现不同的行为,但是Arduino Micro使用的Bootloader(Caterina)在运行后并未执行完全重置,因此通常会对AVR的寄存器进行更改。用户的草图可见。

我能够通过删除修改loaded的行来解决此问题。这是您的代码的简化版本,始终产生3.31 kHz PWM:

PLLFRQ

弄乱PLL后分频器不是一个好主意,因为它可能会影响使用计时器的所有其他Arduino库,包括USB堆栈。