我正在做一个关于控制两个传感器(超声波和红外线)的项目,用Arduino管理它们。 IR接收器内部有一个滤波器系统,因此它以36 kHz的频率接收。我使用模块srf04来处理超声波的东西。如果我做一个必须只控制一个传感器的程序,它就可以工作。但我必须将两个信号插入到一个结果中。所以我使用了protothreads!但它不起作用......错误是什么?
以下是代码:
#include <pt.h>
int iro = 8, iri = 4, us = 12, distanza, us_vcc = 13, ir_vcc = 7;
long durata;
static struct pt pt1, pt2, pt3;
static int irthread(struct pt *pt) {
PT_BEGIN(pt);
while(1) {
PT_WAIT_UNTIL(pt, 1>0);
digitalWrite(iro, HIGH);
delayMicroseconds(9);
digitalWrite(iro, LOW);
delayMicroseconds(9);
}
PT_END(pt);
}
static int usthread(struct pt *pt) {
static unsigned long timer = 0;
PT_BEGIN(pt);
while(1) {
PT_WAIT_UNTIL(pt, millis() - timer > 200);
timer = millis();
pinMode(us, OUTPUT);
digitalWrite(us, LOW);
delayMicroseconds(5);
digitalWrite(us, HIGH);
delayMicroseconds(10);
digitalWrite(us, LOW);
pinMode(us, INPUT);
durata = pulseIn(us, HIGH);
distanza = durata/58;
}
PT_END(pt);
}
static int leggithread(struct pt *pt) {
static unsigned long timer = 0;
PT_BEGIN(pt);
while(1) {
PT_WAIT_UNTIL(pt, millis() - timer > 200);
timer = millis();
Serial.print(distanza);
Serial.print("cm ");
if (digitalRead(iri) == LOW)
Serial.println("ir si");
else
Serial.println("ir no");
}
PT_END(pt);
}
void setup() {
pinMode(iro, OUTPUT);
pinMode(iri, INPUT);
pinMode(us_vcc, OUTPUT);
digitalWrite(us_vcc, HIGH);
pinMode(ir_vcc, OUTPUT);
digitalWrite(ir_vcc, HIGH);
Serial.begin(9600);
PT_INIT(&pt1);
PT_INIT(&pt2);
PT_INIT(&pt3);
}
void loop() {
irthread(&pt1);
usthread(&pt2);
leggithread(&pt3);
}
每个线程的代码的单个部分都可以工作。
更新
我解决了我的问题(已消除irthread()
),代码现在是这样的:
#include <pt.h>
int iro = 8, iri = 4, us = 12, distanza, us_vcc = 13, ir_vcc = 7;
long durata;
static struct pt pt1, pt2;
static int usthread(struct pt *pt) {
static unsigned long timer = 0;
PT_BEGIN(pt);
while(1) {
PT_WAIT_UNTIL(pt, millis() - timer > 200);
timer = millis();
pinMode(us, OUTPUT);
digitalWrite(us, LOW);
delayMicroseconds(5);
digitalWrite(us, HIGH);
delayMicroseconds(10);
digitalWrite(us, LOW);
pinMode(us, INPUT);
durata = pulseIn(us, HIGH);
}
PT_END(pt);
}
static int leggithread(struct pt *pt) {
static unsigned long timer = 0;
PT_BEGIN(pt);
while(1) {
PT_WAIT_UNTIL(pt, millis() - timer > 200);
timer = millis();
distanza = durata/58;
Serial.print(distanza);
Serial.print("cm ");
if(digitalRead(iri) == LOW)
Serial.println("ir si");
else
Serial.println("ir no");
}
PT_END(pt);
}
void setup() {
pinMode(iro, OUTPUT);
tone(iro, 36000);
pinMode(iri, INPUT);
pinMode(us_vcc, OUTPUT);
digitalWrite(us_vcc, HIGH);
pinMode(ir_vcc, OUTPUT);
digitalWrite(ir_vcc, HIGH);
Serial.begin(9600);
PT_INIT(&pt1);
PT_INIT(&pt2);
}
void loop() {
usthread(&pt1);
leggithread(&pt2);
}
现在的问题是超声波传感器。如果我在没有protothreads的单个程序中控制它,它可以到达3米距离的物体。现在,即使我在1米处放置一些东西,“distanza”最大为15厘米。错误是什么?
答案 0 :(得分:6)
在irthread()
中,宏PT_WAIT_UNTIL
的第二个参数始终求值为true:
PT_WAIT_UNTIL(pt, 1>0);
因此程序将停留在irthread()的无限循环中,因为在这种情况下,宏PT_WAIT_UNTIL的部分结果类似于if(!(1>0)) return 0;
;语句return 0
永远不会被调用。
适用于usthread()
和leggithread()
,因为第二个参数是 false,前200毫秒 ,并且设置了变量,因此它在 为一次 之后的另一个200毫秒内将再次为假。
一些背景信息位于 How protothreads really work 。
答案 1 :(得分:0)
leggithread()
和usthread()
中的计时器相互干扰。他们使用相同的变量timer
。当时间到了,自上次以来大约200毫秒后,在leggithread()
中,变量被重置。这意味着另一个函数中的条件usthread()
(后面称之为),即使条件即将成立,也将为假。因此,在usthread()
可以工作之前至少再过200毫秒(在端口12上输出10微秒脉冲)。
无法保证将调用这两个函数。如果你运气不好,如果它是一个确定性的系统(从同一个时钟,微控制器的晶体驱动),则只能调用其中一个。
可能是随机调用哪一个或者在几个频率之间可能存在一些混叠(例如,一个频率由每个循环的执行指令数表示 - 当程序改变时该频率将改变)。
如果您希望leggithread()
和usthread()
每秒工作五次,那么每个人都应该使用单独的变量,例如timer1
和{{1} }。
答案 2 :(得分:0)
为什么要将while(1)
放在你的功能中?因为1总是如此 -
while(1) {
// The code in it will repeat forever
}
// And the Arduino will never get here
要么输入逻辑而不是1(例如while(x > 10)
,while(task_finished)
),要么不要将代码放在while
语句中。
static int usthread(struct pt *pt) {
static unsigned long timer = 0;
PT_BEGIN(pt);
while(1) { // <<<<<<<<< Fault 1
PT_WAIT_UNTIL(pt, millis() - timer > 200);
PT_BEGIN(pt);
while(1) { //<<<<<<<<< Fault 2
PT_WAIT_UNTIL(pt, millis() - timer > 200);
timer = millis();