9

我正在做一个关于控制两个传感器(超声波和红外线)的项目,用 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 米处,“距离”也是最大 15 厘米。错误是什么?

4

3 回答 3

9

irthread()宏的第二个参数中PT_WAIT_UNTIL总是计算为真:

PT_WAIT_UNTIL(pt, 1>0);

因此程序将陷入 irthread() 的无限循环,因为在这种情况下宏 PT_WAIT_UNTIL 的部分结果类似于if(!(1>0)) return 0;:该语句return 0永远不会被调用。


它适用于usthread()并且leggithread()因为第二个参数在前 200 毫秒内为假,并且变量已设置,因此在单次为真后,它会在另外 200 毫秒内再次为假。

一些背景信息在protothreads 如何真正工作

于 2011-06-03T19:28:31.830 回答
1

定时器leggithread()相互usthread()干扰。他们使用相同的变量,timer。当时间到时,自上次以来大约 200 毫秒后,例如leggithread(),变量被重置。usthread()这意味着即使那里的条件即将为真,另一个函数中的条件(即在之后调用)将是假的。因此,至少要再过 200 毫秒usthread()才能工作(在端口 12 上输出 10 微秒的脉冲)。

不能保证这两个函数都会被调用。如果你不走运,如果它是一个确定性系统(由同一个时钟驱动,微控制器的晶体),则只能调用其中一个。

调用哪一个可能是随机的,或者在几个频率之间可能存在一些混叠(例如,一个频率由每个循环的执行指令数表示 - 该频率会随着程序的变化而变化)。

如果你想要两者leggithread()usthread()每秒工作五次,那么它们应该有一个独立的计时器,使用单独的变量,例如,timer1timer2

于 2011-06-05T14:32:01.757 回答
-1

你为什么要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();
于 2016-02-06T11:23:21.090 回答