【问题标题】:Programming a PWM in an Arduino Mega ATmega2560 micro-controller在 Arduino Mega ATmega2560 微控制器中编程 PWM
【发布时间】:2012-09-19 13:04:40
【问题描述】:

我正在尝试在 Arduino Mega (ATmega2560) 上启用 PWM,但我遇到了一些问题。

首先,我正在尝试在Ada 中对此进行编程。我希望将三个 Timer3 通道与 FastPWM 一起使用,所以我写了

procedure Main is
begin

   -- Nullify Timer3 buffers
   TCCR3A := 0;
   TCCR3B := 0;
   TCCR3C := 0;

   -- Waveform Generation Mode
   --  Fast PW, 8-bit, TOP = 0x00FF, Update OCR3x at BOTTOM, TOV3 Flag Set on TOP
   --  => WGM33|WGM32|WGM31|WGM30 = 0|1|0|1
   TCCR3A := TCCR3A or TCCR3A_WGM30;
   TCCR3B := TCCR3B or TCCR3B_WGM32;

   -- Compare Output Mode:
   --  Fast PWM, non-inverting mode
   --  => COM3A1|COM3A0|COM3B1|COM3B0|COM3C1|COM3C0 = 1|0|1|0|1|0
   TCCR3A := TCCR3A or TCCR3A_COM3A1 or TCCR3A_COM3B1 or TCCR3A_COM3C1;

   -- Clock Select: clk/1024 => CS32|CS31|CS30 = 1|1|1
   TCCR3B := TCCR3B or TCCR3B_CS32 or TCCR3B_CS31 or TCCR3B_CS30;

   -- Set Timer3 pins as output :
   -- Channel A : Digital Pin 5 / Chip Pin 5 (PE3/OC3A/AIN1)
   -- Channel B : Digital Pin 2 / Chip Pin 6 (PE4/OC3B/INT4)
   -- Channel C : Digital Pin 3 / Chip Pin 7 (PE5/OC3C/INT5)
   DDRE := DDRE_DDE3 or DDRE_DDE4 or DDRE_DDE5;

   OCR3AH := 0;
   OCR3AL := 250;

   OCR3BH := 0;
   OCR3BL := 250;

   OCR3CH := 0;
   OCR3CL := 250;

end Main;

硬件连接正常;我在 Arduino IDE 上使用简单的代码对其进行了测试。所以对我来说,很明显代码缺少某些东西或出错了,这应该是由 PWM 初始化中的问题引起的。谁能解释一下我在哪里犯了这样的错误?

提前致谢。

更新

如果 Ada 很难得到整个逻辑,C 中的等效代码是(你可以使用AS6 构建它,结果是一样的,即不生成信号):

int main(void){
    TCCR3A = 0;
    TCCR3B = 0;
    TCCR3C = 0;

    /* Waveform Generation Mode
    Fast PW, 8-bit, TOP = 0x00FF, Update OCR3x at BOTTOM, TOV3 Flag Set on TOP
    => WGM33|WGM32|WGM31|WGM30 = 0|1|0|1 */
    TCCR3A = TCCR3A|(1<<WGM30);
    TCCR3B = TCCR3B|(1<<WGM32);

    /* Compare Output Mode:
    Fast PWM, non-inverting mode
    => COM3A1|COM3A0|COM3B1|COM3B0|COM3C1|COM3C0 = 1|0|1|0|1|0*/
    TCCR3A = TCCR3A|(1<<COM3A1)|(1<<COM3B1)|(1<<COM3C1);

    /* Clock Select: clk/1024 => CS32|CS31|CS30 = 1|1|1 */
    TCCR3B = TCCR3B|(1<<CS32)|(1<<CS31)|(1<<CS30);

    /* Set Timer3 pins as output :
    Channel A : Digital Pin 5 / Chip Pin 5 (PE3/OC3A/AIN1)
    Channel B : Digital Pin 2 / Chip Pin 6 (PE4/OC3B/INT4)
    Channel C : Digital Pin 3 / Chip Pin 7 (PE5/OC3C/INT5)*/
    DDRE = DDRE|(1<<DDE3)|(1<<DDE4)|(1<<DDE5);

    /* Set PWM Duty Cycles */
    OCR3AH = 0;
    OCR3AL = 250;

    OCR3BH = 0;
    OCR3BL = 250;

    OCR3CH = 0;
    OCR3CL = 250;
}

【问题讨论】:

  • 这可能有点过于本地化,无法在此处接收答案。特别是在不知道您的这些变量与什么相关的情况下。也许您的供应商会更有帮助。
  • 顺便说一句:我希望你在发布之前先把火扑灭。 :-)
  • 或许应该迁移到electronics.stackexchange.com
  • @T.E.D.,寄存器的名字和C里用的一样,只是语法不同,所以这里用的变量和C用WinAVR或AVR用的没有区别工作室。例如,如果我在 Ada 中设置 DDRE := DDRE_DDE2,这仅意味着在 C 中我正在执行 DDRE = 0b00000200。 AVR Studio 中的 C 库也使用命名变量,如 DDE2。
  • @T.E.D.哈哈,是的,一旦开始。

标签: c arduino ada avr pwm


【解决方案1】:

查看www.atmel.com/Images/doc2549.pdf第136页,我看到一个注释:

“功率降低定时器/计数器 3 位,PRTIM3,在“PRR1 – 功率降低寄存器 1”上 必须将第 57 页写入零才能启用 Timer/Counter3 模块。"

可能相关?

我不知道电源管理的默认设置是什么,我也没用过2560。

其余的对我来说看起来不错,尽管我在 328p 上使用了计时器库 avr-timer0.adb 等,而不是自己滚动。

【讨论】:

    【解决方案2】:

    我不确定,但是如果您忘记了 main 函数末尾的无限循环,程序将停止,所有中断都将被禁用,控制器进入一个空循环。

    没有中断就没有 PWM。

    int main(void){
    ....
    while (1) {
    }
    return 0;
    }
    

    【讨论】:

    • 其实定时器只使用中断来通知软件。它们无需进一步指令即可运行稳定的 PWM 信号。
    【解决方案3】:

    您需要在 SREG 中设置 SEI 标志以启用中断并在 main 中添加无限循环。 Avr 程序在主函数结束后不会终止或挂起,而是重新开始。 http://www.atmel.com/webdoc/avrassembler/avrassembler.wb_SEI.html

    【讨论】:

    • 他们没有。它们只是以无限循环结束(跳转到自身),但永远不会再次开始主循环。
    【解决方案4】:

    立即出现一个观察结果——几乎可以肯定这是不对的:

    --  => COM3A1|COM3A0|COM3B1|COM3B0|COM3C1|COM3C0 = 1|0|1|0|1|0
    TCCR3A := TCCR3A or TCCR3A_COM3A1 or TCCR3A_COM3B1 or TCCR3A_COM3C1;
    

    为什么?因为像COM3A0 这样的命名常量只是表示位位置(0 到 7)的整数的别名。在 C 中,当我们设置这些时,我们会执行以下操作:

    REGISTER |= (1<<COM3A0);
    

    和COM3A0 = 3,那么它变成(1

    在与当前寄存器值进行 OR 运算之前将 1 向左移动位数。 因此,除非您的 COM3A0 例如已经移位,否则此语句所做的只是对几个 1 进行 OR 运算,然后零并将单个结果分配给 TCCR3A。

    【讨论】: