Introduction
Sometimes, the ATMEGA8 has not enough GPIO pins. Typical situation might be if several 7-segment LED display digits are used. Shift register ICs, like the 74HC595, can be used to overcome this limitation. This device can take a serial stream of 8 bits and output them in parallel on its 8 output pins.In this post I want to show how to use the ATMEGA8 SPI (serial peripheral interface) hardware to control a single 74HC595.
In a SPI communication between a master and a slave, the master always provides the clock signal. I'm using the ATMEGA8 as SPI master. The SPI slave is looking at the clock signal line and the data line, and reads the value of the data line on each clock edge.
The SPI master can also receive data back from the slave over a third connection, but I will not show this here. A lot of ICs use the SPI interface for communication. Examples are sensors, external memory chips, ADC/DAC chips, etc. Also the programming of the ATMEGA8 flash memory is done using its SPI interface.
74HC595
The 74HC595 functionality is described in its datasheet (google for it). It has 5 relevant control inputs. I will permanently connect the OE (output enable) pin to GND, so it is always enabled, and I'm left with 4 signals that have to be controlled actively. These are- SER serial input signal
- SRCLK shift register clock
- RSCLR shift register clear
- RCLK output register clock
The device (SPI slave in this case) will sample the SER input on each rising edge of the SRCLK input and shift it into its internal register. This works only while the SRCLR input is high. In order to transfer the value in the shift register to the output pins, a rising edge on the RCLK is needed. The transfer of 8 bits can be seen in the following picture.
ATMEGA8 SPI setup
The SPI hardware of the ATMEGA8 creates the clock signal on the SCK pin (alternative function of pin PB5), and the serialized bit stream on the MOSI "master out slave in" pin (alternative function of pin PB3). For the other two control lines of the 74HC595 chip (SRCLR and RCLK) I use pins PB5 and PB1 on the ATMEGA8. The SPI hardware can be enabled and configured in the software by setting some bits in the SPCR (SPI Control Register).
I use the three marked bits to enable the SPI hardware (SPE), change the byte ordering to transmit the least significant bit first (DORD, for data order), and to use the SPI in master mode (MSTR). The transmission is initiated by writing an 8-bit value into the SPDR (SPI Data Register). The end of the transmission is indicated by the SPI hardware if the SPIF bit in the SPSR register is set by the SPI hardware. Here is the complete program:
#include <avr/io.h> #include <util/delay.h> #include <stdint.h> // define connections of 74HC595 input pins to ATMEGA8 #define P_SRCLR PB2 #define P_SER PB3 #define P_RCLK PB1 #define P_SRCLK PB5 void write_byte_SPI(uint8_t value) { PORTB &= ~(1<<P_SRCLR); // clear register PORTB |= (1<<P_SRCLR); // register can take data //SPI Data Register – SPDR SPDR = value; // write byte while(!(SPSR & (1<<SPIF))); // wait for end of transmission PORTB &= ~(1<<P_RCLK); // register clock low PORTB |= (1<<P_RCLK); // register clock high // will write data to output buffers } int main(void) { // Set SCK MOSI MISO and SS as output DDRB = (1<<P_SRCLR)|(1<<P_SER)|(1<<P_RCLK)|(1<<P_SRCLK); //SPI Control Register – SPCR // Enable SPI, change data order and set to master mode SPCR = (1<<SPE)|(1<<DORD)|(1<<MSTR); for (uint8_t i = 1;;++i) { write_byte_SPI(i); _delay_ms(300); } }
The setup uses 8 LEDs to display the state of the 74HC595 output pins. There are only 4 pins of the ATMEGA8 used to control 8 LEDs (display the value of counter variable i in binary form). That is why this is also called "port extension". By chaining multiple 74HC595 chips, one can control almost any number of LEDs. In the picture, the ATMEGA8 can be seen on the top right, connected by the 4 wires to the 74HC595 chip on the bottom.