Cookies   I display ads to cover the expenses. See the privacy policy for more information. You can keep or reject the ads.

Video thumbnail
Anytime we send information from one computer to another whether that's over the internet or even a simple wired connection like this
There's a lot involved to make sure that the information is received correctly depending on the network or or connections involved
there are lots of different ways for errors to occur and
Often the reliability of a network depends more on detecting and correcting these errors than then avoiding them altogether
So for the next couple videos will look at some mathematical tricks that we can use to detect and even correct errors
And I'll show you how some of that math can be done really elegantly in hardware with just a handful of logic gates
but before we get into any of that in this video
I want to figure out the bare minimum of what it takes to send data from one computer to another and for computer
I'm going to use these Arduino nanos
So what's the most basic thing we can do to transmit information from one of these Arduino and receive it correctly on the other?
well, if we're gonna program one of these is a transmitter and that's going to send some data and we'll program the other is a
Receiver. Let's start by figuring out how the transmitter is going to work
well
One of the simplest ways to send data is with one data line that has two levels
If it's low that means we're sending a zero
And if it's high that means we're sending a one this is a pretty basic method and this is has a fancy name
It's called NRZ encoding which is non-return-to-zero
Which maybe sounds like kind of a weird name because it looks like it's, you know going between zero and one here
So what is this non-return-to-zero business? Well, maybe the the name makes more sense
If you look at return to zero encoding which looks like this
So there's some baseline voltage level here and then to send a zero
It pulses in the negative direction and then to send a one it pulses in the positive direction
And then between each bit it returns to zero
So that's what this return to zero
Business is all about but this is a bit more complicated right because there's three different voltage levels. So we're starting to get
outside the world of digital sort of on or off logic
So we'll stick with the NRZ encoding where logic low means zero and high means one
So let's the first arduino up and get it to transmit some data
So i'll connect it to a breadboard here
and i'll hook the 5 volt pins and the ground pin up to the power rails of the breadboard and then for energy data we
just need a single data signal that we can control to go high or low like this and so we can use any of the
Digital pins on the Arduino here. So hook up an LED so we can just monitor whichever data pin we're using
And I'll hook this led up to one of these data pins
And let's see. I think that's it's like d3
Maybe so our LEDs hooked up to today to pin d3 on the Arduino and then I'll just hook the other end of the LED
To ground with a current limiting resistor. I think this is 330. Ohms but anything that's a couple hundred
ohms ought to be fine
And so now we ought to be able to transmit data by switching pin d3 high and low
to transmit a 1 or 0 and then we should be able to see that by just looking at the LED to see if it's
On or off and then at least give us a starting place to start to see what what it looks like to transmit some data
So let's program this Arduino to transmit some data
So I'll start with the pin assignments and we're just using pin 3, so I'll call pin 3 the transmit data
And I'll set that as an output pin since we're transmitting then of course
We'll need a string telling us what message we want to transmit so go with an old classic hello world
We're going to transmit one character at a time. So to keep track of what character we're on
Let's loop from 0 through the length of our message
One byte at a time
Then the actual byte of data to transmit is going to be the character from our message at the current byte index
So each time through this loop transmit byte
Will be you know
one character from from our message we can treat this character variable like it's an 8-bit number that represents the letter since that's actually what
It is
So then to transmit each byte we'll need another loop to go through each of the eight bits
So in here we want to figure out if the particular bit we're transmitting is on or off so to do that
we'll take the
byte that we're transmitting and
Then end it with with a number that has one bit set to see if the same bit is set in the byte we're sending
so if we end with eighty hex that lets us test if the first bit is set, but we can then shift that to the
shift that to the right to test the other bits
So if bedad index is zero, which will be at the beginning of the loop
Then we won't then you know, this is shifting right to the zero places
Which is not shifting it at all and then we'll test the first bit
But then if we come through this loop the second time we're testing
Instead of bit zero we're testing bit one, then it'll shift this bit that's set in this 0x80
It'll shift that one bit to the right and then when we end it with TX byte
We'll be testing that the spit and then each time through the loop
We'll just be testing each bit on down the line through all eight bits
So at this point now we're we're looping through our message
So we're going one one byte at a time through the message and then for each byte
We're going one bit at a time through that byte and then TX bit will be
You know at this point in our code TX bit will be whatever bit we want to send
So now we just need to transmit that bit and to do that
All we need to do is set the transmit data signal high or low depending on the value of the bit
We're sending and that's pretty much it. So this will set the value of the TX data signal
That's the that's that pin three that we hooked up to the LED
It'll set that high or low based on whether the transmit bit is is a one or a zero
So this will go through our whole message and transmit our whole message a bit at a time. But unless we add some delays
It's going to transmit it so fast
We won't be able to see it do anything and also if we don't know how long each bit takes it's gonna be hard for
The receiver to know how many bits it's getting so so let's slow it down a bit
So to make it easy to adjust I'll define a target transmit rate here in bits per second and just to start out
You know relatively slow. We'll start with five bits per second and then we can use this
Transmit rate of five bits per second to add a delay right after we output the new data bit so do delay
And then transmit rate is bits per second. So a thousand divided by transmitted rate will be
Milliseconds per bit and so in this case since transmit rate is is five. So five bits per second
This will give us you know thousand divided by five will be 200 milliseconds. So in other words, we're gonna have a
Delay of 200 milliseconds between each bit that we output and if you think about it
The receiver is gonna need to know this transmitted rate in order to have any hope of interpreting this signal
But at this point let's let's give it a try
So I'll go ahead and connect the computer here to the Arduino with the USB cable and it's powered up
so let me just make sure I'm on the right port and go ahead and upload this and
It's done and and right away you can see the LED is blinking. So maybe that means it's signalling each bit. I don't know
It's kind of hard to tell
Yeah, if it's if it's actually working
right
It does seem to be outputting something
Sort of random ish looking but it's hard to hard to keep track of what it's doing if you can't kind of look at it
You know five times per second and see exactly what state it's in which is pretty hard to do just by looking at it
Although it. Looks like it's done sending the message and it's just stuck on
At least I'm assuming that's what happening is is that the last bit was a one?
But one thing we can do to check if this is working, right, you know, well, we could slow it down, you know
Maybe slow it down. So it's sending one bit every five seconds
And then that would give us more time to to actually consult a stopwatch or something and and watch it
But that's kind of a pain
So what I'm gonna do is I'm gonna hook it up to an oscilloscope that will actually graph the voltage over time
And give us you know a way to quickly see exactly what it's doing
and so now if we look at the scope what we see is we see that our
Our voltages is up here at five volts. So zeros here in the middle, and then it's two volts per division
So 2 volts four volts and then a minimal and this is almost 5 volts here
And so it's just constantly here at 5 volts and it makes sense
Right because our LED is on so we're outputting the high voltage here
So we're seeing 5 volts here
And then the way I've got this set up now is each of these divisions across this 500 milliseconds. So to two squares across
Is going to be one second and then and I can also do a single shot here that will stop it and then it'll start
Once it sees a a transition
So now if I reset the Arduino, so it reruns that program and then outputs that data again
I'll reset it and then when you see it starting to output the data
And I'll see on the scope that it's going high and low so we can actually see exactly what the LED was doing
So we take a closer
Look at this we can try to figure out if the right data is being sent now
Since each horizontal division here is 500 milliseconds. That means this is one second
Now since what we think we're doing is sending five bits per second
Well, then we ought to be able to interpret this one second interval as five bits
So it looks like we've got one zero zero one zero here
So, let's see if that matches what we expect and we're sending the message helloworld
So the first letter we're sending is a capital H. So we take a look at an ASCII table
it looks like a capital H is encoded as 72 in decimal or
1 0 0 1 0 0 0 in binary and sure enough. That's what we see though
We're sending each character as 8 bits and this is only 7 bits
So presumably we need to include an extra 0 here at the beginning
And so now this is the first byte of our message
Now one thing to notice here is that it's not all that clear how to know where our message starts
I made a video a few years ago about framing that talks about solving that particular problem
But for now, we'll just assume that we know how to find where the first bit is
So this is the first byte of our message then the next byte will just be the next eight bits
So that looks like 0 1 1 0 0 1 0 1 which represents a lowercase e?
Then the next byte looks like 0 1 1 0 1 1 0 0 which represents a lowercase L?
So sure looks like it's starting to spell out hello world
So it's great that we're able to verify that everything's working with this scope
But you know if you don't have a scope or certainly, you know
As we as we start to make this thing a little bit more complex and want to keep troubleshooting it
it's gonna be kind of a pain to have to hook that back up and
Interpret the the bits just from looking at the graph there
So what I'm going to do instead is hook this LCD panel
up to up to the Arduino and then what we can do is update this LCD screen to show exactly what data we're sending and
What we're doing?
So it'll be a little bit easier to tell what's going on
And the way this LCD works pretty easy to interface with the Arduino. There's a bunch of pins that you can connect here
But if you're not doing anything fancy with the LCD
Which which we're not planning to do we just need to connect pins d4 d5 d6 and d7
Just four of the data pins. And then there's the RS pin the register select pin and the enable pin
I think those are the only six pins that we need to connect to the Arduino and then there's a few other things we need
To hook up, you know power and things but we'll go through all that. So I'll start by disconnecting the USB here
So and then a pin pin d4 on the on the LCD, I'll just hook up to d4
You know data data pin 4 on the Arduino and I'll do the same same thing for d5
Just hook up d5 to pin 5 on the Arduino
Hook up pin 6 to pin 6 on the Arduino and hook up pin 7 to pin 7 on the Arduino
so those are those are the four data pins just D 4 5 6 & 7 that we need to hook up and we also
Need to hook up this RS pin, which is register select
And so I'll just hook that up to pin 8 on the Arduino
It doesn't really matter which pins as long as we're hooking these up to some digital pins
in the code will tell they are the the LCD which pins it's using and then finally the enable pin is
We need to hook that up as well. So I'll just hook that up to pin D 10 on the Arduino
So those are the only connections we'll need to the Arduino. But of course, we also need to give power to the LCD
So the VSS pin goes to ground and the VDD pin goes
To five volts and then you know because we're not using the full functionality of the LCD
We're only gonna be writing to it. We aren't reading from it. It has some internal memory and stuff that we're not going to use
There's this readwrite pin
So if we just tie that to ground the RW pin
Tie that to ground that just means we're always gonna be writing to it to do that
We only need four of the data lines
and then there's this pin v-0 which is used for setting the contrast and
And typically what you do with that is just hook it up to a variable resistor
I have this little potentiometer that actually came with the LCD the LCD comes with a potentiometer at least where I got it
So I'll just hook through the potentiometer to ground and then we can we can adjust that to adjust the contrast
and then finally, there's this a and K which are the anode and cathode of the backlight LED and
So we want to hook power up to that
So hook the cathode of that backlight LED to ground and then the anode we want to hook up to five volts
But of course we need a current limiting resistor. So I'll hook hook that up there
And I think that's a 330. Ohm current limiting resistor
But anything, you know a couple hundred almost ought to be fine. And so there we go
So look at this back up. We see the back light comes on
Of course
We're sending our data but nothing's gonna display on the screen because we haven't written any code to use it
But let's go and take a look at that
And for the LCD, we're just gonna use a library that does most of the work
so if you got a sketch include library manage libraries
I just want to make sure there's this liquid crystal library and make sure that's installed
so we've got that and
Then we just go up to the top and we'll include that and then I'll define the pins that we're using
So we've got LCD
you know d4 through d7 are the data pins and then LCD RS is
the the register select and we hook that to pin eight of the
Arduino and then the LCD enable pin we hook to pin nine of the Arduino and so basically before we
Do our transmit loop here
I'll just initialize the LCD and so you just define this object and then in the constructor
We're going to send in all of the pins that were that it uses
So the RS pin en pin and then LCD d4 d5 d6 and d7 the data pins
So that will initialize the LCD and then that'll give us this LCD object that we can do things with so we do begin
and
Start by telling it how big the LCD is so we have a 16 character by 2 line LCD
There's a bunch of different commands and you can you can look up online how this works
But do LCD set cursor will move the cursor. So 0 0 will be the top left
And then what I'll do is I'll just print the message that we're gonna send and so I'll just put the the message this message
Helloworld, that'll put that on the LCD and then on the second line of the screen
I'll just have it print out each bit as it sends it so go to the go to this second line
And the column will be the bit index
So that'll start it at bit 0 and then move
You know a bit 1 2 3 4 5 6 7 across and then that'll be on the second line
Which is starts at 0 so line 0 would be would be the first line. So now we're on line 1
It's the second line and then we'll print the the bit so TX bit. It's a boolean
So if it's if it's true, then we'll print a 1 on the rise
Well print a 0 so that'll that'll output that bit on the second line
And then what we'll do is after we've output the whole the whole character and we move on to the next byte
I'll clear the second line. So here clear the second line of the display
so we'll just go to 0 1 so that's the
the beginning of the second line and just print 8 spaces to just write over the
Zeros and ones that we might may have printed there on the previous character
and then the only thing I can do is the LCD has this cursor feature which will actually put a little
Underscore cursor on a character and so what we can do is we can keep track of which
Byte. We're sending by by moving the cursor along underneath the character of our message
But basically every time I print what I want to do is move my cursor back to the character that were that were
currently at working on
So I'll set the cursor to point to the byte that were they were writing on the first line and then you just say LCD
Det cursor that'll turn the cursor on and then we'd really want to turn the cursor off when we're doing other things
That's no cursor. Same thing down here
So just copy these and then when we update the display here
We'll go back and highlight the byte that we're sending and then same thing here turn the cursor off before we start
Hopefully this all makes sense
Once you see it actually working and I really want one other thing I'll do is at the very end here
I'll just turn off the data bit because you notice now it just sort of ends either on or off depending on what data we
Happen to be sending so this will just turn it off when it's done
So let's go ahead and upload this and see if it works
No, it looks like I missed a semicolon. Oh I missed a period
There we go
Yeah, it's a programming
And there it goes now, it looks like it's outputting something and you can see that that cursor moving along showing, you know
Which which character it's actually outputting and you can also see the ones and zeros
That are being printed as it as it outputs each bit
And so this should be easier to keep track of because you can see when it outputs a zero the L
You should be off and when it outputs a one and we should see the LED on so even if you don't have an oscilloscope
You know if you slow the clock down a bit
It should be fairly straightforward to
To match this up and just to verify that it's doing what we expect it to do and then once you verify that it's outputting
The right bit so you can also look and see you know, so this is you know, what is this value?
This is 32 plus 1 is 33
so the last at least the last byte it out put it was a 33 and
33 is in fact the ASCII value for an exclamation point so you can also verify that so the LCD makes it a lot easier
to just you know
both see what's going on as well as troubleshoot this so great now that we've built something that will transmit this hello world message using
NRZ encoding now, let's move on to building receiver
And so for the receiver
actually
The hardware is gonna be the same because most of the hardware here is for the LCD and and the receivers gonna have an LCD
As well so, you know
It's gonna be hooked up the exact same way and then the transmit signal instead of being a transit signal
Then we've got a receive signal but I'm still gonna hook it up in the same place. I'm gonna hook it up to d3
but now d3 will just be an input instead of an output and we'll hook the output of this over to the input here and
That'll be the input now for our receiver. But otherwise the hardware is gonna work the same way
So really the only difference is, you know
I'm using a green LED here
Just so that once I program them I could tell which ones which because there certainly could be programmed differently
But other than that the hardware is gonna be the same so I won't walk through building all of it
But it is going to be programmed completely differently. So let's go ahead and program the receiver
So for the receiver, we're just gonna start a new a new sketch and we'll start by defining the pins
and actually we can copy a bunch of that from our
Transmitter because our pin assignments are going to be pretty much the same because most of them are for the LCD
The only different one is going to be the transmit data is now going to be receive data
so pin 3 is going to be for receive data and
Then in our setup we'll want to set our pin mode
Or that rx data pin and receive data pin to be input. So this is obviously a big difference right now
Our receive data is an input pin rather than over here
We had our transmit data which was an output pin, but then beyond that we can also copy some of the LCD stuff
So a copy the include therefore liquid-crystal library
And then the initialization here is also going to be the same
Although I'm gonna put it outside the setup here so that we have a global variable because I want to be able to use this
LCD
variable from
Inside the setup as well as in the loop because we're actually gonna be doing all of our reading in the loop here
But we do need to setup the LCD in our setup and that's just the LCD 16 comma to tell it that it's a 16
Character wide by 2 rows and then, you know, our receiver also needs to keep track of our message
So we'll define a character string will just say 16 bytes for now
And this will be the the message that we're receiving
Although in our setup to start out with we'll start with that string as empty because we haven't received anything yet
And then in the loop
What we'll do is we'll add
characters to that message string as we receive them so we can have a boolean which is our received bit and that's just going to
Equal whatever value is is on the RX data signal line. So we do in our digital read for the RX data pin
That'll tell us what bit is there. But of course we want to do this at the right time
So we'll put a delay in here of 200 milliseconds because we expect to receive a bit every 200 milliseconds
And so that's pretty much it. We're receiving these bits
Of course, it's not very useful. If we don't do something with them and actually display what we're receiving
so what we need to do is we need to take this bit build a byte from that as we receive bits add it to
Our message and then output all of that to the LCD screen
so
what I'll do is I'll define a byte which is our received byte and that can start equal to 0 and then also define an
integer for a bit position
We'll start that equal to 0 as well
so that tells us which bit we're on because we're gonna be receiving these bits one at a time and
Then for every 8 bits we want to make a byte. So what we'll do is
Say if the receive bit basically means if it's a 1 so if it's on you know
if we if we if we read a high value then what we want to do is we want to take our
Rx byte and flip the the bit corresponding to our current bit position
So what we could do is we can or it with a value that has the the current bit position set
So if we do is 0 X 8 0 that'll be the first bit
But then we can shift that right to the bit position that we're on and then you know bit position
We'll just go from zero to seven
So for our first bit, you know
It'll be zero and and this will basically flip on that first bit in the receive bite
and then the next time we come through the loop we'll do is
Increment that bit position and so the next time through the loop bit position will be one
And then it'll shift this zero eight zero to the right so it'll be zero
X4 0 and then if that bit is said it'll flip that bit and then next time through the position will be two
And so on and it'll it'll flip those bits one at a time
and then what we want to do is if we come in here and
If bit position is eight, then we want to set the position back to zero
Of course
the other thing we want to do once we wrap around is set our byte back to zero because
The way we're building this byte is it starts at zero and then we just only flip on those bits where the bit is is
a 1 and
so as we receive this byte if we get to a point where we've received the whole byte, so if
If for a bit position 8 here after we've received a bit
So we've received that 8 bit then what we'll do is we'll concatenate on the byte that we got
so
take our message and concatenate on the the received byte and
that'll just be one byte that will that will stick on there and that ought to basically be it in terms of
Receiving that message and building it up
But of course we want to output stuff to the LCD so we can actually see what this is doing
We'll start by going to the the top and printing the message. So whatever our message happens to be at this point in time
We'll print that out and then we'll go to the second line and then we basically just to print each bit
So we'll do a for loop here to go through, you know, all eight bits and then we want to print that bit
so the LCD dot print and then
The receive byte but then we want to figure out if the if the bit is set
So we're going from you know bit, you know 0 through through 7 here, basically
So we want to check if that set so we can end the the byte that we've built up so far by 0 x8 0
shift right eye and that'll that'll tell us if the ithe bit in receive byte is set and
Then if it is we want to print a 1 otherwise we'll print a 0
but
You know, of course, we may not have received the whole bite yet
So we only want to print a 1 or a 0 if we've actually gotten that far through the byte
so if we say if I is
Less than our current bit position, right?
Because if we've only received four bits of the byte, we only want to print those four bits. Otherwise, I'll just print a space
Overwrite anything that might be there and so that should output
Yeah, so that should output our message on the first line
And then on the second line
It'll output the ones and zeros that we've received so far of the current byte
And then I can also set the cursor to show just where we are in the message although in this case
It'll always be just the last character that we're receiving but I'll do it anyway on the first line and then turn the cursor on
And then before we do all this mess, I'll turn the cursor off so that should be that should be everything
so this this this loop function
You know that Arduino is automatically going to call that as fast as it can so we'll you know delay 200
milliseconds and then receive that that bit use that bit to build up a byte add that byte to our message and then just sort
of print out where we are and then it'll just go back to the top of the loop and wait another 200 milliseconds and get
the next bit so let's connect our receiver and program this so plug that in and
upload
And
There it goes and you can see it's just printing zeroes, you know, which which makes sense, right?
Because this is our input and our input is just low. So it's looking at that every 200 milliseconds and every 200 milliseconds
It's low. So it reads in a zero, so we're just getting a bunch of zeros
So now let's hook it up to our transmitter and send it some data and see if we can get it to receive that correctly
and so I basically just want to hook up a wire between the data signal on the transmitter here and
the data signal on our receiver
And because our signals a voltage and a voltage only makes sense as a difference of potential
Both of these need to share the same ground potential
So in practice what that means is that our transmitter and receiver need to be connected with two wires one
For the data signal and then one for the common ground
So let's power these up and see if it works. So I'll just connect a five volt power supply
To our receiver and we see it's receiving the zeroes
And then I'll connect power to our transmitter
And we can see it's starting to receive some zeros and ones
But the message that we're getting looks to be just gibberish. So what's going on there?
Well, of course what's happening is the mitr is sending each character as eight bits and the receivers receiving those eight bits
But the eight bits aren't necessarily lined up that is to say like the eight bits that make up the h-here that we sent
You know, some of those bits might have been received, you know partway through a byte here
And so and so those bits got shifted over and so this first byte which is this weird little character here
Might have just been some of the the bits at the end of the H and then the next character which looks like a blank
might have been
You know the rest of the character of the bits from the H and then some of the dips from the e and so forth
And so if it doesn't line up, you know, obviously we're not going to receive the same thing
So what we can do is it you're trying to get these things in sync we can reset both of them at the same time
And let's see if we could get it to be synched up
There's the H so it looks like we're doing okay there and now it looks like it's working
But what happened here it looks like we were receiving things just fine but then
It looks like things something went off the rails. So what's going on there?
Well, if we look back at the code, there is there is something that might be a problem which is when we're transmitting
Let's see here. We are transmitting
we've got this for loop and we're just going through each bit and
We're writing and updating the LCD and then delaying this is going to be 200 milliseconds
When we're reading we're delaying 200 milliseconds
And then we're we're reading the the bit and then we're also updating the LCD
But we're actually doing a little bit more processing here we have this for loop
We're printing a little bit more here, and we're also moving the cursor and we're printing the whole binary. Whereas here
We're only printing one bit. We're moving the cursor. We're printing one bit and then we're moving the cursor back
But we're doing less here when we transmit and so even though our delay statement is the same, you know
This is going to be 200 milliseconds and then our delight delight statement when we receive is 200 milliseconds
There's some extra delay in our receiver because we're doing a little bit of extra processing
So if we reduce this delay
Instead of 200 let's make that like 198 maybe
So let's give that a try. I'll reprogram the receiver so plug in the USB here and hit upload
And there we go, so now we've got the slower slightly slower speed here, so maybe this will be better in sync
So let's reset both of them and give it a try
So far so good
Huh and looks like that's not quite enough. I don't know if I'm too slow or too fast. Let's try one 96
upload that
Okay, now let's just reset both of these and see if that's better
Well, it certainly looks a lot better this is a lot more promising right? Oh
But
Almost what happened here. So this last thing it's last character instead of an exclamation point we got a quote
We almost made it to the end
So what's going on here?
and the reality is is actually this delay thing is is really a bad way to try to synchronize these things because you
Know we really don't know how much time this processing is going to take so we could tweak this and maybe get a little bit
Better and get a little bit longer message
But this is hardly what I would call a reliable
Means of communication here because this is only going to work for a little bit while these things stay in sync
but eventually they're going to get out of sync so
Delay, really isn't the right way to ensure that we're reading at a fixed time interval
Now there are better ways with arduino to do that
So one would be using timer interrupts and with timer interrupts
we can have the arduino run code exactly over 200 milliseconds so we could have the transmitter transmit a bit exactly every 200 milliseconds and
We could have the receiver read input exactly every 200 milliseconds and when I say exactly every 200 milliseconds
I mean as exact as the Arduino can possibly get
Using the clock oscillator that that's on the Arduino, which is this little ceramic resonator
Which is this little thing here that's gonna isolate at 16 megahertz
So how accurate is the clock oscillator on the arduino?
Because that's going to tell us the best case we can possibly do in terms of getting the timing synchronized between both of these
We can actually look at that by hooking a our oscilloscope probe up to it
And then if we look at the oscilloscope, we can see well, here's our 16 megahertz clock looks pretty good
But let's actually measure to see how close it is to 16 megahertz. So we've got our frequency here turn that on to channel 1
And it looks like it's fifteen point nine seven nine
megahertz so not exactly 16 megahertz
And I wouldn't expect it to be exactly 16 megahertz because these ceramic resonators that are on these Arduino
Nana's aren't the most precise clock source in the world
But the real question is how different is the clock on the receiver here from the clock on the transmitter?
So let's look up another probe to the clock on the transmitter just to compare and so now that's hooked up
Let's turn on channel 2 and compare
It's already we can see we're getting something here, but it's not in sync with channel 1 which I wouldn't expect
You know, there's no reason to expect these clocks to be in sync, you know, we can change our trigger here
So if we trigger on channel 2
We can have channel 2 in sync and then channel 1 goes out of sync
But you know, so that suggests that they are different frequencies, but let's actually measure and see how different they are
So we go back to our measurement frequency counter here. So channel 1 was fifteen point nine seven nine megahertz and
channel two is
sixteen point zero three mega or zero zero three megahertz
So they are different but how big a difference is that?
And and does it matter for what we're trying to do in terms of transmitting data from one to the other
Well, if you look at the difference here it's about
0.15 percent. So how big a deal is 0.15 percent?
0.15 percent another way to look at that if you if you take one over 0.15 percent you you get about
667 so what does that mean? That means if the transmitters the faster one, which it is then for every
667 bits that the transmitter sends the receiver is only going to try to receive
666 bits so that means we're gonna get out of sync in under 666 bits. So that's obviously no good
So it looks like unfortunately we're out of luck
If we want to use this NRZ encoding just by itself, you know, maybe better clocks would help a little bit
But they're only gonna get you so far and actually as the bitrate is faster as we send more data
faster than the importance of having those clocks synchronized becomes even more important because the shorter the time interval between
The bits the more important it is for both sides of this communication to agree on how how long that interval is
So trying to improve the clocks is kind of a dead end unless you go for atomic clocks or something, you know completely unreasonable
but what is very easy and very common is to send the data like this, but then also send a clock so
Essentially, we'd send two signals that would look something like this
We'd have the data which looks just like our NRZ encoding
In fact, it's exactly the same
but then we have a second signal that we would send which would have a clock and then the clock would just pulse on and
off and then the other
Receiver could then use that clock to figure out when to read the data
and so then it doesn't matter if the internal oscillator if those are off by a little bit because if the transmitter is sending its
own clock along with the data then you can just recover that clock and read the data using that clock and this is actually pretty
easy to implement
the only downside is that instead of having one data signal and then of course the ground will have two data signals or while a
Data signal on a clock but two signals plus the ground
So it does take a few more wires to transmit this way, but for our little setup here, that's just fine
So for a clock signal that's just going to be another pin coming off for Arduino here
So, let's see if we're using pin three for our data then
We're using pin four five six seven eight for the LCD now
Let's use pin two for the clock and I'll just hook that up to another LED over here
Because this is just going to be a second signal that we're gonna send across from our transmitter to our receiver
And just like before I'll connect that led to ground through a current limiting resistor. Again. That's a 330
Ohm resistor and same thing here on the receiver
I'll connect pin two in the same way to an LED down here and
Finally instead of just these two wires connecting data and ground. We're gonna need three wires
connecting clock data and ground
so hookup clock data and ground on our transmitter and then the other end here I'll connect clock data and ground on our receiver and
So, there we go
Now we have our new clock signal and of course a new connection between the transmitter and receiver
Because we now need a third wire for our clock
So now let's go ahead and program it. So now to add the code to send the clock
I'll start with the transmitter
We've got another pin assignment here transmitted clock is on pin two
We'll want to set that to an output pin
So pin 2 will be an output pin on our transmitter and then when we transmit here
We're out putting our data bit and then we basically want to then pulse our clock. So I'll put the clock
And then low so once our bit is set on the data line
Then our clock goes high and then low to signal that we've got a new bit there
But I am going to tweak the timing a little bit here. So what I want to do is
Instead of having our whole delay down here at the end
What I'll do is I'll put a delay right after we set the bit and I will delay for half of our delay time then
Then I'll update the LCD
Then we'll pulse the clock and then actually while we're pulsing the clock the clock will go high
For the other half of our delay and then go low. So what we've got here is
We're transmitting our data byte or bit rather one bit at a time here
We're transmitting our data bit
And then we're delaying for half of our bit time then updating the LCD to say that we're sending the bit
And we do that right before we actually pulsed the clock high which is which kind of moment that the bit is
Is being sent if you will and we pulsed the clock high
Then wait for the other half of the the bit time and then the clock goes low. So that'll be the transmitter
Let's upload that and give that a try
And there it goes and
You know we can see
It looks like it's transmitting hello world and now we can obviously see the clock is flashing
and so every time this flashes that indicates that we're sending a bit and
Just so we're clear what that looks like. We can hook this scope up to that as well
So look one probe up to our clock line and then hook the other up to our data line
So the scope hooked up we can see both of them are currently 0, but if we reset
actually, what I'll do is I'll single-shot this and then
reset
1 starts transmitting again and there we go
We're capturing and you can see the clock on the top and then the data on the bottom
If we take a closer, look there's a couple things I'll point out first
it's easy to pick out each bit of data just by looking at the points where the clock goes from low to high the
Receiver doesn't necessarily need to know anything about the expected timing. In fact, the other thing I'll point out
Is that while the clock looks pretty good on the left here where it's lined up with these 500 millisecond grid lines
There's another of a skew that we get over to the right side here and you can see the clock doesn't even line up with
Those 500 millisecond grid lines anymore
So we're definitely not doing a great job of hitting our target rate of five bits per second, but that's okay
we're sending our less than perfect clock and it's the rising edges of that clock that matter and
as long as the data bits always line up with the clock then it's okay if the clock drifts a little bit and this is
A really important aspect of engineering to design systems that can deal with things going wrong or or deal with imperfections like this
so in this case
It's timing and you know because our clock doesn't have to be perfect we can get away with cheaper or less accurate timing hardware
but of course at this point
we're still not using the clock for receiving so we still may
Get some of these errors like this if we're not perfectly synced up
So let's take a look at what we can do about that
So if we come over to the receiver here, you know currently we've got this loop where we're delaying, you know
Approximately the right amount of time
Between bits and then reading and then reading the bit
But what we want to do is we want to read the bit
When the clock transitions high and there's actually a really cool way to do that with your do we know which is using interrupts?
So the Arduino supports these pin interrupts
basically
the way that it works is you define a function that you want to have called when a pin transitions so we can make a
Function called on clock pulse and then what we can do is in the setup here. We can attach an interrupt
Yeah
And the way this works is you have to pass in the the interrupt
Number which you can get using this digital pin to interrupt function and then you pass the pin number
That'll give us the interrupt number that we want to attach
And then you you give it the function name that you wanted to call
So if we say on clock pulse then that's going to call this on clock pulse function
When something happens with our received clock and then we just need to tell it what we're interested in
So in this case we can say rising and that means when the receive clock signal rises that is it goes from 0 to 1
Then call this function
And then of course in this function, that's when we read our bit. So basically we can take all of this stuff
Well, maybe not the LCD stuff, but we can take all this stuff
We read that bit and move it into this on clock pulse function
The basically this says you know, essentially we won't do anything in our loop we get rid of this delay
I suppose we won't really do anything in our loop maybe still update the LCD there
But we won't read any data in the loop
what we'll do is we'll only read data in this on clock pulse function and that function is only going to get called when the
the clock pulses
so in this on clock pulse function
We'll do all this all this stuff we're doing before so we'll say well read our RX bit received a bit
We'll update our bit position if we're if we're at the end of a bite
Otherwise, we'll update our bite
And increment our bit position and then if we've gotten to the end of the bite
Then we'll update our message and add the new the new bite to it
So then what do we want to do in the loop?
Well, I guess we still want to update the LCD, but we don't want to just update it constantly. So what I can do is
Create a variable. I'll call it
LCD update out LCD and
Start off as true, and then the loop we can say if update LCD is true then update the LCD
so basically in our loop we're only going to do anything if this update LCD saying is true and if it is then we're gonna
Well update the LCD
But first thing we'll do is set that to false
So if update LCD is true
then we'll set it to false and then update the LCD and then at that point our loop isn't going to do anything and then
We want to change this to true when we receive a bit. So here
in our
in our on clock pulse when we get that clock pulse will receive the bit will update our
Bit position will update our message will update a received byte
And then we'll say update LCD equals true and then the next time through the loop
It'll it'll update the LCD
We don't want to actually update the LCD in this clock pulse because this is an interrupt Handler and in an interrupt handler
You want to keep it pretty tight?
You don't want to waste a bunch of time in the interrupt handler
But also the LCD library might might actually make use of interrupts
And so if we're calling it from inside an interrupt handler, then interrupts will be disabled and it may not work
so
it's best to
To not do very much inside an interrupt handler to sort of update your data structures and then set some flag that we can then
Use in our loop
One other little gotcha with interrupt handlers is any of the variables that we're modifying in the interrupt handler?
I'll set this volatile keyword on here and that basically just tells the compiler
You know
don't try to do too much optimization with these things because there's an interrupt handler that might be mucking around with them when when
when you don't suspect because the compiler doesn't know exactly when this interrupt handler might get called because you know
We don't really know until the hardware actually calls it. So anyway, that should that should do it
Let me connect the USB to the receiver there and upload this code
Our X clock is not declared
No
Thought I define that
Guess not and there goes and so there we go. And the first thing you'll notice is that we're not receiving those zeros anymore
So remember before every 200 milliseconds would look at the data signal and if it was low
You know would say well must be receiving a zero and and we just, you know receive a zero every 200 milliseconds
But now it's actually waiting for that clock so we don't see just printing those zeros like it was before
The other nice thing about that is that it's also not only waiting for the clock to receive a bit
It's it's waiting for the clock to receive the first bit
And so we don't worry about keeping them in sync by resetting both of them at exactly the same time
So it's already just waiting for that first bit of the first byte
So if we just reset the transmitter
then as soon as it starts sending it starts receiving a bite and the byte is always going to be aligned just just perfectly and
So now we see we're receiving the message just fine. And in fact, we should continue to receive the message just fine
I wouldn't expect any problems now that we have the clock in there to keep everything in sync and so we can continue we can
just reset this and reset the transmitter whenever we're ready and
Retransmit that signal and we should be able to do this all day
We should have no problems transmitting this because we've got the clock will keep everything in sync
Doesn't matter if the timing is a little bit off we really should have no problems with this at all
However, there are still things that could go wrong
So it's always possible that an error
introduces itself into the transmission and that's the case any time that you have any kind of communication network is always a chance for
Errors to crop up but what happened here?
Well, I did something a little bit sneaky, um the connection between the transmitter and receiver
I have this little button
In here that I can push that interrupts the data signal and so I can actually cause it to miss bits
By pushing this and so I had that off frame and and just introduced a little bit of a bit error
Right there in the middle of the message and you might think well, that's not very realistic
I mean how often you're sending a message where someone has a you know a way to
Interrupt the message while you're sending it
But the reality is any communication system is susceptible to errors and in fact any communication channel has a theoretical maximum
Bandwidth and particularly as the bitrate gets close to that theoretical maximum
then the channel becomes more susceptible to noise and
Noise can cause errors where you miss a bit or something something is off a little bit
And so I put this switch here, obviously when we're sending five bits per second over just a short distance
We're over not anywhere near close to the theoretical maximum here
But I put this switch here to simulate that because you know in high speed or wireless networks, things like that
it's very common to get errors and what I want to talk about in the next video is how do you detect those errors because
what happened here is the transmitter sent a series of bits and the receiver actually received a different series of bits and
You know
I mean you can look at this and say well that's probably not the message that we intended to send
But as the receiver, how do you know that you know?
This is certainly a representation of the bits that the receiver received. It just happens that
Interrupted some of those bits and so we got a little bit weird a bit of a weird message
But is there a way to tell with you know some amount of certainty on the receiver side here that yeah
We got these bits, but the bits were wrong
well
it turns out there are a number of different ways of detecting that and figuring that out and and knowing
That maybe you need to ask the transmitter to retransmit the message or even knowing how to reconstruct the correct message with
Incomplete data and so that's what I'll be covering in the next video. So this video was really just kind of a lab setup
I guess where we're just setting this up
particularly with this ability to introduce these errors so that we can
explore a little bit deeper in the next video how to
How to detect those errors and perhaps even how to correct them in future videos. I
Want to thank my supporters on patreon who are helping make more of these videos possible. I particularly appreciated their feedback on this video
Specifically I asked them if I was hitting the right balance between taking the time to walk through every step of the process
While keeping it engaging the overwhelming feedback was very positive
But I love more feedback if you've got a different perspective and if you'd like consider supporting me on patreon if you're able if not
That's totally cool
I know there are a number of people who support this work
Explicitly to make sure that it's free for others who aren't able to support it directly. So definitely an extra. Thank you to them