🌟

Arduino的定时器中断功能

2024/05/06に公開

Arduino是什么?

Arduino是一种单板控制器。Arduino有MPU,GPIO,UART的接口。
这个经常被使用为电子制作。我对Ardunio兴趣原因是在工作中想用它。
虽然日本公司可以从大型FA公司比较低价格买控制器。比如说三菱的PLC。
但是,外国公司不可能。因为Ardunio很便宜,所以我想使用Ardunio作为控制器,而不是PLC。

树莓派是很有名为电子制作的单板。树莓派和Arduino的区别在于有无OS。树莓派有Linux。理由我不用树莓派是我不太信任OS的实时性能。因为我想做1ms时间精度GPIO控制、没有OS的单板比好的。

定时器中断功能是什么?

Arduino的MPU有这个功能。MPU接受16MHz的clock输入。它有一些register用于计算clock的上开。这些register的数值达到一定值的时候,会产生中断信号。举例来说,register的数值达到65535的时候,就会产生一个中断信号。

为什么用定时中断器功能?

举例来说,用于LED闪烁的源代码

void loop(){
    digitalWrite(LED_BUILTIN, LOW);
    delay(1000);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(1000);
}

你想做只LED闪烁的话,这些源代码没问题。但是,嵌入式设备的话,有问题。CPU执行delay()的时候,它不能其他处理。
其实,到处理LED闪烁的时间,就产生中断信号。然后,CPU处理。没有接受中断信号的时间,CPU可以执行其他处理。

每隔100us产生一次定时器中断的方法

你因该设定Arduino的registers。这次,我们使用CTC模式。
Arduino有三个定时器。我们使用Timer1。其他Timer被用于其他功能,比如说delay(),所以用Timer1很适合。

bit数 关数
Timer0 8 delay(), millis(), micros() ...etc
Timer1 16
Timer2 8 tone()

你因该代码写入setup()内。

TCCR1A = 0; // Initialize Timer1
TCCR1B = (1 << WGM12) | (1 << CS10); // CTC mode Divide 1
OCR1A = 1600 - 1; // 100μs
TIMSK1 = (1 << OCIE1A); // Enable Timer1 A Match interrupt

中断处理。变量led_sts是全局变量。LED——BUTIN是全局定量。

ISR(TIMER1_COMPA_vect) {
    if (led_sts) {
      digitalWrite(LED_BUILTIN, LOW);
      led_sts = 0;
    } 
    else {
      digitalWrite(LED_BUILTIN, HIGH);
      led_sts = 1;
    }
}

详细

TCCR1A 一个一个bit的意思。

TCCR1B 一个一个bit的意思。


这次,我们设定,WGM12 = 1、CS10 = 1、其他都是0,所以模式CTC,分频比1。
你设定OCRA1的数值的话,可以变中断产生时的数值。
因为clock频率是16MHz,100us是(1600-1)。

TIMSK1是中断允许register。

这次,只OCIE1A是1,其他是0。

不需要定义WGM12和CS10。ArduinoIDE不会报错。

ISR是(Interrupt Service Routine)。

ISR(中断事情){
    // 中断处理
}

応用例

准备变量,为了调用中断例程而进行递减,你可以使用多个软件定时器。这个方法的优点是用一个硬件中断信号可以使用多个软件定时器的中断功能。有多重终端的话,优先级考虑太麻烦。
所以,一个硬件中断很好。这个方法的缺点是精度比较不好,但是控制IO的话,没问题。

定时器的变量到0的时候,执行LED闪烁处理。

举例说,每隔1msLED闪烁。

void setup() {
  pinMode(13, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  TCCR1A = 0; // Initialize Timer1
  TCCR1B = (1 << WGM12) | (1 << CS10); // CTCmode, Divine 1
  OCR1A = 1600 - 1; // 100μs
  TIMSK1 = (1 << OCIE1A); // Enable Timer1 A match interrupt
 timer = 0;
  led_sts = 0;
}

ISR(TIMER1_COMPA_vect) {
  if (timer > 0) {
    timer--;
    } 
}

Void loop(){
  if (timer == 0) {
    cycle_time = os_time - cycle_start;
    LED();
    timer = 9;
  }
}

void LED(){
  if (led_sts) {
    digitalWrite(LED_BUILTIN, LOW);
    led_sts = 0;
  } 
  else {
    digitalWrite(LED_BUILTIN, HIGH);
    led_sts = 1;
  }
}

将timer = 9的部分更改,即可改变Lチカ的控制周期。
如果这个数量是变量的话,从电脑用UART你可以设定控制周期。

Discussion