极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 6114|回复: 7

[救急!]Arduino定时器是否与其他端口冲突

[复制链接]
发表于 2015-4-27 21:30:15 | 显示全部楼层 |阅读模式
我用pulse sensor测量心率,并且用dht11测量温湿度。pulse sensor的用到端口A0和timer2定时器中断,dht11用端口7.现在的问题是,只要将这两个模块代码组合在一起,就只能读出心率,而温湿度都为0,只要分开测试都是好的,请问是什么原因??

  1. #include "dht11.h"
  2. #include "Wire.h"

  3. dht11 DHT11;

  4. #define DHT11PIN 8
  5. int pulsePin = 0;                 // Pulse Sensor purple wire connected to analog pin 0
  6. int blinkPin = 13;                // pin to blink led at each beat
  7. int fadePin = 5;                  // pin to do fancy classy fading blink at each beat
  8. int fadeRate = 0;                 // used to fade LED on with PWM on fadePin


  9. // these variables are volatile because they are used during the interrupt service routine!
  10. volatile int BPM;                   // used to hold the pulse rate
  11. volatile int Signal;                // holds the incoming raw data
  12. volatile int IBI = 600;             // holds the time between beats, the Inter-Beat Interval
  13. volatile boolean Pulse = false;     // true when pulse wave is high, false when it's low
  14. volatile boolean QS = false;        // becomes true when Arduoino finds a beat.

  15. void setup()
  16. {
  17.   Serial.begin(9600);
  18.    pinMode(blinkPin,OUTPUT);         // pin that will blink to your heartbeat!
  19.   pinMode(fadePin,OUTPUT);          // pin that will fade to your heartbeat!
  20.   interruptSetup();                 // sets up to read Pulse Sensor signal every 2mS

  21.   Serial.println("DHT11 TEST PROGRAM ");
  22. }
  23.   void loop()
  24. {
  25.   Serial.println("\n");

  26.   int chk = DHT11.read(DHT11PIN);

  27.   Serial.print("Read sensor: ");
  28.   switch (chk)
  29.   {
  30.     case DHTLIB_OK:
  31.                 Serial.println("OK");
  32.                 break;
  33.     case DHTLIB_ERROR_CHECKSUM:
  34.                 Serial.println("Checksum error");
  35.                 break;
  36.     case DHTLIB_ERROR_TIMEOUT:
  37.                 Serial.println("Time out error");
  38.                 break;
  39.     default:
  40.                 Serial.println("Unknown error");
  41.                 break;
  42.   }
  43.   Serial.print("Humidity (%): ");
  44.   Serial.println((float)DHT11.humidity, 2);
  45.   Serial.print("Temperature (oC): ");
  46.   Serial.println((float)DHT11.temperature, 2);
  47.    delay(2000);
  48.   //  sendDataToProcessing('S', Signal);     // send Processing the raw Pulse Sensor data
  49.   if (QS == true){                       // Quantified Self flag is true when arduino finds a heartbeat
  50.         fadeRate = 255;                  // Set 'fadeRate' Variable to 255 to fade LED with pulse
  51.         sendDataToProcessing('B',BPM);   // send heart rate with a 'B' prefix
  52.         sendDataToProcessing('Q',IBI);   // send time between beats with a 'Q' prefix
  53.         QS = false;                      // reset the Quantified Self flag for next time   
  54.      }
  55.   
  56.   ledFadeToBeat();
  57.   
  58.   delay(20);                             //  take a break
  59. }
  60. void ledFadeToBeat(){
  61.     fadeRate -= 15;                         //  set LED fade value
  62.     fadeRate = constrain(fadeRate,0,255);   //  keep LED fade value from going into negative numbers!
  63.     analogWrite(fadePin,fadeRate);          //  fade LED
  64.   }


  65. void sendDataToProcessing(char symbol, int data ){
  66.     Serial.print(symbol);                // symbol prefix tells Processing what type of data is coming
  67.     Serial.println(data);                // the data to send culminating in a carriage return
  68.   }


复制代码
下面是定时器中断的代码



  1. volatile int rate[10];                    // used to hold last ten IBI values
  2. volatile unsigned long sampleCounter = 0;          // used to determine pulse timing
  3. volatile unsigned long lastBeatTime = 0;           // used to find the inter beat interval
  4. volatile int P =512;                      // used to find peak in pulse wave
  5. volatile int T = 512;                     // used to find trough in pulse wave
  6. volatile int thresh = 512;                // used to find instant moment of heart beat
  7. volatile int amp = 100;                   // used to hold amplitude of pulse waveform
  8. volatile boolean firstBeat = true;        // used to seed rate array so we startup with reasonable BPM
  9. volatile boolean secondBeat = true;       // used to seed rate array so we startup with reasonable BPM


  10. void interruptSetup(){     
  11.   // Initializes Timer2 to throw an interrupt every 2mS.
  12.   TCCR2A = 0x02;     // DISABLE PWM ON DIGITAL PINS 3 AND 11, AND GO INTO CTC MODE
  13.   TCCR2B = 0x06;     // DON'T FORCE COMPARE, 256 PRESCALER
  14.   OCR2A = 0X7C;      // SET THE TOP OF THE COUNT TO 124 FOR 500Hz SAMPLE RATE
  15.   TIMSK2 = 0x02;     // ENABLE INTERRUPT ON MATCH BETWEEN TIMER2 AND OCR2A 中断屏蔽寄存器
  16.   sei();             // MAKE SURE GLOBAL INTERRUPTS ARE ENABLED      
  17. }


  18. // THIS IS THE TIMER 2 INTERRUPT SERVICE ROUTINE.
  19. // Timer 2 makes sure that we take a reading every 2 miliseconds
  20. ISR(TIMER2_COMPA_vect){                         // triggered when Timer2 counts to 124
  21.     cli();                                      // disable interrupts while we do this
  22.     Signal = analogRead(pulsePin);              // read the Pulse Sensor
  23.     sampleCounter += 2;                         // keep track of the time in mS with this variable
  24.     int N = sampleCounter - lastBeatTime;       // monitor the time since the last beat to avoid noise

  25. //  find the peak and trough of the pulse wave
  26.     if(Signal < thresh && N > (IBI/5)*3){       // avoid dichrotic noise by waiting 3/5 of last IBI
  27.         if (Signal < T){                        // T is the trough
  28.             T = Signal;                         // keep track of lowest point in pulse wave
  29.          }
  30.        }
  31.       
  32.     if(Signal > thresh && Signal > P){          // thresh condition helps avoid noise
  33.         P = Signal;                             // P is the peak
  34.        }                                        // keep track of highest point in pulse wave
  35.    
  36.   //  NOW IT'S TIME TO LOOK FOR THE HEART BEAT
  37.   // signal surges up in value every time there is a pulse
  38. if (N > 250){                                   // avoid high frequency noise
  39.   if ( (Signal > thresh) && (Pulse == false) && (N > (IBI/5)*3) ){        
  40.     Pulse = true;                               // set the Pulse flag when we think there is a pulse
  41.     digitalWrite(blinkPin,HIGH);                // turn on pin 13 LED
  42.     IBI = sampleCounter - lastBeatTime;         // measure time between beats in mS
  43.     lastBeatTime = sampleCounter;               // keep track of time for next pulse
  44.          
  45.          if(firstBeat){                         // if it's the first time we found a beat, if firstBeat == TRUE
  46.              firstBeat = false;                 // clear firstBeat flag
  47.              return;                            // IBI value is unreliable so discard it
  48.             }   
  49.          if(secondBeat){                        // if this is the second beat, if secondBeat == TRUE
  50.             secondBeat = false;                 // clear secondBeat flag
  51.                for(int i=0; i<=9; i++){         // seed the running total to get a realisitic BPM at startup
  52.                     rate[i] = IBI;                     
  53.                     }
  54.             }
  55.          
  56.     // keep a running total of the last 10 IBI values
  57.     word runningTotal = 0;                   // clear the runningTotal variable   

  58.     for(int i=0; i<=8; i++){                // shift data in the rate array
  59.           rate[i] = rate[i+1];              // and drop the oldest IBI value
  60.           runningTotal += rate[i];          // add up the 9 oldest IBI values
  61.         }
  62.         
  63.     rate[9] = IBI;                          // add the latest IBI to the rate array
  64.     runningTotal += rate[9];                // add the latest IBI to runningTotal
  65.     runningTotal /= 10;                     // average the last 10 IBI values
  66.     BPM = 60000/runningTotal;               // how many beats can fit into a minute? that's BPM!
  67.     QS = true;                              // set Quantified Self flag
  68.     // QS FLAG IS NOT CLEARED INSIDE THIS ISR
  69.     }                       
  70. }

  71.   if (Signal < thresh && Pulse == true){     // when the values are going down, the beat is over
  72.       digitalWrite(blinkPin,LOW);            // turn off pin 13 LED
  73.       Pulse = false;                         // reset the Pulse flag so we can do it again
  74.       amp = P - T;                           // get amplitude of the pulse wave
  75.       thresh = amp/2 + T;                    // set thresh at 50% of the amplitude
  76.       P = thresh;                            // reset these for next time
  77.       T = thresh;
  78.      }
  79.   
  80.   if (N > 2500){                             // if 2.5 seconds go by without a beat
  81.       thresh = 512;                          // set thresh default
  82.       P = 512;                               // set P default
  83.       T = 512;                               // set T default
  84.       lastBeatTime = sampleCounter;          // bring the lastBeatTime up to date        
  85.       firstBeat = true;                      // set these to avoid noise
  86.       secondBeat = true;                     // when we get the heartbeat back
  87.      }
  88.   
  89.   sei();                                     // enable interrupts when youre done!
  90. }// end isr



复制代码
回复

使用道具 举报

发表于 2015-4-28 07:50:34 | 显示全部楼层
看一下 vcc 是多少?我最近遇到的几个问题都是 arduino pro micro 出来的 vcc 比较低 4.6v导致设备无法工作
回复 支持 反对

使用道具 举报

发表于 2015-4-28 10:54:48 | 显示全部楼层
因为 DHT 在读取数据时不可以被 interrupt 太久,
你的 ISR( ) 做太多事情,
尤其那个  Signal = analogRead(pulsePin);              
就要用掉大约 110 us, (别怀疑, 这句 analogRead( ) 就是要大约 0.11 ms 啦!
加上其它句子铁定会让 DHT 读取错误
比较简单可以先在读取 DHT11 的时候把中断禁止:

cli( ); // 禁止中断
int chk = DHT11.read(DHT11PIN);
sei( );  // 允许中断

但是, 这样是否影响到你的 pulse sensor 取样就要测试才知道 !
你测试看看再分享给大家
回复 支持 反对

使用道具 举报

发表于 2015-4-28 12:41:25 | 显示全部楼层
建议独立供电,DHT113.3V就可以
回复 支持 反对

使用道具 举报

发表于 2015-4-28 18:48:04 | 显示全部楼层
你看看 DHT11 是如何读取数据的
然后你就会相信为何被 ISR( ) 打断太久就无法读到正确的数据 !
  1. //
  2. //    FILE: dht11.cpp
  3. // VERSION: 0.4.1
  4. // PURPOSE: DHT11 Temperature & Humidity Sensor library for Arduino
  5. // LICENSE: GPL v3 (http://www.gnu.org/licenses/gpl.html)
  6. //
  7. // DATASHEET: http://www.micro4you.com/files/sensor/DHT11.pdf
  8. //
  9. // HISTORY:
  10. // George Hadjikyriacou - Original version (??)
  11. // Mod by SimKard - Version 0.2 (24/11/2010)
  12. // Mod by Rob Tillaart - Version 0.3 (28/03/2011)
  13. // + added comments
  14. // + removed all non DHT11 specific code
  15. // + added references
  16. // Mod by Rob Tillaart - Version 0.4 (17/03/2012)
  17. // + added 1.0 support
  18. // Mod by Rob Tillaart - Version 0.4.1 (19/05/2012)
  19. // + added error codes
  20. //

  21. #include "dht11.h"

  22. // Return values:
  23. // DHTLIB_OK
  24. // DHTLIB_ERROR_CHECKSUM
  25. // DHTLIB_ERROR_TIMEOUT
  26. int dht11::read(int pin)
  27. {
  28.         // BUFFER TO RECEIVE
  29.         uint8_t bits[5];
  30.         uint8_t cnt = 7;
  31.         uint8_t idx = 0;

  32.         // EMPTY BUFFER
  33.         for (int i=0; i< 5; i++) bits[i] = 0;

  34.         // REQUEST SAMPLE
  35.         pinMode(pin, OUTPUT);
  36.         digitalWrite(pin, LOW);
  37.         delay(18);
  38.         digitalWrite(pin, HIGH);
  39.         delayMicroseconds(40);
  40.         pinMode(pin, INPUT);

  41.         // ACKNOWLEDGE or TIMEOUT
  42.         unsigned int loopCnt = 10000;
  43.         while(digitalRead(pin) == LOW)
  44.                 if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

  45.         loopCnt = 10000;
  46.         while(digitalRead(pin) == HIGH)
  47.                 if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

  48.         // READ OUTPUT - 40 BITS => 5 BYTES or TIMEOUT
  49.         for (int i=0; i < 40; i++)
  50.         {
  51.                 loopCnt = 10000;
  52.                 while(digitalRead(pin) == LOW)
  53.                         if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

  54.                 unsigned long t = micros();

  55.                 loopCnt = 10000;
  56.                 while(digitalRead(pin) == HIGH)
  57.                         if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;

  58.                 if ((micros() - t) > 40) bits[idx] |= (1 << cnt);
  59.                 if (cnt == 0)   // next byte ?
  60.                 {
  61.                         cnt = 7;    // restart at MSB
  62.                         idx++;      // next byte!
  63.                 }
  64.                 else cnt--;
  65.         }

  66.         // WRITE TO RIGHT VARS
  67.         // as bits[1] and bits[3] are allways zero they are omitted in formulas.
  68.         humidity    = bits[0];
  69.         temperature = bits[2];

  70.         uint8_t sum = bits[0] + bits[2];  

  71.         if (bits[4] != sum) return DHTLIB_ERROR_CHECKSUM;
  72.         return DHTLIB_OK;
  73. }
  74. //
  75. // END OF FILE
复制代码
回复 支持 反对

使用道具 举报

发表于 2015-4-28 18:57:57 | 显示全部楼层
tsaiwn 发表于 2015-4-28 18:48
你看看 DHT11 是如何读取数据的
然后你就会相信为何被 ISR( ) 打断太久就无法读到正确的数据 !

如果库的看不太懂
请看看这我加入注释的独立版本:
只要在收取 40 bits 期间被 ISR( ) 打断就错乱了 !
  1. //Test the DHT11 -- Modified by [email]tsaiwn@cs.nctu.edu.tw[/email]
  2. int dhPin = 8;  // 温溼度讯號接脚连入 Arduino 的 Pin 8
  3. byte dat[5];   // 存放湿度2byte, 温度 2 byte, checksum 1 byte
  4. byte readData( ) {  // 每次读取 8 bits  ( one byte)
  5. byte data;
  6. for(int i=0; i<8; i++) {
  7.   if(digitalRead(dhPin) == LOW) {   // 一开始要 LOW 才表示要传过来
  8.     while(digitalRead(dhPin) == LOW); //等待 50us;
  9.     // 现在已经变成 HIGH 了
  10.     delayMicroseconds(30); //判断高电平持续时间,以判定资料是‘0’还是‘1’;
  11.     if(digitalRead(dhPin) == HIGH)  // 持续了 30 us 以上就是 1
  12.         data |= (1<<(7-i)); //高位在前,低位元在后;
  13.     //如果这时已经是 LOW, 表示这 bit 是 0, 不必塞入 data
  14.     //..而且以下的 while 也会立即结束(因为 LOW), 准备接收下一个 bit
  15.     while(digitalRead(dhPin) == HIGH); // 等待下一bit的接收;
  16.     //这时一定已经变成 LOW 了
  17.   }// if
  18. }// for(
  19. return data;   // 收完 8 bit = one byte = one char
  20. } // readData(
  21. void start_test(  ) {  // 每次要与 DHT11 沟通
  22. digitalWrite(dhPin,LOW); //拉低到 LOW,发表示要开始沟通的信號;
  23. delay(30); //延时要大於 18ms,以便 DHT11 能检测到开始信號;我们用30ms
  24. digitalWrite(dhPin,HIGH);   // 拉高HIGH, 让 DHT11 拉低到 LOW 告诉我们要传送
  25. delayMicroseconds(40);  // 给40us等待 DHT11 响应;
  26. pinMode(dhPin,INPUT);  // 改为输入 mode 准备 digitalRead( )
  27. while(digitalRead(dhPin) == HIGH);   // 必须等到 LOW
  28. delayMicroseconds(80); //DHT11 发出响应,会拉低 80us;所以至少等80us
  29. while(digitalRead(dhPin) == LOW);  // 继续等到变 HIGH
  30. delayMicroseconds(80); //DHT11 会拉高到HIGH 80us 后开始发送资料;
  31. /// 以下连续读入 5 bytes (40 bits), 最后的 byte 是 checksum 校验值
  32. for(int i=0;i < 5;i++) dat[i] = readData( ); //接收温湿度资料,校验位元;
  33. pinMode(dhPin,OUTPUT);  // 改为 Output mode, 准备拉高HIGH
  34. digitalWrite(dhPin,HIGH); //发送完一次资料后释放bus,等待下一次开始信號;
  35. }
  36. void setup(  ) {  Serial.begin(9600);  pinMode(dhPin, OUTPUT); }
  37. void loop(  ) {
  38.   start_test( );  // 读取湿度温度和检核位到 dat[ ]; 其中dat[4]是checkSum
  39.   // 根据datasheet规定, dat[4] 要 == (dat[0]+dat[1]+dat[2]+dat[3]) %256
  40.   // 否则表示沟通有错误 !!
  41.   Serial.print("Current humdity = ");
  42.   Serial.print(dat[0], DEC); //显示湿度的整数部分;
  43.   Serial.print('.');
  44.   Serial.print(dat[1],DEC); //显示湿度的小数位;(其实是 0)
  45.   Serial.println(" %");  // 注意有空格要用 " %"  不可用 ' %'
  46.   Serial.print("Current temperature = ");
  47.   Serial.print(dat[2], DEC); //显示温度的整数部分;
  48.   Serial.print('.');
  49.   Serial.print(dat[3],DEC); //显示温度的小数位;(其实是 0)
  50.   Serial.println(" C");
  51.   delay(1985);
  52. }
  53. /// END
复制代码
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-5-4 15:01:38 | 显示全部楼层
tsaiwn 发表于 2015-4-28 10:54
因为 DHT 在读取数据时不可以被 interrupt 太久,
你的 ISR( ) 做太多事情,
尤其那个  Signal = analogRea ...

我也怀疑就是因为中断打乱了dht11的时序,我的解决方法是没有用中断,直接用delay(2)进行取样,测试能够同时读出数据,但是稳定性不太好。
回复 支持 反对

使用道具 举报

发表于 2020-3-27 17:47:04 | 显示全部楼层
wufeng2991 发表于 2015-5-4 15:01
我也怀疑就是因为中断打乱了dht11的时序,我的解决方法是没有用中断,直接用delay(2)进行取样,测试能 ...

你好楼主,我也遇到了同样的问题,我不太明白怎么用delay解决,您能详细说说么
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊 ( 浙ICP备09023225号 )

GMT+8, 2020-7-10 12:18 , Processed in 0.050500 second(s), 24 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表