2017-03-14 7 views
0

NodeMCU 보드를 사용하여 커패시터의 방전 시간을 측정하려고합니다. 아래의 전체 스케치를 참조하십시오. 이 코드는 잘 동작하지만, 타이밍을 위해 ESP.getCycleCount() 함수와 인터럽트를 사용하여 더 나은 시간 스케일을 얻으려면이 코드를 개선하고 싶습니다.Arduino/ESP8266 샘플을 얻기 위해 인터럽트 사용하기

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 개 샘플을 취 방전 핀을 설정

    • 충전 캡을 설정 인터럽트는 방전을 측정 시각.

    • 인터럽트가 오면 시간이 경과합니다. 네거티브 캡주기가 수행되고 한 번의 샘플링이 완료됩니다. LOW에 핀 낙하에 즉시 반응 시간이 훨씬 더 높은 해상도를 사용 :

이 변화의 주요 목적은 타이밍이 더 정확한 확인하는 것입니다. 현재 마이크로 초 해상도가 작업을 수행하지만 심각한 한계가 있습니다.

다음

내 완료, 작업, 스케치 :

// 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; 
} 
+0

이의 당신에게 마이크로보다 더 정확한 타이밍 정보를 제공하는 방법이 표시되지 않습니다 ... – dandavis

답변

0

그래서,이 자신을 대답 얻었다.

시간 분해능의 경우 : 프로세서 사이클을 계산하는 ESP.getCycleCount()을 사용하면 훨씬 더 정확한 시간을 얻을 수 있습니다. 80MHz NodeMCU 보드는 사이클 당 12.5ns 또는 마이크로 초당 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)); 
}