我写了一些简单的代码,我在我的Arduino Uno上使用了timer1。问题是我无法以任何方式停止计时器。
我正在使用该程序计数并在显示屏上显示引脚2上外部中断的数量,同时测量时间。但是当我按下按钮fin
时,我想停止为程序生成中断,这会增加名为cas
的可变时间。你能以某种方式帮忙吗?
我的代码:
#include <OLED_I2C.h>
#define alarm_output 10
#define fin 13
int suma=0;
int alarm=0;
float cas=0;
OLED myOLED(SDA, SCL, 8);
extern uint8_t MediumNumbers[];
extern uint8_t BigNumbers[];
extern uint8_t SmallFont[];
void setup(void) {
pinMode(alarm_output,OUTPUT);
digitalWrite(alarm_output,LOW);
pinMode(fin,INPUT_PULLUP);
pinMode(9,INPUT_PULLUP);
//interrupt
interrupts();
attachInterrupt(digitalPinToInterrupt(2), displej, CHANGE);
//first screen
myOLED.begin();
myOLED.setFont(SmallFont);
myOLED.print("TIME:", 0, 30);
myOLED.print("INTERRUPT:", 0, 56);
myOLED.print("Laser game", CENTER, 0);
myOLED.setFont(MediumNumbers);
myOLED.printNumF(cas,1,RIGHT,20);
myOLED.setFont(BigNumbers);
myOLED.printNumI(suma, RIGHT, 40);
myOLED.update();
//start loop
up:;
if(digitalRead(9)==1)
goto up;
// TIMER 1 for interrupt frequency 10 Hz:
cli(); // stop interrupts
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 10 Hz increments
OCR1A = 24999; // = 16000000 / (64 * 10) - 1 (must be <65536)
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS12, CS11 and CS10 bits for 64 prescaler
TCCR1B |= (0 << CS12) | (1 << CS11) | (1 << CS10);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei(); // allow interrupts
}
void displej(){
suma++;
alarm=3;
}
ISR(TIMER1_COMPA_vect){
cas=cas+0.1;
if(alarm>0)
alarm--;
}
void loop(void) {
myOLED.setFont(MediumNumbers);
myOLED.printNumF(cas,1,RIGHT,20);
myOLED.setFont(BigNumbers);
myOLED.printNumI(suma, RIGHT, 40);
myOLED.update();
if(digitalRead(fin)==0){
cli();
TCCR1B |= (0 << CS12) | (0 << CS11) | (0 << CS10); //this do now work
detachInterrupt(digitalPinToInterrupt(2));
sei();
}
if(alarm>0)
digitalWrite(alarm_output,HIGH);
else
digitalWrite(alarm_output,LOW);
delay(10);
}
答案 0 :(得分:2)
当然可以!有两种方法可以做到。您只需停止计时器中断,但使用以下命令保持计时器运行:
TIMSK1 &= ~(1 << OCIE1A);
或者,您可以通过将时钟源更改为“无”来完全停止计时器:
TCCR1B &= ~(1<< CS12);
TCCR1B &= ~(1<< CS11);
TCCR1B &= ~(1<< CS10);
它有效地撤消了您首先选择时钟源所做的操作。此后,CS12-CS11-CS10位将为0-0-0,时钟源将停止。见第134数据表。
答案 1 :(得分:1)
我已经测试了“关闭计时器”的所有三种方法。只需在下面的代码中注释掉您喜欢的那个就可以看到它。这三个都有效地让Arduino的LED熄灭闪烁。
void setup(void) {
pinMode(13,OUTPUT);
digitalWrite(13,LOW);
interrupts();
// TIMER 1 for interrupt frequency 10 Hz:
cli(); // stop interrupts
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 10 Hz increments
OCR1A = 24999; // 200 millisecond cycle
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS12, CS11 and CS10 bits for 64 prescaler
TCCR1B |= (0 << CS12) | (1 << CS11) | (1 << CS10);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei(); // allow interrupts
}
volatile uint8_t count = 0;
volatile uint8_t timer_flip = 0;
ISR(TIMER1_COMPA_vect){
if (timer_flip == 0)
timer_flip = 1;
else
timer_flip = 0;
if (timer_flip == 1)
digitalWrite(13, HIGH);
else
digitalWrite(13, LOW);
count++;
}
void loop(void)
{
if (count > 100) // runs for a few seconds
{
//cli(); // One way to disable the timer, and all interrupts
//TCCR1B &= ~(1<< CS12); // turn off the clock altogether
//TCCR1B &= ~(1<< CS11);
//TCCR1B &= ~(1<< CS10);
//TIMSK1 &= ~(1 << OCIE1A); // turn off the timer interrupt
}
}
这个确切的代码现在正在我旁边的Uno上运行。我已经测试了上面所有三个“关闭”机制,它们都有效。
为了制作一个最小的,可验证的例子,我剥离了所有OLED的东西。我将引脚13更改为输出并将其设置为闪烁LED(尽管它可以停止定时器和/或中断明显禁用)。
几个学习要点:
volatile
在中断服务程序中写入的任何变量。