2 wire bus without libary

Hello everyone, i'm a beginner at Arduino programming and have a question about a project=).
At second, I know that there are some libary's like wire.h which i can use to do the same, but I like to
write my own libary and I want to keep the code as small as possible. I only wish for normal answers and not something like: "it's stupid" or "use a libary...".

Okay, i've tried a long time to get this little sketch running, but no matter what I try, it still get the wrong numbers. The sketch should trannsmit a decimal number over 2 wires to an other Atmelchip (Atmega328P / Attiny84 /Attiny85 / Mega2560). In that case I use two Arduino UNO, in the future I want to build up a RTC with an Attiny85 (the code is already written...=). Because of the PCINT I can use nearly every pin I want, so thats the big advantage.
I thought it's because of bouncing at the on/off cycle. So I used my oscilloscop to see it, but there was nearly nothing. I added a bouncetime to be sure, but nothing changed. I made it slower and slower, but I always got the wrong numbers. Maybe the bug is in the calculation, because if I reset the transmitter I got diffrent numbers each time, but if I reset the receiver I got always the same.
I think its the ISR, but I don't know why.

Has anyone an idea?

PS: please correct my language if you want =)

Serielle_Uebertragung_Empfang.ino (1.8 KB)

Serielle_Uebertragung_Sender.ino (1.08 KB)

CNElectronics:
"it's stupid" or "use a libary...".

I'm sorry to say it, but it is even worse.

You are using low level writing to registers. When you are new to Arduino, you should start with the higher level Arduino functions.
You could start for example with the real interrupts and the function attachInterrupt().

Using Serial.println() in a ISR is not good. Using a delay in a ISR can't be right.

The Arduino has macro's for bits. You could write the bits instead of using an array and converting it.

Is there something to detect the start of a new databyte ?

Is the data always going in one direction ? That means it is a software SPI bus ?

Thank you Koepel for your answer :slight_smile:
Right, its a good idea to use the attachInterrupt() and I will try it , but I think it doesn't solve the problem. I only use the Serialmonitor to see which Bit was send and which was received, but I don't like it neither. At the reset of the transmitter, I get normaly more ones I want. For example: 15 in binary looks like: B00001111 but I receive a 31 --> B00011111 and after a few cycles of restart, I get different numbers (I told the transmitter to send only 15...), first 31, then 31, 63, 62, 62, I don't know why. I've set the delay to 1000ms but nothing changed

I'm new at programming with the Arduino IDE and don't know really much functions and methodes, but I know the registers a little bit and how to use bitMath and portmanipulation, for example its not necessary to use the lowPower libary or in that case the PinCahngeInt. I try to use as little as possible libarys in my sketches, only for bigger projects with LCDs or WiFi modules. It's only an experiment to get more knowledge about bus systems.=)

Can you explain what bitWrite() means, I don't understand...

The idea behind this sketch was the SN74HC595. You write data to one wire and push it into the register with the second wire. The latch in my example is the "8" -bit long number (its like UART --> baudrate = 9600, you have to set transmitter and receiver to the same speed)

Yes, the Data always going in one direction and right, it is a mix of SPI and UART.

The SPI bus has a chip select, when that becomes active the data and clock starts.

Your code is a little confusing to me. I think that once the bits are out of sync, there is no way to make them go back into sync.

The 595 can be used with the function shiftOut(): https://www.arduino.cc/en/Tutorial/ShiftOut.

bitWrite() can set a bit in a variable to 0 or 1.
Did you read the reference ?
See the "Bits and Bytes" section: Arduino Reference - Arduino Reference

To stay in sync you need a start signal. Or you need a special protocol for the bits, perhaps even with a checksum.
To avoid specific timing, you need two handshake signals.

Right, but I thought I don't need a third wire because I using an Interrupt. So each time the ISR is called, its something like the next clock cycle. :confused:

I would try the shiftOut() and a third line :slight_smile:

Yes, I read the reference, but not complete, only these functions I needed in a sketch or which I understand at reading (I'm not from England or USA :wink: )

Some times I need new thoughts to move forward. I watched a few videos today about SPI, I²C and UART, maybe it will help me to understand how I can get my sketch running :slight_smile:

I would try it another way.

Thanks

When adding a third wire for acknowledge or handshake, then it is possible.

The next code is probably what you wanted to make.
Let me know if you tried it.

With Arduino Uno boards and Arduino IDE 1.8.5.

Transmitter

// Communication with 3 wires, Transmitter
// ---------------------------------------
// 
// One way communication between two Arduino boards.
//
// Using standard Arduino functions.
//
// It uses 3 pins on each board:
//   CLOCK  3  output   ------->  input   3  rising edge is clock signal
//   DATA   4  output   ------->  input   4
//   ACK    5  input    <-------  output  5  rising edge is acknowledge (handshake)
//
// They are digital signals.
// The pins don't change between input and output and no pullup resistors are needed.
//
// Transmit a bit:
//   Set databit at DATA.
//   Make CLOCK high.
//   Wait for ACK to become high.
//   Make CLOCK low
//   Wait for ACK to become low.
//
//


const int clockPin = 3;
const int dataPin = 4;
const int ackPin = 5;

const unsigned long timeout = 1000;  // timeout in ms

byte counter;


void setup()
{
  Serial.begin( 9600);
  
  Serial.println();
  Serial.println("One way communication. Transmitter");

  pinMode( clockPin, OUTPUT);
  pinMode( dataPin, OUTPUT);
  pinMode( ackPin, INPUT);

  delay( 1000);  // receiver needs to start up
}


void loop()
{
  Serial.print( "Sending ");
  Serial.print( counter);
  Serial.print( " ... ");
  bool success = Send( counter);
  if( !success)
    Serial.println( "Fail !, timeout !");
  Serial.println( "done.");
  
  counter++;
  
  delay( 1000);
}


// Returns false when there was a timeout.
bool Send( byte data)
{
  bool success = true;


  for( int i=0; i<8 && success; i++)
  {
    unsigned long previousMillis = millis();
    while( digitalRead( ackPin) == HIGH)
    {
      if( millis() - previousMillis >= timeout)
      {
        success = false;
        break;
      }
    }

    
    if( bitRead( data, i) == 1)
      digitalWrite( dataPin, HIGH);
    else
      digitalWrite( dataPin, LOW);


    digitalWrite( clockPin, HIGH);

    previousMillis = millis();
    while( digitalRead( ackPin) == LOW)
    {
      if( millis() - previousMillis >= timeout)
      {
        success = false;
        break;
      }
    }
    
    digitalWrite( clockPin, LOW);
  }
  return( success);
}

Receiver

// Communication with 3 wires, Receiver
// ------------------------------------


const int clockPin = 3;
const int dataPin = 4;
const int ackPin = 5;

const unsigned long timeout = 5000;  // 5 seconds timeout

volatile byte data;
volatile bool newData;


void setup()
{
  Serial.begin( 9600);
  Serial.println();
  Serial.println("One way communication. Receiver");

  pinMode( clockPin, INPUT);
  pinMode( dataPin, INPUT);
  pinMode( ackPin, OUTPUT);

  attachInterrupt( digitalPinToInterrupt( clockPin), receiveISR, CHANGE);
}


void loop()
{
  if( newData)
  {
    Serial.println( data);
    newData = false;
  }
}

void receiveISR()
{
  static byte _index = 0;
  static byte _incoming;

  if( digitalRead( clockPin) == HIGH)
  {
    int x = digitalRead( dataPin);
    int y;
    if( x == HIGH)
      y = 1;
    else
      y = 0;
    bitWrite( _incoming, _index, y);

    _index++;
    if( _index >= 8)
    {
      data = _incoming;
      newData = true;
      _index = 0;
    }
    
    digitalWrite( ackPin, HIGH);
  }
  else
  {
    digitalWrite( ackPin, LOW);
  }
}

A bytes takes about 0.5ms, which can be compared to a serial baudrate of 19200. That is not very fast, but every bit requires an acknowledge from the receiver.

Warning: the two sketches above get 0 out of 10 points from me. They are useless, because there is no mark for the beginning of a byte. They could get out of sync. In real life they can not be used.

You wanted to avoid UART or I2C/TWI hardware and make something simple with two wires. That is not possible, well, at least not reliable. With three wires it will work, but the sketches above are not enough. Do you see where this is going ?

Now that I think of it, I could alter my sketch. For example without interrupt but with the acknowledge/handshake line. Or for example with the interrupt but without the acknowledge line. Then I would be closer to what you have. However, using a delay and hoping that the Receiver captured it in a interrupt is not very reliable. Some libraries (OneWire, DHT, NeoPixel) turn off the interrupts for some time.