Arduino таймер4 пользовательский выпуск ШИМ - PullRequest
0 голосов
/ 21 февраля 2019

Я сделал хороший код, который генерирует быстрый ШИМ с рабочим циклом 50%, и я могу изменить частоту с помощью потенциометра.Он выводит прямые и инвертированные каналы с некоторым временем простоя.Я использую Arduino Micro aka ATmega32U4.Код на самом деле код "Atmel".Код работает нормально, пока я не выключу и снова не включу Arduino Micro.

Я запрограммировал код и регистрировал так, чтобы частота могла изменяться от 10 кГц до 100 кГц.Но после включения / выключения частота меняется с 5 кГц на 50 кГц.После того, как это произошло, мне нужно снова запрограммировать плату, используя 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 голосов
/ 22 февраля 2019

Я точно не знаю, почему у вас изменилось поведение сразу после программирования, но загрузчик, который использует Arduino Micro (Caterina), не выполняет полный сброс после запуска, поэтому изменения, вносимые загрузчиком в регистры AVR, частовиден эскиз пользователя.

Мне удалось устранить проблему, удалив строку, которая изменяет PLLFRQ.Вот упрощенная версия вашего кода, которая всегда выдает ШИМ 3,31 кГц:

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-стек.

...