【问题标题】:Timer1 acting weird on Arduino UNO (ATMEGA328)Timer1 在 Arduino UNO (ATMEGA328) 上表现怪异
【发布时间】:2019-01-23 20:59:37
【问题描述】:

我正在尝试实现我在 YouTube 上看到的一个简单的 timer1 示例:http://youtu.be/Tj6xGtwOlB4?t=22m7s。这个例子是用 c++ 编写的,用于独立的 ATMEGA328 芯片,我正试图让它在 Arduino UNO 上工作。这是我的工作代码:

void setup() {
  //initialize port for LED
  DDRB =  0b11111111; //initialize port B as output (really only care about 5th bit)
  PORTB = 0b00000000; //set ouput values to zero
  TCCR1A = 0; //clear control register A (not sure that I need this)
  TCCR1B |= 1<<CS10; //no prescaler, turns on CS10 bit of TCCR1B
}

void loop() {
  if (TCNT1 >= 255){
    TCNT1 = 0; //resets timer to zero
    PORTB ^=1<<PINB5; //1<<PINB5 is same as 0b00100000, so this toggles bit five of port b which is pin 13 (red led) on Arduino
  } 
}

一切正常,但 TCNT1 最多只能计数 255。如果我将 if 语句中的值设置为更高的值,则 if 语句中的代码永远不会执行。 Timer1 应该是一个 16 位定时器,所以为什么计数停止在 255 是没有意义的。arduino 是在幕后做些什么来搞砸这个吗?在 youtube 上的示例中它似乎工作得很好(没有 arduino)。

【问题讨论】:

    标签: c++ timer arduino atmega


    【解决方案1】:

    首先.... 为什么要设置寄存器? Arduino唯一的好处就是封装了一些功能,为什么不用呢?而不是

    DDRB =  0b11111111;
    PORTB = 0b00000000;
    ...
    PORTB ^=1<<PINB5;
    

    简单地使用

    int myoutpin = XXXX; // Put here the number of the ARDUINO pin you want to use as output
    ...
    pinMode(myoutpin, OUTPUT);
    ...
    digitalWrite(myoutpin, !digitalRead(myoutpin));
    

    我认为计时器可能也有一些类似的功能..

    至于你的问题,我试过这段代码:

    // the setup routine runs once when you press reset:
    void setup() {
      TCCR1A = 0; //clear control register A (not sure that I need this)
      TCCR1B |= 1<<CS10; //no prescaler, turns on CS10 bit of TCCR1B
      Serial.begin(9600);
    }
    
    // the loop routine runs over and over again forever:
    void loop() {
      if (TCNT1 >= 12000){
        TCNT1 = 0; //resets timer to zero
        Serial.println("Timer hit");
      } 
    }
    

    在模拟器中运行良好;我应该用一个真正的 Arduino 来试试,但我现在还没有……一旦我得到一个,我会尝试使用它

    【讨论】:

    • 我可以使用 pinMode() 函数来设置输出,但是使用 digitalWrite/digitalRead 比直接端口操作慢得多(在 UNO 上慢约 25 倍)。此外,我需要比使用 micros() 更高的时间分辨率。直接访问定时器应该提供大约 63 ns 的分辨率。或许我已经快要从arduino毕业了,但目前它仍然是一个方便的硬件和sdk平台。你知道你是否可以使用 UNO 和 arduino SDK 在真正的 C++ 中编程(即使用 main() 和 while(1) 而不是 setup() 或 loop())?
    • 顺便说一句,我在实际的 arduino Uno 上尝试了您的模拟代码,并且“计时器命中”从未出现。我将“无计时器”放在 if 语句之外并打印出来。有趣的是,如果我将 sei() 添加到 setup() 中,它确实有效。我认为 sei() 启用中断。不知道为什么这很重要。
    • 我不知道为什么它的行为不同。您可以尝试使用 8 位寄存器(TCNT1H 和 TCNT1L)并在软件中连接它们。至于使用纯 C 可以,但不能在 Arduino IDE 中。您可以编写代码,然后调用 gcc 进行 avr 编译和 avrdude 进行编程(命令行工具,都包含在 arduino ide 包中)
    【解决方案2】:

    我也遇到过同样的问题,在 Atmel 文档中,我发现其他引脚会影响计数器模式。即管脚:WGM13,WGM12,WGM11,WGM10 分别为 0,1,0,0,计数器将处于 CTC 模式,即计数到 OCR1A 的值,而不是 (2^16-1 ) 这可能是您的代码中的情况。

    WGM11,WGM10 是 TCCR1A 中的第 1,0 位,WGM13,WGM12 是 TCCR1B 中的第 4,3 位,因此将它们设置为零就可以了。

    【讨论】:

      【解决方案3】:

      我的一个代码有类似的情况。我无法找到问题的确切原因。最后,我删除了 setup 和 loop 函数,并用 c 代码替换了它们。 然后它工作正常。如果您需要这些功能,则通过清除 TCCR1A 和 TCCR1B 寄存器来启动代码。我希望这是由于 Arduino IDE 不确定而发生的。但它有效。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-06-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多