Arduino timer4 自定义 PWM 问题

Posted

技术标签:

【中文标题】Arduino timer4 自定义 PWM 问题【英文标题】:Arduino timer4 custom PWM issue 【发布时间】:2019-02-21 19:35:44 【问题描述】:

我编写了一个很好的代码,它可以生成具有 50% 占空比的快速 PWM,并且我可以使用电位计更改频率。它输出带有一些死区时间的直通道和反通道。我正在使用 Arduino Micro 又名 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】:

我不确定为什么您在编程后会立即出现不同的行为,但是 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 堆栈。

【讨论】:

以上是关于Arduino timer4 自定义 PWM 问题的主要内容,如果未能解决你的问题,请参考以下文章

Arduino :PWM详解和电路搭建以及示例代码

Esp8266学习4. 基于Arduino的PWM与红外信号处理

Arduino 实现PWM输出背后的相关知识

Esp8266学习4. 基于Arduino的PWM与红外信号处理

Esp8266学习4. 基于Arduino的PWM与红外信号处理

arduino uno PWM的for语句执行中按按钮怎么立即停止