[救急!]Arduino定时器是否与其他端口冲突
我用pulse sensor测量心率,并且用dht11测量温湿度。pulse sensor的用到端口A0和timer2定时器中断,dht11用端口7.现在的问题是,只要将这两个模块代码组合在一起,就只能读出心率,而温湿度都为0,只要分开测试都是好的,请问是什么原因??#include "dht11.h"
#include "Wire.h"
dht11 DHT11;
#define DHT11PIN 8
int pulsePin = 0; // Pulse Sensor purple wire connected to analog pin 0
int blinkPin = 13; // pin to blink led at each beat
int fadePin = 5; // pin to do fancy classy fading blink at each beat
int fadeRate = 0; // used to fade LED on with PWM on fadePin
// these variables are volatile because they are used during the interrupt service routine!
volatile int BPM; // used to hold the pulse rate
volatile int Signal; // holds the incoming raw data
volatile int IBI = 600; // holds the time between beats, the Inter-Beat Interval
volatile boolean Pulse = false; // true when pulse wave is high, false when it's low
volatile boolean QS = false; // becomes true when Arduoino finds a beat.
void setup()
{
Serial.begin(9600);
pinMode(blinkPin,OUTPUT); // pin that will blink to your heartbeat!
pinMode(fadePin,OUTPUT); // pin that will fade to your heartbeat!
interruptSetup(); // sets up to read Pulse Sensor signal every 2mS
Serial.println("DHT11 TEST PROGRAM ");
}
void loop()
{
Serial.println("\n");
int chk = DHT11.read(DHT11PIN);
Serial.print("Read sensor: ");
switch (chk)
{
case DHTLIB_OK:
Serial.println("OK");
break;
case DHTLIB_ERROR_CHECKSUM:
Serial.println("Checksum error");
break;
case DHTLIB_ERROR_TIMEOUT:
Serial.println("Time out error");
break;
default:
Serial.println("Unknown error");
break;
}
Serial.print("Humidity (%): ");
Serial.println((float)DHT11.humidity, 2);
Serial.print("Temperature (oC): ");
Serial.println((float)DHT11.temperature, 2);
delay(2000);
//sendDataToProcessing('S', Signal); // send Processing the raw Pulse Sensor data
if (QS == true){ // Quantified Self flag is true when arduino finds a heartbeat
fadeRate = 255; // Set 'fadeRate' Variable to 255 to fade LED with pulse
sendDataToProcessing('B',BPM); // send heart rate with a 'B' prefix
sendDataToProcessing('Q',IBI); // send time between beats with a 'Q' prefix
QS = false; // reset the Quantified Self flag for next time
}
ledFadeToBeat();
delay(20); //take a break
}
void ledFadeToBeat(){
fadeRate -= 15; //set LED fade value
fadeRate = constrain(fadeRate,0,255); //keep LED fade value from going into negative numbers!
analogWrite(fadePin,fadeRate); //fade LED
}
void sendDataToProcessing(char symbol, int data ){
Serial.print(symbol); // symbol prefix tells Processing what type of data is coming
Serial.println(data); // the data to send culminating in a carriage return
}
下面是定时器中断的代码
volatile int rate; // used to hold last ten IBI values
volatile unsigned long sampleCounter = 0; // used to determine pulse timing
volatile unsigned long lastBeatTime = 0; // used to find the inter beat interval
volatile int P =512; // used to find peak in pulse wave
volatile int T = 512; // used to find trough in pulse wave
volatile int thresh = 512; // used to find instant moment of heart beat
volatile int amp = 100; // used to hold amplitude of pulse waveform
volatile boolean firstBeat = true; // used to seed rate array so we startup with reasonable BPM
volatile boolean secondBeat = true; // used to seed rate array so we startup with reasonable BPM
void interruptSetup(){
// Initializes Timer2 to throw an interrupt every 2mS.
TCCR2A = 0x02; // DISABLE PWM ON DIGITAL PINS 3 AND 11, AND GO INTO CTC MODE
TCCR2B = 0x06; // DON'T FORCE COMPARE, 256 PRESCALER
OCR2A = 0X7C; // SET THE TOP OF THE COUNT TO 124 FOR 500Hz SAMPLE RATE
TIMSK2 = 0x02; // ENABLE INTERRUPT ON MATCH BETWEEN TIMER2 AND OCR2A 中断屏蔽寄存器
sei(); // MAKE SURE GLOBAL INTERRUPTS ARE ENABLED
}
// THIS IS THE TIMER 2 INTERRUPT SERVICE ROUTINE.
// Timer 2 makes sure that we take a reading every 2 miliseconds
ISR(TIMER2_COMPA_vect){ // triggered when Timer2 counts to 124
cli(); // disable interrupts while we do this
Signal = analogRead(pulsePin); // read the Pulse Sensor
sampleCounter += 2; // keep track of the time in mS with this variable
int N = sampleCounter - lastBeatTime; // monitor the time since the last beat to avoid noise
//find the peak and trough of the pulse wave
if(Signal < thresh && N > (IBI/5)*3){ // avoid dichrotic noise by waiting 3/5 of last IBI
if (Signal < T){ // T is the trough
T = Signal; // keep track of lowest point in pulse wave
}
}
if(Signal > thresh && Signal > P){ // thresh condition helps avoid noise
P = Signal; // P is the peak
} // keep track of highest point in pulse wave
//NOW IT'S TIME TO LOOK FOR THE HEART BEAT
// signal surges up in value every time there is a pulse
if (N > 250){ // avoid high frequency noise
if ( (Signal > thresh) && (Pulse == false) && (N > (IBI/5)*3) ){
Pulse = true; // set the Pulse flag when we think there is a pulse
digitalWrite(blinkPin,HIGH); // turn on pin 13 LED
IBI = sampleCounter - lastBeatTime; // measure time between beats in mS
lastBeatTime = sampleCounter; // keep track of time for next pulse
if(firstBeat){ // if it's the first time we found a beat, if firstBeat == TRUE
firstBeat = false; // clear firstBeat flag
return; // IBI value is unreliable so discard it
}
if(secondBeat){ // if this is the second beat, if secondBeat == TRUE
secondBeat = false; // clear secondBeat flag
for(int i=0; i<=9; i++){ // seed the running total to get a realisitic BPM at startup
rate = IBI;
}
}
// keep a running total of the last 10 IBI values
word runningTotal = 0; // clear the runningTotal variable
for(int i=0; i<=8; i++){ // shift data in the rate array
rate = rate; // and drop the oldest IBI value
runningTotal += rate; // add up the 9 oldest IBI values
}
rate = IBI; // add the latest IBI to the rate array
runningTotal += rate; // add the latest IBI to runningTotal
runningTotal /= 10; // average the last 10 IBI values
BPM = 60000/runningTotal; // how many beats can fit into a minute? that's BPM!
QS = true; // set Quantified Self flag
// QS FLAG IS NOT CLEARED INSIDE THIS ISR
}
}
if (Signal < thresh && Pulse == true){ // when the values are going down, the beat is over
digitalWrite(blinkPin,LOW); // turn off pin 13 LED
Pulse = false; // reset the Pulse flag so we can do it again
amp = P - T; // get amplitude of the pulse wave
thresh = amp/2 + T; // set thresh at 50% of the amplitude
P = thresh; // reset these for next time
T = thresh;
}
if (N > 2500){ // if 2.5 seconds go by without a beat
thresh = 512; // set thresh default
P = 512; // set P default
T = 512; // set T default
lastBeatTime = sampleCounter; // bring the lastBeatTime up to date
firstBeat = true; // set these to avoid noise
secondBeat = true; // when we get the heartbeat back
}
sei(); // enable interrupts when youre done!
}// end isr
看一下 vcc 是多少?我最近遇到的几个问题都是 arduino pro micro 出来的 vcc 比较低 4.6v导致设备无法工作 因为 DHT 在读取数据时不可以被 interrupt 太久,
你的 ISR( ) 做太多事情,
尤其那个Signal = analogRead(pulsePin);
就要用掉大约 110 us, (别怀疑, 这句 analogRead( ) 就是要大约 0.11 ms 啦!
加上其它句子铁定会让 DHT 读取错误
比较简单可以先在读取 DHT11 的时候把中断禁止:
cli( ); // 禁止中断
int chk = DHT11.read(DHT11PIN);
sei( );// 允许中断
但是, 这样是否影响到你的 pulse sensor 取样就要测试才知道 !
你测试看看再分享给大家
建议独立供电,DHT113.3V就可以 你看看 DHT11 是如何读取数据的
然后你就会相信为何被 ISR( ) 打断太久就无法读到正确的数据 !//
// FILE: dht11.cpp
// VERSION: 0.4.1
// PURPOSE: DHT11 Temperature & Humidity Sensor library for Arduino
// LICENSE: GPL v3 (http://www.gnu.org/licenses/gpl.html)
//
// DATASHEET: http://www.micro4you.com/files/sensor/DHT11.pdf
//
// HISTORY:
// George Hadjikyriacou - Original version (??)
// Mod by SimKard - Version 0.2 (24/11/2010)
// Mod by Rob Tillaart - Version 0.3 (28/03/2011)
// + added comments
// + removed all non DHT11 specific code
// + added references
// Mod by Rob Tillaart - Version 0.4 (17/03/2012)
// + added 1.0 support
// Mod by Rob Tillaart - Version 0.4.1 (19/05/2012)
// + added error codes
//
#include "dht11.h"
// Return values:
// DHTLIB_OK
// DHTLIB_ERROR_CHECKSUM
// DHTLIB_ERROR_TIMEOUT
int dht11::read(int pin)
{
// BUFFER TO RECEIVE
uint8_t bits;
uint8_t cnt = 7;
uint8_t idx = 0;
// EMPTY BUFFER
for (int i=0; i< 5; i++) bits = 0;
// REQUEST SAMPLE
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
delay(18);
digitalWrite(pin, HIGH);
delayMicroseconds(40);
pinMode(pin, INPUT);
// ACKNOWLEDGE or TIMEOUT
unsigned int loopCnt = 10000;
while(digitalRead(pin) == LOW)
if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
loopCnt = 10000;
while(digitalRead(pin) == HIGH)
if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
// READ OUTPUT - 40 BITS => 5 BYTES or TIMEOUT
for (int i=0; i < 40; i++)
{
loopCnt = 10000;
while(digitalRead(pin) == LOW)
if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
unsigned long t = micros();
loopCnt = 10000;
while(digitalRead(pin) == HIGH)
if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
if ((micros() - t) > 40) bits |= (1 << cnt);
if (cnt == 0) // next byte ?
{
cnt = 7; // restart at MSB
idx++; // next byte!
}
else cnt--;
}
// WRITE TO RIGHT VARS
// as bits and bits are allways zero they are omitted in formulas.
humidity = bits;
temperature = bits;
uint8_t sum = bits + bits;
if (bits != sum) return DHTLIB_ERROR_CHECKSUM;
return DHTLIB_OK;
}
//
// END OF FILE tsaiwn 发表于 2015-4-28 18:48 static/image/common/back.gif
你看看 DHT11 是如何读取数据的
然后你就会相信为何被 ISR( ) 打断太久就无法读到正确的数据 !
如果库的看不太懂
请看看这我加入注释的独立版本:
只要在收取 40 bits 期间被 ISR( ) 打断就错乱了 !//Test the DHT11 -- Modified by [email protected]
int dhPin = 8;// 温溼度讯號接脚连入 Arduino 的 Pin 8
byte dat; // 存放湿度2byte, 温度 2 byte, checksum 1 byte
byte readData( ) {// 每次读取 8 bits( one byte)
byte data;
for(int i=0; i<8; i++) {
if(digitalRead(dhPin) == LOW) { // 一开始要 LOW 才表示要传过来
while(digitalRead(dhPin) == LOW); //等待 50us;
// 现在已经变成 HIGH 了
delayMicroseconds(30); //判断高电平持续时间,以判定资料是‘0’还是‘1’;
if(digitalRead(dhPin) == HIGH)// 持续了 30 us 以上就是 1
data |= (1<<(7-i)); //高位在前,低位元在后;
//如果这时已经是 LOW, 表示这 bit 是 0, 不必塞入 data
//..而且以下的 while 也会立即结束(因为 LOW), 准备接收下一个 bit
while(digitalRead(dhPin) == HIGH); // 等待下一bit的接收;
//这时一定已经变成 LOW 了
}// if
}// for(
return data; // 收完 8 bit = one byte = one char
} // readData(
void start_test() {// 每次要与 DHT11 沟通
digitalWrite(dhPin,LOW); //拉低到 LOW,发表示要开始沟通的信號;
delay(30); //延时要大於 18ms,以便 DHT11 能检测到开始信號;我们用30ms
digitalWrite(dhPin,HIGH); // 拉高HIGH, 让 DHT11 拉低到 LOW 告诉我们要传送
delayMicroseconds(40);// 给40us等待 DHT11 响应;
pinMode(dhPin,INPUT);// 改为输入 mode 准备 digitalRead( )
while(digitalRead(dhPin) == HIGH); // 必须等到 LOW
delayMicroseconds(80); //DHT11 发出响应,会拉低 80us;所以至少等80us
while(digitalRead(dhPin) == LOW);// 继续等到变 HIGH
delayMicroseconds(80); //DHT11 会拉高到HIGH 80us 后开始发送资料;
/// 以下连续读入 5 bytes (40 bits), 最后的 byte 是 checksum 校验值
for(int i=0;i < 5;i++) dat = readData( ); //接收温湿度资料,校验位元;
pinMode(dhPin,OUTPUT);// 改为 Output mode, 准备拉高HIGH
digitalWrite(dhPin,HIGH); //发送完一次资料后释放bus,等待下一次开始信號;
}
void setup() {Serial.begin(9600);pinMode(dhPin, OUTPUT); }
void loop() {
start_test( );// 读取湿度温度和检核位到 dat[ ]; 其中dat是checkSum
// 根据datasheet规定, dat 要 == (dat+dat+dat+dat) %256
// 否则表示沟通有错误 !!
Serial.print("Current humdity = ");
Serial.print(dat, DEC); //显示湿度的整数部分;
Serial.print('.');
Serial.print(dat,DEC); //显示湿度的小数位;(其实是 0)
Serial.println(" %");// 注意有空格要用 " %"不可用 ' %'
Serial.print("Current temperature = ");
Serial.print(dat, DEC); //显示温度的整数部分;
Serial.print('.');
Serial.print(dat,DEC); //显示温度的小数位;(其实是 0)
Serial.println(" C");
delay(1985);
}
/// END tsaiwn 发表于 2015-4-28 10:54 static/image/common/back.gif
因为 DHT 在读取数据时不可以被 interrupt 太久,
你的 ISR( ) 做太多事情,
尤其那个Signal = analogRea ...
我也怀疑就是因为中断打乱了dht11的时序,我的解决方法是没有用中断,直接用delay(2)进行取样,测试能够同时读出数据,但是稳定性不太好。 wufeng2991 发表于 2015-5-4 15:01
我也怀疑就是因为中断打乱了dht11的时序,我的解决方法是没有用中断,直接用delay(2)进行取样,测试能 ...
你好楼主,我也遇到了同样的问题,我不太明白怎么用delay解决,您能详细说说么
页:
[1]