Folks,
Have a situation here....have an i2C set up where the master is a Mega and the slave is a micro.
I successfully sent a message to the master, the message consist of few buttons statuses. Then trying to sent a variable to from the master to the slave. Everything appears to work fine (communications wise) but the buttons status doesn't change at all if the corresponding button is pressed, it looks like the slave code is stuck on the wire.read. If I remove the the part of the code that do the wire.read I can touch the buttons and the corresponding LED's will lit, I can also read the data sent from the slave to the master on the master serial monitor, but the minute I add the wire.read, the buttons are not read and the LED's dont get energize. The issue is on the subroutine i2cMessage_From_Master()
Slave Code:
// Libraries
#include <Button.h> // Library for buttons
#include <SPI.h>
#include <Wire.h> // Library for i2C communications
//Configure DI to pin #
#define StartPin 1 //Connect a tactile button switch (or something similar)
#define ParkPin 4 //Connect a tactile button switch (or something similar)
#define ReversePin 5 //Connect a tactile button switch (or something similar)
#define NeutralPin 6 //Connect a tactile button switch (or something similar)
#define DrivePin 7 //Connect a tactile button switch (or something similar)
#define ebrakePin 11 //Connect a tactile button switch (or something similar)
#define AWDPin 12 //Connect a tactile button switch (or something similar)
#define PULLUP true //To keep things simple, we use the Arduino's internal pullup resistor.
#define INVERT true //Since the pullup resistor will keep the pin high unless the
//switch is closed, this is negative logic, i.e. a high state
//means the button is NOT pressed. (Assuming a normally open switch.)
#define DEBOUNCE_MS 100 //A debounce time of 100 milliseconds usually works well for tactile button switches.
Button StartSignal (StartPin, PULLUP, INVERT, DEBOUNCE_MS);
Button DriveButton (DrivePin, PULLUP, INVERT, DEBOUNCE_MS);
Button ReverseButton (ReversePin, PULLUP, INVERT, DEBOUNCE_MS);
Button ParkButton (ParkPin, PULLUP, INVERT, DEBOUNCE_MS);
Button NeutralButton(NeutralPin, PULLUP, INVERT, DEBOUNCE_MS);
Button eBrakeButton(ebrakePin, PULLUP, INVERT, DEBOUNCE_MS);
Button AWDButton(AWDPin, PULLUP, INVERT, DEBOUNCE_MS);
// Declare Global Variables
bool eBrakeEngage;
bool ParkMode;
bool AWDMode;
bool NeutralMotion;
bool IgnitionStatus;
bool SystemReady;
bool ForwardMotion;
bool ReverseMotion;
int Speed = 0; //Hard coded for now, eventually this will be a value coming to this Arduino via CAN Msg. Have to code the "read CAN message sub routine 1st
int modbus = 0; // hange this to the desired Communication method. 0 = i2C Communications 1 = Modbus (RS485) Communications
int ButtonStatus [6]; // Store all Button Status to be sent on the i2C bus.
const int PrechargeDelay = 2000; //Configure this value to make sure is long enough the system reached precharge state
const int Slave_Address = 10; // This Controller Address on the RS485 Network
const int Tx_Rx = 12; //HIGH = Transmit Data (Tx); LOW = Receive Data (Rx)
//Declare I/O pins
//Digital Outputs
int Start_OutPin = 8; //Physical Pin #13, , Digital pin 8, also A8
int FWD_S_OutPin = 9; //Physical Pin #13, Digital pin 9, also A9
int RWD_S_OutPin = 10; //Physical Pin #14, Digital pin 10, also A10
int PRK_LED1OutPin = 18; //Physical Pin #21, Digital pin 18, Analog A0
int RWD_LED1OutPin = 19; //Physical Pin #22, Digital pin 19, Analog A1
int NTRL_LED1OutPin = 20; //Physical Pin #23, Digital pin 20, Analog A2
int FWD_LED1OutPin = 21; //Physical Pin #24, Digital pin 21, Analog A3
void setup()
{
// Configure each Pin as Input or Output
// Inputs. All inputs are configured as INPUT_PULLUP, this make inputs to be active low. This way will prevent any noise triggering the input in the case of active high.
pinMode(ReversePin, INPUT_PULLUP); // declare ReversePin as INPUT_PULLUP, the pin will be active with a logic "0"
pinMode(DrivePin, INPUT_PULLUP); // declare DrivePin as INPUT_PULLUP, the pin will be active with a logic "0"
pinMode(ParkPin, INPUT_PULLUP); // declare ParkPin as INPUT_PULLUP, the pin will be active with a logic "0"
pinMode(NeutralPin, INPUT_PULLUP); // declare NeutralPin as INPUT_PULLUP, the pin will be active with a logic "0"
pinMode(ebrakePin, INPUT_PULLUP); // declare StartPin as INPUT_PULLUP, the pin will be active with a logic "0"
pinMode(AWDPin, INPUT_PULLUP); // declare StartPin as INPUT_PULLUP, the pin will be active with a logic "0"
//Outputs
pinMode(RWD_S_OutPin, OUTPUT);
pinMode(FWD_S_OutPin, OUTPUT);
pinMode(Start_OutPin, OUTPUT);
pinMode(PRK_LED1OutPin, OUTPUT);
pinMode(RWD_LED1OutPin, OUTPUT);
pinMode(NTRL_LED1OutPin, OUTPUT);
pinMode(FWD_LED1OutPin, OUTPUT);
pinMode (Tx_Rx,OUTPUT);
// Turn OFF all outputs.
digitalWrite(RWD_S_OutPin,LOW);
digitalWrite(FWD_S_OutPin,LOW);
digitalWrite(Start_OutPin,LOW);
digitalWrite(PRK_LED1OutPin,LOW);
digitalWrite(RWD_LED1OutPin,LOW);
digitalWrite(NTRL_LED1OutPin,LOW);
digitalWrite(FWD_LED1OutPin,LOW);
digitalWrite(Tx_Rx,LOW);
// Start applicable Communications
Serial.begin (9600); // Local Comms with Arduino IDE Serial Monitor, This could be commented out once full functionality has been proven
//Uncomment if Modbus comms is desired
//Serial1.begin(9600); // Start RS485 Comms
// Comment out the next 3 instructions if Modbus communications is desired
Wire.begin(Slave_Address); // Start i2C communications with respective address. Blank () argument is in Master Mode, (#) is in slave Mode
Wire.onReceive(i2cMessage_From_Master); // Register an Event handler for "incoming" Data from Master. Receive Data from Master
Wire.onRequest (i2cMessage_To_Master); // Register an Event handler for Data "request" from Master. Send Data to Master
// Initialize all variables
IgnitionStatus = 1; // Since this arduino will be powered by Ignition, set Ignition Status to "1" (ON. No need to waste an input on this.
ParkMode = 1; // Set the system to be in park mode
delay(PrechargeDelay); //delay to make sure the system is precharged.
SystemReady = 1;
delay (250);
digitalWrite(Start_OutPin,HIGH); // System should be Pre-charge. Send Ready/Start Signal (pulse) to both F-SDU & R-SDU
digitalWrite(PRK_LED1OutPin,HIGH);
delay (2000);
digitalWrite(Start_OutPin,LOW); // System should be Pre-charge. Turn OFF Ready/Start
}
void loop()
{
Read_Buttons();
Output_Update();
// Uncomment the next two instructions if Modbus coomunications are desired
//ModbusMessage_To_Master();
//ModbusMessage_From_Master();
}
void Read_Buttons()
{
// Avoid inadvertnly turning a button OFF by pressing the button twice. The mode or direction can be only be override by another button.
//Example1: if doing forward motion and the forward motion button is pressed by mistake, nothing will happend, if the 1st "if" condition is removed, the system will go out of "forward motion" because that will toggle
// the variable value.
//Example2: If the syetm is in Froward motion and speed = 0 then reverse button can be pressed, then forward motion = 0 and Reverse motion = 1
if (ForwardMotion == 0 & Speed == 0 ) //Do not check for the button if the system is already in the mode or motion governed by the button
{
DriveButton.read();
if (DriveButton.wasReleased()) //When the Signal goes OFF
{
NeutralMotion = 0;
ParkMode = 0;
ReverseMotion = 0;
ForwardMotion = !ForwardMotion;
//Serial.println ("Forward Motion Selected ");
}
}
if (ReverseMotion == 0 & Speed == 0) //Do not check for the button if the system is already in the mode or motion governed by the button
{
ReverseButton.read();
if (ReverseButton.wasReleased()) //When the Signal goes OFF
{
NeutralMotion = 0;
ParkMode = 0;
ForwardMotion = 0;
ReverseMotion = !ReverseMotion;
// Serial.println ("Reverse Motion Selected ");
}
}
if (NeutralMotion == 0 & Speed == 0) //Do not check for the button if the system is already in the mode or motion governed by the button
{
NeutralButton.read();
if (NeutralButton.wasReleased()) //When the Signal goes OFF
{
ParkMode = 0;
ReverseMotion = 0;
ForwardMotion = 0;
NeutralMotion = !NeutralMotion;
//Serial.println ("Neutral Motion Selected ");
}
}
if (ParkMode == 0 & Speed == 0) //Do not check for the button if the system is already in the mode or motion governed by the button
{
ParkButton.read();
if (ParkButton.wasReleased()) //When the Signal goes OFF
{
ReverseMotion = 0;
ForwardMotion = 0;
NeutralMotion = 0;
ParkMode = !ParkMode;
//Serial.println ("Park Mode Selected ");
}
}
if ( Speed == 0) //Do not check for the button if the system is already in the mode or motion governed by the button
{
AWDButton.read();
if (AWDButton.wasReleased()) //When the Signal goes OFF
{
//ReverseMotion = 0;
//ForwardMotion = 0;
//NeutralMotion = 0;
AWDMode = !AWDMode;
//Serial.println ("AWD Mode Selected1 ");
}
}
if ( Speed == 0) //Do not check for the button if the system is already in the mode or motion governed by the button
{
eBrakeButton.read();
if (eBrakeButton.wasReleased()) //When the Signal goes OFF
{
//ReverseMotion = 0;
//ForwardMotion = 0;
//NeutralMotion = 0;
eBrakeEngage = !eBrakeEngage;
//Serial.println ("eBrake Engage ");
}
}
}
void Output_Update()
{
// *********************************Parking***************************************
if ( IgnitionStatus == 1 & SystemReady == 1 & Speed == 0 & ParkMode == 1 ) // This will only happend when the system is power up by the ignition button
{
digitalWrite(RWD_S_OutPin,LOW);
digitalWrite(RWD_LED1OutPin,LOW);
digitalWrite(NTRL_LED1OutPin,LOW);
digitalWrite(FWD_S_OutPin,LOW);
digitalWrite(FWD_LED1OutPin,LOW);
digitalWrite(PRK_LED1OutPin,HIGH); // This is for testing purposes only, but ouput supposed to be OFF. If Output OFF, Only RED LED that is connected directly to VCC will be lit
}
// *********************************Reverse Motion***************************************
if ( IgnitionStatus == 1 & SystemReady == 1 & ReverseMotion == 1 & ForwardMotion == 0 & NeutralMotion == 0 & Speed == 0 & ParkMode == 0 )
{
digitalWrite(PRK_LED1OutPin,LOW);
digitalWrite(NTRL_LED1OutPin,LOW);
digitalWrite(FWD_S_OutPin,LOW);
digitalWrite(FWD_LED1OutPin,LOW);
digitalWrite(RWD_S_OutPin,HIGH);
digitalWrite(RWD_LED1OutPin,HIGH);
//Serial.println(" System In Reverse Motion ");
}
// *********************************Neutral Motion***************************************
if ( IgnitionStatus == 1 & SystemReady == 1 & ReverseMotion == 0 & ForwardMotion == 0 & NeutralMotion == 1 & Speed == 0 & ParkMode == 0 )
{
digitalWrite(PRK_LED1OutPin,LOW);
digitalWrite(RWD_S_OutPin,LOW);
digitalWrite(RWD_LED1OutPin,LOW);
digitalWrite(FWD_S_OutPin,LOW);
digitalWrite(FWD_LED1OutPin,LOW);
digitalWrite(NTRL_LED1OutPin,HIGH);
//Serial.println(" System In Neutral Motion ");
}
// *********************************Forward Motion***************************************
if ( IgnitionStatus == 1 & SystemReady == 1 & ReverseMotion == 0 & ForwardMotion == 1 & NeutralMotion == 0 & Speed == 0 & ParkMode == 0 )
{
digitalWrite(PRK_LED1OutPin,LOW);
digitalWrite(RWD_S_OutPin,LOW);
digitalWrite(RWD_LED1OutPin,LOW);
digitalWrite(NTRL_LED1OutPin,LOW);
digitalWrite(FWD_S_OutPin,HIGH);
digitalWrite(FWD_LED1OutPin,HIGH);
//Serial.println("System In Forward Motion ");
}
// *********************************AWD Mode***************************************
//if ( IgnitionStatus == 1 & SystemReady == 1 & Speed == 0 & AWDMode == 1)
//{
// Make sure Button Works but for now nothing will be done. I'm planning running the car in AWD at all times
//Serial.println(" AWD Mode Selected ");
//}
// *********************************Ebrake***************************************
if ( IgnitionStatus == 1 & SystemReady == 1 & Speed == 0 )
{
// Make sure Button Works but for now nothing will be done. I'm planning running the car in AWD at all times
//Serial.println(" Ebrake Engage ");
}
}
/*void ModbusMessage_To_Master()
{
//digitalWrite(Tx_Rx,HIGH); // HIGH = Transmitting Data to Serial
Serial1.print ("<");
Serial1.print (Slave_Address);
Serial1.print (";");
Serial1.print (ParkMode);
Serial1.print (";");
Serial1.print (ReverseMotion);
Serial1.print (";");
Serial1.print (NeutralMotion);
Serial1.print (";");
Serial1.print (ForwardMotion);
Serial1.print (";");
Serial1.print (eBrakeEngage);
Serial1.print (";");
Serial1.print (AWDMode);
Serial1.print (">");
Serial1.println (" ");
digitalWrite(Tx_Rx,LOW); // LOW = Receiving Data from Serial
delay (5);
}
void ModbusMessage_From_Master()
{
digitalWrite(Tx_Rx,LOW); // LOW = Receiving Data from Serial
if(Serial1.available()) // Check if there is Data in the serial buffer
{
if(Serial1.read()=='<') // New Message from Master.
{
int TargetAddress = Serial1.parseInt(); //
if ( TargetAddress == Slave_Address)
{
Serial.println (" We have a message from Master");
Speed = Serial1.parseInt();
Serial.println (Speed);
}
else
{
Serial.println (" No New Message");
}
}
}
}
*/
void i2cMessage_From_Master()
{
if (Wire.available())
{
Speed = Wire.read();
Serial.print("Speed = ");
Serial.println (Speed);
}
}
// requests data handler function
void i2cMessage_To_Master()
{
ButtonStatus [0] = ParkMode ;
ButtonStatus [1] = ReverseMotion;
ButtonStatus [2] = NeutralMotion;
ButtonStatus [3] = ForwardMotion;
ButtonStatus [4] = eBrakeEngage;
ButtonStatus [5] = AWDMode;
//ButtonStatus [6] = 170; // for whatever reason this one make the outputs to randomly go ON & OFF
for (int i = 0; i <= 7; i++)
{
Wire.write(ButtonStatus [i] ); // Send to Master all button Status
}
}
Master Code:
#include <Wire.h> // Library for i2C communications
int ButtonStatus [6];
int Speed;
void setup()
{
Wire.begin(); //Blank () argument is in Master Mode, (#) is in slave Mode
Serial.begin (9600);
Speed = 0;
}
void loop()
{
i2CMessage_From_Slave();
i2CMessage_To_Slave();
Speed = Speed + 1 ;
if (Speed >= 200)
{
Speed = 0;
}
}
void i2CMessage_From_Slave()
{
Wire.requestFrom(10, 6); // Request button Status from slave 10, data size = 6 INT
if(Wire.available())
{
for (int i = 0; i <= 6; i++)
{
ButtonStatus [i] = Wire.read();
Serial.println (ButtonStatus [i]);
}
}
}
void i2CMessage_To_Slave()
{
Wire.beginTransmission(10); // informs the bus that we will be sending data to slave device 10
Wire.write(Speed); // send Speed Value
Wire.endTransmission(); // informs the bus and the slave device that we have finished sending data
}