【问题标题】:How do I configure an interrupt for the hardware PWM on the Arduino Due?如何为 Arduino Due 上的硬件 PWM 配置中断?
【发布时间】:2016-03-12 20:27:37
【问题描述】:

我正在做一个关于 Arduino 的项目,因为要制作一个数字合成器。我将使用 PWM 以所需的音符频率生成输出波,并以 192kHz 的频率采样。

我能够以所需的频率输出 PWM 并调整脉冲宽度(用示波器测试),但我需要配置中断,以便我可以为不同类型的波计算下一个所需的 PWM 值在不同的声音频率(正弦波、锯齿波等)。每次中断触发(在 192kHz 时),一个函数将根据音符值(可听频率)计算下一个脉冲宽度值。

到目前为止,这是我的代码。我能够让 PWM 工作,但我在中断中的虚拟代码(打开和关闭引脚)不会切换引脚。我用示波器对此进行了测试。我知道代码的问题是中断没有正确触发/执行,因为输出引脚在设置代码中设置为高电平,这也发生在示波器上。但是,中断测试引脚不切换。我错过了什么?

uint32_t pwmPin = 8; // PWM output pin
uint32_t channel = g_APinDescription[pwmPin].ulPWMChannel;
uint32_t sampFreq = 192000ul; // sample at 192kHz
uint32_t clkAFreq = 42000000ul;
uint32_t pwmFreq = (clkAFreq * 2)/sampFreq;
uint16_t dutyPercent = 50;
uint16_t dutyAct = pwmFreq * (100-dutyPercent) / 100;

void setup() {
  // put your setup code here, to run once:


 pinMode(5, OUTPUT); // interrupt test pin

  pmc_enable_periph_clk(PWM_INTERFACE_ID);
  PWMC_ConfigureClocks(clkAFreq, 0, VARIANT_MCK);

  PIO_Configure(
     g_APinDescription[pwmPin].pPort,
     g_APinDescription[pwmPin].ulPinType,
     g_APinDescription[pwmPin].ulPin,
     g_APinDescription[pwmPin].ulPinConfiguration);

  //uint32_t
  channel = g_APinDescription[pwmPin].ulPWMChannel;
  PWMC_ConfigureChannel(PWM_INTERFACE, channel, clkAFreq, 0, 0);
  PWMC_SetPeriod(PWM_INTERFACE, channel, pwmFreq);
  PWMC_EnableChannel(PWM_INTERFACE, channel);
  PWMC_SetDutyCycle(PWM_INTERFACE, channel, dutyAct);
  PWMC_EnableChannelIt(PWM_INTERFACE, channel);
  dutyPercent = 50; //square wave

}

void loop() {
  // put your main code here, to run repeatedly:

}


void PWM_Handler()          // this is what I looked up in startup_sam4s.c
{
  int i;                    // 
  digitalWrite(5, HIGH);    // toggle pin
  i++;                      // delay a little
  digitalWrite(5, LOW);     // toggle pin
}

【问题讨论】:

  • 你能解释一下“以 192kHz 采样波形”吗?外部设备是否正在对 Arduino 输出进行采样?或者 Arduino 正在对外部输入进行采样?
  • 我通常认为 PWM 信号是具有调制占空比的方波。您认为“不同类型波(正弦波、锯齿波等)的 PWM 值”是什么样的?
  • 在 PWM_Handler() 中没有定义i 的值,因此引脚 5 为高电平的时间非常短。尝试改用delay(500)
  • PWM 输出恒定为 192kHz。所以 PWM 输出的频率总是以 192kHz 上升。然后程序计算所需波形和频率的下一个脉冲宽度。
  • 在哪里拨打PWM_Handler()

标签: arduino interrupt pwm


【解决方案1】:

对于任何偶然发现这一点的人,这是我让中断起作用的方法:

uint32_t totalTime = 0; // total elapsed time

uint32_t pwmPin = 8; // PWM output pin
uint32_t irqPin = 5; // interrupt test pin
uint32_t channel = g_APinDescription[pwmPin].ulPWMChannel; // set channel for PWM out
uint32_t sampFreq = 192000ul; // sampling frequency (Hz)
uint16_t maxDutyCount = 255;
uint32_t clkAFreq = 42000000ul; // clock frequency (Hz)
uint32_t pwmFreq = (clkAFreq * 2)/sampFreq; // calculate PWM frequency
uint16_t dutyPercent = 128; // starting duty percent
uint16_t dutyAct = pwmFreq * (maxDutyCount-dutyPercent) / maxDutyCount; // 

void setup() {
  // put your setup code here, to run once:
  pinMode(irqPin, OUTPUT);

  pmc_enable_periph_clk(PWM_INTERFACE_ID);
  PWMC_ConfigureClocks(clkAFreq, 0, VARIANT_MCK);

  PIO_Configure(
   g_APinDescription[pwmPin].pPort,
   g_APinDescription[pwmPin].ulPinType,
   g_APinDescription[pwmPin].ulPin,
   g_APinDescription[pwmPin].ulPinConfiguration);

   channel = g_APinDescription[pwmPin].ulPWMChannel; // channel 5
   PWMC_ConfigureChannel(PWM_INTERFACE, channel, clkAFreq, 0, 0);
   PWMC_SetPeriod(PWM_INTERFACE, channel, pwmFreq);
   PWMC_EnableChannel(PWM_INTERFACE, channel);
   PWMC_SetDutyCycle(PWM_INTERFACE, channel, dutyAct);
   PWM_INTERFACE->PWM_IER1 = 0x20; //enable interrupt on channel 5
   PWM_INTERFACE->PWM_IDR1 = 0xFFFFFFDF; //enable interrupt on channel 5
   PWM_INTERFACE->PWM_IER2 = 0x00002001; //enable interrupt on channel 5
   PWM_INTERFACE->PWM_IDR2 = 0xFFFFDFFE; //enable interrupt on channel 5

   NVIC_DisableIRQ(PWM_IRQn); // set up interrupt
   NVIC_ClearPendingIRQ(PWM_IRQn);
   NVIC_SetPriority(PWM_IRQn, 0);
   NVIC_EnableIRQ((IRQn_Type)36); //NVIC_EnableIRQ(PWM_IRQn);
   PWMC_EnableChannel(PWM_INTERFACE, channel);
   //Enable of the Interrupts (writing CHIDx and FCHIDx
   //in PWM_IER1 register, and writing WRDYE, ENDTXE,
   //TXBUFE, UNRE, CMPMx and CMPUx in PWM_IER2 register)
}

void loop() {
}


void PWM_Handler(void) // PWM interrupt handler
{
   volatile long dummy = PWM_INTERFACE->PWM_ISR1; // clear interrupt flag
   dummy = PWM_INTERFACE->PWM_ISR2; // clear interrupt flag
//your code here!
}

【讨论】:

    猜你喜欢
    • 2015-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多