arduino中斷和一些問題

上次做的arduino小項目在測試過程中發現了一些小問題,至此又引出了一系列問題。大概是這樣的,之前檢測煙霧傳感器使用電位器分壓替代的,今天找到了打火機和小木棍就點火實測了一把(好久沒玩火了)。測試過程中發現這個MQ135傳感器並不是很靈敏,把火苗放在下面傳感器測試值升高的很有限(50升到100的樣子),而且火滅掉後或者有風吹過測量值很快就下來了,我估計這是和這個傳感器所主要測量的氣體相關,這個傳感器主要是測氨氣,一些有機氣體和煙霧,可能小木棍燃燒過程中這類氣體相對較少。

因此就出現了一個問題,我之前的程序裏面採用的並非實時監測,而是在每一秒求100次採集平均值(而且是寫死的),這樣做主要爲了減少虛警,但是如果要提高監測靈敏度的話還是需要增加一個虛警時間閾值的參數,將求平均的時間縮短,實際實現還是增加一個隊列存儲一段時間的採樣數據(虛警時間閾值窗口),然後每次採樣的時候求一次平均值。這樣的話相當於實時在對煙霧進行檢測並且實時檢測是否超過閾值需要報警,而且可以通過調整虛警時間閾值這個參數來改變報警的靈敏度。爲了實現這個功能就需要用到arduino的中斷。幸好arduino是有內部中斷的,即便是UNO這個最低的型號,它裏面有3個定時器,每一個都可以作爲中斷,也就是說最多可以同時又三個定時中斷,我找到了一篇文章詳細的介紹了中斷的設置方式,http://www.instructables.com/id/Arduino-Timer-Interrupts/?ALLSTEPS具體就不詳細說明了,看代碼即可。具體就不詳細說明了,看代碼即可。

int i = 0;

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);
  cli();//stop interrupts
  //set timer1 interrupt at 1Hz
  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 1hz increments
  OCR1A = 15624;// = (16*10^6) / (1*1024) - 1 (must be <65536)
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS12 and CS10 bits for 1024 prescaler
  TCCR1B |= (1 << CS12) | (1 << CS10);  
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);
  sei();//allow interrupts
  delay(100000);
}

ISR(TIMER1_COMPA_vect){//timer1 interrupt 1Hz toggles pin 13 (LED)
//generates pulse wave of frequency 1Hz/2 = 0.5kHz (takes two cycles for full wave- toggle high then toggle low)
  i++;
  Serial.println(i);
}

void loop() {
  // put your main code here, to run repeatedly:

}

在這個100Hz中斷中進行MQ135採集,10ms採樣間隔,然後在中斷中進行平均值計算,並給出報警標誌。在使用中斷過程中又發現了一個問題,就是蜂鳴器報警失效了,這個我之前單獨給蜂鳴器寫了一個庫,最終發現問題應該是arduino函數堆棧問題,這裏主函數loop裏面調用蜂鳴器庫函數,蜂鳴器庫函數裏面又有delay函數,估計是在這個delay裏面再進中斷的時候掛掉的,解決的方法也很簡單,把這個蜂鳴器庫函數去掉封裝,直接放到loop函數裏面即可。這也進一步說明問題應該是由於arduino函數堆棧大小不夠導致的函數入棧或者出棧時出了問題。

這進一步又讓我懷疑arduino的中斷系統,它是如何處理多箇中斷的,是否支持中斷嵌套,是否有中斷隊列等等,這個如果寫實時性高複雜的代碼就需要注意這些問題,後面有時間對現在一些有名的處理器的中斷機制做一個總結。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章