728x90

728x90

Tuesday, February 17, 2026

ATMega644P SPI SN74HC595N TC1604A LCD

The SN74HC595N is an output expansion chip that could drive any devices, LED, relay or even writing data to LCD. A character LCD is easily controlled by this chip in write mode. A single chip SN74HC595N can control the HD44780 using its 4-bit data transfer mode.

ATMega644P SPI SN74HC595N TC1604A LCD 

 

 ATMega644P SPI SN74HC595N TC1604A LCD

In this example the ATMega644P master SPI send HD44780 LCD data and command to the LCD via an SN74HC595N shift registers chip.

ATMega644P SPI SN74HC595N TC1604A LCD
A finished Assembling. SN74HC595N is soldered on-board. A 16x4 LCD stays at the top.

 

ATMega644P SPI SN74HC595N TC1604A LCD
Soldering side

 

ATMega644P SPI SN74HC595N TC1604A LCD
Schematic Diagram

 The original post uses Arduino Uno to control this LCD module.

Source Code "main.c":

  1. /*
  2. * 12-spi_74hc595_1604.c
  3. *
  4. * Created: 2/17/2026 3:27:49 PM
  5. * Author : Admin
  6. */

  7. #include <stdio.h>
  8. #include <avr/io.h>
  9. #include <util/delay.h>
  10. #define F_CPU 16000000UL

  11. #define DDR_SPI DDRB
  12. #define PRT_SPI PORTB
  13. #define DD_MOSI 5
  14. #define DD_MISO 6
  15. #define DD_SCK 7
  16. #define DD_SS 4

  17. void SPI_MasterInit(void)
  18. {
  19. /* Set MOSI and SCK output, all others input */
  20. DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
  21. /* Enable SPI, Master, set clock rate fck/16
  22. data is sample at the falling edge of SCK*/
  23. SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
  24. }

  25. void SPI_MasterTransmit(char cData)
  26. {
  27. /* Start transmission */
  28. SPDR = cData;
  29. /* Wait for transmission complete */
  30. while(!(SPSR & (1<<SPIF)))
  31. ;
  32. }

  33. void SPI_SlaveInit(void)
  34. {
  35. /* Set MISO output, all others input */
  36. DDR_SPI = (1<<DD_MISO);
  37. /* Enable SPI */
  38. SPCR = (1<<SPE);
  39. }

  40. char SPI_SlaveReceive(void)
  41. {
  42. /* Wait for reception complete */
  43. while(!(SPSR & (1<<SPIF)))
  44. ;
  45. /* Return Data Register */
  46. return SPDR;
  47. }

  48. /*TWI LCD Driver*/
  49. #define RS 1
  50. #define RW 2
  51. #define EN 3
  52. #define BL 0


  53. char backLight=0;

  54. void lcd_delay(unsigned int counts){
  55. for (unsigned int i=0;i<counts;i++);
  56. }

  57. void spi_lcd_command(char command){
  58. char data;
  59. data=command&0xF0;
  60. SPI_MasterTransmit(data|(backLight<<BL)|(1<<EN));
  61. PRT_SPI&=~(1<<DD_SS);
  62. PRT_SPI|=(1<<DD_SS);
  63. SPI_MasterTransmit(data|(backLight<<BL));
  64. PRT_SPI&=~(1<<DD_SS);
  65. PRT_SPI|=(1<<DD_SS);
  66. data=command<<4;
  67. SPI_MasterTransmit(data|(backLight<<BL)|(1<<EN));
  68. PRT_SPI&=~(1<<DD_SS);
  69. lcd_delay(10);
  70. PRT_SPI|=(1<<DD_SS);
  71. SPI_MasterTransmit(data|(backLight<<BL));
  72. PRT_SPI&=~(1<<DD_SS);
  73. PRT_SPI|=(1<<DD_SS);
  74. }

  75. void spi_lcd_data(char command){
  76. char data;
  77. data=command&0xF0;
  78. SPI_MasterTransmit(data|(backLight<<BL)|(1<<EN)|(1<<RS));
  79. PRT_SPI&=~(1<<DD_SS);
  80. PRT_SPI|=(1<<DD_SS);
  81. SPI_MasterTransmit(data|(backLight<<BL)|(1<<RS));
  82. PRT_SPI&=~(1<<DD_SS);
  83. PRT_SPI|=(1<<DD_SS);
  84. lcd_delay(50);
  85. data=command<<4;
  86. SPI_MasterTransmit(data|(backLight<<BL)|(1<<EN)|(1<<RS));
  87. PRT_SPI&=~(1<<DD_SS);
  88. PRT_SPI|=(1<<DD_SS);
  89. SPI_MasterTransmit(data|(backLight<<BL)|(1<<RS));
  90. PRT_SPI&=~(1<<DD_SS);
  91. PRT_SPI|=(1<<DD_SS);
  92. }

  93. void spi_lcd_xy(int8_t x, int8_t y){
  94. //16x2
  95. //char addr[]={0x80,0xC0};
  96. //16x4
  97. char addr[]={0x80,0xC0,0x90,0xD0};
  98. spi_lcd_command(addr[y-1]+x-1);
  99. }

  100. void spi_lcd_line_1(void){
  101. spi_lcd_command(0x80);
  102. }

  103. void spi_lcd_line_2(void){
  104. spi_lcd_command(0xC0);
  105. }

  106. void spi_lcd_line_3(void){
  107. spi_lcd_command(0x90);
  108. }

  109. void spi_lcd_line_4(void){
  110. spi_lcd_command(0xD0);
  111. }

  112. void spi_lcd_cursor_off(void){
  113. spi_lcd_command(0x0C);
  114. }

  115. void spi_lcd_text(char *txt){
  116. while(*txt) spi_lcd_data(*txt++);
  117. }

  118. void i2c_lcdClear(void){
  119. spi_lcd_command(0x01);
  120. _delay_ms(10);
  121. }

  122. void spi_lcd_init(void){
  123. SPI_MasterTransmit(0);
  124. lcd_delay(500);
  125. spi_lcd_command(0x33);
  126. lcd_delay(10);
  127. spi_lcd_command(0x32);
  128. lcd_delay(10);
  129. spi_lcd_command(0x28);
  130. lcd_delay(10);
  131. spi_lcd_command(0x0F);
  132. lcd_delay(10);
  133. spi_lcd_command(0x01);
  134. _delay_ms(10);
  135. spi_lcd_command(0x06);
  136. lcd_delay(10);
  137. }

  138. int main(void)
  139. {
  140. /* Replace with your application code */
  141. _delay_ms(1000);
  142. SPI_MasterInit();
  143. PRT_SPI|=(1<<DD_SS); //Set CS Pin High
  144. spi_lcd_init();
  145. spi_lcd_line_1();
  146. spi_lcd_text("ATMega644P SPI");
  147. spi_lcd_line_2();
  148. spi_lcd_text("SN74HC595N LCD");
  149. spi_lcd_line_3();
  150. spi_lcd_text("TC1604A-01(R)");
  151. spi_lcd_line_4();
  152. spi_lcd_text("Example Using C");
  153. unsigned char data[7],msg[16];
  154. while (1)
  155. {
  156. }
  157. }





AVR Hardware Experiment:

ATMega644P SPI SN74HC595N TC1604A LCD
Tested ATMega644P

For a full tutorial list of ATMega644P using C in Microchip Studio IDE please see this page.


 

 

Monday, February 16, 2026

ATMega644P SPI DS3234 RTC LCD

Overview

The DS3234 is a low-cost, extremely accurate SPI bus real-time clock (RTC) with an integrated temperature-compensated crystal oscillator (TCXO) and crystal. The DS3234 incorporates a precision, temperature-compensated voltage reference and comparator circuit to monitor VCC. When VCC drops below the power-fail voltage (VPF), the device asserts the RST output and also disables read and write access to the part when VCC drops below both VPF and VBAT. The RST pin is monitored as a push button input for generating a µP reset. The device switches to the backup supply input and maintains accurate timekeeping when main power to the device is interrupted. The integration of the crystal resonator enhances the long-term accuracy of the device as well as reduces the piece-part count in a manufacturing line. The DS3234 is available in commercial and industrial temperature ranges, and is offered in an industry-standard 300-mil, 20-pin SO package. 

ATMega644P SPI DS3234 RTC LCD

It does not have a DIP version due to larger footprint. But a ready to use module is widely available at very low cost. 

SparkFun DeadOn RTC Breakout - DS3234 - SparkFun Electronics

Its internal time keeping and general purpose registers are similar to the DS1307 and almost identical to DS3232 (TWI version). However its SPI interface yield a higher speed data communication than TWI.

ATMega644P SPI DS3234 RTC LCD
DS3234 Pin Configuration and Description

 Its timing data is very precise due its internal 32.678KHz crystal oscillator with programmable capacitors array.

ATMega644P SPI DS3234 RTC LCD
Block Diagram

The DS3234 provides 256 bytes of general-purpose battery-backed read/write memory. The SRAM can be written or read whenever VCC is above either VPF or VBAT.  

ATMega644P SPI DS3234 RTC LCD
 Address Map for DS3234 Timekeeping Registers and SRAM

This SPI chip doesn't have a device address. It just uses a Chip Select (CS) pin that is active low. Its R/W MSB bit of the internal SRAM address identifies between device write and read( '0' for read and '1' for write).

ATMega644P SPI DS3234 RTC LCD
DS3234 Single-Byte Write and Read Sequence

 However for a high speed multiple write or read bytes we can use its SPI mutliple-Byte Burst Transfer.

ATMega644P SPI DS3234 RTC LCD
SPI Multiple-Byte Burst Transfer

 It is very common for data reading from this chip.

ATMega644P and DS3234 Interfacing

Programming and interfacing with this chip is very easy using a simple 8-bit MCU dedicated SPI communication module. Even a low-end 8-bit micro-controller that doesn't have an SPI communication interface the programmer can emulate an SPI communication protocol to interact with this RTC chip. 

ATMega644P SPI DS3234 RTC LCD
Typical Operating Circuit

Commonly a master MCU uses only four wire SPI to make a bi-directional communication interface with this RTC chip.

ATMega644P SPI DS3234 RTC LCD
Proteus Simulation

 

ATMega644P SPI DS3234 RTC LCD
Virtual DSO Waveform

 

In this example the ATMega644P read the time and date data from the SRAM of DS3234. A character LCD show time and date on the display. Serial data inputs to MISO pin are sample at the trailing edge of each clock cycles of SCK pin to correct the data reception that is CPOL=0 and CPHA=1.

C Source Code "main.c":

  1. /*
  2. * 12-spi_ds3234_1602.c
  3. *
  4. * Created: 2/16/2026 10:52:32 PM
  5. * Author : Admin
  6. */

  7. #include <stdio.h>
  8. #include <avr/io.h>
  9. #include <util/delay.h>
  10. #define F_CPU 16000000UL

  11. #define DDR_SPI DDRB
  12. #define PRT_SPI PORTB
  13. #define DD_MOSI 5
  14. #define DD_MISO 6
  15. #define DD_SCK 7
  16. #define DD_SS 4

  17. void SPI_MasterInit(void)
  18. {
  19. /* Set MOSI and SCK output, all others input */
  20. DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
  21. /* Enable SPI, Master, set clock rate fck/16
  22. data is sample at the falling edge of SCK*/
  23. SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0)|(1<<CPHA);
  24. }

  25. void SPI_MasterTransmit(char cData)
  26. {
  27. /* Start transmission */
  28. SPDR = cData;
  29. /* Wait for transmission complete */
  30. while(!(SPSR & (1<<SPIF)))
  31. ;
  32. }

  33. void SPI_SlaveInit(void)
  34. {
  35. /* Set MISO output, all others input */
  36. DDR_SPI = (1<<DD_MISO);
  37. /* Enable SPI */
  38. SPCR = (1<<SPE);
  39. }

  40. char SPI_SlaveReceive(void)
  41. {
  42. /* Wait for reception complete */
  43. while(!(SPSR & (1<<SPIF)))
  44. ;
  45. /* Return Data Register */
  46. return SPDR;
  47. }

  48. int main(void)
  49. {
  50. /* Replace with your application code */
  51. SPI_MasterInit();
  52. PRT_SPI|=(1<<DD_SS); //Set CS Pin High
  53. lcd_init();
  54. lcd_text("ATMega644P AVR");
  55. lcd_xy(1,2);
  56. lcd_text("DS3234 SPI RTC");
  57. _delay_ms(5000);
  58. lcd_command(0x0C);
  59. unsigned char data[7],msg[16];
  60. while (1)
  61. {
  62. PRT_SPI&=~(1<<DD_SS);
  63. SPI_MasterTransmit(0x00);
  64. for (char i=0;i<7;i++)
  65. {
  66. SPI_MasterTransmit(0x00);
  67. data[i]=SPDR;
  68. }
  69. PRT_SPI|=(1<<DD_SS);
  70. sprintf(msg,"Date: 20%02X/%02X/%02X",data[6],data[5],data[4]);
  71. lcd_xy(1,1);
  72. lcd_text(msg);
  73. sprintf(msg,"Time: %02X:%02X:%02X",data[2],data[1],data[0]);
  74. lcd_xy(1,2);
  75. lcd_text(msg);
  76. _delay_ms(100);
  77. }
  78. }



I can not buy this chip at local store. So I only tested this SPI RTC chip using a software simulator. 

 

 

 

 

Sunday, February 15, 2026

ATMega644P SPI and SN74HC165 Shift Registers Example

Overview

The SNx4HC165 devices are 8-bit parallel-load shift registers that, when clocked, shift the data toward a serial (QH) output. Parallel-in access to each stage is provided by eight individual direct data (A-H) inputs that are enabled by a low level at the shift/load (SH/LD) input. The SNx4HC165 devices also feature a clock-inhibit (CLK INH) function and a complementary serial (QH) output. Clocking is accomplished by a low-to-high transition of the clock (CLK) input while SH/LD is held high and CLK INH is held low. The functions of CLK and CLK INH are interchangeable. Because a low CLK and a low-to-high transition of CLK INH also accomplish clocking, CLK INH must be changed to the high level only while CLK is high. Parallel loading is inhibited when SH/LD is held high. While SH/LD is low, the parallel inputs to the register are enabled independently of the levels of the CLK, CLK INH, or serial (SER) inputs. 

ATMega644P SPI and SN74HC165 Shift Registers Example 

 

This input expansion chip can be used in Programmable Logic Controllers, Appliances, Video Display Systems, Keyboards etc. This old digital IC is very easy to use with a typical 8-bit MCU since it has a small footprint and its Dual In-Line Package version. It is widely available at very low cost.


16-pin (N) package image
A DIP-16 Sample

 It has DIP-16 footprint and various SMD packages.

 

ATMega644P SPI and SN74HC165 Shift Registers Example
Pin Configuration and Functions

 It made from some digital logic gates and flip-flops.

Logic Diagram Positive Logic
Logic Diagram Positive Logic

 To load parallel input data (H:A) take a look at the timing diagram below.

ATMega644P SPI and SN74HC165 Shift Registers Example
Load Shift Sequence

Typically the SI (Serial Data In) is ignored or wires it GND. The Clock Inhabit (CLK INH) must wired to GND. At the transition from logic low to logic high of SH/LD pin allows parallel data loading and serial data shifting out via Serial Data Out (SO) pin.

In this example the ATMega644P read parallel input data of an SN74HC165N and display it on PORTD.

Source Code "main.c":

  1. /*
  2. * 12-spi_sn74hc165.c
  3. *
  4. * Created: 2/16/2026 11:12:37 AM
  5. * Author : Admin
  6. */

  7. #include <avr/io.h>
  8. #include <util/delay.h>
  9. #define F_CPU 16000000UL

  10. #define DDR_SPI DDRB
  11. #define PRT_SPI PORTB

  12. #define DD_SS 4
  13. #define DD_MOSI 5
  14. #define DD_MISO 6
  15. #define DD_SCK 7


  16. void SPI_MasterInit(void)
  17. {
  18. /* Set MOSI and SCK output, all others input */
  19. DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
  20. /* Enable SPI, Master, set clock rate fck/16 */
  21. SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
  22. }

  23. void SPI_MasterTransmit(char cData)
  24. {
  25. /* Start transmission */
  26. SPDR = cData;
  27. /* Wait for transmission complete */
  28. while(!(SPSR & (1<<SPIF)))
  29. ;
  30. }

  31. void SPI_SlaveInit(void)
  32. {
  33. /* Set MISO output, all others input */
  34. DDR_SPI = (1<<DD_MISO);
  35. /* Enable SPI */
  36. SPCR = (1<<SPE);
  37. }
  38. char SPI_SlaveReceive(void)
  39. {
  40. /* Wait for reception complete */
  41. while(!(SPSR & (1<<SPIF)))
  42. ;
  43. /* Return Data Register */
  44. return SPDR;
  45. }


  46. int main(void)
  47. {
  48. /* Replace with your application code */
  49. SPI_MasterInit();
  50. //PRT_SPI|=(1<<DD_SS);
  51. DDRD=0xFF;
  52. _delay_ms(1000);
  53. while (1)
  54. {
  55. PRT_SPI&=~(1<<DD_SS);
  56. PRT_SPI|=(1<<DD_SS);
  57. SPI_MasterTransmit(0x00);
  58. PORTD=SPI_SlaveReceive();
  59. _delay_ms(100);
  60. }
  61. }




I don't have this chip because local stores don't stock this part. So I can test it only in simulator. 

ATMega644P SPI and SN74HC165 Shift Registers Example 


ATMega644P SPI and SN74HC165 Shift Registers Example
SPI Transfer and Receive One Byte Of Data Waveform

We can connect multiple SN74HC165N chips using a daisy-chain configuration. Here I scan two input ports of two SN74HC165N. So the master MCU needs to shift 16 clock cycles (two bytes of data).

ATMega644P SPI and SN74HC165 Shift Registers Example
Using Two SN74HC165N chips (Daisy-Chain)
ATMega644P SPI and SN74HC165 Shift Registers Example
SPI Waveform

Source Code "main.c":

  1. /*
  2. * sn74hc165_2.c
  3. *
  4. * Created: 2/16/2026 12:49:13 PM
  5. * Author : Admin
  6. */

  7. #include <avr/io.h>
  8. #include <util/delay.h>
  9. #define F_CPU 16000000UL

  10. #define DDR_SPI DDRB
  11. #define PRT_SPI PORTB

  12. #define DD_SS 4
  13. #define DD_MOSI 5
  14. #define DD_MISO 6
  15. #define DD_SCK 7


  16. void SPI_MasterInit(void)
  17. {
  18. /* Set MOSI and SCK output, all others input */
  19. DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
  20. /* Enable SPI, Master, set clock rate fck/16 */
  21. SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
  22. }

  23. void SPI_MasterTransmit(char cData)
  24. {
  25. /* Start transmission */
  26. SPDR = cData;
  27. /* Wait for transmission complete */
  28. while(!(SPSR & (1<<SPIF)))
  29. ;
  30. }

  31. void SPI_SlaveInit(void)
  32. {
  33. /* Set MISO output, all others input */
  34. DDR_SPI = (1<<DD_MISO);
  35. /* Enable SPI */
  36. SPCR = (1<<SPE);
  37. }
  38. char SPI_SlaveReceive(void)
  39. {
  40. /* Wait for reception complete */
  41. while(!(SPSR & (1<<SPIF)))
  42. ;
  43. /* Return Data Register */
  44. return SPDR;
  45. }


  46. int main(void)
  47. {
  48. /* Replace with your application code */
  49. SPI_MasterInit();
  50. //PRT_SPI|=(1<<DD_SS);
  51. DDRD=0xFF;
  52. DDRC=0xFF;
  53. while (1)
  54. {
  55. PRT_SPI&=~(1<<DD_SS);
  56. PRT_SPI|=(1<<DD_SS);
  57. SPI_MasterTransmit(0x00);
  58. PORTD=SPI_SlaveReceive();
  59. SPI_MasterTransmit(0x00);
  60. PORTC=SPI_SlaveReceive();
  61. _delay_ms(100);
  62. }
  63. }




For PIC Micro-controller users check this post:

For ATMega32 AVR micro-controller user check this post:



 

 

320x50

Search This Blog

tyro-728x90