Building a Days Counter with Arduino Leonardo and an RTC 3231 - arduino-uno

I've been trying to create a days counter that starts counting from a unix timestamp. I'm using an arduino Leonardo, an RTC DS 3231 and a 7-segment serial display(by microbot). Here's the display link: Serial Display Link
But I cannot get the display to print ny output. I think I might have messed up with the connections.
I have connected the Vcc and Gnd from the rtc to the 3.3v and gnd of the arduino and the Sda and Scl to the Sda and Scl of the arduino.
For the display I connected the Vcc to the 5V, the gnd to the gnd and the Rx to the digital output 5( Is this correct? I know I have messed up sth here)
Here is the code:
#include <Time.h>
#include <TimeLib.h>
#include <SPI.h>
#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"
#include "RTClib.h"
RTC_DS1307 rtc = RTC_DS1307();
Adafruit_7segment clockDisplay = Adafruit_7segment();
int hours = 0;
int minutes = 0;
int seconds = 0;
unsigned long previousMillis = 0; // will store last millis event time
unsigned long sensorpreviousMillis = 0; // will store last millis event time
unsigned long fiveMinuteInterval = 300000; // interval at which to use event time (milliseconds)
unsigned long postDaysInterval = 7200000 ; //seconds in a day 86400000
#define DISPLAY_ADDRESS 0x70
unsigned long theDateWeGotTogether = 1441843200; //in unixtime
unsigned long days ;
int weeks ;
void setup() {
Serial.begin(115200);
clockDisplay.begin(DISPLAY_ADDRESS);
rtc.begin();
bool setClockTime = !rtc.isrunning();
if (setClockTime) {
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
}
void loop() {
// DateTime now = rtc.now();
days = ((now() - theDateWeGotTogether) / 86400); //86400 is the number of seconds in a day
unsigned long currentMillis = millis();
ShowDaysReading();
time_t t = now();
if(currentMillis - sensorpreviousMillis > fiveMinuteInterval)
{
// save the last time you performed event
sensorpreviousMillis = currentMillis;
DateTime Zeit = rtc.now();
}
}
void ShowDaysReading()
{
days = ((now() - theDateWeGotTogether) / 86400); //86400 number of seconds in a day
weeks = ((now() - theDateWeGotTogether) / (86400 * 7) ); //86400 number of seconds in a day
clockDisplay.print(days);
}

Related

Printing the output data of a turbidity sensor with Arduino UNO

I am reading the output in voltage of a turbidity sensor : https://www.dfrobot.com/product-1394.html?tracking=5b603d54411d5 with an Arduino UNO. I want to print the value of volts outage and its NTU (turbidity units) on an LCD screen ADM1602U Sparkfun.
I cant seem to print the dtata correctly on the lCD, it opens and lights up (so I think the wiring is ok) but no data appear.
Here is the code I am using:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// Set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27, 16, 2);
int sensorPin = A0;
int val = 0;
float volt;
float ntu;
void setup()
{
Serial.begin(9600);
lcd.init();
// Turn on the blacklight and print a message.
lcd.backlight();
}
void loop()
{
volt = ((float)analogRead(sensorPin)/1023)*5;
ntu = -1120.4*square(volt)+5742.3*volt-4353.8;
val = analogRead(volt);
Serial.println(volt);
lcd.clear();
lcd.setCursor(0,0);
lcd.print(volt);
lcd.print(" V");
lcd.setCursor(0,1);
lcd.print(ntu);
lcd.print(" NTU");
delay(10);
}
float round_to_dp( float in_value, int decimal_place )
{
float multiplier = powf( 10.0f, decimal_place );
in_value = roundf( in_value * multiplier ) / multiplier;
return in_value;
}
I used an analogread just to see if I was getting correct voltage values for the sensor and I am.
Thanks
Ok so I found the answer, the libary used was not appropriate to print on a 16x2 LCD display. The following code worked FYI:
#include <Wire.h>
#include <SoftwareSerial.h>
// Set the LCD address to 0x27 for a 16 chars and 2 line display
SoftwareSerial LCD(10, 11); // Arduino SS_RX = pin 10 (unused), Arduino SS_TX = pin 11
int sensorPin = A0;
float volt;
float ntu;
void setup()
{
Serial.begin(9600);
LCD.begin(9600); // set up serial port for 9600 baud
delay(500); // wait for display to boot
}
void loop()
{
volt = ((float)analogRead(sensorPin)/1023)*5;
ntu = -1120.4*square(volt)+5742.3*volt-4352.9;
Serial.println(volt);
// move cursor to beginning of first line
LCD.write(254);
LCD.write(128);
// clear display by sending spaces
LCD.write(" ");
LCD.write(" ");
// move cursor to beginning of first line
LCD.write(254);
LCD.write(128);
LCD.print(volt);
LCD.write(" V");
LCD.write(254);
LCD.write(192);
LCD.print(ntu);
LCD.write(" NTU");
delay(1000);
}

how to use ultrasonic sensor hc sr04 and gps neogps 6m and gsm sim900 on arduino uno

I’m trying to send an sms with the location when the ultrasonic sensor measures a certain distance but when I add the gpsSerial(9600) line in the void setup, the ultrasonic sensor readings become inconsistent such as it reads 24 cm then skips to 18 cm then back to 24 cm. i would really appreciate it if anyone familiar with arduino or has faced this problem before would help me out. here is my code:
#include <TinyGPS.h>
#include <SoftwareSerial.h>
#include "NewPing.h"
#define TRIGGER_PIN 7
#define ECHO_PIN 8
#define MAX_DISTANCE 100
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
float duration, distance;
SoftwareSerial gsmSerial(2, 3);
SoftwareSerial gpsSerial(5, 4);
TinyGPS gps; //Creates a new instance of the TinyGPS object
bool newData = false;
void setup()
{
Serial.begin(9600);
gsmSerial.begin(9600);
gpsSerial.begin(9600);
}
void loop()
{
// Send ping, get distance in cm
distance = sonar.ping_cm();
if (distance < 4 )
{
//sendSMS();
Serial.println("Bin is full!!, SMS SENT!!");
Serial.println(distance);
delay(1200);
}
else
{
Serial.println(distance);
delay(2000);
}
delay(2000);
}
void sendSMS(){
// For one second we parse GPS data and report some key values
for (unsigned long start = millis(); millis() - start < 1000;)
{
while (gpsSerial.available())
{
char c = gpsSerial.read();
//Serial.print(c);
if (gps.encode(c))
newData = true;
}
}
if (newData) //If newData is true
{
float flat, flon;
unsigned long age;
gps.f_get_position(&flat, &flon, &age);
gsmSerial.print("AT+CMGF=1\r");
delay(400);
gsmSerial.println("AT + CMGS = \"+26xxxxxxxx\"");// recipient's mobile
number
delay(300);
gsmSerial.print("BIN IS FULL!, PLEASE COLLECT # https://www.google.com
/maps/?q=");
gsmSerial.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
gsmSerial.print(",");
gsmSerial.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
delay(200);
gsmSerial.println((char)26); // End AT command with a ^Z, ASCII code
26
delay(2000);
gsmSerial.println();
}
}
I've tried to reproduce your problem on Arduino Uno with HC SR04, but with no success – my measurements were stable (more than 100 same measurements in a row). I have even set the sensor to 24 cm distance from the measured obstacle. I used a code derived from what you have provided:
#include <SoftwareSerial.h>
#include "NewPing.h"
#define TRIGGER_PIN 7
#define ECHO_PIN 8
#define MAX_DISTANCE 100
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
float duration, distance;
SoftwareSerial gsmSerial(2, 3);
SoftwareSerial gpsSerial(5, 4);
void setup() {
Serial.begin(9600);
gsmSerial.begin(9600);
gpsSerial.begin(9600);
}
void loop() {
// Send ping, get distance in cm
distance = sonar.ping_cm();
if (distance < 4 ) {
Serial.println("Bin is full!!, SMS SENT!!");
Serial.println(distance);
}
else {
Serial.println(distance);
}
delay(2000);
}
My conclusion is your code is fine and the problem is HW related. Check the wiring and if possible, try to use another HC-SR04 sensor.
BTW1: During testing, I was sending data to gpsSerial (rx) just to be sure, it is not caused by the GPS module sending some periodic data.
BTW2: How do you power the GPS and GSM module? Are you using Arduino to power these? If yes, this also can be the source of your problems since these modules could drain large peak currents and Arduino as source is not powerful enough ...

how use the MPU 6050 in ultra low power mode

I'm currently trying to set up a fermentation specific gravity monitor, using a tilt sensor. The process can take several weeks, and must be contained in a sterile container, so must be battery powerered. I'm using a slightly modified ESP8266-01, which enters sleep mode then wakes once an hour to take a measurement, transmit the data, and return to sleep mode. I'm using an MPU6050 for the tilt sensor. Firstly, I can't seem to put the mpu into sleep mode when the esp is off, it always seems to take around 4mA, and secondly, I only need one axis, is it possible to disable everything else to limit power consumption further? I can't seem to find anything in the manual to disable axis, only to calibrate them. my code is below
experimenting with the registers below seem to make no difference, adding them, taking them out altogether, still takes around 4mA. Tried setting to 1 to put the mpu to sleep at the end of the cycle but makes no difference.
Wire.write(0x6B);
Wire.write(0);
I'm very new to this and im struggling to interpret the manual when it refers to bit6 in addr 6b, how do i set bit 6?
If i could restict the mpu to only 1 axis, no acceleration, and to deep sleep inbetween measurements I should be able to get the power consumption around 0.5mA which gives me agood battery life using a single 18650. Any advice would be greatly appreciated!
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include "MPU6050.h"
#include "I2Cdev.h"
#include "Wire.h"
// Update these with values suitable for your network.
const char* ssid = "****";
const char* password = "******";
IPAddress server(192, 168, 1, 90);
WiFiClient espClient5;
PubSubClient client(espClient5);
long lastMsg = 0;
char msg[50];
const uint8_t scl = 5; //D1
const uint8_t sda = 4; //D2
int val;
int prevVal = 0;
String pubString;
char gravity[50];
MPU6050 mpu;
const int sleepTimeS = 10; //only 10 seconds for testing purposes, set to
1hr when operational
int counter=0;
int16_t ax, ay, az;
int16_t gx, gy, gz;
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* payload, unsigned int length) { //not
required in this application
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "test";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("AliveRegister", "FermentMon");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
#define ONE_WIRE_BUS 2 // D4 on physical board
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);
float prevTemp = 0;
void setup() {
counter = 0;
Serial.begin(9600);
Wire.begin(0,2);
Wire.write(0x6B); //PWR_MGMT_1 register
Wire.write(0); // set to zero wakes teh 6050
Wire.endTransmission(true);
delay(100);
setup_wifi();
client.setServer(server, 1883);
client.setCallback(callback);
if (!client.connected()) {
reconnect();
}
Serial.println("Initialize MPU");
mpu.initialize();
Serial.println(mpu.testConnection() ? "Connected" : "Connection failed");
float temp;
DS18B20.requestTemperatures();
temp = DS18B20.getTempCByIndex(0); // first temperature sensor
char buff[100];
dtostrf(temp, 0, 2, buff);
temp = temp + 0.5;
int tRound = int(temp);
client.publish("Fermenter/temperature", buff);
Serial.print("Fermenter Temperature: ");
Serial.println(temp);
prevTemp = tRound;
mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
val = map(ax, -17000, 17000, 0, 180);
pubString = String(val);
pubString.toCharArray(gravity, pubString.length() + 1);
client.publish("Fermenter/angle", gravity);
Serial.print("Gravity angle: ");
Serial.println(val);
delay(500);
// counter = counter+1;
Serial.println("sleep mode");
Wire.write(0x6B); //PWR_MGMT_1 register
Wire.write(1); // set to zero wakes teh 6050
// sleep
ESP.deepSleep(sleepTimeS * 1000000);
delay(2000);
}
void loop() {
client.loop();
}
I'm very new to this and im struggling to interpret the manual when it refers to bit6 in addr 6b, how do i set bit 6?
Setting a bit is simple.
Use the follow functions to avoid any brain storming.
// Write register bit
void writeRegisterBit(uint8_t reg, uint8_t pos, bool state)
{
uint8_t value;
value = readRegister8(reg);
if (state)
{
value |= (1 << pos);
}
else
{
value &= ~(1 << pos);
}
writeRegister8(reg, value);
}
// Write 8-bit to register
void writeRegister8(uint8_t reg, uint8_t value)
{
Wire.beginTransmission(MPU_addr);
#if ARDUINO >= 100
Wire.write(reg);
Wire.write(value);
#else
Wire.send(reg);
Wire.send(value);
#endif
Wire.endTransmission();
}
Example Usage: writeRegisterBit(MPU6050_REG_INT_PIN_CFG, 5, 1); //Register 37;Interrupt Latch Enable
For your application:
void acclSetSleepEnabled(bool state)
{
writeRegisterBit(MPU6050_REG_PWR_MGMT_1, 6, state);
}
If i could restict the mpu to only 1 axis, no acceleration, and to deep sleep inbetween measurements I should be able to get the power consumption around 0.5mA which gives me agood battery life using a single 18650
To enter low power accelerometer mode use the following function:
void lowPowerAccel(uint8_t frequency) {
uint8_t value;
value = readRegister8(MPU6050_REG_PWR_MGMT_2);
value &= 0b00111000;
value |= (frequency << 6) | 0b111;
writeRegister8(MPU6050_REG_PWR_MGMT_2, value);
value = readRegister8(MPU6050_REG_PWR_MGMT_1);
value &= 0b10010111;
value |= 0b00111000;
writeRegister8(MPU6050_REG_PWR_MGMT_1, value);
}
This lowPowerAccel function also puts the gyro to standy mode. The function needs a wake up frequency parameter.
This is defined as follows:
/*
* LP_WAKE_CTRL | Wake-up Frequency
* -------------+------------------
* 0 | 1.25 Hz
* 1 | 2.5 Hz
* 2 | 5 Hz
* 3 | 10 H
*/
#define LP_WAKE_CTRL_1_25 0x00
#define LP_WAKE_CTRL_2_5 0x01
#define LP_WAKE_CTRL_5 0x02
#define LP_WAKE_CTRL_10 0x03
I hope, I could answer some of your questions.
Good luck! :)
Are you using a breakout board for the MPU6050? e.g. GY-521. Often they use linear regulators and leds which will consume additional power. It may be necessary to remove these and run the IMU from a direct power source.
Each register in the MPU6050 is 8 bits wide. When setting an individual bit to a desired value you can either use bitwise manipulation (not practical here as we aren't directly interacting with the registers) or directly set all of the bits in the register to the register's new state e.g. 0b00100000 ~ 0x20. Instead of writing a 1 to 0x6B when attempting to put the MPU6050 to sleep you should be writing 0x20.
https://www.invensense.com/wp-content/uploads/2015/02/MPU-6000-Register-Map1.pdf
Referencing page 40-42, if you want to take things a step further you can disable the temperature sensor, accelerometers, and redundant gyroscope axes to save power while the device is active.

Blink LED without delay

So I'm creating a code so that I can read and store temperature values
for at least 8hours and store it in the Arduino EEPROM. I also want the Built in LED to flash once every second, while the temperature sensor records once every minute. I wrote the following but I'm left with the LED staying on for a whole minute then off for another minute and so on. I want it to keep constantly flashing. I know it's because of my delay(6000) but I don't know how to fix it. Any help is appreciated, thanks!
#include <EEPROM.h> //Librería para controlar la EEPROM de la Arduino
float tempC; //Initialize variable for storing Temperature
int tempPin = 0; //Conected at A0
int addr = 0; //Cantidad de espacios (bytes) iniciales
int count = 0; //counter needed to stop at a certain point before overflowing the EEPROM memory
int Voltages[501]; // Array with space for 501 data Points.A little over 8 hours. Holding integer values of Voltages.
float Temps[501]; //Holds float values for Temperatures
const int SWITCH = 8; //set switch to port 8
int ledState = LOW; // ledState used to set the LED
unsigned long previousMillis = 0; // will store last time LED was updated
const long interval = 1000; // blink once per second
void setup(){
Serial.begin(115200);
pinMode(LED_BUILTIN,OUTPUT);
pinMode(SWITCH,INPUT_PULLUP);}
void loop(){
int i;
if (digitalRead(SWITCH)==HIGH & count<=501){
for (int i=0;i<EEPROM.length();i++){
EEPROM.write(i,0);} // Clears the EEPROM so that only new recorded values are shown. In case of terminating before 8h
Serial.println("-------Recording-------");
unsigned long currentMillis = millis(); // current time
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis; // save the last time the LED blinked
if (ledState == LOW) {// if the LED is off turn it on and vice-versa:
ledState = HIGH;} else {
ledState = LOW;}
digitalWrite(LED_BUILTIN, ledState);}
for (i=0; i<501; i++){
count = count+1;
int v = analogRead(tempPin); // reads voltage
Voltages[i] = v;
Serial.println(i);
Serial.println(Voltages[i]);
delay(60000);
EEPROM.put(addr, Voltages[i]); //stores voltages in EEPROM
addr= addr +2;}}
I think the solution you are looking for involves the use of timer interrupts. That would execute an interrupt service routine (might as well be a blinking led) regardless of what happens in the rest of your loop function. This might give you a better in-sight: Arduino timer interrupts

Sending data from Proteus to Ms.Excel sheet

I am unable to send serial output data to Ms.Excel sheet.
I am using Proteus 8 professional software, Arduino 1.8.5 IDE with windos 7 OS in a 32bit system. Could anyone please guide me to send the data.
Here is my Ardunio code:
int incomingByte = 0;
unsigned long time;
unsigned long day = 86400000; // 86400000 milliseconds in a day
unsigned long hour = 3600000; // 3600000 milliseconds in an hour
unsigned long minute = 60000; // 60000 milliseconds in a minute
unsigned long second = 1000; // 1000 milliseconds in a second
void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
}
void loop() {
if (Serial.available() > 0)
{
incomingByte = Serial.read(); // read the incoming byte:
Serial.print("Time: ");
time = millis();
int days = time / day ; //number of days
int hours = (time % day) / hour; //the remainder from
days division (in milliseconds) divided by hours, this gives the full hours
int minutes = ((time % day) % hour) / minute ; //and so on...
int seconds = (((time % day) % hour) % minute) / second;
Serial.print(days,DEC);
Serial.println(hours);
Serial.println(minutes);
Serial.println(seconds);
delay(1000);
}
}

Resources