I have three I2C devices connected to Uno and powered independently. The setup randomly fails (Arduino just stops running and needs to be reset, sometimes, LCD back-light goes out as well until the reset, etc.
Trough trial and error I discovered the issue with pull-up resistors (see details below) that improved things quite a bit (it used to freeze up within seconds of resetting Arduino, now it fails randomly but not all the time).
I am guessing there is another issue I am not seeing and any advice will be appreciated.
thank you
P.S. I also have an issue with uploading a program (I have to disconnect separate power to relay in order to upload a program - details are described here).
P.S. issue with pull-up resistors - I2C pins on arduino (SDA/SCL have internal pull ups and any pull-up resistor on I2C devices should be disabled. I did this for both of my MCP4725 DACs and it worked fine during prototyping when used separately. But the set up wouldn't work when three I2C devices connected simultaneously AND powered through a separate 5V supply (grounds connected with Arduino). I re-enabled pull-up on one of the DAC and set-up is working much better (no idea why) but still freezes occasionally. Should I enable pull-ups on all three? is there anything else missing?
#include <Wire.h>
#include <LiquidCrystal_I2C.h> // Using version 1.2.1
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
#include <Adafruit_MCP4725.h>
Adafruit_MCP4725 dac_R; // constructor
Adafruit_MCP4725 dac_L;
//CURRENT READINGS
const int numReadings = 10; //number of current readings
int readings_1[numReadings]; int readings_2[numReadings]; // the readings from the analog input acs715
int readIndex = 0; // the index of the current reading
int total_1 = 0; int total_2 = 0; // the running total current from acs715
int analogInPin1 = A0; int analogInPin2 = A1; // Analog input pin that acs715 is connected to
float amps_1 =0; float amps_2 =0; //amps calculation from average
float pramps_1 =0; float pramps_2 =0; //previous amps
unsigned long lastampreading = 0; // last time acs715 was read
unsigned long ampreadinginterval = 10; // interval for acs715 reading
float amplimit = 12; // maximum amps allowed per motor
//DAC OPERATIONS
unsigned long lastVupdate = 0; // last time POT was read
unsigned long Vupdateinterval = 200; // how often POT should be read
uint32_t dac_value = 0;
int adcValueRead = 0;
float voltageRead = 0;
float dac_expected_output;
int dac_increment = 100;
int speedpercent = 0; //speed as percent
//INPUT SPEED OPERATIONS
int speedinput = A2; // POT input
int speedincrement = 50; // POT input is mapped to smaller resolution (from 1023)
int input_speed = 0; // input speed that would be anything between 0 and speedincrement above.
//Motor pins
int turnon = 5; //receives signal to turn motors on or off (set as input_pullup pin in void setup section)
int Lmotor = 11; int Rmotor = 12; // activates relay to turn on PWM controller (set as output in void setup section)
boolean MotorsOn = false; // tracks whether motors are on
int reversesense = 4; //receives signal to reverse direction of motors (set as input_pullup pin in void setup section)
int reverser = 13; //activates DSDP relay to reverse direction
boolean reverse = false; // tracks whether direction is forward or reversed
unsigned long buttoninterval = 500; //these are for button debouncing.
unsigned long buttonlastread = 0;
void setup() {
// initialize serial communications at 9600 bps:
Serial.begin(9600);
for (int thisReading = 0; thisReading < numReadings; thisReading++) { //creates placeholder variables for tracking average current readings from each motor.
readings_1[thisReading] = 0;
readings_2[thisReading] = 0;}
dac_R.begin(0x62);
dac_L.begin(0x61);
lcd.begin(16,2); // sixteen characters across - 2 lines
lcd.backlight();
lcd.setCursor(0,0);
dac_R.setVoltage(0, false); //sets DAC output to zero
dac_L.setVoltage(0, false);
pinMode(turnon, INPUT_PULLUP);
pinMode(Rmotor, OUTPUT);
pinMode(Lmotor, OUTPUT);
digitalWrite(Rmotor, HIGH);
digitalWrite(Lmotor, HIGH);
pinMode(reversesense, INPUT_PULLUP);
pinMode(reverser, OUTPUT);
digitalWrite(reverser, HIGH);
}
void loop() {
//IF MOTOR TURN ON BUTTON IS PUSHED
if (digitalRead(turnon)== LOW) {
if ((millis() - buttonlastread) > buttoninterval) {
buttonlastread = millis();
FTurnMotorsOnOff(); //call function to turn motor on or off
}
}
//IF REVERSE BUTTON IS PUSHED
if (digitalRead(reversesense)== LOW) {
if ((millis() - buttonlastread) > buttoninterval) {
buttonlastread = millis();
if (MotorsOn == true){ //shut down the motors before engaging in reverse.
Fsettledown();
}
Freverse(); //call function to reverse motor
}
}
if (MotorsOn == true) {
//MONITOR THROTTLE INPUT AND SEND SIGNAL TO MOTOR CONTROLS
if ((millis() - lastVupdate) > Vupdateinterval){
lastVupdate=millis();
input_speed = map(analogRead(speedinput),0,1023,speedincrement, 0); //map POT input to 1-50 resolution
int currspeed = map(dac_value,0,4000, 0, speedincrement); //also map DAC output (not actual output but what it is set to output) to the same range (1-50).
if (input_speed != currspeed) {
if (input_speed > currspeed && input_speed > 2) { //if POT is higher than DAC, then its accellerating. ignore pot reading lower than 2
dac_value += (1000/speedincrement); //so, if speed is increasing, don't set DAC all the way to POT reading at once
// Instead, increase by 1000/speedincrement that would increase of 20 every 200ms (200 is Vupdateinterval) and it would take 40,000ms (40 seconds) to reach full speed of about 6mph.
}
else if (input_speed < currspeed) {
dac_value += -(4000/speedincrement); // if speed is decreasing, deceleration is faster
}
dac_R.setVoltage(dac_value, false); //set DAC output to each motor.
dac_L.setVoltage(dac_value, false);
speedpercent = (currspeed*100/speedincrement); //calculate percent value of the speed.
LCDUpdate(6);
}
//MONITOR CURRENT DRAW FOR EACH MOTOR
if ((millis() - lastampreading) > ampreadinginterval) { //amps should be read once every 10ms
lastampreading = millis();
//Read and maintain the total for the last numReadings
total_1 = total_1 - readings_1[readIndex];
readings_1[readIndex] = analogRead(analogInPin1);
total_1 = total_1 + readings_1[readIndex];
//second ACS715 code is commented out for testing purposes
readIndex = readIndex + 1;
if (readIndex >= numReadings) { // once 10 readings are done, calculate average amps
readIndex = 0;
amps_1 = ampsreading(total_1); //call function below to calculate average amps over numReadings
if (abs(amps_1-pramps_1) > 0.2) { // update amp reading if the chage is more than 0.2.
pramps_1 = amps_1;
LCDUpdate(5);
// pramps_2 = amps_2;
//IF CURRENT EXCEEDS ALLOWABLE LIMIT, INITIATE SHUTDOWN
//if ((amps_1 >= amplimit) || (amps_2 >= amplimit)) {
if (amps_1 >= amplimit) {
Fsettledown(); // Initiate shutdown if the current is exceeded.
return;
}
}
}
}
}
}
}
void FTurnMotorsOnOff() {
//removed code to meet the forum 9000 character limit requirement
}
void Freverse() {
//removed code to meet the forum 9000 character limit requirement
}
float ampsreading (int total) {//calculates amp value from total readings and number of readings.
int average = total / numReadings;
float amps = (float) (((long)average * 5000 / 1024) - 500 ) / 133;
return amps;
}
void Fsettledown(){ //slows everything down quickly and shut down.
for (int i=dac_value; i >= 0; i=i-(4000/speedincrement)){
dac_R.setVoltage(i, false);
dac_L.setVoltage(i, false);
delay(100); // delay used here since this function rarely is called for and nothing else should be happening when this function is being executed
}
digitalWrite(Rmotor, HIGH);
digitalWrite(Lmotor, HIGH);
MotorsOn = false;
dac_value=0;
LCDUpdate(4);
}
void LCDUpdate (int scenario) {
//removed LCD update code to meet the forum 9000 character limit requirement
}