Interfacing with Allegro Serial-Input Latches - Part 1

Copyright, Peter H. Anderson
Dept of Electrical Engineering
Morgan State University, Baltimore, MD, Oct, 96

Introduction.

This section deals with interfacing the parallel port with serial latches. Serial latches provide a simple and inexpensive technique for extending the parallel ports output capability to virtually any number of output bits.

Typical devices include the following. Parenthetical entries are single unit prices from Newark Electronics. All devices are manufactured by Allegro MicroSytems. Obtaining Allegro devices is discussed in another section.

UCN5841 - 8-bit, Open Collector Output, 500 mA Sink.

A typical arrangement using the UCN5841 8-bit is shown in Figure #1. Note, however, the general concepts are applicable to the other devices.

All of these devices consist of a n-bit shift register and a corresponding n-bit latch with various types of driver stages to interface with peripherals. Thus, the interface consists of three signal leads; Data, Clock and Strobe. Data appearing on the S erial_In is transferred into the least significant bit of the shift register and all bits are shifted right on a rising edge of the clock pulse. Once the 8-bit shift register has been loaded, the data in the shift register is transferred to the latch usi ng the Strobe input.

With the Strobe input in a low state the latches remain in their previous states. When at logic one, the latches follow the shift register bits. Thus, to transfer the contents of the shift register to latches, the shift register is first serially loaded with the Strobe input in a low state. It is then brought high causing the shift register data to be transferred to the latch, and then low to again isolate the latch from the shift register.

In addition, with the 5841, another input, /Output Enable (/OE) is provided. When at logic one, all outputs are at logic one. In Figure #1, I hardwired this to a logic zero. However, a parallel port output bit; e.g., Data_7, could be used such that d uring normal operation, the logic state is zero and all peripherals are enabled. This then permits all peripherals to be turned off by simply bringing Data_7 to a logic one. An important point is that when power is removed from the PC, the Data_7 output will be open, thus appearing as a logic one and all peripherals will then be turned off.

Note that the drivers are inverting. That is, a TTL logic one loaded into the shift register and later transferred to the latch, causes the driver corresponding output transistor to turn on, causing "near" ground to appear on the output.

The nature of the driver output is shown in Figure #2. The maximum V_ce_sat is 1.1 to 1.6 Volts for sink currents of 100 to 350 mA respectively. Note that an internal flyback diode is provided for suppressing L di/dt transients caused by turning off suc h inductive devices as motors and solenoids.

Cascading Sections.

The 5841 may be cascaded to implement a 16, 24, 32, etc bit serial latch. This is discussed in another section.

Programs.

Program SERIAL_1.C illustrates how a single byte may be output to the serial latch. In program SERIAL_2.C this has been extended to show how to drive two stepping motors as shown in Figure #3.

Program SERIAL_1.C.

The program outputs the value 0xaa to the serial latch (line 16) and holds it for five seconds. The least significant bit is then winked 10 times (lines 19 - 27).

In function ser_out() (line 29), the pattern is output to the shift register, one bit at a time, starting with the most significant bit (lines 35-39). Finally, strobe is brought high and then low (line 41).

/*
** Program SERIAL_1.C
**
** Illustrates how to write a value to an 8-bit serial latch
**
** Peter H. Anderson, MSU, Oct 5, '96
*/

#include <stdio.h>                                            /* 1 */
#include <dos.h>                                              /* 2 */
                                                              /* 3 */
#define DATA 0x03bc                                           /* 4 */
                                                              /* 5 */
void ser_out(int d);                                          /* 6 */
void clock(int bit);                                          /* 7 */
void latch(void);                                             /* 8 */
                                                              /* 9 */
void main(void)                                               /* 10 */
{                                                             /* 11 */
   int n, value;                                              /* 12 */
                                                              /* 13 */
    value = 0xaa; /* value to write to serial latch*/         /* 14 */
                                                              /* 15 */
   ser_out(value);  /* output it */                           /* 16 */
   delay(5000); /* pause to admire */                         /* 17 */
                                                              /* 18 */
   for (n=0; n<10; n++)                                       /* 19 */
   /* now wink least sig bit on and off 10 times */           /* 20 */
   {                                                          /* 21 */
      value = value^0x01;                                     /* 22 */
      delay(1000);                                            /* 23 */
      value = value^0x01;                                     /* 24 */
      delay(1000);                                            /* 25 */
   }                                                          /* 26 */
}                                                             /* 27 */
                                                              /* 28 */
void ser_out(int d)                                           /* 29 */
{                                                             /* 30 */
   int n, bit;                                                /* 31 */
   outportb(DATA, 0x00);  /* strobe and clock set to 0 */     /* 32 */
                                                              /* 33 */
   /* output each bit, most significant bit first */          /* 34 */
   for (n=7; n>=0; n--)                                       /* 35 */
   {                                                          /* 36 */
      bit = (d >> n) & 0x01;                                  /* 37 */
      clock(bit);                                             /* 38 */
   }                                                          /* 39 */
                                                              /* 40 */
   latch();                                                   /* 41 */
}                                                             /* 42 */
                                                              /* 43 */
void latch(void)                                              /* 44 */
{                                                             /* 45 */
   outportb(DATA, 0x04);  /* bring strobe high */             /* 46 */
   outportb(DATA, 0x00);  /* and low */                       /* 47 */
}                                                             /* 48 */
                                                              /* 49 */
void clock(int bit)                                           /* 50 */
/* bring least sig bit high and then low */                   /* 51 */
{                                                             /* 52 */
   outportb(DATA, (bit << 1));                                /* 53 */
   outportb(DATA, (bit << 1) | 0x01);                         /* 54 */
   outportb(DATA, (bit << 1));                                /* 55 */
}                                                             /* 56 */

Program SERIAL_2.C.

In program SERIAL_2.C, functions ser_out(), clock() and latch() are the same as in the previous program. That is, the data passed to function ser_out() is serially output to the 8-bit serial latch.

Note that in Figure #3, the low nibble controls motor_0 and the high nibble controls motor_1. Thus, in controlling two stepping motor, the new pattern for one is calculated and logically ored with the current pattern for the other and the result is outpu t using the ser_out() function.

An array of the eight stepping motor states is declared globally (line 20). Further, an array consisting of the current index for each motor is declared globally (line 22). Thus, the current stepping motor pattern for stepping motor 0 is patts[index[0]] and for motor 1, it is patts[index[1]]. Calculating the new pattern for a selected motor is simply a matter of either incrementing (or decrementing) the appropriate index.

In function turn_motor (line 34), the identified motor is advanced one step with a delay of length "speed" between steps, and this is repeated until the specified time duration is exceeded. The timing of the duration is implemented using the ftime() func tion which is discussed in another section dealing with control of a DC motor using an "H" Bridge.

In function one_step() (line 49), the index corresponding to the identified motor is either incremented (0, 1, 2, 3, 4, 5, 6, 7, 0) or decremented (0, 7, 6, 5, 4, etc) depending on the specified direction. Thus, the new pattern for the specified motor is calculated. The two stepping motor patterns are then logically ored together (line 67) and this value is passed to function ser_out().

In debugging the routine, I used the #ifdef (line 79) and #endif precompiler directives to insert printf statements in function ser_out(). In writing this section, I decided to leave this in as an example of how to quickly test code using the #ifdef, #i fndef, #else and #endif precompiler directives. Note that this test code can easily be removed in the final product by simply undefining TEST in line 8.

/*
** Program SERIAL_2.C
**
** Illustrates how to control two stepping motors on one serial latch
**
** Peter H. Anderson, MSU, Oct 5, '96
*/

#include <stdio.h>                                            /* 1 */
#include <dos.h>                                              /* 2 */
#include <conio.h>                                            /* 3 */
#include <sys\timeb.h>                                        /* 4 */
                                                              /* 5 */
#define DATA 0x03bc                                           /* 6 */
                                                              /* 7 */
#define TEST                                                  /* 8 */
                                                              /* 9 */
#define CW 0                                                  /* 10 */
#define CCW 1                                                 /* 11 */
                                                              /* 12 */
void turn_motor(int motor, int dir, int speed, int duration   /* 13 */
);                                                            /* 14 */
void one_step(int motor, int dir);                            /* 15 */
void ser_out(int d);                                          /* 16 */
void clock(int bit);                                          /* 17 */
void latch(void);                                             /* 18 */
                                                              /* 19 */
int patts[8] = {0x01, 0x03, 0x02, 0x06, 0x04, 0x0c, 0x08, 0   /* 20 */
x09};                                                         /* 21 */
int index[2] = {0x00, 0x00};                                  /* 22 */
                                                              /* 23 */
int value=0x00;                                               /* 24 */
                                                              /* 25 */
void main(void)                                               /* 26 */
{                                                             /* 27 */
   clrscr();                                                  /* 28 */
   turn_motor(0, CW, 500, 1000);                              /* 29 */
   turn_motor(1, CCW, 500, 1000);                             /* 30 */
                                                              /* 31 */
}                                                             /* 32 */
                                                              /* 33 */
void turn_motor(int motor, int dir, int speed, int duration   /* 34 */
)                                                             /* 35 */
{                                                             /* 36 */
   struct timeb t_start, t_current;                           /* 37 */
   ftime(&t_start);                                           /* 38 */
   do                                                         /* 39 */
   {                                                          /* 40 */
      one_step(motor, dir);                                   /* 41 */
      delay(speed);                                           /* 42 */
      ftime(&t_current);                                      /* 43 */
   }                                                          /* 44 */
   while (1000 * (t_current.time - t_start.time)              /* 45 */
         + (t_current.millitm - t_start.millitm) < duration); /* 46 */
}                                                             /* 47 */
                                                              /* 48 */
void one_step(int motor, int dir)                             /* 49 */
{                                                             /* 50 */
   if(dir == CW)                                              /* 51 */
   {                                                          /* 52 */
      ++(index[motor]);                                       /* 53 */
      if (index[motor] == 8)                                  /* 54 */
       {                                                      /* 55 */
          index[motor] = 0;                                   /* 56 */
       }                                                      /* 57 */
   }                                                          /* 58 */
   else                                                       /* 59 */
   {                                                          /* 60 */
      --(index[motor]);                                       /* 61 */
      if (index[motor] < 0)                                   /* 62 */
      {                                                       /* 63 */
         index[motor] = 7;                                    /* 64 */
      }                                                       /* 65 */
   }                                                          /* 66 */
   ser_out((patts[index[1]] << 4) | (patts[index[0]]));       /* 67 */
}                                                             /* 68 */
                                                              /* 69 */
void ser_out(int d)                                           /* 70 */
{                                                             /* 71 */
   int n, bit;                                                /* 72 */
   outportb(DATA, 0x00);  /* strobe and clock set to 0 */     /* 73 */
                                                              /* 74 */
   /* output each bit, most significant bit first */          /* 75 */
   for (n=7; n>=0; n--)                                       /* 76 */
   {                                                          /* 77 */
      bit = (d >> n) & 0x01;                                  /* 78 */
#ifdef TEST                                                   /* 79 */
      if (bit == 0)                                           /* 80 */
      {                                                       /* 81 */
         printf("0 ");                                        /* 82 */
      }                                                       /* 83 */
      else                                                    /* 84 */
      {                                                       /* 85 */
         printf("1 ");                                        /* 86 */
      }                                                       /* 87 */
#endif                                                        /* 88 */
      clock(bit);                                             /* 89 */
   }                                                          /* 90 */
   latch();                                                   /* 91 */
#ifdef TEST                                                   /* 92 */
   printf("\n");                                              /* 93 */
#endif                                                        /* 94 */
}                                                             /* 95 */
                                                              /* 96 */
void latch(void)                                              /* 97 */
{                                                             /* 98 */
   outportb(DATA, 0x04);  /* bring strobe high */             /* 99 */
   outportb(DATA, 0x00);  /* and low */                       /* 100 */
}                                                             /* 101 */
                                                              /* 102 */
void clock(int bit)                                           /* 103 */
/* bring least sig bit high and then low */                   /* 104 */
{                                                             /* 105 */
   outportb(DATA, (bit << 1));                                /* 106 */
   outportb(DATA, (bit << 1) | 0x01);                         /* 107 */
   outportb(DATA, (bit << 1));                                /* 108 */
}                                                             /* 109 */