运行下面的代码,当我发送Serial 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");
}
}
答案 0 :(得分:13)
设置TCCR1A和B的方式都是正确的。
请参阅660-pg ATmega328数据表。 132~135获得更多帮助&amp;如果您想知道从现在开始在哪里寻找低级帮助,请提供信息。
但是,您有2个主要问题,1个小问题和1个推荐。
将其添加到代码的底部:
ISR(TIMER1_COMPA_vect)
{
//insert your code here that you want to run every time the counter reaches OCR1A
}
如果您设置OCR1A = 20,并按上述方法添加ISR代码,您的代码将运行正常。
最好在配置剩余的计时器后设置OCR1A ,否则在某些情况下计时器可能无法开始计数(参见&#34; Thorsten&#39;&#34;#34 ;在此评论:http://www.righto.com/2009/07/secrets-of-arduino-pwm.html)
所以,移动OCR1A = 20; 在上之后你的TIMSK1系列之前的 。
摆脱&#34; noInterrupts&#34;和&#34;中断&#34;。这里不需要它们。
现在,这是我编写的代码,它将更好地展示您尝试做的事情,以及我正在谈论的内容:
/*
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++;
}
运行它,看看你的想法。
证明&#34;主要问题1&#34;以上是真实的(至少根据我的理解 - 并基于Arduino Nano的测试,使用IDE 1.6.0):
下面的代码编译,但不会继续打印&#34; a&#34; (但它可以打印一次)。请注意,为了简单起见,我注释掉了等待串行数据的部分,并简单地告诉它打印一个&#34; a&#34;每半秒钟:
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
//}
另一方面,下面的代码可以正常运行,并且&#34; a&#34;将继续打印出来。这个和上面的唯一区别是这个在底部没有注释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
}
我在这里写的一篇文章的最后部分列出了最有用的Arduino资源:http://electricrcaircraftguy.blogspot.com/2014/01/the-power-of-arduino.html。检查出来。
特别要看第一个链接,在&#34; Advanced&#34;由Ken Shirriff和Nick Gammon创作。他们非常棒!
如果它能解决您的问题,请将此答案投票,并接受为正确的答案;谢谢!
此致
加布里埃尔史泰博斯
http://www.ElectricRCAircraftGuy.com/
答案 1 :(得分:2)
Gabriel Staples非常正确,你没有看到“a”的原因是你没有为中断提供ISR处理程序。因此,编译器生成的代码会跳回到地址0x0000并重新开始草图。
提供“空”ISR处理程序的替代方法是:
EMPTY_INTERRUPT (TIMER1_COMPA_vect);
使用EMPTY_INTERRUPT处理程序,我得到一个响应(“a”),OCR1A低至1:
OCR1A = 1;
虽然如果你不打算对它们做任何事情,你不得不想知道为什么要启用中断。
有关Arduino上interrupts的更多信息。
答案 2 :(得分:0)
TCCR1B |= (1 << WGM12);
TCCR1B |= (1 << CS11);
虽然我认为它可能是:
TCCR1A |= (1 << WGM12);
TCCR1B |= (1 << CS11);
可能唯一的错误就在那里,因为你忘记设置TCCR1A并且你设置了2倍的另一个。
答案 3 :(得分:0)
TCCR1A | =(1&lt;&lt; WGM12);是按位运算(按位OR)。 在这种特殊情况下,只设置TCCR1A的一位,即位置WGM12中的一位。 TCCR1B | =(1 <&lt; CS11);在位置CS11中设置不同的位
答案 4 :(得分:0)
取决于程序需要对这种快速中断执行的操作,例如在输出引脚上产生高速时钟,可以使用TCCR1A中的COM位(在我的存储器中有4个最有意义的位)将其设置为硬件,以在与定时器相关的引脚上切换输出,而无需写入ISR( )回调会在软件中处理定时器中断。