Hello, I'm trying to write a program for my device.
Usually during the timer phase, it can happen once a day, twice a day or even once a week, the program gets stuck and sometimes the relay stays open. Sometimes the program gets stuck when it is not in the timer phase and does not accept any input until it is reset.
It has 4 different programs with different prices and different timers to count. Once the user inserts coin via the coin selector, as a certain balance is reached and the related button is pressed, a timer starts and opens up a relay for that time period.
I'm using an arduino nano, fed by a small 700mA smps, the relay circuit even though it has an opto-isolated scheme, the gnd and 5V pins are from the same source as the arduino.
I think the problem lies in the code because I have used similar hardware setup before but still not so sure, I'm mostly suspicious of the rs485 commands and the progTimer function.
//Parameters of the program
unsigned long previousMillis = 0; //Old time point
unsigned long buttonMillis1 = 0; //Old button point
unsigned long buttonMillisFast1 = 0;
uint8_t buttonHang1 = 0; // A hanger for button pressed
uint16_t buttonValue1 = 0; // Button Analog reader
uint8_t buttonReading1 = 0; // Button Digital State
uint8_t buttonState1 = 0;
uint8_t lastButtonState1 = 0;
unsigned long buttonMillis2 = 0; //Old button point
uint8_t buttonHang2 = 0; // A hanger for button pressed
uint16_t buttonValue2 = 0; // Button Analog reader
uint8_t buttonReading2 = 0; // Button Digital State
uint8_t buttonState2 = 0;
uint8_t lastButtonState2 = 0;
unsigned long setMillis = 0; //Old button point
uint8_t setHang = 0; // A hanger for button pressed
uint16_t setValue = 0; // Button Analog reader
uint8_t setReading = 0; // Button Digital State
uint8_t setState = 0;
uint8_t lastSetState = 0;
uint8_t setCount = 0;
uint16_t setOnceState = 0; // The State variable of coin for Edge Detection
uint8_t setOnceLastState = 0;
uint8_t setOnceInState = 0; // The State variable of coin for Edge Detection
uint8_t setInLastState1 = 0;
uint8_t setInLastState2 = 0;
uint8_t setInLastState3 = 0;
uint8_t setInLastState4 = 0;
uint8_t setStateInput = 0;
uint8_t setStateOutput = 0;
uint8_t outPinSelect = 0;
int16_t progTimeMain = 0;
unsigned long timerMillis = 0;
char myStr[9];
uint8_t stateToLed = 0;
uint8_t balance = 0; // Money Balance
uint16_t coinState = 0; // The State variable of coin for Edge Detection
uint8_t coinLastState = 0;
uint8_t coinInState = 0; // The State variable of coin for Edge Detection
unsigned long panelMillis = 0;
unsigned long panelMillis1 = 0;
uint8_t but_state_set = 0;
uint8_t but_state_up = 0;
uint8_t but_state_down = 0;
const uint16_t intervalSn = 1000;
const uint8_t debounceDelay = 40; // Debounce for analog buttons and such
const uint16_t pressedTime = 300; // Debounce for analog buttons and such
const uint8_t dispMillis = 20; // the refresh ms for the 7 segment displays
const uint8_t dispSelectMillis = 180; // the refresh ms for the 7 segment displays, in select mode
// Inputs - Outputs
uint8_t button_set = A6;
uint8_t button_up = A5;
uint8_t button_down = A7;
const uint8_t coinPin = A4;
const uint8_t input0 = A3;
const uint8_t input1 = A2;
const uint8_t input2 = A1;
const uint8_t input3 = A0;
const uint8_t output1 = 7;
const uint8_t output2 = 5;
const uint8_t output3 = 3;
const uint8_t rs485En = 2;
The ones given above are the parameters and variables,
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "HC595AnodeMultiDig.h"
#include "PanelParameters.h"
#include "PanelVariables.h",
#include <EEPROM.h>
#include <SoftwareSerial.h>
#include <avr/wdt.h>
uint16_t dataArray [21] = {0, 0, 0, 0, 0, 0, 0, 102, 202, 87, 47, 4, 8, 8, 8, 0, 0, 0, 0, 0,0};
uint16_t dataStored [21] = {};
uint16_t dataValueLast = 0;
uint16_t baudRate = 9600;
uint8_t i = 0; // Menu Numbering
uint8_t j = 0; // Set Enabler
uint8_t rs485ControlState = 0;
uint8_t rsReceiveControl = 0;
uint8_t setActiveControl = 0;
const byte numChars = 10;
uint8_t rs485OutState = 0;
unsigned long constRs485Send = 0;
unsigned long constRs485Send1 = 0;
uint16_t turnoverNon = 0;
uint16_t turnoverT = 0;
const uint8_t rxPin = 6;
const uint8_t txPin = 4;
const char bal[] = "BA";
const char tim[] = "TI";
const char tO[] = "SO";
const char tU[] = "ST";
const char tK[] = "SK";
const char tC[] = "SC";
SoftwareSerial rs485(rxPin, txPin);
//HardwareSerial & rs485 = Serial;
void firstUpdate()
{
for (int k = 3; k < 11; k++)
{
dataArray[k] = (256*(EEPROM.read(k+20)) + EEPROM.read(k));
}
for (int k = 16; k < 20; k++)
{
dataArray[k] = (256*(EEPROM.read(k+20)) + EEPROM.read(k));
}
// Writing with only byte values
for (int k = 11; k < 15; k++){
dataArray[k] = EEPROM.read(k);
}
// To verify the change in variables
for (int k = 3; k < 20; k++)
{
dataStored[k] = dataArray[k];
}
}
void setup()
{
rs485.begin(baudRate);
//Serial.begin(baudRate);
//Serial.begin(baudRate);
// put your setup code here, to run once:
pinMode(ds_pin, OUTPUT);
pinMode(stcp_pin, OUTPUT);
pinMode(shcp_pin, OUTPUT);
pinMode(rxPin, INPUT_PULLUP);
pinMode(button_set, INPUT);
pinMode(button_up, INPUT);
pinMode(button_down, INPUT);
pinMode(input0, INPUT);
pinMode(input1, INPUT);
pinMode(input2, INPUT);
pinMode(input3, INPUT);
pinMode(output1, OUTPUT);
pinMode(output2, OUTPUT);
pinMode(output3, OUTPUT);
pinMode(rs485En, OUTPUT);
//wdt_disable();
delay(2000);
firstUpdate(); // To read the EEPROM values
//wdt_enable(WDTO_2S);
}
void loop()
{
// wdt_reset();
// The Coin reading functions, for it to be displayed, dataarray =
coinRead(coinPin);
if (dataArray[0] != balance)
{
dataArray[0] = balance;
rs485Write(bal, balance);
}
// send the balance data constantly, within the given interval
if (millis() - constRs485Send > 2000)
{
rs485Write(bal, balance);
constRs485Send = millis();
}
// send the program data constantly, within the given interval
if (millis() - constRs485Send1 > 3000)
{
rs485Write(tim, setStateOutput);
constRs485Send1 = millis();
}
// The input checker, will reveal the state of the object
setInputs(input0, input1, input2, input3,
dataArray[11], dataArray[12], dataArray[13], dataArray[14]);
progTimer(dataArray[7], dataArray[8], dataArray[9], dataArray[10],
output1, output1, output2, output3);
// Menu is only working while the Program is not ON
if (setStateOutput == 0) {dispMenu();}
else {
if (millis() - panelMillis1 > dispMillis)
{
stateToLed = num7Convert(setStateOutput);
dig2Display (0, 49); dig2Display (1, stateToLed); // P and state
num7Display (progTimeMain); // Display remaining time
clearCache();
panelMillis1 = millis();
}
// if set button is pressed, program forcefully terminates
if (setOnce(button_set))
{
setStateOutput = 0;
rs485Write(tim, setStateOutput);
}
}
}
void updateEEprom_8bit(uint8_t regNo){
// Scan the arrays for the 8 bit values, compare and update if necessary
if (dataStored[regNo] != dataArray[regNo])
{
dataStored[regNo] = dataArray[regNo];
EEPROM.update(regNo,(dataStored[regNo]));
}
}
void updateEEprom_16bit(uint8_t regNo){
// Scan the arrays for the 8 bit values, compare and update if necessary
if (dataStored[regNo] != dataArray[regNo])
{
dataStored[regNo] = dataArray[regNo];
EEPROM.update(regNo, ((dataStored[regNo])%256));
EEPROM.update((regNo+20), ((dataStored[regNo])/256));
}
}
void rs485Write (char *regText, uint16_t dataValue)
{
if (dataValueLast != dataValue)
{
dataValueLast = dataValue;
itoa(dataValueLast, myStr,10); // The value which will be given for the function
}
digitalWrite(rs485En, HIGH); // To allow sending data via RS485
delay(3);
rs485.write('<'); // Start the send parameter
rs485.write(regText); // Write the fun no first
rs485.write(myStr); // Write the data value second
rs485.write('>'); // End the send parameters
rs485.flush(); // Wait until sending is finished
digitalWrite(rs485En, LOW); // Enable receive mode
}
}
void rs485DataEqualize()
{
if (i == 7) rs485Write(tO, dataArray[7]);
if (i == 8) rs485Write(tU, dataArray[8]);
if (i == 9) rs485Write(tK, dataArray[9]);
if (i == 10) rs485Write(tC, dataArray[10]);
}
void dispMenu ()
{
// Menu limiting
if (i>15 && i<35) i = 0;
if (i>250) i = 15;
// Showing the Balance
if (i == 0)
{
if (millis() - panelMillis > dispMillis)
{
menu7Display(i);
num7Display(dataArray[i]);
clearCache();
panelMillis = millis();
}
j = 0; // To prevent j from not being 0 when cleared
}
// menu is changeable while j = 0
if (j == 0) {i = buttonCountDir(button_up,button_down,i);}
// Display the Turnover Non Clearable
if (i == 1)
{
turnoverNon = dataArray[16] * dataArray[11] + dataArray[17] * dataArray[12] + dataArray[18] * dataArray[13] + dataArray[19] * dataArray[14];
if (turnoverNon > 9999)
{
dataArray[16] = 0; dataArray[17] = 0; dataArray[18] = 0; dataArray[19] = 0;
}
if (millis() - panelMillis > dispMillis)
{
menu7Display(i);
num7Display(turnoverNon);
clearCache();
panelMillis = millis();
}
}
// Display the Turnover Clearable
if (i == 2)
{
turnoverT = dataArray[3] * dataArray[11] + dataArray[4] * dataArray[12] + dataArray[5] * dataArray[13] + dataArray[6] * dataArray[14];
if (turnoverT > 9999)
{
dataArray[3] = 0; dataArray[4] = 0; dataArray[5] = 0; dataArray[6] = 0;
}
if (millis() - panelMillis > dispMillis)
{
menu7Display(i);
num7Display(turnoverT);
clearCache();
panelMillis = millis();
}
}
// The value of the programs
if (i > 2 && i < 7)
{
if (millis() - panelMillis > dispMillis)
{
menu7Display(i);
num7Display(dataArray[i]);
clearCache();
panelMillis = millis();
}
}
// The functions that can be changed
if (i > 6 && i < 15)
{
j = setCountDir(button_set,j);
// Menu Set only active in the changeable situation
if (j == 0) // When Set is not selected
{
if (setActiveControl == 1)
{
if (i >= 11 && i <= 14) {updateEEprom_8bit(i);}
if (i >= 7 && i <= 10) {updateEEprom_16bit(i);}
setActiveControl = 0;
rs485DataEqualize();
}
// Menu variable inside value to be
if (millis() - panelMillis > dispMillis)
{
menu7Display(i);
num7Display(dataArray[i]);
clearCache();
panelMillis = millis();
}
}
else if (j == 1) // When Set is selected
{
setActiveControl = 1;
// Inside set value, making the values changeable
dataArray[i] = buttonCountDir(button_up,button_down,dataArray[i]);
//The general display for the menu part
if (millis() - panelMillis > dispMillis)
{
menu7Display(i);
clearCache();
panelMillis = millis();
}
// While the value is changeable, LED will flicker
if (millis() - panelMillis1 > dispSelectMillis)
{
num7Display(dataArray[i]);
clearCache();
panelMillis1 = millis();
}
}
}
// For the situation where the clear method is
if (i == 15)
{
// Display is changed for the clear menu
if (millis() - panelMillis > dispMillis)
{
menu7Display(i); // Menu Number will be displayed as usual
dig4Display(1, 99); // C symbol
dig4Display(2, 243); // l symbol
dig4Display(3, 244); // r symbol with dot
clearCache();
panelMillis = millis();
}
// If the set button is pressed, the values related to money will be cleared
if (setOnce(button_set))
{
balance = 0; dataArray[3] = 0; dataArray[4] = 0; dataArray[5] = 0; dataArray[6] = 0;
// Balance,OnYikG,TamYikG,KopG,CilaG
i = 0;
}
}
}
// Function to only set one variable once,and then return to 0 position
uint8_t setOnce(uint8_t setPin){
uint8_t setOnceActive = 0;
setOnceState = analogRead(setPin);
if (setOnceState < 100){
setOnceInState = 1;
} else setOnceInState = 0;
// compare the coinState to its previous state
if (setOnceInState != setOnceLastState) {
// if the state has changed, increment the counter
if (setOnceInState == 1) {
setOnceActive = 1;
}
}
setOnceLastState = setOnceInState;
return setOnceActive;
}
uint8_t setCountDir (uint8_t button3, uint8_t setValue)
{
setValue = analogRead(button3);
if (setValue < 100)
{setReading = 1;} else {setReading = 0; setState = 0;}
// Check if the state of the pin has changed
if(setReading != lastSetState)
{
setMillis = millis();
}
// If the debounce time has passed, Let the button hang
if (setReading == 1 && (millis() - setMillis > debounceDelay))
{
setHang = 1;
setState = 1;
}
// When the button is unpressed, then it will count one time, release the hang
if (setState != setHang)
{
setHang = 0;
setCount++;
}
lastSetState = setReading;
if (setCount > 1) {setCount = 0;}
return setCount;
}
uint16_t buttonCountDir (uint8_t button1, uint8_t button2, uint16_t countValue1)
{
//Count Up
buttonValue1 = analogRead(button1);
if (buttonValue1 < 100)
{buttonReading1 = 1;} else {buttonReading1 = 0; buttonState1 = 0;}
// Check if the state of the pin has changed
if(buttonReading1 != lastButtonState1)
{
buttonMillis1 = millis();
}
// If the debounce time has passed, Let the button hang
if (buttonReading1 == 1 && (millis() - buttonMillis1 > debounceDelay))
{
buttonHang1 = 1;
buttonState1 = 1;
}
// When the button is unpressed, then it will count one time, release the hang
if (buttonState1 != buttonHang1)
{
buttonHang1 = 0;
countValue1++;
}
lastButtonState1 = buttonReading1;
// Count Down
buttonValue2 = analogRead(button2);
if (buttonValue2 < 100)
{buttonReading2 = 1;} else {buttonReading2 = 0; buttonState2 = 0;}
// Check if the state of the pin has changed
if(buttonReading2 != lastButtonState2)
{
buttonMillis2 = millis();
}
// If the debounce time has passed, Let the button hang
if (buttonReading2 == 1 && (millis() - buttonMillis2 > debounceDelay))
{
buttonHang2 = 1;
buttonState2 = 1;
}
// When the button is unpressed, then it will count one time, release the hang
if (buttonState2 != buttonHang2)
{
buttonHang2 = 0;
countValue1--;
}
lastButtonState2 = buttonReading2;
return countValue1;
}
void coinRead(uint8_t coinPinout){
coinState = analogRead(coinPinout);
if (coinState < 100){
coinInState = 1;
} else coinInState = 0;
// compare the coinState to its previous state
if (coinInState != coinLastState) {
// if the state has changed, increment the counter
if (coinInState == 1) {
balance++;
// P10 Panel print program which only works when the balance changes
// P10.BALANCE(balanceF);
}
}
coinLastState = coinInState;
}
// The function to read the inputs, deduct price and give the state command
void setInputs(uint8_t setInPin1, uint8_t setInPin2,
uint8_t setInPin3, uint8_t setInPin4,
uint8_t price1, uint8_t price2,
uint8_t price3, uint8_t price4)
{
uint16_t setInValue1 = analogRead(setInPin1);
uint16_t setInValue2 = analogRead(setInPin2);
uint16_t setInValue3 = analogRead(setInPin3);
uint16_t setInValue4 = analogRead(setInPin4);
uint8_t setInState1 = 0;
uint8_t setInState2 = 0;
uint8_t setInState3 = 0;
uint8_t setInState4 = 0;
// if the Out state has been activated, do not read the pins
if (setStateOutput == 0)
{
if (setInValue1 < 100){setInState1 = 1;} else setInState1 = 0;
if (setInState1 != setInLastState1)
{
if (setInState1 == 1 && balance >= price1)
{setStateInput = 1; balance = balance - price1;}
}
setInLastState1 = setInState1;
if (setInValue2 < 100){setInState2 = 1;} else setInState2 = 0;
if (setInState2 != setInLastState2)
{
if (setInState2 == 1 && balance >= price2)
{setStateInput = 2; balance = balance - price2;}
}
setInLastState2 = setInState2;
if (setInValue3 < 100){setInState3 = 1;} else setInState3 = 0;
if (setInState3 != setInLastState3)
{
if (setInState3 == 1 && balance >= price3)
{setStateInput = 3; balance = balance - price3;}
}
setInLastState3 = setInState3;
if (setInValue4 < 100){setInState4 = 1;} else setInState4 = 0;
if (setInState4 != setInLastState4)
{
if (setInState4 == 1 && balance >= price4)
{setStateInput = 4; balance = balance - price4;}
}
setInLastState4 = setInState4;
}
}
// Timer usage
void progTimer(uint16_t time1, uint16_t time2, uint16_t time3,
uint16_t time4, uint8_t outPin1, uint8_t outPin2,
uint8_t outPin3, uint8_t outPin4)
{
// Caution for the relays to forcefully close when this
if (setStateOutput == 0)
{
digitalWrite(output1, LOW);
digitalWrite(output2, LOW);
digitalWrite(output3, LOW);
progTimeMain = 0;
}
if (setStateInput != 0)
{
setStateOutput = setStateInput;
setStateInput = 0; // Reset the input State
//rs485Millis = millis();
}
// Main Timer notation and process start, Only One time operation
if (setStateOutput != 0 && progTimeMain == 0)
{
switch(setStateOutput)
{
case 1: progTimeMain = time1; outPinSelect = outPin1;
dataArray[3]++; dataArray[16]++; rs485OutState = 1; break;
case 2: progTimeMain = time2; outPinSelect = outPin2;
dataArray[4]++; dataArray[17]++; rs485OutState = 2; break;
case 3: progTimeMain = time3; outPinSelect = outPin3;
dataArray[5]++; dataArray[18]++; rs485OutState = 3; break;
case 4: progTimeMain = time4; outPinSelect = outPin4;
dataArray[6]++; dataArray[19]++; rs485OutState = 4; break;
}
updateEEprom_16bit(rs485OutState + 2);
updateEEprom_16bit(rs485OutState + 15);
rs485Write(tim, rs485OutState);
digitalWrite(outPinSelect, HIGH);
}
// While the program state is high and the progTimeMain function is not 0
// start counting
if (setStateOutput != 0 && progTimeMain != 0)
{
// Every second decrease counter by 1
if (millis() - timerMillis >= 1000)
{
timerMillis = millis();
progTimeMain--;
}
// If counter reaches 0, shut down the timer output, with relay
if (progTimeMain <= 0 || setStateOutput == 0)
{
setStateOutput = 0;
rs485OutState = 0;
digitalWrite(outPinSelect, LOW);
rs485Write(tim, rs485OutState);
timerMillis = 0;
}
}
}