 |
www.angelfire.com/dragon/letstry
cwave04 at yahoo dot com | 
|
|
|
Controlling the pins independently
Notice that writing a single byte to the parallel port affects all
its output pins. There is no direct way to control a single pin
individually. However, such a facility would be of great use for us. So
let us write some code for that.
We shall be using 3 output pins of the parallel port
for 3 different purposes.
The 3 pins may be any of
the 8 output pins. In out program we shall use the pins D4,D5 and
D7. We shall call them MOSI, SCK and RST. These are the names of
the microcontroller pins that we shall hook them up with. We
shall now learn how to control these 3 pins independently of one
another. First we shall identify each pin by its mask:
#define SCK (1<<4)
#define MOSI (1<<5)
#define RST (1<<7)
Then we can easily turn on any given pin (say SCK) without
affecting the others. for this we shall use a global variable
unsigned char outByte;
|
- To make SCK equal to 1:

outByte |= SCK;
Out32(PPORT_OUT, outByte);
|
- To make SCK equal to 0:

outByte &= ~SCK;
Out32(PPORT_OUT, outByte);
|
- To toggle SCK (we shall not need this):

outByte ^= SCK;
Out32(PPORT_OUT, outByte);
|
We shall need to do this repeatedly so it will be a good idea to
write a function

void outp() {
Out32(PPORT_OUT, outByte);
Sleep(10);
}
|
We shall soon put extra stuff inside this function.
Drawing the wave form
It will be important (but difficult) to
keep track of the pins simultaneously. For example the
microcontroller datasheet will often ask you to do something like this:
Make MOSI and SCK both 0, hold them for some time, now make SCK 1 and
then after
some time 0 again, then make MOSI 1 and hold it. While MOSI is 1,
make SCK 1, then 0, then 1 and then 0 again. Now bring MOSI down
to 0.
Does it sound mindboggling? Well, there is a visually appealing
way to present the same steps and datasheets use it
frequently. It is called a timing diagram:
To achieve this timing diagram we can use the following C code snippet:

outByte &= ~SCK;
outByte &= ~MOSI;
outp();
outByte |= SCK;
outp();
outByte &= ~SCK;
outp();
outByte |= MOSI;
outp();
outByte |= SCK;
outp();
outByte &= ~SCK;
outp();
outByte |= SCK;
outp();
outByte &= ~SCK;
outp();
outByte &= ~MOSI;
outp();
|
Do you see that it is going to difficult to keep track of things?
A little mistake would send a wrong pulse, and yet it is
difficult to locate the mistake.
Here is a useful device to automatically generate the timing
diagram on screen as the pulses are emitted.
To draw the wave forms we shall use the function
drawWave given below. Its working is pretty straight
forward. Suppose that it gets a sequence 000111000, then it will
print:
|
|
|
|___
|
|
___|
|
|
This ASCII art has one line per symbol in the
sequence. The line for a symbol is determined by both the current
symbol as well as the last symbol:
0 followed by 0 : |
0 followed by 1 : |___
1 followed by 1 : |
1 followed by 0 : ___|

#define ZO fprintf(stderr,"\t|___ ");
#define OZ fprintf(stderr,"\t ___|")
#define ZZ fprintf(stderr,"\t| ")
#define OO fprintf(stderr,"\t |")
void drawWave(int lastByte,
int currByte,
int mask) {
fprintf(stderr,"\t");
if(currByte & mask) {
if(lastByte & mask)
OO;
else
ZO;
}
else {
if(lastByte & mask)
OZ;
else
ZZ;
}
}
|
and change the outp() function as follows.

void outp(char *rem) {
int val;
Out32(PPORT_OUT, outByte);
delay();
if(!verbose) return;
fprintf(stderr,"!%4s: ",rem);
drawWave(outByte,MOSI);
drawWave(outByte,SCK);
drawWave(outByte,RST);
if(outByte & SCK)
fprintf(stderr,(val ? "\t1" : "\t0"));
fprintf(stderr,"\n");
}
|
Notice that we have a global variable called verbose. If it
is false then no visual output is prodoced. It is very important to have
such a control, otherwise you screen will be flooded by too much
diagnostic output!
To use this function effciently it will help have the following function:
void setPin(unsigned char mask, unsigned char status, char *pinName) {
if(status)
outByte |= mask;
else
outByte &= ~mask;
outp(pinName);
}
|
Now if we can produce the timing diagram given earlier by
outByte = 0;
outp("init");
setBit(MOSI,0,"MOSI");
setBit(SCK,1,"SCK");
setBit(SCK,0,"SCK");
setBit(MOSI,1,"MOSI");
setBit(SCK,1,"SCK");
setBit(SCK,0,"SCK");
setBit(MOSI,1,"MOSI");
setBit(SCK,1,"SCK");
setBit(SCK,0,"SCK");
setBit(MOSI,0,"MOSI");
|
This would now produce the following timing diagram on screen:
!init: | | |
!MOSI: | | |
!SCK : | |___ |
!SCK : | ___| |
!MOSI: |___ | |
!SCK : | |___ |
!SCK : | ___| |
!MOSI: | | |
!SCK : | |___ |
!SCK : | ___| |
!MOSI: ___| | |
It is much easier to compare
this ASCII art with the timing digram than
trying to match the code with the steps. This little trick would
prove extremely helpful later.
You may be wondering why we have put an exclamation mark at the start of
each line. This is because we may later need to print messages other than
the timing diagram on the screen. In order to see the timing diagram alone
we can then save the entire output in a file and use some filter (like
grep or find) to extract only the lines starting with an exclamation mark.
|