5

在电子产品和 Arduino 方面,我是新手——所以最好的方法就是玩弄它,对吧?

我已经开始了一个利用 LDR(光密度电阻器)的小项目,并想用它来计算光束被阻挡或关闭的频率。

出于调试目的,我设置了一个以定义频率(5 Hz 等)闪烁的小 LED,并使用 LCD 显示输出。

展示

我的右上角有问题......它似乎执行错误。它的目的是显示注册的频率,但在调试时我已将其设置为以 5 秒(5,000 毫秒)的间隔显示计数。但无论我设置什么频率,它似乎都是最大值(当我让它显示正确的数字 [5 sec x 5 Hz = 25] 我将除以时间间隔并以 Hz 为单位得到结果)。它还显示 24.0 for 9 Hz 等。

我也有这个:YouTube 视频

...但一开始的一些摸索导致 LED 移动了一点,所以它计数错误。但最终它“有效”..但 24.0 保持不变

这是我的代码:

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 8, 9, 10, 11 , 12);
int booBlocked = 0;
int counter = 0;
int checkValue = counter + 1;

int ledPin = 3;                // LED connected to digital pin 3
int value = LOW;                // previous value of the LED
long previousMillis = 0;        // will store last time LED was updated
long freqency = 5; // Hz (1/sec)
long thousand = 1000;
long interval = thousand / freqency; // milliseconds
//long interval = 59;           // interval at which to blink (milliseconds)

int tValue = 0; // Threshold value used for counting (are calibrated in the beginning)
long pMillis = 0;
long inter = 5000;
int pCount = 0;
float freq = 0;  // Calculated blink frequency...

void setup() { 
  lcd.begin(16, 2);
  lcd.setCursor(0,1);  lcd.print(interval);
  lcd.setCursor(4,1);  lcd.print("ms");

  pinMode(ledPin, OUTPUT);      // sets the digital pin as output 

  lcd.setCursor(0,0);  lcd.print(freqency);
  lcd.setCursor(4,0);  lcd.print("Hz");
}

void loop() {
  // Print LDR sensor value to the display  
  int sensorValue = analogRead(A0);
  lcd.setCursor(7,1);
  lcd.print(sensorValue);
  delay(100);

  if (millis() > 5000){
    doCount(sensorValue);
    updateFreq();
    lcd.setCursor(7+5,0);
    lcd.print(freq);
  } else {
    setThresholdValue(sensorValue);
    lcd.setCursor(7+5,1);
    lcd.print(tValue);
  }

 // LED BLINK
  if (millis() - previousMillis > interval) {
    previousMillis = millis();   // remember the last time we blinked the LED
    // if the LED is off turn it on and vice-versa.
    if (value == LOW)
      value = HIGH;
    else
      value = LOW;
    digitalWrite(ledPin, value);
  }    
}

void updateFreq(){
 long now = millis();
 long t = now - pMillis;
 if (t >= 10000) {
   freq = (float) (counter - pCount);
   //freq = ((float) (counter - pCount)) / (float) 10.0;
   pMillis = now;   // remember the last time we blinked the LED
   pCount = counter;
  } 
}

void setThresholdValue(int sensorValue){
  if (sensorValue > int(tValue/0.90)){
    tValue = int (sensorValue*0.90);
  }
}

void doCount(int sensorValue){
    // Count stuff
  if (sensorValue < tValue){
    booBlocked = 1;
    //lcd.setCursor(0,0);
    //lcd.print("Blocked");
  } else {
    booBlocked = 0;
    //lcd.setCursor(0,0);
    //lcd.print("       ");    
  }

  if (booBlocked == 1) {
   if (counter != checkValue){
    counter = counter + 1;
    lcd.setCursor(7,0);
    lcd.print(counter);
   }   
  } else {
   if (counter == checkValue){
    checkValue = checkValue + 1;
     }
   }
}

更新

更“干净”的代码(请参阅我自己的答案)

#include <LiquidCrystal.h>
// Initiate the LCD display
LiquidCrystal lcd(7, 8, 9, 10, 11 , 12); // see setup at http://lassenorfeldt.weebly.com/1/post/2013/02/ardunio-lcd.html
long updateInterval = 150;                // ms
long updateTime = 0;

// Declare the pins
int ledPin = 3;                       // LED connected to digital pin 3

// LED setup
int value = LOW;                      // previous value of the LED
long previousMillis = 0;              // will store last time LED was updated 
long freqency = 16;                   // Hz (1/sec)
long thousand = 1000;
long blinkInterval = thousand / freqency;  // milliseconds

//// LDR counter variables ////
// Counting vars
static int counter = 0;
int booBlocked = 0;
int checkValue = counter + 1;
// Calibration vars
long onBootCalibrationTime = 5000;     // time [time] to use for calibration when the system is booted
static int threshold = 0;              // Value used for counting (calibrated in the beginning)
float cutValue = 0.90;                 // Procent value used to allow jitting in the max signal without counting.

// Frequency vars
float freq = 0;                        // Calculated blink frequency...
long frequencyInterval = 5000;        // time [ms] 
long pMillis = 0;
int pCount = 0;



void setup() {
  // Setup the pins
  pinMode(ledPin, OUTPUT);      // sets the digital pin as output 

  // display static values
  lcd.begin(16, 2);
  lcd.setCursor(0,0);  lcd.print(freqency);
  lcd.setCursor(4,0);  lcd.print("Hz");
  lcd.setCursor(0,1);  lcd.print(blinkInterval);
  lcd.setCursor(4,1);  lcd.print("ms");

  // Setup that allows loggin
  Serial.begin(9600);  // Allows to get a readout from Putty (windows 7)
}

void loop() {  
  long time = millis();
  int sensorValue = analogRead(A0);

  // Blink the LED
  blinkLED(time);

  // Calibrate or Count (AND calculate the frequency) via the LDR
  if (time < onBootCalibrationTime){
    setThresholdValue(sensorValue);
  } else {    
    doCount(sensorValue);
    updateFreq(time);
  }


  // Update the LCD
  if (time > updateTime){
    updateTime += updateInterval;  // set the next time to update the LCD

   // Display the sensor value
    lcd.setCursor(7,1);  lcd.print(sensorValue);
   // Display the threshold value used to determined if blocked or not
    lcd.setCursor(7+5,1);  lcd.print(threshold);
   // Display the count
    lcd.setCursor(7,0);
    lcd.print(counter);
   // Display the calculated frequency
    lcd.setCursor(7+5,0);  lcd.print(freq);   
  }  
}

void blinkLED(long t){
  if (t - previousMillis > blinkInterval) {
    previousMillis = t;   // remember the last time we blinked the LED
    // if the LED is off turn it on and vice-versa.
    if (value == LOW)
      value = HIGH;
    else
      value = LOW;
    digitalWrite(ledPin, value);
  }
}

void setThresholdValue(int sValue){
  if (sValue > int(threshold/cutValue)){
    threshold = int (sValue*cutValue);
  }
}

void doCount(int sValue){
  if (sValue < threshold){
    booBlocked = 1;
  } else {
    booBlocked = 0;  
  }

  if (booBlocked == 1) {
   if (counter != checkValue){
    counter = counter + 1;
   }   
  } else {
   if (counter == checkValue){
    checkValue = checkValue + 1;
     }
   }
}

void updateFreq(long t){
 long inter = t - pMillis;
 if (inter >= frequencyInterval) {
   freq = (counter - pCount) / (float) (inter/1000);
   pMillis = t;           // remember the last time we blinked the LED
   pCount = counter;
  } 
}

这段代码不能解决我的问题,但更容易阅读。

4

4 回答 4

0

您的计划的问题是光密度电阻器会吸收周围的所有环境光,因此对环境完全敏感。

还有其他项目希望吗?这似乎是一种工程学习体验,而不是编码体验。

你有没有想过汽车项目?就我个人而言,我更喜欢家庭自动化,但电机项目几乎是立竿见影的。

于 2013-02-13T01:48:01.247 回答
0

我建议doCount()按照这些思路重新编写您的函数,以使事情更简单,更容易掌握:

void doCount(int sensorValue){

  static int previousState;
  int currentState;

  if ( previousState == 0 ) {
      currentState = sensorValue > upperThreshold;
  } else {
      currentState = sensorValue > lowerThreshold;
  }

  if ( previousState != 0 ) {
      if ( currentState == 0 ) {
          counter++;
      }
  }

  previousState = currentState;

}

例如,让lowerThresholdupperThreshold分别为前一个 的 90% 和 110%,tValue并且您有一个滞后来平滑对嘈杂 ADC 读数的反应。

于 2013-02-13T14:24:13.370 回答
0

我想我发现了其中一个错误..我使用的delay()是引起了一些麻烦的..

我清理了代码:

#include <LiquidCrystal.h>
// Initiate the LCD display
LiquidCrystal lcd(7, 8, 9, 10, 11 , 12); // see setup at http://lassenorfeldt.weebly.com/1/post/2013/02/ardunio-lcd.html
long updateInterval = 150;                // ms
long updateTime = 0;

// Declare the pins
int ledPin = 3;                       // LED connected to digital pin 3

// LED setup
int value = LOW;                      // previous value of the LED
long previousMillis = 0;              // will store last time LED was updated 
long freqency = 16;                   // Hz (1/sec)
long thousand = 1000;
long blinkInterval = thousand / freqency;  // milliseconds

//// LDR counter variables ////
// Counting vars
static int counter = 0;
int booBlocked = 0;
int checkValue = counter + 1;
// Calibration vars
long onBootCalibrationTime = 5000;     // time [time] to use for calibration when the system is booted
static int threshold = 0;              // Value used for counting (calibrated in the beginning)
float cutValue = 0.90;                 // Procent value used to allow jitting in the max signal without counting.

// Frequency vars
float freq = 0;                        // Calculated blink frequency...
long frequencyInterval = 5000;        // time [ms] 
long pMillis = 0;
int pCount = 0;



void setup() {
  // Setup the pins
  pinMode(ledPin, OUTPUT);      // sets the digital pin as output 

  // display static values
  lcd.begin(16, 2);
  lcd.setCursor(0,0);  lcd.print(freqency);
  lcd.setCursor(4,0);  lcd.print("Hz");
  lcd.setCursor(0,1);  lcd.print(blinkInterval);
  lcd.setCursor(4,1);  lcd.print("ms");

  // Setup that allows loggin
  Serial.begin(9600);  // Allows to get a readout from Putty (windows 7)
}

void loop() {  
  long time = millis();
  int sensorValue = analogRead(A0);

  // Blink the LED
  blinkLED(time);

  // Calibrate or Count (AND calculate the frequency) via the LDR
  if (time < onBootCalibrationTime){
    setThresholdValue(sensorValue);
  } else {    
    doCount(sensorValue);
    updateFreq(time);
  }


  // Update the LCD
  if (time > updateTime){
    updateTime += updateInterval;  // set the next time to update the LCD

   // Display the sensor value
    lcd.setCursor(7,1);  lcd.print(sensorValue);
   // Display the threshold value used to determined if blocked or not
    lcd.setCursor(7+5,1);  lcd.print(threshold);
   // Display the count
    lcd.setCursor(7,0);
    lcd.print(counter);
   // Display the calculated frequency
    lcd.setCursor(7+5,0);  lcd.print(freq);   
  }  
}

void blinkLED(long t){
  if (t - previousMillis > blinkInterval) {
    previousMillis = t;   // remember the last time we blinked the LED
    // if the LED is off turn it on and vice-versa.
    if (value == LOW)
      value = HIGH;
    else
      value = LOW;
    digitalWrite(ledPin, value);
  }
}

void setThresholdValue(int sValue){
  if (sValue > int(threshold/cutValue)){
    threshold = int (sValue*cutValue);
  }
}

void doCount(int sValue){
  if (sValue < threshold){
    booBlocked = 1;
  } else {
    booBlocked = 0;  
  }

  if (booBlocked == 1) {
   if (counter != checkValue){
    counter = counter + 1;
   }   
  } else {
   if (counter == checkValue){
    checkValue = checkValue + 1;
     }
   }
}

void updateFreq(long t){
 long inter = t - pMillis;
 if (inter >= frequencyInterval) {
   freq = (counter - pCount) / (float) (inter/1000);
   pMillis = t;           // remember the last time we blinked the LED
   pCount = counter;
  } 
}

它没有我希望的那么精确。但我相信这可能是由于我闪烁 LED 的方式。

我还发现float cutValue = 0.90;有影响...将条降低到 0.85 会降低计算频率.. ??

于 2013-02-16T15:58:39.617 回答
0

在 Albert 非常好心地帮助我使用他很棒的 FreqPeriodCounter 库之后,我完全更改了代码

我还加了一个电位器来控制频率

这是我的代码:

#include <FreqPeriodCounter.h>
#include <LiquidCrystal.h>

// FrequencyCounter vars
const byte counterPin = 3;  // Pin connected to the LDR
const byte counterInterrupt = 1; // = pin 3
FreqPeriodCounter counter(counterPin, micros, 0);

// LCD vars
LiquidCrystal lcd(7, 8, 9, 10, 11 , 12); // see setup at http://lassenorfeldt.weebly.com/1/post/2013/02/ardunio-lcd.html
long updateInterval = 200;                // ms
long updateTime = 0;

// LED vars
int ledPin = 5;                       // LED connected to digital pin 3
int value = LOW;                      // previous value of the LED
float previousMillis = 0;              // will store last time LED was updated 
static float freqency;                   // Hz (1/sec)
static float pfreqency;
static float blinkInterval;  // milliseconds

boolean logging = true;              // Logging by sending to serial

// Use potentiometer to control LED frequency
int potPin = 5;    // select the input pin for the potentiometer
int val = 0;       // variable to store the value coming from the sensor

void setup(void){ 
  // Setup the pins
  pinMode(ledPin, OUTPUT);      // sets the digital pin as output 

  val = analogRead(potPin);
  freqency = map(val, 0, 1023, 0, 25);                   // Hz (1/sec)
  pfreqency = freqency;
  blinkInterval = 1000 / (freqency*2);                  // milliseconds


  // LCD display static values
  lcd.begin(16, 2);
  lcd.setCursor(0,0);  lcd.print(freqency);
  lcd.setCursor(4,0);  lcd.print("Hz");
  lcd.setCursor(14,0);  lcd.print("Hz");
  lcd.setCursor(0,1);  lcd.print(blinkInterval);
  lcd.setCursor(4,1);  lcd.print("ms");

  //   
  attachInterrupt(counterInterrupt, counterISR, CHANGE);

  // Logging
  if (logging) {Serial.begin(9600);}
}

void loop(void){ 
  // Loop vars
  float time = (float) millis();
  float freq = (float) counter.hertz(10)/10.0;

  // Blink the LED
  blinkLED(time);


  if (logging) {
    if(counter.ready()) Serial.println(counter.hertz(100));
  }

  // Update the LCD
  if (time > updateTime){
    updateTime += updateInterval;  // set the next time to update the LCD
    lcdNicePrint(7+3, 0, freq); lcd.setCursor(14,0);  lcd.print("Hz"); 
    val = analogRead(potPin);
    freqency = map(val, 0, 1023, 1, 30);

    if (freqency != pfreqency){
      pfreqency = freqency;      
      blinkInterval = 1000 / (freqency*2);                  // milliseconds

      lcdNicePrint(0,0, freqency);  lcd.setCursor(4,0);  lcd.print("Hz");
      lcd.setCursor(0,1);  lcd.print(blinkInterval);
      lcd.setCursor(4,1);  lcd.print("ms");
    }
  }
}

void lcdNicePrint(int column, int row, float value){
  lcd.setCursor(column, row);  lcd.print("00");
  if (value < 10) {lcd.setCursor(column+1, row);  lcd.print(value);}
  else {lcd.setCursor(column, row);  lcd.print(value);}
}  

void blinkLED(long t){

  if (t - previousMillis > blinkInterval) {
    previousMillis = t;   // remember the last time we blinked the LED
    // if the LED is off turn it on and vice-versa.
    if (value == LOW)
      value = HIGH;
    else
      value = LOW;
    digitalWrite(ledPin, value);
  }
}

void counterISR()
{ counter.poll();
}
于 2013-02-24T10:32:27.680 回答