|
The serial interface is useful and good fun to implement
nevertheless if you try to integrate the basic serial functions with other
stuff, you will find that they can cause great trouble. I 'll remind you
what the problem is. You have tasks in your program that require the use
of delays, you have to keep the timing right for specific tasks. During
a delay our microcontroller is busy, it cannot handle serial communication.
If a microcontroller is busy running in a delay loop and bytes arrive
from a PC, they will be dropped. Thus, communication to be elegand has
to be interrupt driven. The code that will be presented here is mainly
the code of the AVR306 application note. Download it and go through, it
mentions something about circular buffers, isn't it?
Usually in computing arises the following issue. Two different
tasks or processes need to exchange data between each other for some reason.
Say, there is one task that generates data and another task that consumes
data. Not an issue you think, this is exactly what we did with our thermometer,
our GetT routine generated data and our Display routine consumed them
so, just run them interchangeably. Get data, display data, get data, display
data ad infinitum. Well, these tasks are synchronous, wagons of the same
train, they move with the same speed, this is why it is easy. What if
we had a task that could generate data too fast to be consumed?
We would have to introduce a kind of memory between these
tasks to solve the problem. Yes, a buffer whould be able to hold the fast
generated data for as long as the slow consumer needs them. Now, that
you have the solution we may see the problem again.
When a byte is sent via the serial port, 10 signal changes
occur at the line, 8 for the 8 bits plus 2 for the start and stop indicators.
When communcation is set to 19200 baud rate, it takes 10/19200 sec = half
msec for a byte to be communicated. We have a single register and in a
single msec two bytes will arrive. On the other hand, our micro needs
time to talk to other devices, delays may have been introduced, the question
is: How it can deal with all the incoming bytes when it is busy talking
to other devices? The answer is simple: Store data fast, deal with them
on microcontroller's free time. No, there are no micros having depression.
So here is how it looks like, there is an array that holds
incoming bytes that arrive asynchronously with the main loop and two pointers.
The Write pointer for the task that generates data, to remember where
to write to and the Read pointer for the task that consumes data, to remember
where to read from. Both pointers move right and they wrap around.

As you would expect, the Write pointer is ahead of the
Read pointer and there are data only in between these pointers. If the
Write pointer is too fast, it will manage to catch the Read pointer up
and you will get an overflow, the next byte that will arrive will fall
into the shadows. If the Read pointer is too fast, it will manage to catch
the Write pointer up and you will get an underflow, not too bad, your
buffer will just be empty.
|