converting an int array into a string - c++

I'm currently working on a project that is mostly run on a Raspberry pi, but has tasks complete by microcontroller. Currently, my RPi is sending a string of integers separated by commas to a microcontroller (ESP 32 Thing plus), the microcontroller is then converting that into an intergern array and using those values to set the level of a PWM output. Simultaneously, the microcontroller is reading an analogue input and storing those values into another int array, this data needs to be sent back to the RPi. I've been trying for ages to convert this into a string to be sent back, which works for the most part using sprintf() and strcat(), but it only works when I have just the number values. It would be good to have commas separate the numbers, but as soon as I do that, I get a really weird out put and the numbers start changing from their actual value to "1792" or 44" and it cycles between them or if I us a float array then I get 6 variables correct and then the rest are changes to "512".
Its a lot to send but possibly better to see the whole thing.
#include <stdio.h>
// variables to hold, parse and manipulate data
const byte numChars = 64;
const byte stringLength = 255;
char receivedChars[1000];
char tempChars[1000];
char messageFromPC[stringLength] = {0};
int MyArray[] = {};
int LaserMeasurmentArray[200] = {};
char LaserMeasurmentString[] = "";
int BrakeArray [60] = {10,200,600,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,500,0,0,0};
int AccelleratingArray [60] = {10,200,600,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,500,0,0,0};
int TimeStamps[200] = {};
char TimeStampString = '0';
int i = 0;
int SizeOfArray = 0;
int MyArraySize = 0;
int Counter = 0;
int CounterLaser = 0;
//Clutch/Brake Setup
int ClutchPin = 33;
int BrakePin = 27;
int ButtonPin = 32;
int ButtonState = LOW;
int Delay = 10;
int PWM = 1023;
const int LaserPin = A0;
//Millis variables
unsigned long PreviousMillisAccel = 0;
unsigned long PreviousMillisLaser = 0;
unsigned long CurrentMillis = 0;
const int PeriodWrite = 8;
const int PeriodRead = 5;
//Action States
boolean newData = false;
boolean SendData = false;
boolean AccellerationInProgress = false;
boolean BrakingInProgress = false;
//============
void setup() {
Serial.begin(115200);
//ledcSetup(ledChannel, freq, resolution);
ledcSetup(1, 5000, 10);
ledcSetup(2, 5000, 10);
//ledcAttachPin(LED, ledChannel);
ledcAttachPin(ClutchPin, 1);
ledcAttachPin(BrakePin, 2);
pinMode(LaserPin, INPUT);
pinMode(ButtonPin, INPUT_PULLUP);
}
//============
void loop() {
recvWithStartEndMarkers();
if (newData == true) {
strcpy(tempChars, receivedChars);
//Serial.print(receivedChars);
//Serial.println();
parseData();
//showParsedData();
//ButtonPress();
ButtonState = HIGH;
while (ButtonState == HIGH) {
ButtonState = digitalRead(ButtonPin);
}//while
Serial.println();
Serial.print("Accellerating");
Serial.println();
PWMSignal();
Serial.println();
Serial.print("Deccellerating");
Serial.println();
PWMSignal2();
newData = false;
ButtonState = HIGH;
while (ButtonState == HIGH) {
ButtonState = digitalRead(ButtonPin);
}//While
SendReply();
}
}
//============
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= stringLength) {
ndx = stringLength - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
//============
void parseData() { // split the data into its parts
i = 0;
String serialResponse = tempChars;
char buf[sizeof(tempChars)];
serialResponse.toCharArray(buf, sizeof(buf));
char *p = buf;
char *str;
while ((str = strtok_r(p, ",", &p)) != NULL && i < 1180 ){ // delimiter is the comma
MyArray[i] = atoi(str);
//Serial.println(str);
MyArraySize = i;
i++;
}//While
}//parseData
//============
void showParsedData() {
for(int i = 0; i < MyArraySize+1; i++){
Serial.print(MyArray[i]);
Serial.print(",");
}//For
Serial.println();
}
void PWMSignal(){
int Counter = 0;
CounterLaser = 0;
CurrentMillis = millis();
AccellerationInProgress = true;
while(AccellerationInProgress == true) {
CurrentMillis = millis();
if (Counter == 60){
AccellerationInProgress = false;
}//if
else if (CurrentMillis - PreviousMillisAccel >= PeriodWrite) {
ledcWrite(1, AccelleratingArray[Counter]);
//Serial.println(AccelleratingArray[Counter]);
Counter = Counter + 1;
PreviousMillisAccel = CurrentMillis;
}//else if
if (CurrentMillis - PreviousMillisLaser >= PeriodRead){
LaserMeasurmentArray[CounterLaser] = analogRead(LaserPin);
Serial.println(LaserMeasurmentArray[CounterLaser]);
TimeStamps [CounterLaser] = CurrentMillis;
PreviousMillisLaser = CurrentMillis;
CounterLaser = CounterLaser + 1;
}//if
}//While Accel
ledcWrite(1, 0);
}//PWMSignal
void PWMSignal2() {
int Counter = 0;
BrakingInProgress = true;
while(BrakingInProgress == true) {
CurrentMillis = millis();
if (Counter == 60){
BrakingInProgress = false;
}//if
else if (CurrentMillis - PreviousMillisAccel >= PeriodWrite) {
ledcWrite(2, BrakeArray[Counter]);
//Serial.println(BrakeArray[Counter]);
Counter = Counter + 1;
PreviousMillisAccel = CurrentMillis;
}//else if
if (CurrentMillis - PreviousMillisLaser >= PeriodRead){
LaserMeasurmentArray[CounterLaser] = analogRead(LaserPin);
Serial.println(LaserMeasurmentArray[CounterLaser]);
TimeStamps [CounterLaser] = CurrentMillis;
PreviousMillisLaser = CurrentMillis;
CounterLaser = CounterLaser + 1;
}//if
}//While Accel
ledcWrite(1, 0);
ledcWrite(2, 0);
}//PWMSignal2
void SendReply() {
//Serial.println("Laser Data");
//Serial.println(sizeof(LaserMeasurmentArray));
for (int i = 0; i<=200; i++){
Serial.println(LaserMeasurmentArray[i]);
}
for (int i = 0; i <= 200; i++){
int buff = LaserMeasurmentArray[i];
char str [7];
sprintf(str,"%u" ,buff);
strcat(LaserMeasurmentString,str);
strcat(LaserMeasurmentString, ",");
}
Serial.print(LaserMeasurmentString);
}//sendReply
If someone could point out what I am doing wrong or have misunderstood, that would be great, thank you.

Related

LED at full brightness after dim button is not touched for certain amount of time

I made a simple 1 button LED dimmer and I would like to have the LED go back to full brightness after the button has not been touched for a set amount of time. But the code I came up with does not seem to be working as I cannot dim the LED
int buttonPin = 12;
int LEDPin = 3;
int buttonVal;
int LEDbright = 0;
int dt = 500;
int fdt = 60000;
void setup() {
// put your setup code here, to run once:
pinMode(buttonPin, INPUT);
pinMode(LEDPin, OUTPUT);
Serial.begin(9600);
}
void loop() {
static unsigned long whenButtonWasTouchedMs = 0;
buttonVal = digitalRead(buttonPin);
Serial.print("Button = ");
Serial.print(buttonVal);
Serial.print(", ");
delay(dt);
if (buttonVal == 1) {
LEDbright = LEDbright + 20;
whenButtonWasTouchedMs = millis();
}
Serial.println(LEDbright);
//
if (LEDbright > 255) {
LEDbright = 255;
delay(dt);
}
unsigned long afterButtonWasTouchedMs = millis() - whenButtonWasTouchedMs;
if (afterButtonWasTouchedMs >= 60000) {
LEDbright = 0;
analogWrite(LEDPin, LEDbright);
}
}
Your question doesn't seem to line up with how the code was written. It looks like you want to do the opposite (have the light get brighter when the button is held down, and then switch off 60 seconds after the button was released).
Here's the code I came up with to help with your stated problem:
int buttonPin = 12;
int LEDPin = 3;
int buttonVal;
int whenButtonWasTouched;
unsigned int LEDbright = 255;
int dt = 500;
int fdt = 60000;
unsigned long whenButtonWasTouchedMs = 0;
void setup() {
// put your setup code here, to run once:
pinMode(buttonPin, INPUT);
pinMode(LEDPin, OUTPUT);
Serial.begin(9600);
}
void loop() {
//static unsigned long whenButtonWasTouchedMs = 0;
buttonVal = digitalRead(buttonPin);
Serial.print("Button = ");
Serial.print(buttonVal);
Serial.print(", ");
delay(dt);
if (buttonVal == 1) {
LEDbright = LEDbright - 20;
whenButtonWasTouchedMs = millis();
}
//
if (LEDbright < 20 || LEDbright > 255) { // The LEDbright > 255 part is because sometimes there can be an integer overflow if we don't keep this.
LEDbright = 0;
}
Serial.println(LEDbright);
unsigned long afterButtonWasTouchedMs = millis() - whenButtonWasTouched;
if (afterButtonWasTouchedMs >= 60000) {
LEDbright = 255;
}
analogWrite(LEDPin, LEDbright);
}
As you can see I changed it so that analogWrite is not in the if statement, it checks for integer overflows, and prints out the adjusted value for the led brightness. To make it grow brighter as the button is held and then switch off after 60 seconds just change the minus sign to a plus sign in the LEDbright adjustment line, and change some of the other values around.
int buttonPin = 12;
int LEDPin = 3;
int buttonVal;
unsigned int LEDbright = 0;
int dt = 500;
int fdt = 60000;
unsigned long whenButtonWasTouchedMs = 0;
void setup() {
// put your setup code here, to run once:
pinMode(buttonPin, INPUT);
pinMode(LEDPin, OUTPUT);
Serial.begin(9600);
}
void loop() {
//static unsigned long whenButtonWasTouchedMs = 0;
buttonVal = digitalRead(buttonPin);
Serial.print("Button = ");
Serial.print(buttonVal);
Serial.print(", ");
delay(dt);
if (buttonVal == 1) {
LEDbright = LEDbright + 20;
whenButtonWasTouchedMs = millis();
}
if (LEDbright > 255) {
LEDbright = 255;
delay(dt);
}
Serial.println(LEDbright);
unsigned long afterButtonWasTouchedMs = millis() - whenButtonWasTouchedMs;
if (afterButtonWasTouchedMs >= 60000) {
LEDbright = 0;
}
analogWrite(LEDPin, LEDbright);
}

How can I make sure that my Arduino stopwatch's timing is exact?

I have a school assignment to create a stopwatch using Multifunction Shield. The functionality is simple: the leftmost button is for start/stop and the rightmost button is for resetting, if the stopwatch is stopped. The precision is 100ms.
My code is working as expected I thought, but my teacher returned it saying that I cannot guarantee that the code is executed every 100ms so that the stopwatch does not lag behind. What am I doing wrong?
There's a bit of a legacy code from previous HW, hope it's not a problem.
// Funshield Constants
// Constants for switching ON/OFF
constexpr int ON = LOW;
constexpr int OFF = HIGH;
// 7-Segs
constexpr int latchPin = 4;
constexpr int clockPin = 7;
constexpr int dataPin = 8;
// Buzzer
constexpr int buzzerPin = 3;
// LEDS
constexpr int firstPin = 13;
constexpr int secondPin = 12;
constexpr int thirdPin = 11;
constexpr int fourthPin = 10;
// Buttons
constexpr int firstButton = A1;
constexpr int secondButton = A2;
constexpr int thirdButton = A3;
// Trimr
constexpr int trimrPin = A0;
// Digits
constexpr int digits[11] = { 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0xFF };
constexpr int digitsPos[4] = { 0x08, 0x04, 0x02, 0x01 };
// End of Funshield Constants
// Beginning of the Program
// Buttons Variables
unsigned int buttons[] = {firstButton, secondButton, thirdButton};
unsigned int lengthOfButtons = sizeof(buttons) / sizeof(buttons[0]);
unsigned int previousButtonState[] = {1, 1, 1};
// Global Variables
unsigned long int previousMillis = millis();
unsigned int numberDigits[] = {0, 0, 0, 0};
unsigned int interval = 100;
bool isRunning = false;
int numberLength = 0;
int digitIndex = 0;
int dotIndex = 1;
int number = 0;
int DISPLAY_DECIMAL_DOT = 0x7F;
// Functions
unsigned long int displayController(unsigned long int previousMillis, unsigned int interval) {
unsigned long int currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
updateSetNumber(++number, 1);
}
return previousMillis;
}
int calculateNumberLength(int innerNumber) {
int len = 0;
while (innerNumber != 0) {
innerNumber = innerNumber / 10;
len++;
}
if (len <= dotIndex) len = dotIndex + 1;
return len;
}
void updateSetNumber(int innerNumber, int dot) {
numberLength = calculateNumberLength(innerNumber) - 1;
dotIndex = dot;
for (int i = 0; i < 4; i++) {
numberDigits[i] = innerNumber % 10;
innerNumber = innerNumber / 10;
}
}
void displayLoop() {
if (digitIndex > numberLength) {
digitIndex = (digitIndex + 1) % 4;
return;
}
if ((digitIndex == dotIndex) && (dotIndex > 0)) {
displayDigit(digits[numberDigits[digitIndex]] & DISPLAY_DECIMAL_DOT, digitsPos[digitIndex]);
} else {
displayDigit(digits[numberDigits[digitIndex]], digitsPos[digitIndex]);
}
digitIndex = (digitIndex + 1) % 4;
}
void displayDigit(byte digit, byte pos) {
digitalWrite(latchPin, OFF);
shiftOut(dataPin, clockPin, MSBFIRST, digit);
shiftOut(dataPin, clockPin, MSBFIRST, pos);
digitalWrite(latchPin, ON);
digitalWrite(latchPin, OFF);
}
// Program
void setup() {
for (int i = 0; i < lengthOfButtons; i++) {
pinMode(buttons[i], INPUT);
}
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}
void loop() {
if (isRunning) {
previousMillis = displayController(previousMillis, interval);
}
unsigned int currentButtonState = digitalRead(buttons[0]);
if ((!isRunning) && (digitalRead(buttons[2]) == ON)) {
digitIndex = 0;
number = 0;
updateSetNumber(number, 1);
}
displayLoop();
if (currentButtonState != previousButtonState[0]) {
if (currentButtonState == ON) {
isRunning = !isRunning;
}
previousButtonState[0] = currentButtonState;
}
}
The problem your teacher is pointing to is probably how you update previousMillis. Imagine that for some reason, an interrupt took too long or you fall victim to the fact that millis skips a number every now and then and your function doesn't get called until 102ms after the last time. Since you set previousMillis to currentMillis, you're going to be off by that 2ms from now on. Instead, add the interval to the previousMillis variable. That way you cancel out that little lag and the next tick is on time.
if(currentMillis - previousMillis >= interval) {
previousMillis += interval; // instead of = currentMillis which may be off
}

function that set pin high for defined number of times and time

I have this problem where I try to set an output pin high for a set time and times.
I do the call with hapticFeedback(1000, 2, 1);
the variables are defined as
unsigned long hapticPreviousMillis = 0;
int hapticState = LOW;
int oneshotHaptic = 0;
here is the function. For some reason I only get the pin set HIGH and not the blinks and LOW
void hapticFeedback(int activeLength, int repeats, int oneshotHaptic) {
if (oneshotHaptic == 1) {
for (int x = 0; x <= repeats; x++) {
unsigned long currentMillis = millis();
if (currentMillis - hapticPreviousMillis >= (unsigned long)activeLength) {
hapticPreviousMillis = currentMillis;
if (hapticState == LOW) {
hapticState = HIGH;
}
else {
hapticState = LOW;
}
digitalWrite(haptic, hapticState);
}
}
}
oneshotHaptic = 0;
}
So I figured it out and if anyone else is looking for this here is what I came up with. It might not be the smoothest of code but it does what I intended it to do
in the loop I have
if (setOneshotHaptic == 1) {
hapticFeedback(activeLength);
}
and the haptic function look like this
void hapticFeedback(int activeLength) {
unsigned long currentMillis = millis();
if (currentMillis - hapticPreviousMillis >= (unsigned long)activeLength) {
hapticPreviousMillis = currentMillis;
if (x == repeats) {
setOneshotHaptic = false;
hapticState = HIGH;
x = 0;
}
if (hapticState == LOW) {
hapticState = HIGH;
x++;
}
else {
hapticState = LOW;
}
digitalWrite(haptic, hapticState);
}
}
whenever i like to have haptic feedback i can define the following vars
setOneshotHaptic = true;
repeats = 3;
activeLength = 1000;
When the number of repeats has been reached I lay down the oneshot, force the output to high for it to be low by the routine and finally reset my repeat counter.
There might be nicer ways to do this. However I couldn't find them and this works for me....

if statement doesn't work on Nucleo64 but it does on Maple mini

I have a code that works on Maple Mini but I have to change hardware to Nucleo F030r8 because it has more ADC's and it totally sucks.
In the modbus_update() function there is a check of the size of inputBuffer and the following code should run only if the value of this variable is bigger than 0.
if (inputBuffer > 0 && micros() - microsFlag >= T3_5) {
...
}
But it runs even if value of inputBuffer is exactly 0. The strange thing is that this code (with different serial ports opening method) runs perfectly on Maple Mini. Does anyone have any idea what can be be the problem?
Here is the whole code:
#define BAUDRATE 19200
#define RE_PIN PC12
#define TE_PIN PF4
#define LED_PIN LED_BUILTIN
#define SLAVE_ID 1
#define BUFFER_SIZE 256 // max frame size
#define READ_INTERNAL_REGISTERS 4 // function code
#define MIN_REGISTER_ADDRESS 30001
#define MAX_REGISTER_ADDRESS 30020
#define MAX_SENSORS_PER_ROW 10
#define SENSORS_PER_ROW 7
#define MAX_ROWS 2
#define ROWS 1
#define DEBUG true
#define INVALID_VALUE 0x7FFF
const byte INPUTS[] = {PA0, PA1, PA4, PB0, PC1, PC0};
unsigned char frame[BUFFER_SIZE];
unsigned char functionCode;
unsigned int T1;
unsigned int T1_5; // inter character time out
unsigned int T3_5; // frame delay
unsigned long millisFlag = 0;
unsigned long microsFlag = 0;
unsigned char inputBuffer = 0;
int dlyCounter = 0;
int16_t sensorVals[MAX_SENSORS_PER_ROW * MAX_ROWS];
/*
HardwareSerial *modbus = &Serial;
HardwareSerial Serial1(PA10, PA9);
HardwareSerial *debug = &Serial1;
*/
HardwareSerial debug(PA10, PA9);
void setup() {
pinMode(LED_PIN, OUTPUT);
for (int i = 0; i < SENSORS_PER_ROW; i++) {
pinMode(INPUTS[i], INPUT_PULLUP);
}
debug.begin(BAUDRATE, SERIAL_8E1);
modbus_configure(BAUDRATE, 0); // baud rate, low latency
microsFlag = micros();
}
void loop() {
readSensorVals(100);
modbus_update();
}
unsigned int modbus_update() {
unsigned char overflow = 0;
while (Serial.available()) {
if (overflow) {
Serial.read(); // empty the input buffer
} else {
if (inputBuffer == BUFFER_SIZE) {
overflow = 1;
} else {
frame[inputBuffer] = Serial.read();
inputBuffer++;
}
}
microsFlag = micros();
}
// If an overflow occurred return to the main sketch
// without responding to the request i.e. force a timeout
if (overflow) {
debug.println("Error: input buffer overflow");
return 0;
}
// if inter frame delay occurred, check the incoming package
if (inputBuffer > 0 && micros() - microsFlag >= T3_5) {
debug.println("\nIncoming frame:");
for (int i = 0; i < inputBuffer; i++) {
debug.print(frame[i], HEX);
debug.print(" ");
}
debug.println();
// check CRC
unsigned int crc = ((frame[inputBuffer - 2] << 8) | frame[inputBuffer - 1]); // combine the crc Low & High bytes
if (calculateCRC(frame, inputBuffer - 2) != crc) {
debug.println("Error: checksum failed");
inputBuffer = 0;
return 0;
}
debug.println("CRC OK");
// check ID
unsigned char id = frame[0];
if (id > 242) {
debug.println("Error: Invalid ID");
inputBuffer = 0;
return 0;
}
// check if it's a broadcast message
if (id == 0) {
debug.println("Broadcast message");
inputBuffer = 0;
return 0;
}
if (id != SLAVE_ID) {
debug.println("Not my ID");
inputBuffer = 0;
return 0;
}
debug.println("ID OK");
// check function code
functionCode = frame[1];
if (functionCode != READ_INTERNAL_REGISTERS) {
debug.println("Exception: illegal function");
exceptionResponse(1);
inputBuffer = 0;
return 0;
}
debug.println("Function code OK");
// check frame size (function 4 frame MUST be 8 bytes long)
if (inputBuffer != 8) {
// some workaround here:
//if (inputBuffer != 8 || !(inputBuffer == 9 && frame[inputBuffer] == 0)) {
debug.println("Error: inaccurate frame length");
inputBuffer = 0;
return 0;
}
debug.println("Frame size OK");
// check data address range
unsigned int noOfRegisters = ((frame[4] << 8) | frame[5]); // combine the number of register bytes
if (noOfRegisters > 125) {
debug.println("Exception: illegal data address");
exceptionResponse(2);
inputBuffer = 0;
return 0;
}
unsigned int firstRegAddress = ((frame[2] << 8) | frame[3]); // combine the starting address bytes
debug.print("First address: ");
debug.println(firstRegAddress);
unsigned int lastRegAddress = firstRegAddress + noOfRegisters - 1;
debug.print("Last address: ");
debug.println(lastRegAddress);
unsigned char noOfBytes = noOfRegisters * 2;
unsigned char responseFrameSize = 5 + noOfBytes; // ID, functionCode, noOfBytes, (dataLo + dataHi) * number of registers, crcLo, crcHi
unsigned char responseFrame[responseFrameSize];
responseFrame[0] = SLAVE_ID;
responseFrame[1] = 0x04;
responseFrame[2] = noOfBytes;
unsigned char address = 3; // PDU starts at the 4th byte
for (int index = (int)(firstRegAddress - MIN_REGISTER_ADDRESS); index <= (int)(lastRegAddress - MIN_REGISTER_ADDRESS); index++) {
int16_t temp = (index >= 0 && index < MAX_ROWS * MAX_SENSORS_PER_ROW) ? sensorVals[index] : INVALID_VALUE;
responseFrame[address] = temp >> 8; // split the register into 2 bytes
address++;
responseFrame[address] = temp & 0xFF;
address++;
}
unsigned int crc16 = calculateCRC(responseFrame, responseFrameSize - 2);
responseFrame[responseFrameSize - 2] = crc16 >> 8; // split crc into 2 bytes
responseFrame[responseFrameSize - 1] = crc16 & 0xFF;
debug.println("Frame to send:");
for (int i = 0; i < responseFrameSize; i++) {
debug.print(responseFrame[i], HEX);
debug.print(" ");
}
debug.println();
sendPacket(responseFrame, responseFrameSize);
inputBuffer = 0;
while (Serial.available()) { // empty input buffer
Serial.read();
}
}
}
void modbus_configure(long baud, unsigned char _lowLatency) {
Serial.begin(baud, SERIAL_8E1);
pinMode(TE_PIN, OUTPUT);
pinMode(RE_PIN, OUTPUT);
rxEnable(); // pin 0 & pin 1 are reserved for RX/TX. To disable set TE and RE pin < 2
if (baud == 1000000 && _lowLatency) {
T1 = 1;
T1_5 = 1;
T3_5 = 10;
} else if (baud >= 115200 && _lowLatency) {
T1 = 50;
T1_5 = 75;
T3_5 = 175;
} else if (baud > 19200) {
T1 = 500;
T1_5 = 750;
T3_5 = 1750;
} else {
T1 = 10000000 / baud;
T1_5 = 15000000 / baud; // 1T * 1.5 = T1.5
T3_5 = 35000000 / baud; // 1T * 3.5 = T3.5
}
}
void exceptionResponse(unsigned char exception) {
unsigned char responseFrameSize = 5;
unsigned char responseFrame[responseFrameSize];
responseFrame[0] = SLAVE_ID;
responseFrame[1] = (functionCode | 0x80); // set the MSB bit high, informs the master of an exception
responseFrame[2] = exception;
unsigned int crc16 = calculateCRC(responseFrame, 3); // ID, functionCode + 0x80, exception code == 3 bytes
responseFrame[3] = crc16 >> 8;
responseFrame[4] = crc16 & 0xFF;
sendPacket(responseFrame, responseFrameSize); // exception response is always 5 bytes (ID, functionCode + 0x80, exception code, 2 bytes crc)
}
unsigned int calculateCRC(unsigned char f[], byte bufferSize) {
unsigned int temp, temp2, flag;
temp = 0xFFFF;
for (unsigned char i = 0; i < bufferSize; i++) {
temp = temp ^ f[i];
for (unsigned char j = 1; j <= 8; j++) {
flag = temp & 0x0001;
temp >>= 1;
if (flag)
temp ^= 0xA001;
}
}
// Reverse byte order.
temp2 = temp >> 8;
temp = (temp << 8) | temp2;
temp &= 0xFFFF;
return temp; // the returned value is already swapped - crcLo byte is first & crcHi byte is last
}
void rxEnable() {
if (TE_PIN > 1 && RE_PIN > 1) {
digitalWrite(TE_PIN, LOW);
digitalWrite(RE_PIN, LOW);
digitalWrite(LED_PIN, LOW);
}
}
void txEnable() {
if (TE_PIN > 1 && RE_PIN > 1) {
digitalWrite(TE_PIN, HIGH);
digitalWrite(RE_PIN, HIGH);
digitalWrite(LED_PIN, HIGH);
}
}
void sendPacket(unsigned char f[], unsigned char bufferSize) {
txEnable();
delayMicroseconds(T3_5);
for (unsigned char i = 0; i < bufferSize; i++) {
Serial.write(f[i]);
}
Serial.flush();
delayMicroseconds(T3_5); // allow frame delay to indicate end of transmission
rxEnable();
}
// #param dly delay between sensor readings in milliseconds
void readSensorVals(int dly) {
if (millis() != millisFlag) {
dlyCounter++;
millisFlag = millis();
}
if (dlyCounter >= dly) { // read sensor values
for (int i = 0; i < MAX_ROWS; i++) {
for (int j = 0; j < MAX_SENSORS_PER_ROW; j++) {
int actualIndex = i * MAX_SENSORS_PER_ROW + j;
if (i < ROWS && j < SENSORS_PER_ROW) {
sensorVals[actualIndex] = random(20, 30);
//sensorVals[actualIndex] = (4096 - analogRead(INPUTS[j])) / 20 - 133;
} else {
sensorVals[actualIndex] = INVALID_VALUE;
}
}
}
dlyCounter = 0;
}
}

Arduino RTC subtracting 1 second every 8 hours

I used the RTC, from an Arduino MKR 1300 with integrated RTC, as an alarm that will trigger a "boolean"(it's an integer) that will tell the loop to run a certain method every minute and then send some data every 5 minutes. It's on an active loop but the method to send data ONLY WORKS if it's inside the loop (no idea why). The problem is the RTC apparently is subtracting 1 second at every 8 hours or so after a few days the timing might come off and instead of sending data every xx:10:xx-xx:15:xx it might send data xx:09:xx-xx:14:xx.
Here's the code:
#include <EmonLib.h>
#include <RTCZero.h>
#include <MKRWAN.h>
EnergyMonitor emon1;
EnergyMonitor emon2;
EnergyMonitor emon3;
RTCZero rtc;
LoRaModem modem;
String appEui = "1234567891011121";
String appKey = "ffffffffffffffffffffffffffffffff";
/* INITIAL_TIME */
const byte seconds = 0;
const byte minutes = 0;
const byte hours = 0;
const byte day = 17;
const byte month = 12;
const byte year = 18;
byte second_alarm = 0;
byte minute_alarm = 0;
byte hour_alarm = 0;
byte INTERVAL = 60;
int SEND_LOOP = 5;
int totalKW;
int counter= 0;
int alarm_Triggered = 0;
void setup()
{
Serial.begin(115200);
if (!modem.begin(EU868)) {
Serial.println("Failed to start module");
while (1) {}
};
Serial.print("Your module version is: ");
Serial.println(modem.version());
Serial.print("Your device EUI is: ");
Serial.println(modem.deviceEUI());
Serial.println("Connecting");
int connected = modem.joinOTAA(appEui, appKey);
if (!connected) {
Serial.println("Something went wrong; are you indoor? Move near a window and retry");
while (1) {}
}
Serial.println("Connected");
// Set poll interval to 60 secs.
modem.minPollInterval(60);
analogReadResolution(9);
emon1.current(1, 53);
emon2.current(2, 53);
emon3.current(3, 53);
counter= 0;
rtc.begin(); // initialize RTC
rtc.setAlarmTime(hour_alarm, minute_alarm, second_alarm);
rtc.enableAlarm(rtc.MATCH_HHMMSS);
rtc.attachInterrupt(triggerAlarm);
// Set the time
rtc.setHours(hours);
rtc.setMinutes(minutes);
rtc.setSeconds(seconds);
// Set the date
rtc.setDay(day);
rtc.setMonth(month);
rtc.setYear(year);
}
void loop() {
if (alarm_Triggered == 1) {
dataMonitor();
alarm_Triggered = 0;
}
}
void dataMonitor() {
int totalWatt = 0;
unsigned long delay_send = 0;
int sending = 0;
double Irms1 = emon1.calcIrms(600);
if (Irms1 < 0.3) Irms1 = 0;
double Watt1 = Irms1 * 230;
double Irms2 = emon2.calcIrms(600);
if (Irms2 < 0.3) Irms2 = 0;
double Watt2 = Irms2 * 230;
double Irms3 = emon3.calcIrms(600);
if (Irms3 < 0.3) Irms3 = 0;
double Watt3 = Irms3 * 230;
totalWatt = Watt1 + Watt2 + Watt3;
totalKW = totalKW + totalWatt / 1000;
Serial.println(counter);
sendDataChecker(Irms1, Irms2, Irms3);
setAlarm();
counter= counter+ 1;
}
void sendDataChecker(double Irms1, double Irms2, double Irms3) {
if (counter== SEND_LOOP) {
double IrmsTotal = Irms1 + Irms2 + Irms3;
String msg = "{\"id\":\"avac_aud2\",\"kW\":" + String(totalKW) + ", \"current\":" + String(IrmsTotal) + "}";
int err;
Serial.println("Ready to Send");
modem.beginPacket();
modem.print(msg);
err = modem.endPacket(true);
Serial.println("Sent1");
if (err > 0) {
//message sent correctly
Serial.println("Sent");
counter= 0;
totalKW = 0;
} else {
Serial.println("ERR");
counter= 0;
}
}
}
void setAlarm() {
second_alarm += INTERVAL;
if (second_alarm >= 60) {
minute_alarm++;
second_alarm = 0;
}
if (minute_alarm >= 60) {
hour_alarm++;
minute_alarm = 0;
}
if (hour_alarm >= 24) {
hour_alarm = 0;
}
rtc.setAlarmTime(hour_alarm, minute_alarm, second_alarm);
}
void triggerAlarm() {
alarm_Triggered = 1;
}