Sending data using LIN cominication

Hi I am making a project to conect 1 master arduino UNO to 3 slave arduino UNOs using MCP2003 chips to send data using LIN comunication, I have sucsesfully set the comunication up to send a simple signal and response between the master and slaves with LEDs to signal the when the data is recieved at both the slave and the master, every time i press the relivent button the correct LEDs flash.

However i want to send data that is gathered from sensors on each of the slave arduinos alongside the signal data, when i try to do this the signal and response only work the first time I press the button and does not work on subsiquent presses.

I want to read data from a nine axis motion sensor shield which i have got working seperatly from the main project it is the data from this i want to send to the master along with the identification code.
See below for wiering diagram and code for master and 1st slave and 9 axis motion sensor

master code

volatile const int Rx = 2; // Rx looped from Rx pin (Uno/Nano pin 0)
const int ledPin = 13;
const int CS = 4; // HIGH enables MCP2003 chip
volatile boolean clearToSend = true; // can be used to flag that you shouldn't try to send anything as the LIN bus is busy

const int buttonPin = 7;
const int button2Pin = 8;
const int button3Pin = 9;
int buttonState;
int button2State;
int button3State;
int lastButtonState = LOW;
int lastButton2State = LOW;
int lastButton3State = LOW;
bool responseReceived = false; // Flag to track if the response has been receved 
bool response2Received = false; // Flag to track if the response has been receved 
bool response3Received = false; // Flag to track if the response has been receved 

char inByte[3];
const int led2Pin = 10;
const int led3Pin = 11;
const int led4Pin = 12;

long lastDebounceTime = 0;
long lastDebounceTime2 = 0;
long lastDebounceTime3 = 0;
long debounceDelay = 50;

void busClear() {

#define START_TIMER1 TCCR1B |= (1 << CS10)|(1 << CS12) // //Set CS10 and CS12 bits for 1024 prescaler:
#define STOP_TIMER1  TCCR1B &= 0B11111000

  // initialize Timer1
  TCCR1A = 0;     // set entire TCCR1A register to 0
  TCCR1B = 0;     // same for TCCR1B

  // set compare match register to desired timer count:
  OCR1A = 157; // Set timer to fire CTC interrupt after approx 10ms

  // turn on CTC mode:
  TCCR1B |= (1 << WGM12);

  // enable timer compare interrupt:
  TIMSK1 |= (1 << OCIE1A);

  attachInterrupt(0, rxChange, CHANGE); // run rxChange every time serial Rx changes state

}


//========================

void rxChange() {
  if (PIND & (1<<PIND1) && (PIND & (1<<PIND0))){ // check Tx high and Rx high
    START_TIMER1;
  }
  else if (PIND & (1<<PIND1) &&  (!(PIND & (1<<PIND0)))){ // check Tx high and Rx low
    clearToSend = false;
    digitalWrite(ledPin, HIGH);
    STOP_TIMER1;
  }
}

//========================

ISR(TIMER1_COMPA_vect) // runs if timer runs for 10ms
{
  clearToSend = true;
  digitalWrite(ledPin, LOW);

  STOP_TIMER1;
}




void setup()                     
{ 
  Serial.begin(9600);
  pinMode (CS, OUTPUT); // initialize pin.
  pinMode(Rx, INPUT_PULLUP); // pin looped from Rx pin 0
  digitalWrite (CS, HIGH); // write pin high.
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);
  digitalWrite(led2Pin, HIGH);
  digitalWrite(led3Pin, HIGH);
  digitalWrite(led4Pin, HIGH);
  delay (500);
  digitalWrite(ledPin, LOW);
  digitalWrite(led2Pin, LOW);
  digitalWrite(led3Pin, LOW);
  digitalWrite(led4Pin, LOW);
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(button2Pin, INPUT_PULLUP);
  pinMode(button3Pin, INPUT_PULLUP);
  busClear();
} 

void loop(){
  // add your main loop code in here
  int reading = digitalRead(buttonPin);
  if (reading != lastButtonState){
    lastDebounceTime = millis();
  }

  if ((millis()-lastDebounceTime) > debounceDelay){
    if (reading != buttonState){
      buttonState = reading;
      if (buttonState == LOW){
        byte msg[] = {
          0x41, 0x42, 0x43
        };
        for (int i = 0; i < sizeof msg; i++){
          Serial.write(msg[i]);
        }
      }
    }
  }
  lastButtonState = reading;
  //#########################################
    int reading2 = digitalRead(button2Pin);
  if (reading2 != lastButton2State){
    lastDebounceTime2 = millis();
  }

  if ((millis()-lastDebounceTime2) > debounceDelay){
    if (reading2 != button2State){
      button2State = reading2;
      if (button2State == LOW){
        byte msg[] = {
          0x47, 0x48, 0x49
        };
        for (int i = 0; i < sizeof msg; i++){
          Serial.write(msg[i]);
        }
      }
    }
  }
  lastButton2State = reading2;
  //#########################################
    int reading3 = digitalRead(button3Pin);
  if (reading3 != lastButton3State){
    lastDebounceTime3 = millis();
  }

  if ((millis()-lastDebounceTime3) > debounceDelay){
    if (reading3 != button3State){
      button3State = reading3;
      if (button3State == LOW){
        byte msg[] = {
          0x53, 0x54, 0x55
        };
        for (int i = 0; i < sizeof msg; i++){
          Serial.write(msg[i]);
        }
      }
    }
  }
  lastButton3State = reading3;
  
   if(Serial.available() == 3){// checks the response 
    for (int i = 0; i < 3; i++){
    inByte[i] = Serial.read(); // reads the response signal 
    }

         if(inByte[0] == 0x44 && inByte[1] == 0x45 && inByte[2] == 0x46){// compares the input signal to see if relivent 
         if (!responseReceived) { // Check if the response has not been recieved yet
    digitalWrite(led2Pin, HIGH);// lights 1st led
    	//digitalWrite(led3Pin, HIGH); // lights 2nd led
		 }
		 responseReceived = true; // Set the flag to indicate that the response has been receved
		 delay(100);
		 digitalWrite(led2Pin, LOW);// turn off 1st led
		 responseReceived = false; // Set the flag to indicate that the next response can be recieved 
		 busClear();
		 }else {

   
		 
		 //###################################################

		 if(inByte[0] == 0x50 && inByte[1] == 0x51 && inByte[2] == 0x52){// compares the input signal to see if relivent 
         if (!response2Received) { // Check if the response has not been recieved yet
    digitalWrite(led3Pin, HIGH);// lights 1st led
    	//digitalWrite(led3Pin, HIGH); // lights 2nd led
		 }
		 response2Received = true; // Set the flag to indicate that the response has been receved
		 delay(100);
      digitalWrite(led3Pin, LOW);// turn off 1st led
		 		 response2Received = false; // Set the flag to indicate that the next response can be recieved 
			busClear();
       
		 }else {
			 //###################################################

		 if(inByte[0] == 0x56 && inByte[1] == 0x57 && inByte[2] == 0x58){// compares the input signal to see if relivent 
         if (!response3Received) { // Check if the response has not been recieved yet
    digitalWrite(led4Pin, HIGH);// lights 1st led
    	//digitalWrite(led3Pin, HIGH); // lights 2nd led
		 }
		 response3Received = true; // Set the flag to indicate that the response has been receved
		 delay(100);
      digitalWrite(led4Pin, LOW);// turn off 1st led
		 		 response3Received = false; // Set the flag to indicate that the next response can be recieved 
				  busClear();
			 
		 }else{
      // Reset the responseReceived flag if the condition is not met
     responseReceived = false;
    response2Received = false;
	  response3Received = false;
	digitalWrite(led2Pin, LOW);
    digitalWrite(led3Pin, LOW);
	   digitalWrite(led4Pin, LOW);
}

}}}}

		 
   
   

Slave code

#include <SoftwareSerial.h>

volatile const int Rx = 3; // Rx looped from Rx pin (Uno/Nano pin 0)
const int ledPin = 13;
const int CS = 4; // HIGH enables MCP2003 chip
volatile boolean clearToSend = false; // can be used to flag that you shouldn't try to send anything as the LIN bus is busy
char inByte[3];
const int led2Pin = 8;
const int led3Pin = 9;
bool responseSent = false; // Flag to track if the response has been sent

SoftwareSerial debugSerial(10, 11); // RX, TX

//#########################################################################
void busClear() 
{

#define START_TIMER1 TCCR1B |= (1 << CS10)|(1 << CS12) // //Set CS10 and CS12 bits for 1024 prescaler:
#define STOP_TIMER1  TCCR1B &= 0B11111000

  // initialize Timer1
  TCCR1A = 0;     // set entire TCCR1A register to 0
  TCCR1B = 0;     // same for TCCR1B

  // set compare match register to desired timer count:
  OCR1A = 157; // Set timer to fire CTC interrupt after approx 10ms

  // turn on CTC mode:
  TCCR1B |= (1 << WGM12);

  // enable timer compare interrupt:
  TIMSK1 |= (1 << OCIE1A);

  attachInterrupt(0, rxChange, CHANGE); // run rxChange every time serial Rx changes state

}
//###############################################
void rxChange() {
  if (PIND & (1<<PIND1) && (PIND & (1<<PIND0))){ // check Tx high and Rx high
    START_TIMER1;
  }
  else if (PIND & (1<<PIND1) &&  (!(PIND & (1<<PIND0)))){ // check Tx high and Rx low
    clearToSend = false;
    digitalWrite(ledPin, HIGH);
    STOP_TIMER1;
  }
}

ISR(TIMER1_COMPA_vect) // runs if timer runs for 10ms
{
  clearToSend = true;
  digitalWrite(ledPin, LOW);

  STOP_TIMER1;
}


//##############################################################
void setup()                    
{ 
  Serial.begin(9600);
  debugSerial.begin(9600);
  pinMode (CS, OUTPUT); // initialize pin.
  pinMode(Rx, INPUT_PULLUP); // pin looped from Rx pin 0
  digitalWrite (CS, HIGH); // write pin high.
  pinMode(ledPin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
  pinMode(led3Pin, OUTPUT);
  digitalWrite(led2Pin, HIGH);
  digitalWrite(led3Pin, HIGH);
  delay(500);
  digitalWrite(ledPin, LOW);
  digitalWrite(led2Pin, LOW);
  digitalWrite(led3Pin, LOW);
  busClear();

} 

void loop(){
  // add your main loop code in here
  if(Serial.available() == 3){// checks the input
    for (int i = 0; i < 3; i++){
    inByte[i] = Serial.read(); // reads the input signal 
    }

         if(inByte[0] == 0x41 && inByte[1] == 0x42 && inByte[2] == 0x43){// compares the input signal to see if relivent 
         if (!responseSent) { // Check if the response has not been sent yet
    digitalWrite(led2Pin, HIGH);// lights 1st led
    	digitalWrite(led3Pin, HIGH); // lights 2nd led
    debugSerial.print(0x47); // sends an output to serial debudder (seperate pin output)


 byte msg[] = {
          0x44, 0x45, 0x46
        };
        for (int i = 0; i < sizeof msg; i++){
          Serial.write(msg[i]);
  }
  responseSent = true; // Set the flag to indicate that the response has been sent
  delay(500);
  digitalWrite(led2Pin, LOW);// turns off 1st led
    	digitalWrite(led3Pin, LOW); // turns off 2nd led
		responseSent = false; // Set the flag to indicate that the slave is ready to send next response 
  }
  else {
      // Reset the responseSent flag if the condition is not met
      responseSent = false;
    digitalWrite(led2Pin, LOW);
    digitalWrite(led3Pin, LOW);
  }
}
}
}






9 axis motion sensor code

#include "Arduino_NineAxesMotion.h"        //Contains the bridge code between the API and the Arduino Environment
#include <Wire.h>

NineAxesMotion mySensor;         //Object that for the sensor 
unsigned long lastStreamTime = 0;     //To store the last streamed time stamp
const int streamPeriod = 20;          //To stream at 50Hz without using additional timers (time period(ms) =1000/frequency(Hz))

void setup() //This code is executed once
{
  //Peripheral Initialization
  Serial.begin(9600);           //Initialize the Serial Port to view information on the Serial Monitor
  Wire.begin();                    //Initialize I2C communication to the let the library communicate with the sensor.
  //Sensor Initialization
  mySensor.initSensor();          //The I2C Address can be changed here inside this function in the library
  mySensor.setOperationMode(OPERATION_MODE_NDOF);   //Can be configured to other operation modes as desired
  mySensor.setUpdateMode(MANUAL);	//The default is AUTO. Changing to MANUAL requires calling the relevant update functions prior to calling the read functions
  //Setting to MANUAL requires fewer reads to the sensor
}

void loop() //This code is looped forever
{
  if ((millis() - lastStreamTime) >= streamPeriod)
  {
    lastStreamTime = millis();
    mySensor.updateEuler();        //Update the Euler data into the structure of the object
    mySensor.updateCalibStatus();  //Update the Calibration Status

Thankyou for any help you could provide

It does not sound like you have an upload problem or a problem with Avrdude, stk500, or Bootloader; hence your topic has been moved.

With a single master system such as LIN you need the master to ask the slaves if they have data and if so what it is. By definition a slave cannot originate a message. In a multi master system such as CAN each node becomes a master and it can put its data on the bus whenever it has it or at a predefined schedule. All nodes will receive the data and chose to use or ignore it.

Try this link on LIN: Local Interconnect Network - Wikipedia or this one: LIN Bus Explained - A Simple Intro [2023] – CSS Electronics

For CAN: CAN bus - Wikipedia or communication - Is the CAN bus protocol a master and slave protocol? - Electrical Engineering Stack Exchange

In my system I used CAN, it is a lot less software as the controller does the heavy lifting, much faster and built in error checking.

Thanks for the quick reply

I have the master set up to ask the slave for the data this is what this piece of code is for


if ((millis()-lastDebounceTime2) > debounceDelay){
    if (reading2 != button2State){
      button2State = reading2;
      if (button2State == LOW){
        byte msg[] = {
          0x47, 0x48, 0x49
        };
        for (int i = 0; i < sizeof msg; i++){
          Serial.write(msg[i]);
        }
      }
    }
  }

And this works and causes the first slave to respond with a basic identifier response however if I try to sent the variable information from the sensor alongside the identifier this is when the system only works the first time and then doesn’t work for subsequent requests for information from the master to the slave

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.