I'm using a SG-90 servo and sweeping left and right between two values.
My problem is that there is a distinct delay of about 500ms between direction changes. I would like the position of the servo to be predictable, but due to this at direction changes it is not.
bool servoDir = true;
int servoCnt = 90;
int servoInc = 1;
int servoMin = servoCnt - 5;
int servoMax = servoCnt + 5;
void loop() {
if (servoDir) {
dx = servoInc;
if (servoCnt > servoMax) {
servoDir = false;
}
} else {
dx = -servoInc;
if (servoCnt < servoMin) {
servoDir = true;
}
}
servoCnt += dx;
servo.write(servoCnt);
// delay or other code here (mine is 40ms)
}
I've tried both the Arduino Servo library and the VarspeedServo library. They both show the same thing.
What is the cause of this and what can I do about it?
Update
So if I up the speed at direction change, like so:
int extra = 5;
void loop() {
if (servoDir) {
dx = servoInc;
if (servoCnt > servoMax) {
dx -= extra;
servoDir = false;
}
} else {
dx = -servoInc;
if (servoCnt < servoMin) {
dx += extra;
servoDir = true;
}
}
servoCnt += dx;
servo.write(servoCnt);
// delay or other code here (mine is 40ms)
}
the delay disappears, but the servo position does become a lot less predictable.
You would experience exactly these symptoms if servoMin and servoMax were out of the servo range.... Which they are.
More seriously, these servos are not very precise. Incrementing by 1 at a time is probably the issue. You are experiencing some form of backlash.
You should check and clamp the count against the range AFTER incrementing/decrementing. That's one of the basic rules of embedded programming. Lives may be at stake, or equipment destroyed when sending out out of range values.
bool servoDir = true;
int servoCnt = 90;
int servoInc = 1; // <-- exclusively use this to control speed.
int servoMin = servoCnt - 5; // <-- this range is a bit short for testing
int servoMax = servoCnt + 5;
void loop() {
// 'jog' the servo.
servoCnt += (servoDir) ? servoInc : -servoInc;
// past this point, all position jogging is final
if (servoCnt > servoMax)
{
servoCnt = servoMax;
servoDir = false;
}
else if (servoCnt < servoMin)
{
servoCnt = servoMin;
servoDir = true;
}
servo.write(servoCnt);
// 40ms sounds a bit short for tests.
// 100 ms should give you a 2 seconds (0.5Hz) oscillation
delay(100);
}
Related
I'm working on a circuit that has two separate 4-bit binary counters with LEDs. I press a button and one counter begins counting to 15 in binary. I press a second button and the first counter pauses where it is and the second group of LEDs begin counting to 15 in binary. I got both counters working, but I can't get the first group to pause and the second to begin. I've tried using if statements with a boolean flag, but it messes up the first group of LEDs. How can I get ledPins1[] to pause when button2 is pressed, then resume when ledPins2[] finish?
int ledPin1[] = {2,3,4,5};
int ledPin2[] = {7,8,9,10};
int button1 = 11;
int button2 = 12;
boolean button1Last = LOW;
boolean button1Current = LOW;
boolean button2Last = LOW;
boolean button2Current = LOW;
void setup()
{
pinMode(button1, INPUT);
pinMode(button2, INPUT);
for(int i=0; i<4; i++)
{
pinMode(ledPin1[i], OUTPUT);
}
for(int i=0; i<4; i++)
{
pinMode(ledPin2[i], OUTPUT);
}
}
boolean waitForButtonPush1 (boolean lastStartSwitchState1)
{
boolean currentStartSwitchState1 = digitalRead(button1);
if(lastStartSwitchState1 != currentStartSwitchState1) delay(20);
currentStartSwitchState1 = digitalRead(button1);
return currentStartSwitchState1;
}
boolean waitForButtonPush2 (boolean lastStartSwitchState2)
{
boolean currentStartSwitchState2 = digitalRead(button2);
if(lastStartSwitchState2 != currentStartSwitchState2) delay(20);
currentStartSwitchState2 = digitalRead(button2);
return currentStartSwitchState2;
}
void loop()
{
button1Current = waitForButtonPush1(button1Last);
if(button1Last == LOW && button1Current == HIGH)
{
for (byte counter =0;counter<=15; counter++)
{
displayBinary(counter);
delay(500);
}
}
button2Current = waitForButtonPush2(button2Last);
if(button2Last == LOW && button2Current == HIGH)
{
for (byte counter =0;counter<=15; counter++)
{
displayBinary2(counter);
delay(500);
}
}
}
void displayBinary(byte numToShow)
{
for (int i =0;i<4;i++)
{
if (bitRead(numToShow, i)==1)
{
digitalWrite(ledPin1[i], HIGH);
}
else
{
digitalWrite(ledPin1[i], LOW);
}
}
}
void displayBinary2(byte numToShow)
{
for (int i =0;i<4;i++)
{
if (bitRead(numToShow, i)==1)
{
digitalWrite(ledPin2[i], HIGH);
}
else
{
digitalWrite(ledPin2[i], LOW);
}
}
}
Welcome to the world of embedded devices!
Getting a small microprocessor to do several things at the same time is a bit tricky.
The key is to never block. No calls to delay(), no sending large buffers on the serial port at 9600 bauds in one go, etc...
There are some simple techniques to do it, one of the most commonly used is finite state machines.
Let's analyse your app a bit.
2 similar dssplay counters, with delay
2 buttons, buttons usually need to be debounced, that also involves a delay.
Some code, for you to tinker with:
// ****************************
// pinout
static const byte ledPin1[] = { 2, 3, 4, 5 };
static const byte ledPin2[] = { 7, 8, 9, 10 };
constexpr byte button1 = 11; // using constexpr for these saves 2 bytes of RAM.
constexpr byte button2 = 12;
// ****************************
// Counter data
static constexpr unsigned int led_delay = 500; // 500 ms, for all counters.
// constexpr ?? arduino supports c++17. Not all features in the main .ino
// module and all features in .cpp modules.
// Hint: you could have a member variable in the structure below for delay,
// this would allow for counters running at different speeds, or add buttons
// to increase/decrease speed.
// we have only 2 states, but you could add more, like running
// backwards, or run a different chase pattern maybe?
enum class led_counter_state : byte
{
stopped,
running,
};
struct led_counter_data_t
{
led_counter_state state; // STATE
byte counter; // counter current value
unsigned int timestamp; // used for timing.
const byte* leds; // LED pins.
};
static led_counter_data_t led_counter[2];
void led_display_init()
{
for (byte i = 0; i < 2; ++i)
{
led_counter[i].state = led_counter_state::stopped;
led_counter[i].counter = 0;
led_counter[i].timestamp = 0;
}
led_counter[0].leds = ledPin1;
led_counter[1].leds = ledPin2;
}
// ****************************
// LED cotrrol
static void leds_display_value(const led_counter_data_t& cntr)
{
for (byte i = 0, val = cntr.counter; i < 4; ++i, val >>= 1)
digitalWrite(cntr.leds[i], val & 0x01);
}
static void leds_control(led_counter_data_t& cntr)
{
const auto now = (unsigned int)millis(); // keep track of time.
switch(cntr.state)
{
default: // something is wrong.. stop.
cntr.state = led_counter_state::stopped;
// fall through ...
case led_counter_state::stopped:
return; // if not running, do nothing
case led_counter_state::running:
if (now - cntr.timestamp >= led_delay) // check delay
{
if (++cntr.counter > 15) // advance counter.
cntr.counter = 0;
leds_display_value(cntr); // show value.
cntr.timestamp = now; // keep track of time.
}
break;
}
}
static void leds_start(led_counter_data_t& cntr)
{
if (cntr.state != led_counter_state::stopped)
return;
cntr.state = led_counter_state::running;
if (++cntr.counter > 15) // advance counter.
cntr.counter = 0;
led_display_value(cntr); // show value.
cntr.timestamp = (unsigned int)millis();
}
static void leds_stop(led_counter_data_t& cntr)
{
cntr.state = led_counter_state::stopped;
}
// ****************************
// switch inputs data
static constexpr byte switch_debounce_delay = 30; // 30ms is a good value for
// debouncing
struct switch_data_t
{
byte sw1_state : 1; // no need to waste more than 1 bit per switch
byte sw2_state : 1;
byte timestamp; // we'll only count to 30 ms, so 1 byte timestamp will do
};
static switch_data_t switch_data;
// ****************************
// switch inputs code
static void control_inputs()
{
const auto now = (byte)millis();
if (now - switch_data.timestamp < switch_debounce_delay)
return;
switch_data.timestamp = now;
// All switch control logic is regrouped here, and isolated
// form other control code, this makes the logic easier to
// write, read, and debug.
bool b = digitalRead(button1);
if (b & !switch_data.sw1_state) // button was pushed right now.
{
if (led_counter[0].state == led_counter_state::stopped)
{
leds_start(led_counter[0]); // start counter 1
leds_stop(led_counter[1]); // stop counter 2
}
else
{
leds_stop(led_counter[0]); // stop counter 1
}
}
switch_data.sw1_state = b;
b = digitalRead(button2);
if (b & !switch_data.sw2_state) // button was pushed right now.
{
if (led_counter[1].state == led_counter_state::stopped)
{
leds_start(led_counter[1]); // start counter 2
leds_stop(led_counter[0]); // stop counter 1
}
else
{
leds_stop(led_counter[1]); // stop counter 2
}
}
switch_data.sw2_state = b;
}
// ****************************
void setup()
{
pinMode(button1, INPUT);
pinMode(button2, INPUT);
for (byte i = 0; i < 4; ++i)
{
digitalWrite(ledPin1[i], LOW);
pinMode(ledPin1[i], OUTPUT);
digitalWrite(ledPin2[i], LOW);
pinMode(ledPin2[i], OUTPUT);
}
led_display_init();
}
// ****************************
// The goal, always, is to exit loop() as fast as possible, so
// everything will run smoothly, and appear to run simultaneously.
void loop()
{
control_inputs();
leds_control(led_counter[0]);
leds_control(led_counter[1]);
}
I do not have an arduino with me, so I did not comppile nor ran this, but it should be pretty close. Let me know if you're having issues or have any questions.
i need to add millis in my code but i dont know exactly where should be ok to add millis or where is it acctually needed.Because i have used only delay till now can you help me and tell me where can millis be implemented in this piece of code.If it is possible to add millis somewhere in or after the button modes or switch case because it would be nicer if the modes changed properly because for now their changing either when the button is pressed normal or somtimes you need to pres the button twice to change to the next mode.I would apriciate all the help.
const int BUTTON_SWITCH = 8;
const int BUTTON_ALARM = 9;
const int KNOB = A0;
const int TEMP = A1;
const int tempRES = 10000; // the resistance of the NTC at 25'C is 10k ohm
const int NTC_MATERIAL_CONSTANT = 3950;
const int RED_LED = 4;
const int BUZZER = 3;
int index = 1;
double value;
int state = 0;
unsigned long time_now = 0;
int period = 1000;
char incomingOption;
#include "Display.h"
void setup() {
Serial.begin(9600);
pinMode(BUTTON_SWITCH, INPUT_PULLUP);
pinMode(BUTTON_ALARM, INPUT_PULLUP);
pinMode(RED_LED, OUTPUT);
}
float get_temperature()
{
float temperature, resistance;
int value;
value = analogRead(TEMP);
resistance = (float)value * tempRES / (1024 - value); // Calculate resistance
/* Calculate the temperature according to the following formula. */
temperature = 1 / (log(resistance / tempRES) / NTC_MATERIAL_CONSTANT + 1 / 298.15) - 273.15;
return temperature;
}
void loop() {
if (digitalRead(BUTTON_SWITCH) == LOW) { // button for switching the 3 modes
index = index + 1;
}
if (digitalRead(BUTTON_ALARM) == LOW) { // button for the alarm
displayAlarm();
}
if (Serial.available()) {
// Read entire buffer up to newline character
// Since on the C# side, serialPort1.WriteLine appends a newline character
String respond = Serial.readStringUntil('\n');
if (respond == "RESET") {
digitalWrite(RED_LED, LOW);
digitalWrite(BUZZER, LOW);
}
}
if (index > 3) { // when the code is on the last mode press the button to turn back to the first mode
index = 1;
}
get_temperature();
float celcius;
celcius = get_temperature();
if(celcius<16 || celcius>27){ // if the temperature becomes less than 16 degrees or goes higher than 27 degrees turn on the alarm
displayAlarm();
}
switch (index) {
case 1: displayTime(); break; // switch between the 3 different modes
case 2: displayTemp(); break;
case 3: displayAngle(); break;
}
}
void displayTime() {
float timer = Serial.parseFloat(); // take the current time from the c# application and display it on the arduino board
Display.show(timer);
}
void displayTemp() {
float celcius;
celcius = get_temperature(); // mode for displaying the current temperature
Display.show(celcius);
}
void displayAngle() {
int value = analogRead(KNOB); // read and save analog value from the potentionmeter
value = map(value, 0, 1023, 0, 30); // Map value 0-1023 to 0-30
Display.show(value);
}
void displayAlarm() {
Serial.println("Alarm");
digitalWrite(RED_LED, HIGH);
tone(BUZZER, 1500, 700);
}
How to make a led fade out in 5s using PWM in arduino. I wrote this function, it didn't work. I try to call this function.
const int minPWM = 0;
const int maxPWM = 255;
int fadeValue = 255;
int fadeIncrement = 5;
unsigned long previousFadeMillis;
int fadeInterval = 50;
void setLightPWM(unsigned long thisMillis) {
if (thisMillis - previousFadeMillis >= fadeInterval) {
fadeValue = fadeValue - fadeIncrement;
if (fadeValue <= minPWM) {
// At min, limit and change direction
fadeValue = minPWM;
}
analogWrite(garageLED, fadeValue);
previousFadeMillis = thisMillis;
}
return;
}
Also, I wrote this line in loop()
unsigned long currentMillis = millis();
setLightPWM(currentMillis);
boolean initFade;
long startTime;
void setup(){
startTime=0;
initFade=false;
}
void loop(){
if(initFade){
startTime = millis();
initFade=false;
}
initFade = customizedFade;
}
boolean customizedFade(long fadeTime){
long timePassed = millis()-startTime;
if(timePassed < fadeTime ){
analogWrite(LEDPIN, map(timePassed,0,5000,255,0));
return false;
}
else{
return true;
}
}
I assumed that this code is complete (along with a pinMode(garageLED, OUTPUT) call and the definition of garageLED), and that the idea is to make an LED fade in and out (as you wrote in a comment "at min [...] change direction".
If my assumptions are right, then your code is missing the ability to invert the fade change. When it goes below the minimum it is set to the minimum value, but then nothing happens. At each further call it is set again to the minimum value.
So if the idea was to fade in and out you need to change the "fading direction":
if (fadeValue <= minPWM) {
// At min, limit and change direction
fadeValue = minPWM;
fadeIncrement = - fadeIncrement; //<-- Invert the value of "fadeIncrement"
}
and then the same thing when hitting the maximum value:
if (fadeValue >= maxPWM) {
// At max, limit and change direction
fadeValue = maxPWM;
fadeIncrement = - fadeIncrement; //<-- Invert the value of "fadeIncrement"
}
If the idea is to fade out, then suddenly fully turn on and fade out again, then you only need to set to maximum value when hitting the minimum:
if (fadeValue <= minPWM) {
// At min, limit and change direction
fadeValue = maxPWM;
}
Here is a working sketch whit your code plus some extra lines and my changes. All what I added or modified is marked with a // <-- symbol.
const int garageLED = 5; // <-- added to make the sketch work
const int minPWM = 0;
const int maxPWM = 255;
int fadeValue = 255;
int fadeIncrement = 1; // <-- why not use the smallest increment value?
unsigned long previousFadeMillis;
int fadeInterval = 20; // <-- 20ms interval to get a 5s fade time with (fadeIncrement == 1)
// (fadeInterval = fadeTime/fadeSteps), where fadeTime = 5000 ms
// and fadeSteps = (maxPWM - minPWM)/fadeIncrement.
// So in this case fadeInterval = 5000/((255 - 0)/1) = 5000/255 =~ 19,6
void setLightPWM(unsigned long thisMillis) {
if (thisMillis - previousFadeMillis >= fadeInterval) {
fadeValue = fadeValue - fadeIncrement;
if (fadeValue <= minPWM) {
// At min, limit and change direction
fadeValue = minPWM;
fadeIncrement = - fadeIncrement; //<-- Invert the value of "fadeIncrement"
}
if (fadeValue >= maxPWM) { //<-- Added if block
// At max, limit and change direction
fadeValue = maxPWM;
fadeIncrement = - fadeIncrement; //<-- Invert the value of "fadeIncrement"
}
analogWrite(garageLED, fadeValue);
previousFadeMillis = thisMillis;
}
return;
}
void setup() { // <-- added to make the sketch work
pinMode(garageLED, OUTPUT); // <--
} // <--
void loop() {
unsigned long currentMillis = millis();
setLightPWM(currentMillis);
}
I'm working on a home automation system, one part of which includes an Arduino Mega2560 connected via USB to a RaspberryPi 3 Model B. The Arduino receives two short, simple commands over serial from the Pi; the first command sets 'regions' of led lights, and the second sets colors on the regions previously described. Syntax is as follows for both commands, where bracketed items are single bytes, len+off are 3 ascii bytes interpreted as base-10, and r+g+b are 2 ascii bytes each interpreted as hex. The color set command supports a variable number of regions as shown:
Region Set Command
!c[regionId][stripId][len2][len1][len0][off2][off1][off0]\r
Color Set Command
!b[r1][r0][g1][g0][b1][b0][numRegions][regionId0]([regionId1]...)\r
Each command sends positive/negative acknowledgements so you'd think I'd be able to tell what's going wrong, but I get unexpected behavior when I try to set light colors with the second command, however, despite getting acknowledgements as expected. So far, the only reasonable conclusion I can come to is that for the global array regions discards changes and stays zero always. For example, this exchange results in no lights lit (comments are not in the actual exchange)
Pi sends: !c00144000\r // create regionId 0 on stripId 0; length 144 offset 0
Pi recieves: O // positive confirmation?
Pi sends: !b00009910\r // set regionId 0 to color 0x000099 (blue)
Pi recieves: O // positive confirmation, but no lights?
Pi sends: !x\r // invalid command; triggers default in switch
Pi recieves: X // as expected, all lights turn red
Here's the stripped down source for the Arduino:
#include "Arduino.h"
#include "FastLED.h"
#define WAIT while(!Serial.available()) ;;
// Forward Declarations
const int max_strips = 2;
const int max_strip_length = 300;
const int max_leds = max_strips * max_strip_length;
CRGB leds[max_strips][max_strip_length];
const int max_regions = 20;
int regions[max_regions][3];
const int baud_rate = 9600;
unsigned char buffer[64];
unsigned char currentByte = 0;
unsigned char incommingByte;
unsigned char startChar = '!';
unsigned char endChar = '\r';
bool store = false;
// Helper Functions
void set(CRGB c) {
for(int i = 0; i < max_strips; i++) {
for(int j = 0; j < max_strip_length; j++) {
leds[i][j] = c;
}
}
}
void set(int stripId, int length, int offset, CRGB c) {
for(int i = offset; i < offset+length; i++) {
leds[stripId][i] = c;
}
}
void setup() {
Serial.begin(baud_rate);
for(int i = 0; i < max_strips; i++) {
switch(i) {
case 0: {
FastLED.addLeds<WS2812B, 2, GRB>(leds[0], max_strip_length);
} break;
case 1: {
FastLED.addLeds<WS2812B, 3, GRB>(leds[1], max_strip_length);
} break;
}
}
set(CRGB::Black);
}
void loop() {
if(Serial.available() > 0) {
unsigned char incomingByte = Serial.read();
if(incomingByte == startChar) {
currentByte = 0;
store = true;
}
if(store) {
if(incomingByte == endChar) {
buffer[currentByte++] = incomingByte;
store = false;
switch(buffer[1]) {
case 'b': {
int red = (buffer[2] - '0')*16 + (buffer[3] - '0');
int green = (buffer[4] - '0')*16 + (buffer[5] - '0');
int blue = (buffer[6] - '0')*16 + (buffer[7] - '0');
int numRegions = buffer[8] - '0';
for(int i = 0; i < numRegions; i++) {
int regionId = buffer[9+i] - '0';
if(regionId >= max_regions) {
Serial.write('S');
return;
}
// Never sets anything
set(regions[regionId][0], regions[regionId][1], regions[regionId][2], CRGB(red, green, blue));
}
Serial.write('O');
} break;
case 'c': {
int regionId = buffer[2] - '0';
int stripId = buffer[3] - '0';
int length = (buffer[4] - '0')*100 + (buffer[5] - '0')*10 + (buffer[6] -'0');
int offset = (buffer[7] - '0')*100 + (buffer[8] - '0')*10 + (buffer[9] -'0');
if(regionId >= max_regions) {
Serial.write('R');
return;
}
if(stripId >= max_strips) {
Serial.write('S');
return;
}
regions[regionId][0] = stripId; // WE LOSE THESE VALUES??
regions[regionId][1] = length; // ??
regions[regionId][2] = offset; // ??
Serial.write('O');
} break;
default: {
set(CRGB::Red);
Serial.write('X');
} break;
}
currentByte = 0;
}else if(currentByte > 64){
store = false;
currentByte = 0;
} else {
buffer[currentByte++] = incomingByte;
}
}
}
FastLED.show();
}
I'd appreciate any advice as to what I'm missing here, and regardless, thanks for reading this far!
This was occurring because I have a lot of garbage showing up on the serial interface for the Arduino I'm testing on. Slowing the baud rate down to 2400bps resolves the issue on this device. Other Arduinos in the system do fine with much higher serial rates -- I suspect there's a hardware problem with the crystal on this particular Arduino so clock speeds aren't matching up correctly between the two sides of the serial connection.
I'm a newbie when it comes to electronics and Arduino - so the best way is to just to play around with it, right?
I have started a small project that utilize and LDR (Light Density Resistor) and want to use it to calculate the frequency that a light beam is blocked or turned off.
For debugging purposes I setup a small LED that blinks at a defined frequency (5 Hz etc.) and use a LCD to display the output.
I have a problem with my top right corner... It seems as it performs wrongly. It was the intention that it should show the registered frequency, but while debugging I have set it to show the number of counts in an interval of 5 sec (5,000 msec). But it appears as 24 is the max no matter what frequency I set (When I get it to show the right number [5 sec x 5 Hz = 25] I will divide by the time interval and get the results in Hz). It also shows 24.0 for 9 Hz etc..
I also have this: YouTube video
...but some fumbling in the beginning caused the LED to move a bit so it counted wrong. But in the end it "works".. But the 24.0 keeps being constant
This is my code:
#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;
}
}
}
UPDATE
A more "clean" code (please see my own answer)
#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;
}
}
This code does not fix my question, but is just more easy to read.
The issue with your plan is that a light density resistor is going to pick up all the ambient light around and therefore be completely environment sensitive.
Have any other project hopes? This one seems like an engineering learning experience, not a coding one.
Have you thought of motor projects? Personally I'm more into home automation, but motor projects are almost instantly rewarding.
I'd recommend to re-write your doCount() function along these lines to make things simpler and easier to grasp:
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;
}
Let lowerThreshold and upperThreshold be, for example, 90% and 110%, respectively, of your former tValue, and you have a hysteresis to smoothen the reaction to noisy ADC read-outs.
I think i found one of the bugs.. I was using a delay() which caused some trouble..
I cleaned up the code:
#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;
}
}
Its not as precise as I wished.. but I believe that this is might due to the way I blink the LED.
I also discovered that float cutValue = 0.90; has an influence... lowering the bar to 0.85 decrease the calculated frequency.. ??
I changed the code completely after Albert was so kind to help me out using his awesome FreqPeriodCounter library
I also added a potentiometer to control the frequency
Here is my code:
#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();
}