Arduino timer4自定义PWM问题
Arduino timer4 custom PWM issue
我编写了一个很好的代码,它生成具有 50% 占空比的快速 PWM,我可以用电位器改变频率。它输出带有一些死区时间的直通道和倒通道。我正在使用 Arduino Micro aka ATmega32U4。该代码实际上是 "Atmel" 代码。在我关闭 Arduino Micro 电源然后再打开之前,代码工作正常。
我已经对代码和寄存器进行了编程,以便频率可以在 10kHz 到 100kHz 之间变化。但是通电后 on/off 频率从 5kHz 变为 50kHz。发生这种情况后,我必须再次使用 Arduino IDE 对电路板进行编程,以使其正常工作。上电 on/off 后再次发生变化。我很确定其中一个寄存器被 "Arduino hardware abstraction layer" 覆盖,或者我们应该给它命名。我还没有读出所有的寄存器,所以我不知道哪个被覆盖了。我想这是预分频器。
我如何防止这种情况发生?我应该把寄存器内容写在别的地方吗?或者我应该写几次才能确定?
为什么或如何发生这种情况?
代码如下:
#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;
}
我不确定为什么您在编程后立即会出现不同的行为,但是 Arduino Micro 使用的引导加载程序 (Caterina) 在运行后不会执行完全重置,因此引导加载程序对 AVR 的寄存器进行了更改通常在用户的草图中可见。
我能够通过删除修改 PLLFRQ
的行来解决问题。这是始终产生 3.31 kHz PWM 的代码的简化版本:
void setup()
{
pinMode(5, OUTPUT);
pinMode(13, OUTPUT);
TCCR4A = 0;
TCCR4B = 0x06; // configure prescaler to 64 (CK = CLK / 64 = 1.5 MHz)
TCCR4C = 0;
TCCR4D = 0; // select Fast PWM operation (0 << WGM41)|(0 << WGM40)
OCR4C = 150; // select PWM frequency
OCR4A = 150 / 2; // set duty cycle
DT4 = 0x55; // set dead times. DT = (1 / 48Mhz) * 0...15
// This register write has to be after others.
// Otherwise the PWM generation will not work. I do not know why.
// COM4A1..0 = 01, OC4A and !OC4A connected.
// PWM4A = 1 (activate channel A PWM output)
TCCR4A = 0x42;
}
void loop()
{
}
乱用 PLL 后分频器不是一个好主意,因为它可能会影响所有其他使用定时器的 Arduino 库,包括 USB 堆栈。
我编写了一个很好的代码,它生成具有 50% 占空比的快速 PWM,我可以用电位器改变频率。它输出带有一些死区时间的直通道和倒通道。我正在使用 Arduino Micro aka ATmega32U4。该代码实际上是 "Atmel" 代码。在我关闭 Arduino Micro 电源然后再打开之前,代码工作正常。
我已经对代码和寄存器进行了编程,以便频率可以在 10kHz 到 100kHz 之间变化。但是通电后 on/off 频率从 5kHz 变为 50kHz。发生这种情况后,我必须再次使用 Arduino IDE 对电路板进行编程,以使其正常工作。上电 on/off 后再次发生变化。我很确定其中一个寄存器被 "Arduino hardware abstraction layer" 覆盖,或者我们应该给它命名。我还没有读出所有的寄存器,所以我不知道哪个被覆盖了。我想这是预分频器。 我如何防止这种情况发生?我应该把寄存器内容写在别的地方吗?或者我应该写几次才能确定? 为什么或如何发生这种情况?
代码如下:
#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;
}
我不确定为什么您在编程后立即会出现不同的行为,但是 Arduino Micro 使用的引导加载程序 (Caterina) 在运行后不会执行完全重置,因此引导加载程序对 AVR 的寄存器进行了更改通常在用户的草图中可见。
我能够通过删除修改 PLLFRQ
的行来解决问题。这是始终产生 3.31 kHz PWM 的代码的简化版本:
void setup()
{
pinMode(5, OUTPUT);
pinMode(13, OUTPUT);
TCCR4A = 0;
TCCR4B = 0x06; // configure prescaler to 64 (CK = CLK / 64 = 1.5 MHz)
TCCR4C = 0;
TCCR4D = 0; // select Fast PWM operation (0 << WGM41)|(0 << WGM40)
OCR4C = 150; // select PWM frequency
OCR4A = 150 / 2; // set duty cycle
DT4 = 0x55; // set dead times. DT = (1 / 48Mhz) * 0...15
// This register write has to be after others.
// Otherwise the PWM generation will not work. I do not know why.
// COM4A1..0 = 01, OC4A and !OC4A connected.
// PWM4A = 1 (activate channel A PWM output)
TCCR4A = 0x42;
}
void loop()
{
}
乱用 PLL 后分频器不是一个好主意,因为它可能会影响所有其他使用定时器的 Arduino 库,包括 USB 堆栈。