Timer1 arduino使Serial无法正常工作

Sit*_*.br 2 timer arduino

运行下面的代码,当我发送串行arduino中的任何字符时,不会打印"a".我认为这是timer1代码的错误,但它应该工作,因为这个代码是由我的老师在C类中给出的.

void setup() {

    Serial.begin(115200);

    //http://www.instructables.com/id/Arduino-Timer-Interrupts/?ALLSTEPS
    noInterrupts();
    TCCR1A = 0;// set entire TCCR1A register to 0
    TCCR1B = 0;// same for TCCR1B
    TCNT1  = 0;//initialize counter value to 0
    // set compare match register for 1000000hz increments with 8 bits prescaler
    OCR1A = 1;// = (16*10^6) / (1000000*8) - 1 (must be <65536)
    // turn on CTC mode
    TCCR1B |= (1 << WGM12);
    // Set CS11 bit for 8 prescaler. Each timer has a different bit code to each prescaler
    TCCR1B |= (1 << CS11);  
    // enable timer compare interrupt
    TIMSK1 |= (1 << OCIE1A);
    interrupts();

}

void loop() {

    if (Serial.available()) {

        Serial.println("a");

    }

}
Run Code Online (Sandbox Code Playgroud)

Gab*_*les 13

设置TCCR1A和B的方式都是正确的.

请参阅660-pg ATmega328数据表.132~135如需了解更多帮助和信息,如果您想了解从现在开始的低级别帮助.

但是,您有2个主要问题,1个小问题和1个推荐.

以下是完全破坏您的代码的两个主要问题:

  1. 由于您正在启用定时器比较匹配1A中断("TIMSK1 | =(1 << OCIE1A);"),您还必须定义在发生这种情况时将被调用的中断服务程序(ISR),否则您将运行 - 时间(但不是编译时)问题.也就是说,如果没有为输出比较匹配A定义ISR,一旦输出比较A中断发生,处理器将卡在由编译器为您创建的无限空虚拟ISR中,并且您的主循环将不会进展(见下面的代码以证明这一点).

将其添加到代码的底部:

ISR(TIMER1_COMPA_vect)
{
  //insert your code here that you want to run every time the counter reaches OCR1A
}
Run Code Online (Sandbox Code Playgroud)
  1. 步入ISR需要几微秒,步进ISR需要几微秒,加上在ISR中运行代码所需的时间,你需要使用足够大的OCR1A值以使ISR均匀有时间执行,而不是被连续调用,以至于你永远不会退出ISR(这会将你的代码锁定在一个无限循环中......这也会发生在你的情况下).
    我建议你不要每隔10us调用一次ISR.由于您使用CTC模式(比较匹配时清除定时器),预分频器为8,我建议将OCR1A设置为不低于20左右.OCR1A = 20将每10us调用一次ISR.(预分频器为8表示每个Timer1标记为0.5us,因此OCR1A = 20将每隔20*0.5 = 10us调用ISR).

如果您设置OCR1A = 20,并按上述方法添加ISR代码,您的代码将运行正常.

1小问题:

配置剩余的定时器,最好设置OCR1A ,否则在某些情况下定时器可能无法开始计数(请参阅"Thorsten"的评论:http://www.righto.com/2009/07/secrets -of-arduino-pwm.html)

所以,移动OCR1A = 20; 到您的最后TCCR1B线和之前你TIMSK1线.

1推荐:

摆脱"noInterrupts"和"中断".这里不需要它们.

现在,这是我写的代码,它将更好地展示你正在尝试做什么,以及我在说什么:

/*
timer1-arduino-makes-serial-not-work.ino
-a demo to help out this person here: http://stackoverflow.com/questions/28880226/timer1-arduino-makes-serial-not-work
By Gabriel Staples
http://electricrcaircraftguy.blogspot.com/
5 March 2015
-using Arduino 1.6.0
*/

//Note: ISR stands for Interrupt Service Routine

//Global variables
volatile unsigned long numISRcalls = 0; //number of times the ISR is called

void setup() 
{
  Serial.begin(115200);

  //http://www.instructables.com/id/Arduino-Timer-Interrupts/?ALLSTEPS
//  noInterrupts(); //Not necessary
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;//initialize counter value to 0
  // set compare match register for 1000000hz increments with 8 bits prescaler
  OCR1A = 20;// = (16*10^6) / (1000000*8) - 1 (must be <65536) //better to put this line AFTER configuring TCCR1A and B, but in Arduino 1.6.0 it appears to be ok here (may crash code in older versions, see comment by "Thorsten" here: http://www.righto.com/2009/07/secrets-of-arduino-pwm.html
  // turn on CTC mode [Clear Timer on Compare match---to make timer restart at OCR1A; see datasheet pg. 133]
  TCCR1B |= (1 << WGM12); 
  // Set CS11 bit for 8 prescaler [0.5us ticks, datasheet pg. 135]. Each timer has a different bit code to each prescaler
  TCCR1B |= (1 << CS11);
  // enable timer compare match 1A interrupt; NOW YOU *MUST* SET UP THE CORRESPONDING ISR OR THIS LINE BREAKS THE CODE
  TIMSK1 |= (1 << OCIE1A);

//  OCR1A = 20;// = (16*10^6) / (1000000*8) - 1 (must be <65536) //SETTING OCR1A TO 1 OR 2 FOR SURE BREAKS THE CODE, as it calls the interrupt too often
//  interrupts();

  Serial.println("setup done, input a character");
}

void loop() 
{
  if (Serial.available()) 
  {
    Serial.read(); //read and throw away the first byte in the incoming serial buffer (or else the next line will get called every loop once you send the Arduino a char)
    Serial.println("a");

    //also print out how many times OCR1A has been reached by Timer 1's counter 
    noInterrupts(); //turn off interrupts while reading non-atomic (>1 byte) volatile variables that could be modified by an ISR at any time--incl while reading the variable itself.
    unsigned long numISRcalls_copy = numISRcalls;
    interrupts();
    Serial.print("numISRcalls = "); Serial.println(numISRcalls_copy);
  }

//  Serial.println("test");
//  delay(1000);
}

//SINCE YOU ARE ENABLING THE COMPARE MATCH 1A INTERRUPT ABOVE, YOU *MUST* INCLUDE THE CORRESPONDING INTERRUPT SERVICE ROUTINE CODE
ISR(TIMER1_COMPA_vect)
{
  //insert your code here that you want to run every time the counter reaches OCR1A
  numISRcalls++;
}
Run Code Online (Sandbox Code Playgroud)

运行它,看看你的想法.

证明上面的"主要问题1"是真实的(至少据我所知 - 并且基于对Arduino Nano的测试,使用IDE 1.6.0):
下面的代码编译,但不会继续打印" a"(但它可以打印一次).请注意,为了简单起见,我注释掉了等待串行数据的部分,并简单地告诉它每半秒打印一个"a":

void setup() {

    Serial.begin(115200);

    //http://www.instructables.com/id/Arduino-Timer-Interrupts/?ALLSTEPS
    TCCR1A = 0;// set entire TCCR1A register to 0
    TCCR1B = 0;// same for TCCR1B
    TCNT1  = 0;//initialize counter value to 0
    // set compare match register for 1000000hz increments with 8 bits prescaler
    OCR1A = 20;// = (16*10^6) / (1000000*8) - 1 (must be <65536)
    // turn on CTC mode
    TCCR1B |= (1 << WGM12);
    // Set CS11 bit for 8 prescaler. Each timer has a different bit code to each prescaler
    TCCR1B |= (1 << CS11);  
    // enable timer compare interrupt
    TIMSK1 |= (1 << OCIE1A);
}

void loop() {
    //if (Serial.available()) {
    //    Serial.println("a");
    //}

    Serial.println("a");
    delay(500);
}

//ISR(TIMER1_COMPA_vect)
//{
//  //insert your code here that you want to run every time the counter reaches OCR1A
//}
Run Code Online (Sandbox Code Playgroud)

另一方面,下面的代码有效,"a"将继续打印出来.这个和上面的唯一区别是这个在底部没有注释ISR声明:

void setup() {

    Serial.begin(115200);

    //http://www.instructables.com/id/Arduino-Timer-Interrupts/?ALLSTEPS
    TCCR1A = 0;// set entire TCCR1A register to 0
    TCCR1B = 0;// same for TCCR1B
    TCNT1  = 0;//initialize counter value to 0
    // set compare match register for 1000000hz increments with 8 bits prescaler
    OCR1A = 20;// = (16*10^6) / (1000000*8) - 1 (must be <65536)
    // turn on CTC mode
    TCCR1B |= (1 << WGM12);
    // Set CS11 bit for 8 prescaler. Each timer has a different bit code to each prescaler
    TCCR1B |= (1 << CS11);  
    // enable timer compare interrupt
    TIMSK1 |= (1 << OCIE1A);
}

void loop() {
    //if (Serial.available()) {
    //    Serial.println("a");
    //}

    Serial.println("a");
    delay(500);
}

ISR(TIMER1_COMPA_vect)
{
  //insert your code here that you want to run every time the counter reaches OCR1A
}
Run Code Online (Sandbox Code Playgroud)

额外资源:

  1. 我在这里写的文章的底部有一个最有用的Arduino资源的运行列表:http://electricrcaircraftguy.blogspot.com/2014/01/the-power-of-arduino.html.去看一下.

  2. 特别是看看Ken Shirriff和Nick Gammon在"高级"部分下的第一个链接.他们很棒!

如果它能解决您的问题,请将此答案投票,并接受为正确的答案; 谢谢!

此致,
Gabriel Staples
http://www.ElectricRCAircraftGuy.com/