首页 文章

Arduino / ESP8266使用中断采样

提问于
浏览
0

我正在尝试使用NodeMCU板测量电容器的放电时间 . 见下面的完整草图 . 这段代码工作正常,但我希望通过使用 ESP.getCycleCount() 函数和中断时间来改进它以获得更好的时间尺度 . 感兴趣的部分是这样的:

startTime = micros();
while (digitalRead(capPos) == HIGH) {
  delayMicroseconds (1);
}
endTime = micros();

while 循环我想重写为某种形式的基于中断的函数,监听capPos引脚的下降沿,用以下代码替换上面的函数:

startTime = micros();
attachInterrupt(digitalPinToInterrupt(capPos), dischargeInterrupt, FALLING);
}


void dischargeInterrupt() {

endTime = micros();
detachInterrupt(digitalPinToInterrupt(capPos));

之后,原始代码继续 .

我遇到的问题是如何采取所需的100个样本 . 在获取 startTime 之后设置中断时,此例程将完成并执行100次迭代中的下一次 . 相反,它应该等待:中断到来,然后按照原始草图完成其余的例程 . 作为中断的新手,我不知道从哪个部分开始 .

那么必须做些什么: - loop() 来电 getEC()

  • getEC() 需要100个样本:

  • 给盖子充电,设置放电引脚,设置中断以测量放电时间 .

  • 中断到来,测量时间 . 执行负上限循环并完成一个采样循环 .

这种改变的主要目的是使时序更准确:在引脚下降到低电平时立即做出反应,并在时间上使用更高的分辨率 . 目前的微秒分辨率可以完成这项任务,但这是一个严重的限制 .

在这里,我的完整,有效,草图:

//  capacitor based TDS measurement

// pin D5 C+ - 330 ohm resistor----------|------------|       
//                                       |            |
//                                        cap        EC probe or
//                                       |           resistor (for simulation)
// pin D6 C- ----------------------------|            |
//                                                    |
// pin A0 EC -----------------------------------------|

#include <Average.h>

int capPos = D5;  //C+
int capNeg = D6;  //C-
int EC = D7;      //EC

float CAP = 47; // capacity in nF
#define calibration 150 // a calibration factor to link time with EC.

void setup() {
  Serial.begin(9600);
}

void loop () {
  float EC = getEC(); // get the EC as mS/cm.
  Serial.println (", EC: " + String(EC) + " mS/cm");
  delay(100);
}

float getEC() {

  int samples = 100;              // number of EC samples to take and average.
  unsigned long startTime;        // the time stamp (in microseconds) the measurement starts.
  unsigned long endTime;          // the time stamp (in microseconds) the measurement is finished.
  unsigned int dischargeTime;    // the time it took for the capacitor to discharge.
  Average<unsigned int> discharge(samples); // Take measurements on both the positive and negative cycles.
  unsigned int chargeDelay = 500;         // The time (in microseconds) given to the cap to fully charge/discharge - about 10x RC is a good value.

  int startLevel; // analog level of the pin.
  int endLevel;
  pinMode(A0, INPUT);

  for(int i=0; i<samples; i++) { // take <samples> measurements of the EC.

    // Stage 1: fully charge capacitor for positive cycle.
    // C+ high, C- low, EC disconnected.
    pinMode (EC, INPUT);
    pinMode (capPos,OUTPUT);
    digitalWrite (capPos, HIGH);
    pinMode (capNeg, OUTPUT);
    digitalWrite (capNeg, LOW);
    delayMicroseconds(chargeDelay);

    // Stage 2: positive side discharge; measure time it takes.
    // C+ disconnected, C- low, EC low.
    pinMode (capPos,INPUT); //set C+ to input to keep voltage from grounding a discharging thru this output pin
    pinMode (EC, OUTPUT); 
    digitalWrite (EC, LOW);

    // Measure time until capPos goes LOW. Can't use pulseIn() here as the pin will be high already.
    startTime = micros();
    while (digitalRead(capPos) == HIGH) {
      delayMicroseconds (1);
    }
    endTime = micros();

    // handle potential overflow of micros() just as we measure, this happens every 70 minutes.
    if (endTime < startTime) dischargeTime = 4294967295 - startTime + endTime;
    else dischargeTime = endTime - startTime;
    discharge.push(dischargeTime);

    // Stage 3: fully charge capacitor for negative cycle. C+ low, C- high, EC disconnected.
    pinMode (EC, INPUT); 
    pinMode (capPos,OUTPUT);
    digitalWrite (capPos, LOW);
    pinMode (capNeg, OUTPUT);
    digitalWrite (capNeg, HIGH);
    delayMicroseconds(chargeDelay);

    // Stage 4: negative side charge; don't measure as we just want to balance it the directions.
    // C+ disconnected, C- low, EC low.
    pinMode (capPos,INPUT); //set C+ to input to keep voltage from grounding a discharging thru this output pin
    pinMode (EC, OUTPUT); 
    digitalWrite (EC, HIGH);
    delayMicroseconds(dischargeTime);

  }
  float dischargeAverage = discharge.mean();
  Serial.print("Discharge time: ");
  Serial.print(dischargeAverage);

  // Calculate EC from the discharge time.

  return dischargeAverage;
}

1 回答

  • 0

    所以,让我自己回答 .

    对于时间分辨率:通过使用计算处理器周期的 ESP.getCycleCount() 可以获得更精确的时间 - 在我的80 MHz NodeMCU板上,每个周期为12.5 ns或每微秒80个周期 . 我应该在第一部分中提到过 .

    中断:这是我误解的 . 现在我通过让main函数在循环中等待直到达到超时(设置为1毫秒,正常预期时间在1-100微秒范围内)或者直到中断函数设置了全局变量来解决它 . 所以现在我测量的是12.5纳秒的分辨率!

    这个草图中缺少的一件事是修正处理时序所需的程序时间:从EC引脚上的值下降到开始计数所需的时间,以及从接收中断到停止计数所需的时间 . 如果这个开销是100个周期,那将是1.25微秒,这完全在我的测量时间内 .

    //基于电容的TDS测量

    // pin D5 C+ - 330 ohm resistor----------|------------|       
    //                                       |            |
    //                                        cap        EC probe or
    //                                       |           resistor (for simulation)
    // pin D6 C- ----------------------------|            |
    //                                                    |
    // pin A0 EC -----------------------------------------|
    
    #include <Average.h>
    
    int capPos = D5;  //C+
    int capNeg = D6;  //C-
    int EC = D7;      //EC
    unsigned long startCycle;
    unsigned long endCycle;
    #define CYCLETIME 12.5 // the time it takes in nanoseconds to complete one CPU cycle (12.5 ns on a 80 MHz processor)
    
    float CAP = 47; // capacity in nF
    #define calibration 150 // a calibration factor to link time with EC.
    
    void setup() {
      Serial.begin(9600);
    }
    
    void loop () {
      float EC = getEC(); // get the EC as mS/cm.
      Serial.println (", EC: " + String(EC) + " mS/cm");
      delay(500);
    }
    
    float getEC() {
    
      int samples = 100;              // number of EC samples to take and average.
      unsigned long startTime;        // the time stamp (in microseconds) the measurement starts.
      unsigned long endTime;          // the time stamp (in microseconds) the measurement is finished.
      unsigned int dischargeTime;    // the time it took for the capacitor to discharge.
      Average<unsigned int> discharge(samples); // The sampling results.
      unsigned int chargeDelay = 500;         // The time (in microseconds) given to the cap to fully charge/discharge - about 10x RC is a good value.
      unsigned int timeout = 1;  // discharge timeout in milliseconds - if not triggered within this time, the EC probe is probably not there.
    
      int startLevel; // analog level of the pin.
      int endLevel;
      pinMode(A0, INPUT);
    
      for(int i=0; i<samples; i++) { // take <samples> measurements of the EC.
    
        // Stage 1: fully charge capacitor for positive cycle.
        // C+ high, C- low, EC disconnected.
        pinMode (EC, INPUT);
        pinMode (capPos,OUTPUT);
        digitalWrite (capPos, HIGH);
        pinMode (capNeg, OUTPUT);
        digitalWrite (capNeg, LOW);
        delayMicroseconds(chargeDelay);
    
        // Stage 2: positive side discharge; measure time it takes.
        // C+ disconnected, C- low, EC low.
        startCycle = ESP.getCycleCount();
        pinMode (capPos,INPUT); //set C+ to input to keep voltage from grounding a discharging thru this output pin
        pinMode (EC, OUTPUT); 
        digitalWrite (EC, LOW);
    
        // Use cycle counts and an interrupt to get a much more precise time measurement, especially for high-EC situations.
        endCycle = 0;
        startTime = millis();
        attachInterrupt(digitalPinToInterrupt(capPos), capDischarged, FALLING);
        while (endCycle == 0) {
          if (millis() > (startTime + timeout)) break;
        }
        detachInterrupt(digitalPinToInterrupt(capPos));
        if (endCycle == 0) dischargeTime = 0;
        else {
    
          // Handle potential overflow of micros() just as we measure, this happens about every 54 seconds
          // on a 80-MHz board.
          if (endCycle < startCycle) dischargeTime = (4294967295 - startCycle + endCycle) * CYCLETIME;
          else dischargeTime = (endCycle - startCycle) * CYCLETIME;
          discharge.push(dischargeTime);
        }
    
        // Stage 3: fully charge capacitor for negative cycle. C+ low, C- high, EC disconnected.
        pinMode (EC, INPUT); 
        pinMode (capPos,OUTPUT);
        digitalWrite (capPos, LOW);
        pinMode (capNeg, OUTPUT);
        digitalWrite (capNeg, HIGH);
        delayMicroseconds(chargeDelay);
    
        // Stage 4: negative side charge; don't measure as we just want to balance it the directions.
        // C+ disconnected, C- high, EC high.
        pinMode (capPos,INPUT); //set C+ to input to keep voltage from grounding a discharging thru this output pin
        pinMode (EC, OUTPUT); 
        digitalWrite (EC, HIGH);
        delayMicroseconds(dischargeTime/1000);
    
      }
      float dischargeAverage = discharge.mean();
      Serial.print("Discharge time: ");
      Serial.print(dischargeAverage);
    
      // Calculate EC from the discharge time.
    
      return dischargeAverage;
    }
    
    // Upon interrupt: register the cycle count of when the cap has discharged.
    void capDischarged() {
      endCycle = ESP.getCycleCount();
      detachInterrupt(digitalPinToInterrupt(capPos));
    }
    

相关问题