Featured image of post Drive Max7219/Max7221 with common anode displays

Drive Max7219/Max7221 with common anode displays

As you maybe already know, the max7219 and max7221 chips are serially interfaced (SPI) 8-bit LED drivers. These chips work perfect on 7 segment displays if they have common cathode pins, because they are designed for those display. If you have common cathode 7 segment display you get in touch with the benefit of these led drivers, because they handle the multiplexing in an easy way. They have built-in bcd decoder for easily displaying information and if you don’t want to use the decoder you can byte-wise set every digit of your display. For example, if you want to display the number “0” without bcd decoding, you create the bit mask as follows:

[caption id=“attachment_981” align=“alignnone” width=“400”] 7bit-segment 7bit-segment[/caption]

The bit mask for number “0” is: 0x0111111 To display this number you have to address (e.g.) digit1 and send your “number byte” afterwards. That works perfectly.

While the max7219 is a great thing for driving 7 segment displays with common cathode I came to the point when multiplexing is a pain in the ass. That happened to me when I tried to drive 7 segment displays with common anode. First of all you have to wire your display backwards. That means you have to wire the common anode pins to the segment pins of your max7219 and the cathode pins to the digit pins. As you can imagine, this backwards wiring has an impact for driving your display, because the imaginary multiplexing table is rotated by 90°. For example: I have two 4 x 7 segment displays common anode (ltc-4620hg - 8 digits in total - maximum for max7219). If I want to display the number “0” I cant address digit1, because digit1 is wired across all (from a max7219 perspective) digit pins. Now, what I have to do to display a “0” on digit1 is splitting the byte (my 0x0111111) and scatter each bit to the right position of each digit ( 90° rotation & repositioning).

[caption id=“attachment_997” align=“alignnone” width=“651”] max7219-max7221-from-common-cathode-to-common-anode-multiplex-conversion max7219-max7221-from-common-cathode-to-common-anode-multiplex-conversion[/caption]

If you handle this right, that should do the trick to run your 7-segment common anode display with a max7219/max7221!

After we took a look at the multiplexing, lets write some code to implement this in software, to drive your digits with the ease of the max7219.We call our function Display with 2 parameters:

1
2
3
4
void Display(int dig, int number)
{

}

We store each byte for each line (digit 1a-8a) in an array like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
unsigned char DigValues[] =	{
								0b00000000,
								0b00000000,
								0b00000000,
								0b00000000,
								0b00000000,
								0b00000000,
								0b00000000,
								0b00000000,
								0b00000000};

As we know, there is no bcd decoding and we don’t want to use hex format for displaying numbers on our display I created a char array with all numbers corresponding to their position in the array itself. My array looks like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
char numbers[] = {  0b011111110,
					0b00001100,
					0b10110110,
					0b10011110,
					0b11001100,
					0b11011010,
					0b11111010,
					0b00001110,
					0b01111110,
					0b11111110,
					0b11011110};

Every number[x] is the binary format for the number X (e.g. number[2] represents the binary format for displaying the number 2). First of all we have to shift all bits left, depending on the digit we want to display (keep figure 2 in mind, just shift everything from e.g. a to e -> from digit1 to digit5). We start with the default positioning on digit1, by creating a bit mask where bit1 is high:

1
char bPosition = 0x00000001;

If we want to draw our number onto a different digit, we have to shit this to the left, or leave it, where it is if we want to print to digit1

1
2
3
4
5
	// If [param]dig position is greater than 1
	if ( dig > 1){
		// shift bPosition left to the correct digit ([param]dig -1 )
		bPosition = bPosition<<dig-1;
	}

After we have set the correct position, we iterate through our numbers array and check if we have to set the bit of DigValues[x] at out bPosition location high or low.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
	// iterate through the numbers array
	for(int x = 0; x < 8; x++){
		// check if bit is high at the current location of our selected number
		if ( numbers[number] & (1 << x) )
		{
			// if bitX of numbers is high just binary OR bPosition to the current DigValues value
			DigValues[x] |= bPosition;
		}else{
			// if bitX of numbers is low, invert bPosition and binary AND it with current DigValues value to set bit low
			DigValues[x] = (0b11111111 ^ bPosition) & DigValues[x] ;
		}
		// Send your information to max7219
		SPI_SEND(x,DigValues[x]);
	}

That’s it. Now you can call Display(dig,number) to display every number to every dig on your display. At the moment I don’t need any characters, so I would stop at this point. I hope that helps you to understand how you can use a 7 segment display with common anode in combination with max7219.

Here is an example for a Atmega8 with internal 8Mhz osc

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Define CPU Frequency
#define F_CPU 8000000UL

// Some Includes
#include <avr/io.h>
#include <util/delay.h>

void SPI_SEND(unsigned char addr, char data) {
	// CS Load
	PORTB &= ~(1 << PB2);

	// Transmit Data (Address)
	SPDR = addr;

	// Wait until completed
	while(!(SPSR & (1<<SPIF)));

	// Transmit Data (Information)
	SPDR = data;

	// Wait until complete
	while(!(SPSR & (1<<SPIF)));

	// CS Load
	PORTB |= (1 << PB2);
}

void max7219_Init(void)
{
	/* STEUERBITS */
	SPI_SEND ( 0x0C , 0x01 ) ;   // normal mode
	SPI_SEND ( 0x0A , 0x0f ) ;   // set intensity 0x00 - 0x0F
	SPI_SEND ( 0x0B , 0x07 ) ;   // scan digits 0,1
	SPI_SEND ( 0x09 , 0x00 ) ;   // no decoding
}

void spi_init (void)
{
	// Definition for output ports to Max7219.
	// PORTB2, PORTB3, PORTB5 -> Ausgänge
	DDRB |= (1 << PB3) | (1 << PB5) | (1 << PB2);

	// Define SPI for MAX7219
	// SPE=1 - Turn SPI on
	// MSTR=1 - Controller is Master
	// SPR0=1 -Frequency to osc/16
	SPCR |= ((1 << SPE) | (1 << MSTR)) | (1<<SPR0);
}

void TurnOnAnimation (void){
		for ( int z = 0; z <= 1; z++ ){
			int a = 1;
			for ( int x = 0; x <= 8; x++){
				for ( int y = 0; y <= 7; y++){
					_delay_ms(5);
					SPI_SEND(y,a);
				}
				a = a * 2;
			}
		}
}
	/*

			 ROW 1

			   A
		  ###########
		  #         #
ROW 6 - F #    7    # B - ROW 2
		  #    G    #
		  ###########
		  #         #
ROW 5 - E #         # C - ROW 3
		  #         #
		  ###########
		       D
		     ROW 4

	*/
// DigValues stores 8 byte for the display information
unsigned char DigValues[] =	{0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000,0b00000000};

// Display function
void Display(int dig, int number)
{
	// Array with information about which bit has to be set to display the correct number
	// numbers[0] -> Displays 0
	// numbers[4] -> Displays 4
	// ...
	char numbers[] = {0b011111110,0b00001100,0b10110110,0b10011110,0b11001100,0b11011010,0b11111010,0b00001110,0b01111110,0b11111110,0b11011110};

	// Dig positioning byte
	char bPosition = 0x00000001;

	// If [param]dig position is greater than 1
	if ( dig > 1){
		// shift bPosition left to the correct digit ([param]dig -1 )
		bPosition = bPosition<<dig-1;
	}

	// iterate through the numbers array
	for(int x = 0; x < 8; x++){
		// check if bit is high at the current location of our selected number
		if ( numbers[number] & (1 << x) )
		{
			// if bitX of numbers is high just binary OR bPosition to the current DigValues value
			DigValues[x] |= bPosition;
		}else{
			// if bitX of numbers is low, invert bPosition and binary AND it with current DigValues value to set bit low
			DigValues[x] = (0b11111111 ^ bPosition) & DigValues[x] ;
		}
		// Send your information to max7219
		SPI_SEND(x,DigValues[x]);
	}
}

void main (void)
{

	/* Initialize SPI */
	spi_init();

	/* Initialize MAX7219 */
	max7219_Init();

	/* Run a tiny animation */
	TurnOnAnimation();

	/* Write data to display */
	Display(1,8);
	Display(1,1);
	Display(2,2);
	Display(3,3);
	Display(4,4);
	Display(5,5);
	Display(6,6);
	Display(7,7);
	Display(8,5);
	Display(8,7);

	while(1)
	{

	}
}

[gallery ids=“993,997,981”]

comments powered by Disqus
Developer / Inventor / Creator
Erstellt mit Hugo
Theme Stack gestaltet von Jimmy