I'm working with a TSL235R light to frequency sensor and I'm using the sketch from the Arduino playground, http://playground.arduino.cc/Main/TSL235R. I placed the contents of the void loop() into a separate void function outside of the void loop() and then just called the function() into the void loop() so far.
It runs fine but I want to get just single reading from the sensor and while the sketch continuously loops, that is not what I want. Is there a way to have the sensor continuously loop in the background and then call a function to sample one reading and then store that reading into a global variable?
I'm not sure if what I'm proposing is the best method as it seems to try to link a function to another function and to my understanding, local variables cannot be passed from one function to the next.
I'm not a programmer . My specialty is hardware so the only way I know how to do it is use a 7408 2-input AND Gate and AND the sensor output with a digital HIGH from a digital output.
Input B of gate #1 is sensor output
Algorithm
1- Enable Sensor Reading by sending HIGH to Enable (input A of Gate #1)
2-Read output of gate #1
Output will be sensor output.
After reading and storing value in a variable, disable sensor output by making Enable LOW (input A of gate #1 , (output of a digital output))
done
As long as Enable is LOW on input -! of AND gate, the sensor output cannot pass to the output of the gate.
When Enable is HIGH, AND gate output = sensor output.
This is my latest attempt and it does not work the way I want it to.
volatile unsigned long cnt = 0;
unsigned long oldcnt = 0;
unsigned long t = 0;
unsigned long last;
unsigned long X; //Global variable to store value
boolean readDone = false;
void irq1()
{
cnt++;
}
//////////////////////SETUP/////////////////////////////////
void setup()
{
Serial.begin(115200);
Serial.println("START");
pinMode(2, INPUT);
digitalWrite(2, HIGH);
attachInterrupt(0, irq1, RISING);
}
/////////////////////////MAIN LOOP/////////////////////////////
void loop()
{
GetReading();
}
void FreqReading() {
if (millis() - last >= 1000)
{
last = millis();
t = cnt;
unsigned long hz = t - oldcnt;
Serial.print("FREQ: ");
Serial.print(hz);
Serial.print("\t = ");
Serial.print((hz+50)/100); // +50 == rounding last digit
Serial.println(" mW/m2");
oldcnt = t;
}
}
void GetReading() {
float sens = FreqReading();
for (int i=0; i<2; i++) { //loop once to get just one reading
sens;
X=hz; //Store the value hz from FreqReading() function
}
}
This is my latest attempt and it does not work the way I want it to.
That's a real shame. Too bad you didn't say what the code actually does or what you want it to do. If you had, maybe we could have offered more than sympathy.
void GetReading() {
float sens = FreqReading();
for (int i=0; i<2; i++) { //loop once to get just one reading
sens;
X=hz; //Store the value hz from FreqReading() function
}
}
First off, that function FreqReading is declared to return void. So you can't expect sens to get anything but void from it.
But moreover, I'm wondering what you thing this bit does?
for (int i=0; i<2; i++) { //loop once to get just one reading
sens;
X=hz; //Store the value hz from FreqReading() function
}
The line:
sens;
is legal code, but it doesn't do anything. There's no command there, just the name of a variable.
And the next line references hz, which lives in the FreqReading function. It doesn't exist in this function. That should be throwing you a "not defined in this scope" error.
Here is my latest attempt. My sketch verifies properly but still does not operate properly. The sketch utilizes a keypad lcd shield and is suppose to display the frequency readings from the sensor. When I push the button for ReadingOne or ReadingTwo, it's suppose to take the reading from the sensor, store it in EEPROM and then print that value to the lcd. Once I store two sensor readings, I hit the Calculate button and it should give me a calculated value based on the two EEPROM stored values which will be printed on the lcd. The final DisplaySensorReading button is suppose to just print out the sensor readings repeatedly onto the LCD.
When I click either of the ReadingOne or ReadingTwo buttons, I get really unstable numbers (some being very high and some being very low, never within a certain range) being displayed on the LCD screen which does not correspond to the values when compared to the original sketch written by Robtillaart. I'm wondering if this has to do with the external interrupt attachinterrupt being used.
#include <EEPROM.h>
#include <LiquidCrystal.h> // include the library code:
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
//Global Constants
int LED = 11; //Set LED to pin D11 (PWM) Pins 3,9,10,11 Disabled by library
int LEDlevel = 200; //Set LED brightness
boolean running = true;
volatile unsigned long cnt = 0;
unsigned long oldcnt = 0;
unsigned long t = 0;
unsigned long last;
///////////////////////////// SETUP //////////////////////////////////////
void setup()
{
pinMode(LED, OUTPUT);
pinMode(2, INPUT);
Serial.begin(9600);
Serial.println("START");
digitalWrite(2, HIGH);
attachInterrupt(0, irq1, RISING);
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.setCursor(0,0);
lcd.print("Begin");
lcd.setCursor(0,1);
lcd.print("Press Key:");
}
///////////////////////////// MAIN LOOP //////////////////////////////////////
void loop()
{
keypad();
LEDFunction();
}
//////////////////////// FUNCTIONS ///////////////////////////////
void keypad() {
int x;
x = analogRead (0);
lcd.setCursor(0,1);
if (x < 60) { //Right button
ReadingOne();
}
else if (x < 200) { //Up button
ReadingTwo();
}
else if (x < 400){ //Down button
Calculate();
}
else if (x < 600){ //Left button
Left();
}
else if (x < 800){ //Select button
DisplaySensorReading();
}
}
void LEDFunction() { //Keep LED ON all the time
analogWrite(LED, LEDlevel);
}
void irq1() {
cnt++;
}
void ReadingOne() { //Up Button
if (millis() - last >= 1000)
{
lcd.print ("Sample: ");
last = millis();
t = cnt;
unsigned long hz = t - oldcnt;
//Writing long and store into EEPROM
long address=0;
EEPROMWritelong(address, hz);
address+=4;
// Print to LCD
lcd.setCursor(8,1);
lcd.print(EEPROMReadlong(0));
lcd.print(" ");
oldcnt = t;
}
}
void ReadingTwo() {
if (millis() - last >= 1000)
{
lcd.print("Zero: ");
last = millis();
t = cnt;
unsigned long hz = t - oldcnt;
//Writing long and store into EEPROM
long address=4;
address+=4;
lcd.setCursor(6,1);
lcd.print(EEPROMReadlong(4)); //Will print to lcd reading
lcd.print(" ");
oldcnt = t;
}
}
void Calculate() {
lcd.print ("A= ");
float I = (EEPROMReadlong(0))/(EEPROMReadlong(4));
float ABS = (-1)*(log10(I));
float intABS = ((int)(ABS*100))/100.0;
lcd.setCursor(3,1);
delay(100);
lcd.print(intABS);
lcd.print(" ");
}
void Left() {
lcd.print ("Left ");
}
void DisplaySensorReading() { //Continously print sensor readings to LCD
if (millis() - last >= 1000)
{
last = millis();
t = cnt;
unsigned long hz = t - oldcnt;
Serial.print("FREQ: ");
Serial.print(hz);
Serial.print("\t = ");
Serial.print((hz+50)/100); // +50 == rounding last digit
Serial.println(" mW/m2");
oldcnt = t;
lcd.setCursor(6,1);
lcd.print ("Freq: ");
lcd.print(Serial.print(hz));
}
}
//This function will write a 4 byte (32bit) long to the eeprom at
//the specified address to adress + 3.
void EEPROMWritelong(int address, long value)
{
//Decomposition from a long to 4 bytes by using bitshift.
//One = Most significant -> Four = Least significant byte
byte four = (value & 0xFF);
byte three = ((value >> 8) & 0xFF);
byte two = ((value >> 16) & 0xFF);
byte one = ((value >> 24) & 0xFF);
//Write the 4 bytes into the eeprom memory.
EEPROM.write(address, four);
EEPROM.write(address + 1, three);
EEPROM.write(address + 2, two);
EEPROM.write(address + 3, one);
}
//This function will return a 4 byte (32bit) long from the eeprom
//at the specified address to adress + 3.
long EEPROMReadlong(long address)
{
//Read the 4 bytes from the eeprom memory.
long four = EEPROM.read(address);
long three = EEPROM.read(address + 1);
long two = EEPROM.read(address + 2);
long one = EEPROM.read(address + 3);
//Return the recomposed long by using bitshift.
return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
}
If this was my problem I would strip all the LCD and eeprom code out of the sketch and just focus on getting the buttons to work while displaying debugging data on the Serial Monitor.
Thank you Robin2 for your advice, I've taken that into account and went back to the beginning. Upon observation, I've noticed that the sensor gives me larger and larger values depending on the amount of time it is exposed to light, sort of like how a camera works, the more exposure, the more detailed the picture is. Also, to my understanding, the external interrupt attached is running needs to be set in a continuous loop and that somehow makes the whole sensor iterate in a constant pulsing mode so that with each iteration, the "delay" of sort is exactly the same as the one before so the amount of "exposure" time is always the same and the values read will be constant more or less. Correct me if I'm wrong.
I've placed the function to get the reading from the sensor in the setup and that gives me a very large number even though the whole code is the same. I suspect that the interrupt needs one iteration before the sketch can give a proper reading which the setup doesn't allow since its not looping.
///////////////////////// GLOBAL VARIABLES //////////////////
volatile unsigned long cnt = 0;
unsigned long oldcnt = 0;
unsigned long t = 0;
unsigned long last;
int LEDpin = 11; //Pin 11 for LED light source
int brightness = 255; //PWM brightness from 0-255
unsigned long sens;
///////////////////////////// FUNCTIONS ////////////////////////
void LED() {
analogWrite(LEDpin, brightness);
}
void irq1()
{
cnt++;
}
unsigned long GetFrequency() {
if (millis() - last >= 1000)
{
last = millis();
t = cnt;
unsigned long hz = t - oldcnt;
Serial.print("FREQ: ");
Serial.print(hz);
Serial.print("\t = ");
Serial.print((hz+50)/100); // +50 == rounding last digit
Serial.println(" mW/m2");
oldcnt = t;
}
}
///////////////////////////// SETUP ////////////////////////
void setup()
{
Serial.begin(115200);
Serial.println("START");
pinMode(LEDpin, OUTPUT);
pinMode(2, INPUT);
digitalWrite(2, HIGH);
attachInterrupt(0, irq1, RISING);
GetFrequency();
}
////////////////////////// MAIN LOOP /////////////////////////////
void loop()
{
LED();
}
Yeah, you're calling the getFrequency function immediately after you attach the interrupt. Just for testing, you could throw a delay in there between those two calls to give the thing a little time to run and catch a few interrupts before you ask it to get the frequency.
madsci:
I've placed the function to get the reading from the sensor in the setup and that gives me a very large number
The reason for this is that you don't initialize last before you use it in the test
if (millis() - last >= 1000)
You may need to initialize oldcnt at the same time.
sensor gives me larger and larger values depending on the amount of time it is exposed to light, sort of like how a camera works,
It is not working like a camera. It just continuously outputs a square wave and varies the frequency according to the brightness of the light. When you take a count for a second you are getting a "sort-of" average of the frequency during that second. Because it is continually outputting a square wave your counter keeps counting just in the same way that millis() does.
I don't even get a reading when placing a delay (small or large value) between the interrupt and the function within setup.
Delta_G:
Yeah, you're calling the getFrequency function immediately after you attach the interrupt. Just for testing, you could throw a delay in there between those two calls to give the thing a little time to run and catch a few interrupts before you ask it to get the frequency.
How would I initialize last and oldcnt into the if statement? Would I use &&?
if (millis()-last >= 1000&&...)
Robin2:
madsci:
I've placed the function to get the reading from the sensor in the setup and that gives me a very large number
The reason for this is that you don't initialize last before you use it in the test
if (millis() - last >= 1000)
You may need to initialize oldcnt at the same time.
sensor gives me larger and larger values depending on the amount of time it is exposed to light, sort of like how a camera works,
It is not working like a camera. It just continuously outputs a square wave and varies the frequency according to the brightness of the light. When you take a count for a second you are getting a "sort-of" average of the frequency during that second. Because it is continually outputting a square wave your counter keeps counting just in the same way that millis() does.
It also seems that just by placing my GetFrequency function into setup to try and get it to run just once and return just one value isn't working. I get a blank serial monitor showing nothing. I suspect that the interrupt and function that it is attached to cannot be placed together. Correct me if I'm wrong.
madsci:
How would I initialize last and oldcnt into the if statement? Would I use &&?
THINK a little about what your code is doing.
You need to initialize the values BEFORE the IF statement.
It can be very useful to take a pencil and paper and work through the code step by step working out the value of each variable at each line of the code.