This is my first attempt at the program. Note how I am asking the display to do things for me. I have created a function which will display messages. It accepts two parameters, the numeric value to be displayed and the number of the display unit to use:
void display ( unsigned char digit,
unsigned char pos )
{
/* turn on the required LED unit */
PORTA = enable [pos];
/* set the pattern on the LED */
PORTB = patterns [digit];
}
If I want to display the value 0 on display number 3 (which is the last unit since I have numbered them from 0, I would use:
display ( 0, 3 ) ;
However, this is perhaps confusing, so I would probably end up doing something like this:
#define DIGIT0 0
#define DIGIT1 1
#define DIGIT2 2
#define DIGIT3 3
display ( 0, DIGIT3 ) ;
I tend to write things this way out of reflex, because this provides me with a way that I can drive a display with any number of digits very easily, but keeps the code as clear as possible. If you think about it, having a single function like this is much easier to manage that four separate functions.
Note also that I am using arrays to hold the patterns of the digits, and also the mapping of the bits to the enable lines in PORTA. There is method in my madness here as well, in that if I change to different displays or the way that I address the ports changes
Unfortunately..
The only problem with my elegant code is that it doesn't work very well. Perhaps you can see why. What you see was that the digits are barely recognizable, with parts of one number "smeared" over the next. Connect up the LED unit and run the Exercise 4.1 and you will see what I mean. The problem is due to the order in which I turn the signals on and off:
void display ( unsigned char digit,
unsigned char pos )
{
/* turn on the required LED unit*/
PORTA = enable [pos] ;
/* set the pattern on the LED */
PORTB = patterns [digit] ;
}
I enable the output for a digit before I load the pattern. This means that for an instant, before the second line which sets up the patterns, the wrong pattern (that of the previous LED) is being delivered. Switching the order of the two statements helped, but what I really needed was a delay to let the LED hold the display for a fraction of a second, before I move on to the next.
/* EX 4.1 LED driver */
/* Rob Miles 2000 */
/* Uses 4 digit LED display */
/* connected to PORTA and PORTB */
void setup_hardware (void)
{
/* set all of PORTB for output */
TRISB = 0x00 ;
/* set all of PORTA for output */
TRISA = 0xe0 ;
}
/* a value for each bit in PORTA.*/
/* We can feed in the number of */
/* the LED and it will give us */
/* the value to put into A */
const unsigned char enable [4] =
{
1, 2, 4, 8
} ;
/* these are the patterns for the*/
/* LEDs which were worked out */
/* from the datasheet. Note that */
/* to light a LED the bit on */
/* PORTB must be low */
/* I can use this array to */
/* convert from a digit to the 7 */
/* segments needed */
const unsigned char patterns [10] =
/* 0 1 2 3 4 5 */
{0xc0,0xf9,0xa4,0xb0,0x99,0x92,
/* 6 7 8 9 */
0x83,0xf8,0x80,0x98 } ;
/* this function takes two */
/* parameters, the value to be */
/* displayed and the number of */
/* the LED unit to use */
void display ( unsigned char digit,
unsigned char pos )
{
/* turn on required LED unit */
PORTA = enable [pos] ;
/* set pattern on the LED */
PORTB = patterns [digit] ;
}
void main ( void )
{
setup_hardware () ;
/* repeatedly display numbers */
while (1)
{
display ( 0, 0 ) ;
display ( 1, 1 ) ;
display ( 2, 2 ) ;
display ( 3, 3 ) ;
}
}