Computer Systems Experiments 19 | Develop a 4-Digit Counter

Series: Computer Systems Experiments

Computer Systems Experiments 19 | Develop a 4-Digit Counter

Let’s now design a counter counting from 0000 to 9999. To get started, we have to wrap up all the things that we have learned. First, you need to have a breadboard that finished the last experiment. Second, you need to know about the Makefile file. And finally, you have to be able to know the C language that we have covered in the previous experiment.

Now, let’s start with the code from the last experiment,

static volatile unsigned int *FSEL1 =  (unsigned int *)0x20200004;
static volatile unsigned int *FSEL2 = (unsigned int *)0x20200008;
static volatile unsigned int *SET0 = (unsigned int *)0x2020001c;
static volatile unsigned int *CLR0 = (unsigned int *)0x20200028;
#define DELAY 0x3f00
void main(void) {
// set GPIO 10-13 to output
*FSEL1 = 0b1001001001;
// set GPIO 20-26 to output
*FSEL2 = 0b1001001001001001001;
// assign the rules for displaying digits
int digit[] = {
0b111111,
0b110,
0b1011011,
0b1001111,
0b1100110,
0b1101101,
0b1111101,
0b111,
0b1111111,
0b1101111};
while (1) {
for(int i = 0; i < 4; i++){
*SET0 = (digit[i] << 20) + (1 << (10+i));
// delay a short time to produce pov
for (int c = DELAY; c != 0; c--) ;
*CLR0 = (digit[i] << 20) + (1 << (10+i));
}
}
}

If we want to turn this program into a 4-digit counter, first of all, we have to add a second delay time DELAY_LONG that is used to switch the values.

#define DELAY_LONG 0x3f

Note that we use the value 0x3f because this time is not too fast or too slow. We actually got this value by several times of manual trials. Then we can make this work for our program by adding a for loop to the program,

for (int t = DELAY_LONG; t != 0; t--) {
for(int i = 0; i < 4; i++){
*SET0 = (digit[i] << 20) + (1 << (10+i));
// delay a short time to produce pov
for (int c = DELAY; c != 0; c--) ;
*CLR0 = (digit[i] << 20) + (1 << (10+i));
}
}

Then, to tell which four-digit display we are going to have for each turn, we have to use an algorithm to separate the value we want to display. The result should be,

value = 0    -> a = 0, b = 0, c = 0, d = 0
value = 1 -> a = 0, b = 0, c = 0, d = 1
value = 12 -> a = 0, b = 0, c = 1, d = 2
value = 1234 -> a = 1, b = 2, c = 3, d = 4
value = 5432 -> a = 5, b = 4, c = 3, d = 2
...

Let’s start the value from 0000 by,

int value = 0;

Then we define an array to store the four digits of each value,

int digits[4];

For each value, we use the following algorithm to extract each digit,

digits[0] = (value - value % 1000) / 1000;
digits[1] = value % 1000 / 100;
digits[2] = value % 100 / 10;
digits[3] = value % 10;

To make the program work for us, we have to change the i variable to digits[i] and then it will display our digits in the right position,

for (int t = DELAY_LONG; t != 0; t--) {
for(int i = 0; i < 4; i++){
*SET0 = (digit[digits[i]] << 20) + (1 << (10+i));
// delay a short time to produce pov
for (int c = DELAY; c != 0; c--) ;
*CLR0 = (digit[digits[i]] << 20) + (1 << (10+i));
}
}

After successfully displays a number, we add 1 to the value in order to count for the next number,

value++;

Also, note that the program can only count to 9999 and after that, the value will be overflowed. If the value is 10000 , we have to reset it to 0 so that the overflow problem will not exist.

if (value == 10000) value = 0;

Finally, the overall program is,

static volatile unsigned int *FSEL1 =  (unsigned int *)0x20200004;
static volatile unsigned int *FSEL2 = (unsigned int *)0x20200008;
static volatile unsigned int *SET0 = (unsigned int *)0x2020001c;
static volatile unsigned int *CLR0 = (unsigned int *)0x20200028;
#define DELAY 0x3f00
#define DELAY_LONG 0x3f
void main(void) {
// set GPIO 10-13 to output
*FSEL1 = 0b1001001001;
// set GPIO 20-26 to output
*FSEL2 = 0b1001001001001001001;
    int digit[] = {
0b111111,
0b110,
0b1011011,
0b1001111,
0b1100110,
0b1101101,
0b1111101,
0b111,
0b1111111,
0b1101111};
    int value = 0;
int digits[4];
    while (1) {
digits[0] = (value - value % 1000) / 1000;
digits[1] = value % 1000 / 100;
digits[2] = value % 100 / 10;
digits[3] = value % 10;
// keep the value for a time
for (int t = DELAY_LONG; t != 0; t--) {
for(int i = 0; i < 4; i++){
*SET0 = (digit[digits[i]] << 20) + (1 << (10+i));
// delay a short time to produce pov
for (int c = DELAY; c != 0; c--) ;
*CLR0 = (digit[digits[i]] << 20) + (1 << (10+i));
}
}
value++;
if (value == 10000) value = 0;
}
}

You can also find this code from my repo. The final result is (just a short video clip),