Problem acquiring data on esp32 for geiger counter - arduino

I bought the same boards used in this video on Youtube (the componts are THIS geiger counter (that I am pretty sure its working, the tiks on the speacker are coerent) and THIS esp (I don't know if is here the problem or in the code), I loaded the arduino code into the esp32 board, but the display remains stuck on "Measuring". It connects correctly to the ThingSpeak channel, but always linearly increasing measurements. The number grows continuously (view the attached image). I tried to insert some currentMillis and previousMillis println. Both variables are always 0 in the serial monitor.
So I tried adding currentMillis = millis (); at the beginning of the loop (), at this point the display has finally shown "radioactivity" with the usual increasing numbers. Even if the card is disconnected from the geiger counter, the data are the same and always increasing. How can I solve it?
#define PRINT_DEBUG_MESSAGES
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <IFTTTMaker.h>
#include <ThingSpeak.h>
#include <SSD1306.h>
//#include <credentials.h> // or define mySSID and myPASSWORD and THINGSPEAK_API_KEY
#define LOG_PERIOD 20000 //Logging period in milliseconds
#define MINUTE_PERIOD 60000
#define WIFI_TIMEOUT_DEF 30
#define PERIODE_THINKSPEAK 20000
#ifndef CREDENTIALS
// WLAN
#define mySSID ""
#define myPASSWORD ""
//IFTT
#define IFTTT_KEY "......."
// Thingspeak
#define SECRET_CH_ID 000000 // replace 0000000 with your channel number
#define SECRET_WRITE_APIKEY "XYZ" // replace XYZ with your channel write API Key
#endif
// IFTTT
#define EVENT_NAME "Radioactivity" // Name of your event name, set when you are creating the applet
IPAddress ip;
WiFiClient client;
WiFiClientSecure secure_client;
IFTTTMaker ifttt(IFTTT_KEY, secure_client);
SSD1306 display(0x3c, 5, 4);
volatile unsigned long counts = 0; // Tube events
unsigned long cpm = 0; // CPM
unsigned long previousMillis; // Time measurement
const int inputPin = 7;
unsigned int thirds = 0;
unsigned long minutes = 1;
unsigned long start = 0;
unsigned long entryThingspeak;
unsigned long currentMillis = millis();
unsigned long myChannelNumber = SECRET_CH_ID;
const char * myWriteAPIKey = SECRET_WRITE_APIKEY;
#define LOG_PERIOD 20000 //Logging period in milliseconds
#define MINUTE_PERIOD 60000
void ISR_impulse() { // Captures count of events from Geiger counter board
counts++;
}
void displayInit() {
display.init();
display.flipScreenVertically();
display.setFont(ArialMT_Plain_24);
}
void displayInt(int dispInt, int x, int y) {
display.setColor(WHITE);
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.drawString(x, y, String(dispInt));
display.setFont(ArialMT_Plain_24);
display.display();
}
void displayString(String dispString, int x, int y) {
display.setColor(WHITE);
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.drawString(x, y, dispString);
display.setFont(ArialMT_Plain_24);
display.display();
}
/****reset***/
void software_Reset() // Restarts program from beginning but does not reset the peripherals and registers
{
Serial.print("resetting");
esp_restart();
}
void IFTTT(String event, int postValue) {
if (ifttt.triggerEvent(EVENT_NAME, String(postValue))) {
Serial.println("Successfully sent to IFTTT");
} else
{
Serial.println("IFTTT failed!");
}
}
void postThingspeak( int value) {
// Write to ThingSpeak. There are up to 8 fields in a channel, allowing you to store up to 8 different
// pieces of information in a channel. Here, we write to field 1.
int x = ThingSpeak.writeField(myChannelNumber, 1, value, myWriteAPIKey);
if (x == 200) {
Serial.println("Channel update successful.");
}
else {
Serial.println("Problem updating channel. HTTP error code " + String(x));
}
}
void setup() {
Serial.begin(115200);
displayInit();
ThingSpeak.begin(client); // Initialize ThingSpeak
displayString("Welcome", 64, 15);
Serial.println("Connecting to Wi-Fi");
WiFi.begin(mySSID, myPASSWORD);
int wifi_loops = 0;
int wifi_timeout = WIFI_TIMEOUT_DEF;
while (WiFi.status() != WL_CONNECTED) {
wifi_loops++;
Serial.print(".");
delay(500);
if (wifi_loops > wifi_timeout)
{
software_Reset();
}
}
Serial.println();
Serial.println("Wi-Fi Connected");
display.clear();
displayString("Measuring", 64, 15);
pinMode(inputPin, INPUT); // Set pin for capturing Tube events
interrupts(); // Enable interrupts
attachInterrupt(digitalPinToInterrupt(inputPin), ISR_impulse, FALLING); // Define interrupt on falling edge
unsigned long clock1 = millis();
start = clock1;
}
void loop() {
if (WiFi.status() != WL_CONNECTED)
{
software_Reset();
}
if (currentMillis - previousMillis > LOG_PERIOD) {
previousMillis = currentMillis;
cpm = counts * MINUTE_PERIOD / LOG_PERIOD;
//cpm=105;
counts = 0;
display.clear();
displayString("Radioactivity", 64, 0);
displayInt(cpm, 64, 30);
if (cpm > 100 ) IFTTT( EVENT_NAME, cpm);
}
// Serial.print("minutes: ");
// Serial.println(String(minutes));
//cpm = counts * MINUTE_PERIOD / LOG_PERIOD; this is just counts times 3 so:
cpm = counts / minutes;
if (millis() - entryThingspeak > PERIODE_THINKSPEAK) {
Serial.print("Total clicks since start: ");
Serial.println(String(counts));
Serial.print("Rolling CPM: ");
Serial.println(String(cpm));
postThingspeak(cpm);
entryThingspeak = millis();
}
// if ( thirds > 2) {
// counts = 0;
// thirds = 0;
// }
}
This is based on this work on GITHUB

Your code never updates the value of currentMillis. You set it equal to millis at global scope, likely before init is called and before millis even has a value and then you just leave it with that value. You're not telling that variable to call millis every time, you're just giving it the value of millis at that one instant. You need a line in loop to update that variable.
Because of that, this section never runs:
if (currentMillis - previousMillis > LOG_PERIOD) {
previousMillis = currentMillis;
cpm = counts * MINUTE_PERIOD / LOG_PERIOD;
//cpm=105;
counts = 0;
display.clear();
displayString("Radioactivity", 64, 0);
displayInt(cpm, 64, 30);
if (cpm > 100 ) IFTTT( EVENT_NAME, cpm);
}
and counts never gets set back to 0. That's why you see an ever increasing number.
You're also using this minutes variable as if it will count something, but you never add to it. So it just stays at 1 forever as far as I can tell.

Related

C++ how to query value outside the callback arduino

I want that the measurement interval and MQTT server settings can be changed from cellphone by BLE. I use LightBlue as a mobile application.
Here is my BLE code that works well with my mobile application
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string value = pCharacteristic->getValue();
if (value.length() > 0) {
Serial.println("*********");
Serial.print("New value: ");
for (int i = 0; i < value.length(); i++)
Serial.print(value[i]);
Serial.println();
Serial.println("*********");
}
}
};
void setup() {
Serial.begin(115200);
Serial.println("1- Download and install an BLE scanner app in your phone");
Serial.println("2- Scan for BLE devices in the app");
Serial.println("3- Connect to MyESP32");
Serial.println("4- Go to CUSTOM CHARACTERISTIC in CUSTOM SERVICE and write something");
Serial.println("5- See the magic =)");
BLEDevice::init("MyESP32");
BLEServer *pServer = BLEDevice::createServer();
BLEService *pService = pServer->createService(SERVICE_UUID);
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE
);
pCharacteristic->setCallbacks(new MyCallbacks());
pCharacteristic->setValue("Hello World");
pService->start();
BLEAdvertising *pAdvertising = pServer->getAdvertising();
pAdvertising->start();
}
void loop() {
// put your main code here, to run repeatedly:
delay(2000);
}
This is MQTT code :
void loop() {
unsigned long currentMillis = millis();
// Every X number of seconds (interval = 10 seconds)
// it publishes a new MQTT message
if (currentMillis - previousMillis >= interval) {
// Save the last time a new reading was published
previousMillis = currentMillis;
// New DHT sensor readings
hum = dht.readHumidity();
// Read temperature as Celsius (the default)
temp = dht.readTemperature();
// Read temperature as Fahrenheit (isFahrenheit = true)
//temp = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again).
if (isnan(temp) || isnan(hum)) {
Serial.println(F("Failed to read from DHT sensor!"));
return;
}
// Publish an MQTT message on topic esp32/dht/temperature
uint16_t packetIdPub1 = mqttClient.publish(MQTT_PUB_TEMP, 1, true, String(temp).c_str());
Serial.printf("Publishing on topic %s at QoS 1, packetId: %i", MQTT_PUB_TEMP, packetIdPub1);
Serial.printf("Message: %.2f \n", temp);
// Publish an MQTT message on topic esp32/dht/humidity
uint16_t packetIdPub2 = mqttClient.publish(MQTT_PUB_HUM, 1, true, String(hum).c_str());
Serial.printf("Publishing on topic %s at QoS 1, packetId %i: ", MQTT_PUB_HUM, packetIdPub2);
Serial.printf("Message: %.2f \n", hum);
}
}
Please how I can set the interval to whichever variable from the BLE code instead of 10000.
long interval = 10000;
You need to declare your variable interval as global variable to access it from everywhere in your file. A global variable can be declared outside of functions.
The value you receive is of type std::string and you want to use it as long. You can use toInt() to convert the variable from String to Long.
Try something like this:
long interval = 10000; // Set default value
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string value = pCharacteristic->getValue();
if (value.length() > 0) {
Serial.println("*********");
Serial.print("New value: ");
for (int i = 0; i < value.length(); i++)
Serial.print(value[i]);
Serial.println();
Serial.println("*********");
interval = value.toInt(); // <-- Set received value
}
}
};

GPS receiver + Ublox NEO-6M - Having trouble making a timeout

I'm trying to write some code that will turn on the gps module and wait for data to arrive, so that I can then do things with it. I don't need a continuous stream; I only need the first lat/long received from the gps unit, then I can turn it off. I also need this to just stop if it can't find it's location within a certain amount of time (20 seconds for example)
Here is some simple code that I've tried just to get the gps to read (full code with timeout comes later)
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
TinyGPSPlus gps; // The TinyGPS++ object
SoftwareSerial ss(D4, D3); // The serial connection to the GPS
float latitude , longitude;
int count = 0;
void setup()
{
Serial.begin(9600);
ss.begin(9600);
Serial.println();
Serial.print("Starting");
}
void loop()
{
while (ss.available() > 0)
if (gps.encode(ss.read()))
{
if (gps.location.isValid())
{
latitude = gps.location.lat();
lat_str = String(latitude , 6);
longitude = gps.location.lng();
lng_str = String(longitude , 6);
}
}
Serial.println(lat_str + ":" + lng_str);
delay(100);
count += 1;
String Count = String(count);
Serial.println(Count);
}
When the delay above is 100, then everything works fine, when the delay is 1000, then suddenly no data comes through.
Here is the full code I've tried that includes my timeout and breakout condition, again not working. The cutoff line is in the GPS_mode function here: while ((stoploop < 1) && (previous - startTime < TimeOut)).
#include <SoftwareSerial.h>
#include <TinyGPS++.h>
TinyGPSPlus gps; // The TinyGPS++ object
SoftwareSerial ss(D4, D3); // The serial connection to the GPS d
int stoploop = 0; //used for stopping gps once a signal lock or timeout is reached
unsigned long startTime = millis(); // timer used for gps timeout
const int gpsCutoffPin = D1;
void setup() {
//initialise the serial monitor
Serial.begin(9600);
gps_ss.begin(9600);
//initialise the transistor pins
pinMode(gpsCutoffPin, OUTPUT);
// Start the gps in an off state
digitalWrite(gpsCutoffPin, LOW);
}
void loop() {
Serial.println("Enter GPS mode");
GPS_mode();
Serial.println("Back to the main loop now...");
Serial.println(stoploop);
delay(100000);
}
void GPS_mode(){
//turn on the gps
digitalWrite(gpsCutoffPin, HIGH);
stoploop = 0;
startTime = millis();
previous = millis();
int TimeOut = 60*1000;
gps_ss.listen();
Serial.println(stoploop);
while ((stoploop < 1) && (previous - startTime < TimeOut))
{
while (gps_ss.available() > 0)
{
if (gps.encode(gps_ss.read()))
{
logInfo();
}
yield();
}
}
gpsLat = (gps.location.lat(), DEC);
gpsLon = (gps.location.lng(), DEC);
// turn off the gps
digitalWrite(gpsCutoffPin, LOW);
}
void logInfo(){
// Causes us to wait until we have satelite fix
if(!gps.location.isValid())
{
Serial.println("Not a valid location. Waiting for satelite data.");
//return;
}
else {
//url += String(gps.location.lat(), DEC);
//url += String(gps.location.lng(), DEC);
Serial.println(gps.location.lat(), DEC);
Serial.println(gps.location.lng(), DEC);
stoploop = 2;
//delay(1000);
}
previous = millis();
}
I expect to see some gps data printed to the screen, but I actually don't see anything. I know that the gps is working and is receiving data because the blinking LED tell me so.
I have no idea how to fix this. If anyone could help I'd very much appreciate it.
Thanks

Why does the SD card stop logging without error?

The following sketch is for an Arduino Nano clone. It waits for a START command then collects data from an I2C slave, assembles it for logging on an SD card, writes it to the card, prints it to the serial monitor and repeats. I've tested and retested. The SD card logfile ALWAYS stops after logging the header and 3 out of 30 lines of data, but the serial monitor shows all the expected data. Never in any of my tests was an SD write error generated.
I'd appreciate any ideas as to why the SD stops logging and how to fix it.
Arduino Sketch
#include <Wire.h>
#include <Servo.h>
#include <SD.h>
#include <SPI.h>
// Uncomment the #define below to enable internal polling of data.
#define POLLING_ENABLED
//define slave i2c address
#define I2C_SLAVE_ADDRESS 9
/* ===================================
Arduino Nano Connections
ESC (PWM) Signal - Pin 9 (1000ms min, 2000ms max)
S.Port Signal - Pin 10
SPI Connections
MOSI = Pin 11
MISO = Pin 12
SCLK = PIN 13
I2C Connections
SDA = Pin A4
SCL = Pin A5
Start/Stop Switches
Start = Pin 2 => INT0
Stop = Pin 3 => INT1
===================================*/
Servo esc; // Servo object for the ESC - PIN 9
const unsigned long pause = 800; // Number of ms between readings
const unsigned long testDelay = 30000; // Number of ms between tests
const int CS_pin = 10; // Pin to use for CS (SS) on your board
const int Startpin = 2;
const int Stoppin = 3;
const int readings = 3; // Number of readings to take at every step
const int steps = 5; // Number of steps to stop the ESC and take readings
const byte HALT = 0;
int ESC = 0;
int throttle = 0;
int increment;
volatile bool STOP = 0;
volatile bool START = 0;
const String header = "% Thr,Thrust,Curr,Volts,RPM,Cell1,Cell2,Cell3,Cell4,Cell5,Cell6";
char buffer0[33]; // Buffer for I2C received data
char buffer1[33]; // Buffer for I2C received data
String logEntry = " GOT NO DATA "; //52 bytes
void setup() {
Wire.begin();
Serial.begin(115200);
pinMode(Startpin, INPUT_PULLUP);
pinMode(Stoppin, INPUT_PULLUP);
// Attach an interrupt to the ISR vector
attachInterrupt(digitalPinToInterrupt(Startpin), start_ISR, LOW);
attachInterrupt(digitalPinToInterrupt(Stoppin), stop_ISR, LOW);
esc.attach(9, 1000, 2000);
// attaches the ESC on pin 9 to the servo object and sets min and max pulse width
esc.write(HALT); // Shut down Motor NOW!
increment = 180 / (steps - 1);
// Number of degrees to move servo (ESC) per step (servo travel is 0-180 degrees so 180 = 100% throttle)
delay(500);
Serial.println(" Thrust Meter I2C Master");
//Print program name
//Initialize SD Card
if (!SD.begin(CS_pin)) {
Serial.println("Card Failure");
}
Serial.println("Card Ready");
//Write Log File Header to SD Card
writeSD(header);
Serial.println(header);
}
void loop() {
if (START) {
Serial.println("Start Pressed");
while (!STOP) {
for (throttle = 0; throttle <= 180; throttle += increment) {
for (int x = 0; x < readings; x++) {
if (STOP) {
esc.write(HALT); // Shut down Motor NOW!
Serial.println("Halting Motor");
} else {
wait (pause);
esc.write(throttle); // increment the ESC
wait (200);
ESC = throttle * 100 / 180;
getData(buffer0);
wait (100);
getData(buffer1);
String logEntry = String(ESC) + "," + String(buffer1) + "," + String(buffer0);
writeSD(logEntry);
Serial.println(logEntry);
}
}
}
for (throttle = 180; throttle >= 0; throttle -= increment) {
for (int x = 0; x < readings; x++) {
if (STOP) {
esc.write(HALT); // Shut down Motor NOW!
Serial.println("Halting Motor");
} else {
wait (pause);
esc.write(throttle); // increment the ESC
wait (200);
ESC = throttle * 100 / 180;
getData(buffer0);
wait (100);
getData(buffer1);
String logEntry = String(ESC) + "," + String(buffer1) + "," + String(buffer0);
writeSD(logEntry);
Serial.println(logEntry);
}
}
}
Serial.println("End of Test Pass");
wait (testDelay);
}
esc.write(HALT); // Shut down Motor NOW!
}
}
void writeSD(String logdata) {
File logFile = SD.open("NANO_LOG.csv", FILE_WRITE);
if (logFile) {
logFile.println(logdata);
logFile.close();
} else {
Serial.println("Error writing log data");
}
}
void wait(unsigned long i) {
unsigned long time = millis() + i;
while(millis()<time) { }
}
void start_ISR() {
START = 1;
STOP = 0;
}
void stop_ISR() {
STOP = 1;
START = 0;
}
void getData(char* buff) {
Wire.requestFrom(9, 32);
for (byte i = 0; i < 32 && Wire.available(); ++i) {
buff[i] = Wire.read();
if (buff[i] == '#') {
buff[i] = '\0';
break;
}
}
}
This is the SD card contents:
% Thr,Thrust,Curr,Volts,RPM,Cell1,Cell2,Cell3,Cell4,Cell5,Cell6
0,-12,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
0,-12,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
0,128,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
This is the output from the serial monitor:
Thrust Meter I2C Master
Card Ready
% Thr,Thrust,Curr,Volts,RPM,Cell1,Cell2,Cell3,Cell4,Cell5,Cell6
Start Pressed
0,-12,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
0,-12,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
0,128,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
25,2062,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
25,2520,0.00,15.75,0,3.10,4.20,3.96,3.96,0.00,0.00
25,2710,0.00,15.75,0,3.10,4.20,3.96,3.96,0.00,0.00
50,519,0.00,15.75,0,3.10,4.20,3.96,3.96,0.00,0.00
50,216,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
50,2288,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
75,890,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
75,891,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
75,1386,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
100,2621,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
100,2424,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
100,692,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
100,3409,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
100,227,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
100,3349,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
75,2220,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
75,2249,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
75,509,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
50,1977,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
50,2986,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
50,546,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
25,3746,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
25,3337,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
25,3015,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
0,96,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
0,-12,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
0,-14,0.00,15.76,0,3.10,4.20,3.96,3.96,0.00,0.00
End of Test Pass
The solution to the problem was to replace the SD card with a faster one. Once I did that the data logged as it should. Thanks Patrick for the suggestion.

Alarm.alarmRepeat repeats only twice then stops working

I'm using an arduino uno with a CC3000 WiFi Shield. The ardunio counts people using a light barrier and then reports the countings to the xievly site. It seems to work fine for an hour or two but then nothing happens. Any ideas?
// Libraries
#include <Adafruit_CC3000.h>
#include <SPI.h>
#include <Time.h>
#include <TimeAlarms.h>
// Define CC3000 chip pins
#define ADAFRUIT_CC3000_IRQ 3
#define ADAFRUIT_CC3000_VBAT 5
#define ADAFRUIT_CC3000_CS 10
// Create CC3000 instances
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,
SPI_CLOCK_DIV2); // you can change this clock speed
// WLAN parameters
#define WLAN_SSID "XX"
#define WLAN_PASS "XX"
#define WLAN_SECURITY WLAN_SEC_WPA2
// Xively parameters
#define WEBSITE "https://xively.com/feeds/XX"
#define API_key "XXX"
#define feedID "XXXX``"
uint32_t ip;
Adafruit_CC3000_Client client;
const unsigned long
connectTimeout = 15L * 1000L, // Max time to wait for server connection
responseTimeout = 15L * 1000L; // Max time to wait for data from server
// Visitor Counter
int anzahl =0;
int lastState=LOW;
const int inputPin = 2;
void setup()
{
// Initialize
attachInterrupt(0, count, RISING);
Serial.begin(115200);
if (!cc3000.begin())
{
while(1);
}
// Connect to WiFi network
cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY);
/* Wait for DHCP to complete */
while (!cc3000.checkDHCP())
{
delay(100);
}
unsigned long t = getTime();
cc3000.disconnect();
setTime(hour(t)+2,minute(t),second(t),month(t),day(t),year(t));
Alarm.alarmRepeat(9,59,59, Messung);
Alarm.alarmRepeat(10,59,59, Messung);
Alarm.alarmRepeat(11,59,59, Messung);
Alarm.alarmRepeat(12,59,59, Messung);
Alarm.alarmRepeat(13,59,59, Messung);
Alarm.alarmRepeat(14,59,59, Messung);
Alarm.alarmRepeat(15,59,59, Messung);
Alarm.alarmRepeat(16,59,59, Messung);
Alarm.alarmRepeat(17,59,59, Messung);
Alarm.alarmRepeat(18,59,59, Messung);
Alarm.alarmRepeat(19,59,59, Messung);
Alarm.alarmRepeat(22,59,59, Zeitkorrektur);
}
void count()
{
delay(10);
int val = digitalRead(inputPin);
if (val == HIGH && lastState==LOW)
{
anzahl++;
lastState=val;
}
else
{
lastState=val;
}
}
void Zeitkorrektur()
{
getTime();
}
void Messung()
{
datalog();
}
void loop()
{
Alarm.delay(1000);
}
// Minimalist time server query; adapted from Adafruit Gutenbird sketch,
// which in turn has roots in Arduino UdpNTPClient tutorial.
unsigned long getTime()
{
uint8_t buf[48];
unsigned long ip, startTime, t = 0L;
// Hostname to IP lookup; use NTP pool (rotates through servers)
if(cc3000.getHostByName("pool.ntp.org", &ip)) {
static const char PROGMEM
timeReqA[] = { 227, 0, 6, 236 },
timeReqB[] = { 49, 78, 49, 52 };
Serial.println(F("\r\nAttempting connection..."));
startTime = millis();
do {
client = cc3000.connectUDP(ip, 123);
} while((!client.connected()) &&
((millis() - startTime) < connectTimeout));
if(client.connected()) {
Serial.print(F("connected!\r\nIssuing request..."));
// Assemble and issue request packet
memset(buf, 0, sizeof(buf));
memcpy_P( buf , timeReqA, sizeof(timeReqA));
memcpy_P(&buf[12], timeReqB, sizeof(timeReqB));
client.write(buf, sizeof(buf));
Serial.print(F("\r\nAwaiting response..."));
memset(buf, 0, sizeof(buf));
startTime = millis();
while((!client.available()) &&
((millis() - startTime) < responseTimeout));
if(client.available()) {
client.read(buf, sizeof(buf));
t = (((unsigned long)buf[40] << 24) |
((unsigned long)buf[41] << 16) |
((unsigned long)buf[42] << 8) |
(unsigned long)buf[43]) - 2208988800UL;
Serial.print(F("OK\r\n"));
}
client.close();
}
}
if(!t) Serial.println(F("error"));
return t;
}
void datalog()
{
//noInterrupts();
// Connect to WiFi network
cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY);
/* Wait for DHCP to complete */
while (!cc3000.checkDHCP())
{
delay(100);
}
// Set the website IP
uint32_t ip = cc3000.IP2U32(216,52,233,120);
cc3000.printIPdotsRev(ip);
// Get data & transform to integers
int visitors = (int) anzahl/2; //Visitors going in and out therefore divided by 2
// Prepare JSON for Xively & get length
int length = 0;
String data = "";
data = data + "\n" + "{\"version\":\"1.0.0\",\"datastreams\" : [ {\"id\" : \"Visitors\",\"current_value\" : \"" + String(visitors) + "\"}]}";
length = data.length();
// Send request
Adafruit_CC3000_Client client = cc3000.connectTCP(ip, 80);
if (client.connected()) {
Serial.println("Connected!");
client.println("PUT /v2/feeds/" + String(feedID) + ".json HTTP/1.0");
client.println("Host: api.xively.com");
client.println("X-ApiKey: " + String(API_key));
client.println("Content-Length: " + String(length));
client.print("Connection: close");
client.println();
client.print(data);
client.println();
} else {
Serial.println(F("Connection failed"));
return;
}
Serial.println(F("-------------------------------------"));
while (client.connected()) {
while (client.available()) {
char c = client.read();
Serial.print(c);
}
}
client.close();
Serial.println(F("-------------------------------------"));
Serial.println(F("\n\nDisconnecting"));
cc3000.disconnect();
anzahl =0;
//interrupts();
}
In setup() you configured interrupt with RISING. That means that it fires when the pin goes from low state to high state. But in interrupt handler - count() you have strange logic which looks excessive since you already configured interrupt to fire only once on event.
Let's see what happens in count(). val will always be HIGH (well, considering only normal case, not glitches).. When the first interrupt comes lastState is LOW as initial value and we increment, but all successive calls will not because lastState is HIGH and never becomes LOW again.
So, to fix problem, we simply need to drop lastState because it's not needed
void count()
{
delay(10);
// avoiding glitches - check if it's still high
int val = digitalRead(inputPin);
if (val == HIGH)
anzahl++;
}

Arduino calculating the frequency - what am I doing wrong here?

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();
}

Resources