728x90

Showing posts with label Keypad. Show all posts
Showing posts with label Keypad. Show all posts

Wednesday, February 18, 2026

ATMega644P SPI SN74HC595 and SN74HC165 4x8 Matrix KeyPad Driving

In previous post I use these two SPI chips, SN74HC595 and SN74HC165 to expand the inputs/outputs of an MCU. Here I use these two chip pair to make a matrix keypad. These two 8-bit I/O expansion chip can build up to a 8x8 matrix keypad that yield 64 different keys. But I make only a 4x8 matrix keypad since it's not important.

ATMega644P SPI SN74HC595 and SN74HC165 4x8 Matrix KeyPad Driving
Simulating Program

The 8-bit output port of the SN74HC595 is a column scanner while the lower nibble input port of the SN74HC165 is a row detector (active high). Whenever any key press found the program assign a specific key in its keypad array.

Source Code "main.c":

  1. /*
  2. * 12-spi_sn74hc165_sn74hc595n_keypad.c
  3. *
  4. * Created: 2/18/2026 2:03:34 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_SH 3
  13. #define DD_SS 4
  14. #define DD_MOSI 5
  15. #define DD_MISO 6
  16. #define DD_SCK 7


  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. SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
  23. }

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

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

  47. const char key_16[4][8]={'1','2','3','4','5','6','7','8',
  48. '9','0','A','B','C','D','E','F',
  49. 'G','H','I','J','K','L','M','N',
  50. 'O','P','Q','R','S','T','U','V'};

  51. char key_scan(void){
  52. char data=0,temp,key;
  53. for(char i=0;i<8;i++){
  54. SPI_MasterTransmit(1<<i);
  55. PRT_SPI&=~(1<<DD_SS);
  56. _delay_us(10);
  57. PRT_SPI|=(1<<DD_SS);
  58. _delay_ms(5);
  59. PRT_SPI&=~(1<<DD_SH);
  60. PRT_SPI|=(1<<DD_SH);
  61. SPI_MasterTransmit(0);
  62. data=SPI_SlaveReceive();
  63. if(data==0x01) {temp=key_16[0][i]; break;}
  64. else if(data==0x02) {temp=key_16[1][i]; break;}
  65. else if(data==0x04){temp=key_16[2][i]; break;}
  66. else if(data==0x08){temp=key_16[3][i]; break;}
  67. else temp=0;
  68. _delay_ms(10);
  69. }
  70. return temp;
  71. }

  72. int main(void)
  73. {
  74. /* Replace with your application code */
  75. SPI_MasterInit();
  76. lcd_init();
  77. DDR_SPI|=(1<<DD_SH);
  78. char data=0;
  79. char temp,charCount=0,newLine=0,line=1;
  80. lcd_text("ATMega644P SPI");
  81. lcd_xy(1,2);
  82. lcd_text("MATRIX KEYPAD");
  83. _delay_ms(5000);
  84. lcd_clear();
  85. while (1)
  86. {
  87. temp=key_scan();
  88. if(temp!=0){
  89. lcd_data(temp);
  90. charCount++;
  91. _delay_ms(500);
  92. }
  93. if(charCount>16){
  94. newLine=1;
  95. charCount=0;
  96. line+=1;
  97. }
  98. if(newLine){
  99. newLine=0;
  100. if(line==2) lcd_xy(1,2);
  101. else{
  102. lcd_xy(1,1);
  103. lcd_command(0x01);
  104. _delay_ms(5);
  105. line=1;
  106. }
  107. }
  108. _delay_ms(100);
  109. }
  110. }






The character LCD uses the parallel port of the ATMega644P. But we can control this LCD by adding one more SN74HC595 and one additional Slave Select (SS) pin. 

ATMega644P SPI SN74HC595 and SN74HC165 4x8 Matrix KeyPad Driving
Simulating Program

I separate these two chip using different Slave Select pins. The SN74HC165 doesn't need serial data input. It only need serial clock and Slave Select pins controlled by the MCU. However I think we can cascade this two chip using a shared SPI pins. If I have more time I will test it using this method.


 

For a full tutorial page of ATMega644P Programming Using C please visit this page. 

Thursday, February 5, 2026

ATMega644P TWI MCP23017 Character LCD

The HD44780 based character LCD can be controlled by a micro-controller, digital circuit, an I/O expansion chip or event by hands. In this example I use an output port of the MCP23017 to control a 16x2 LCD in one direction (write only) in 4-bit data transfer mode.

ATMega644P TWI MCP23017 Character LCD

The LCD connect to GPIOB (output register OLATB). That's,

  • LCD RS (GPB0)
  • LCD R/W (GPB1)
  • LCD EN(GPB2)
  • D4:D7(GPB4:GPB7)

Source Code: "main.c"

  1. /*
  2. * 10-i2c_mcp23017_1602.c
  3. *
  4. * Created: 2/5/2026 8:03:45 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. //IOCON.BANK=0
  12. enum BANK0{
  13. IODIRA=0,IODIRB,IPOLA,IPOLB,GPINTENA,GPINTENB,DEFVALA,
  14. DEFVALB,INTCONA,INTCONB,IOCON1,IOCON2,GPPUA,GPPUB,
  15. INTFA,INTFB,INTCAPA,INTCAPB,GPIOA,GPIOB,OLATA,OLATB
  16. };

  17. const char RS=0,RW=1,EN=2;
  18. char BLK_ON=0;

  19. void lcd_command(uint8_t temp){
  20. uint8_t command,led;
  21. command=temp&0xF0;
  22. if(BLK_ON==1) led=0x08;
  23. else led=0;
  24. mcp23017_write(OLATB,command|led|(1<<EN));
  25. _delay_us(10);
  26. mcp23017_write(OLATB,command|led);
  27. _delay_us(25);
  28. command=temp<<4;
  29. mcp23017_write(OLATB,command|led|(1<<EN));
  30. _delay_us(10);
  31. mcp23017_write(OLATB,command|led);
  32. _delay_us(25);
  33. }

  34. void lcd_data(uint8_t temp){
  35. uint8_t data,led;
  36. data=temp&0xF0;
  37. if(BLK_ON==1) led=0x08;
  38. else led=0;
  39. mcp23017_write(OLATB,data|led|(1<<EN)|(1<<RS));
  40. _delay_us(10);
  41. mcp23017_write(OLATB,data|led|(1<<RS));
  42. _delay_us(25);
  43. data=temp<<4;
  44. mcp23017_write(OLATB,data|led|(1<<EN)|(1<<RS));
  45. _delay_us(10);
  46. mcp23017_write(OLATB,data|led|(1<<RS));
  47. _delay_us(25);
  48. }

  49. void lcd_xy(uint8_t x, uint8_t y){
  50. uint8_t cursor[]={0x80,0xC0};
  51. lcd_command(cursor[y-1]+x-1);
  52. }

  53. void lcd_text(uint8_t *text){
  54. while(*text) lcd_data(*text++);
  55. }

  56. void lcd_clear(void){
  57. lcd_command(0x01);
  58. _delay_ms(5);
  59. }

  60. void lcd_init(void){
  61. BLK_ON=1;
  62. mcp23017_write(IODIRB,0x00);
  63. lcd_command(0x33);
  64. _delay_us(10);
  65. lcd_command(0x32);
  66. _delay_us(10);
  67. lcd_command(0x28);
  68. _delay_us(10);
  69. lcd_command(0x0F);
  70. _delay_us(10);
  71. lcd_command(0x01);
  72. _delay_ms(5);
  73. lcd_command(0x06);
  74. _delay_us(10);
  75. }

  76. int main(void)
  77. {
  78. /* Replace with your application code */
  79. lcd_init();
  80. lcd_text("MCP23017 TWI");
  81. lcd_xy(1,2);
  82. lcd_text("MCP23017 LCD");

  83. _delay_ms(10000);
  84. lcd_clear();
  85. lcd_command(0x0C);
  86. lcd_text("Counter Value:");
  87. long counter=0;
  88. char msg[10];
  89. while (1)
  90. {
  91. sprintf(msg,"%ld",counter);
  92. lcd_xy(1,2); lcd_text(msg);
  93. counter++;
  94. _delay_ms(500);
  95. }
  96. }

Source Code: "mcp23017.c"

  1. /*
  2. * mcp23017.c
  3. *
  4. * Created: 2/5/2026 8:06:38 PM
  5. * Author: Admin
  6. */

  7. const char MCP23017_W=0x40;
  8. const char MCP23017_R=0x41;

  9. //IOCON.BANK=0
  10. /*
  11. enum BANK0{
  12. IODIRA=0,IODIRB,IPOLA,IPOLB,GPINTENA,GPINTENB,DEFVALA,
  13. DEFVALB,INTCONA,INTCONB,IOCON1,IOCON2,GPPUA,GPPUB,
  14. INTFA,INTFB,INTCAPA,INTCAPB,GPIOA,GPIOB,OLATA,OLATB
  15. };
  16. */


  17. void mcp23017_write(char address,char data){
  18. twi_start();
  19. /*Select the write address*/
  20. twi_write(MCP23017_W);
  21. /*Select a register address*/
  22. twi_write(address);
  23. /*Send configuration data*/
  24. twi_write(data);
  25. twi_stop();
  26. }

  27. unsigned char mcp23017_read(char address){
  28. /*Select a specific address*/
  29. twi_start();
  30. twi_write(MCP23017_W);
  31. twi_write(address);
  32. twi_stop();
  33. /*Read data from the given address*/
  34. twi_start();
  35. twi_write(MCP23017_R);
  36. unsigned char i2cData=twi_read(1);
  37. twi_stop();
  38. return i2cData;
  39. }

Source Code: "twi.c" 

  1. /*
  2. * twi.c
  3. *
  4. * Created: 2/4/2026 10:22:02 AM
  5. * Author: Admin
  6. */

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


  10. void twi_init(void){
  11. TWSR|=0x00; //Prescaler Selection Bit
  12. TWBR=0x0F; //Baud Rate Generator
  13. TWCR=(1<<TWEN); //Enable The TWI Module
  14. PORTC|=(1<<0);
  15. PORTC|=(1<<1);
  16. }

  17. void twi_start(void){
  18. TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
  19. while((TWCR&(1<<TWINT))==0);
  20. }

  21. void twi_write(unsigned char data){
  22. TWDR=data;
  23. TWCR=(1<<TWINT)|(1<<TWEN);
  24. while((TWCR&(1<<TWINT))==0);
  25. }

  26. unsigned char twi_read(char ACK){
  27. if(ACK==0)
  28. TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWEA);
  29. else
  30. TWCR=(1<<TWINT)|(1<<TWEN);
  31. while((TWCR&(1<<TWINT))==0);
  32. return TWDR;
  33. }

  34. void twi_stop(){
  35. TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
  36. _delay_us(10);
  37. }


Schematic:

ATMega644P TWI MCP23017 Character LCD

 

AVR Prototype Board: 

ATMega644P TWI MCP23017 Character LCD
AVR Experiment Board

For PIC micro-controller using PIC16F887 is a good choice.

This PCB was offered by PCBWay (pcbway.com).

I have been using PCBWay for many years now. PCBWay fabricate PCBs at low cost, fast processing time for only 24 hours, and fast delivery time using any carrier options. This double side 10cmx10cm can be fabricate at only 5USD for 5 to 10pcs by PCBWay. It's a standard PCB with silk screen and solder mask.

A DIY dsPIC30F2010 and dsPIC30F1010 Prototype Board with Programmer
10 PCBs for only 5USD
 

For different size of PCB we can instantly quote on PCBWay website using a zip PCB Gerber file without account.

A DIY dsPIC30F2010 and dsPIC30F1010 Prototype Board with Programmer
PCBWay Instant Quote

 

There is one port left, GPIOA. So I added a 4x4 matrix keypad at GPIOA. The result of keypad scanning will show on the LCD.

Source Code:

 

  1. /*
  2. * 10-i2c_mcp23017_1602_kb.c
  3. *
  4. * Created: 2/5/2026 10:32:40 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. //IOCON.BANK=0
  12. enum BANK0{
  13. IODIRA=0,IODIRB,IPOLA,IPOLB,GPINTENA,GPINTENB,DEFVALA,
  14. DEFVALB,INTCONA,INTCONB,IOCON1,IOCON2,GPPUA,GPPUB,
  15. INTFA,INTFB,INTCAPA,INTCAPB,GPIOA,GPIOB,OLATA,OLATB
  16. };

  17. const char RS=0,RW=1,EN=2;
  18. char BLK_ON=0;

  19. const char key_16[4][4]={'1','2','3','A',
  20. '4','5','6','B',
  21. '7','8','9','C',
  22. '*','0','#','D'};

  23. char keyScan(void){
  24. char data=0,temp,key;
  25. for(char i=0;i<4;i++){
  26. data=0xFF;
  27. data&=~(1<<i);
  28. mcp23017_write(OLATA,data);
  29. _delay_ms(5);
  30. data=mcp23017_read(GPIOA);
  31. data&=0xF0;
  32. if((data&0x10)==0) {temp=key_16[i][0]; break;}
  33. else if((data&0x20)==0){temp=key_16[i][1]; break;}
  34. else if((data&0x40)==0){temp=key_16[i][2]; break;}
  35. else if((data&0x80)==0){temp=key_16[i][3]; break;}
  36. else temp=0;
  37. _delay_ms(10);
  38. }
  39. return temp;
  40. }
  41. void lcd_command(uint8_t temp){
  42. uint8_t command,led;
  43. command=temp&0xF0;
  44. if(BLK_ON==1) led=0x08;
  45. else led=0;
  46. mcp23017_write(OLATB,command|led|(1<<EN));
  47. _delay_us(10);
  48. mcp23017_write(OLATB,command|led);
  49. _delay_us(25);
  50. command=temp<<4;
  51. mcp23017_write(OLATB,command|led|(1<<EN));
  52. _delay_us(10);
  53. mcp23017_write(OLATB,command|led);
  54. _delay_us(25);
  55. }

  56. void lcd_data(uint8_t temp){
  57. uint8_t data,led;
  58. data=temp&0xF0;
  59. if(BLK_ON==1) led=0x08;
  60. else led=0;
  61. mcp23017_write(OLATB,data|led|(1<<EN)|(1<<RS));
  62. _delay_us(10);
  63. mcp23017_write(OLATB,data|led|(1<<RS));
  64. _delay_us(25);
  65. data=temp<<4;
  66. mcp23017_write(OLATB,data|led|(1<<EN)|(1<<RS));
  67. _delay_us(10);
  68. mcp23017_write(OLATB,data|led|(1<<RS));
  69. _delay_us(25);
  70. }

  71. void lcd_xy(uint8_t x, uint8_t y){
  72. uint8_t cursor[]={0x80,0xC0};
  73. lcd_command(cursor[y-1]+x-1);
  74. }

  75. void lcd_text(uint8_t *text){
  76. while(*text) lcd_data(*text++);
  77. }

  78. void lcd_clear(void){
  79. lcd_command(0x01);
  80. _delay_ms(5);
  81. }

  82. void lcd_init(void){
  83. BLK_ON=1;
  84. mcp23017_write(IODIRB,0x00);
  85. lcd_command(0x33);
  86. _delay_us(10);
  87. lcd_command(0x32);
  88. _delay_us(10);
  89. lcd_command(0x28);
  90. _delay_us(10);
  91. lcd_command(0x0F);
  92. _delay_us(10);
  93. lcd_command(0x01);
  94. _delay_ms(5);
  95. lcd_command(0x06);
  96. _delay_us(10);
  97. }

  98. int main(void)
  99. {
  100. /* Replace with your application code */
  101. lcd_init();
  102. lcd_text("MCP23017 TWI");
  103. lcd_xy(1,2);
  104. lcd_text("LCD and Key Pad");

  105. _delay_ms(10000);
  106. lcd_clear();
  107. //Key Pad Init
  108. mcp23017_write(IODIRA,0xF0);
  109. mcp23017_write(GPPUA,0xF0);
  110. char temp,charCount=0,newLine=0,line=1;
  111. while (1)
  112. {
  113. temp=keyScan();
  114. if(temp!=0){
  115. lcd_data(temp);
  116. charCount++;
  117. _delay_ms(500);
  118. }
  119. if(charCount>16){
  120. newLine=1;
  121. charCount=0;
  122. line+=1;
  123. }
  124. if(newLine){
  125. newLine=0;
  126. if(line==2) lcd_xy(1,2);
  127. else{
  128. lcd_xy(1,1);
  129. lcd_command(0x01);
  130. _delay_ms(5);
  131. line=1;
  132. }
  133. }
  134. }
  135. }



Program Simulation:

ATMega644P TWI MCP23017 Character LCD
Program Simulation

AVR Prototype Board: 

ATMega644P TWI MCP23017 Character LCD 

ATMega644P TWI MCP23017 Character LCD

 


 

Click here to download this example

For a full ATMega644P tutorials please visit this page. 

Wednesday, February 4, 2026

ATMega644P TWI MCP23017 LCD Keypad

The MCP23017 can be use as input or output depends on its register configurations. A 4x4 matrix keypad requires only one 8-bit I/O port of its master controller. So I use one general I/O port the GPA of the MCP23017 to scan a 4x4 matrix keypad. Founded key will show on a16x2 character LCD.

ATMega644P TWI MCP23017 LCD Keypad

The LCD is already place on board. The MCP23017 interfaces to the ATMega644P using only two TWI wires. But it need to place and wire on a breadboard module with the keypad.

ATMega644P TWI MCP23017 LCD Keypad 

I use a remembrance 4x4 keypad module that's ready to connect to GPA.

  • "main.c"
  1. /*
  2. * 10-i2c_mcp23017_keypad.c
  3. *
  4. * Created: 2/5/2026 9:05:21 AM
  5. * Author : Admin
  6. */

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

  10. const char MCP23017_W=0x40;
  11. const char MCP23017_R=0x41;

  12. //IOCON.BANK=0
  13. enum BANK0{
  14. IODIRA=0,IODIRB,IPOLA,IPOLB,GPINTENA,GPINTENB,DEFVALA,
  15. DEFVALB,INTCONA,INTCONB,IOCON1,IOCON2,GPPUA,GPPUB,
  16. INTFA,INTFB,INTCAPA,INTCAPB,GPIOA,GPIOB,OLATA,OLATB
  17. };


  18. void mcp23017_write(char address,char data){
  19. twi_start();
  20. /*Select the write address*/
  21. twi_write(MCP23017_W);
  22. /*Select a register address*/
  23. twi_write(address);
  24. /*Send configuration data*/
  25. twi_write(data);
  26. twi_stop();
  27. }

  28. unsigned char mcp23017_read(char address){
  29. /*Select a specific address*/
  30. twi_start();
  31. twi_write(MCP23017_W);
  32. twi_write(address);
  33. twi_stop();
  34. /*Read data from the given address*/
  35. twi_start();
  36. twi_write(MCP23017_R);
  37. unsigned char i2cData=twi_read(1);
  38. twi_stop();
  39. return i2cData;
  40. }

  41. const char key_16[4][4]={'1','2','3','A',
  42. '4','5','6','B',
  43. '7','8','9','C',
  44. '*','0','#','D'};

  45. char keyScan(void){
  46. char data=0,temp,key;
  47. for(char i=0;i<4;i++){
  48. data=0xFF;
  49. data&=~(1<<i);
  50. mcp23017_write(OLATA,data);
  51. _delay_ms(5);
  52. data=mcp23017_read(GPIOA);
  53. data&=0xF0;
  54. if((data&0x10)==0) {temp=key_16[i][0]; break;}
  55. else if((data&0x20)==0){temp=key_16[i][1]; break;}
  56. else if((data&0x40)==0){temp=key_16[i][2]; break;}
  57. else if((data&0x80)==0){temp=key_16[i][3]; break;}
  58. else temp=0;
  59. _delay_ms(10);
  60. }
  61. return temp;
  62. }

  63. int main(void)
  64. {
  65. /* Replace with your application code */
  66. lcd_init();
  67. twi_init();
  68. lcd_text("ATMEGA644P TWI");
  69. lcd_xy(1,2);
  70. lcd_text("MCP23017 KeyPad");
  71. _delay_ms(5000);
  72. lcd_clear();
  73. //Key Pad Init
  74. mcp23017_write(IODIRA,0xF0);
  75. mcp23017_write(GPPUA,0xF0);
  76. char temp,charCount=0,newLine=0,line=1;
  77. while (1)
  78. {
  79. temp=keyScan();
  80. if(temp!=0){
  81. lcd_data(temp);
  82. charCount++;
  83. _delay_ms(500);
  84. }
  85. if(charCount>16){
  86. newLine=1;
  87. charCount=0;
  88. line+=1;
  89. }
  90. if(newLine){
  91. newLine=0;
  92. if(line==2) lcd_xy(1,2);
  93. else{
  94. lcd_xy(1,1);
  95. lcd_command(0x01);
  96. _delay_ms(5);
  97. line=1;
  98. }
  99. }
  100. }
  101. }


We need to add the "twi.c" to project before the twi function can be called. 

  • "twi.c"
  1. /*
  2. * twi.c
  3. *
  4. * Created: 2/4/2026 10:22:02 AM
  5. * Author: Admin
  6. */

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


  10. void twi_init(void){
  11. TWSR|=0x00; //Prescaler Selection Bit
  12. TWBR=0x0F; //Baud Rate Generator
  13. TWCR=(1<<TWEN); //Enable The TWI Module
  14. PORTC|=(1<<0);
  15. PORTC|=(1<<1);
  16. }

  17. void twi_start(void){
  18. TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
  19. while((TWCR&(1<<TWINT))==0);
  20. }

  21. void twi_write(unsigned char data){
  22. TWDR=data;
  23. TWCR=(1<<TWINT)|(1<<TWEN);
  24. while((TWCR&(1<<TWINT))==0);
  25. }

  26. unsigned char twi_read(char ACK){
  27. if(ACK==0)
  28. TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWEA);
  29. else
  30. TWCR=(1<<TWINT)|(1<<TWEN);
  31. while((TWCR&(1<<TWINT))==0);
  32. return TWDR;
  33. }

  34. void twi_stop(){
  35. TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
  36. _delay_us(10);
  37. }

 

  •  Schematic

 

ATMega644P TWI MCP23017 LCD Keypad
Proteus Circuit and Simulation
ATMega644P TWI MCP23017 LCD Keypad
Keypad Scanning
  •  ATMega644P AVR Board Experiment
 
 
ATMega644P TWI MCP23017 LCD Keypad
AVR Prototype Board Experiment
 
ATMega644P TWI MCP23017 LCD Keypad
AVR Prototype Board Experiment
 

This PCB was offered by PCBWay (pcbway.com).

I have been using PCBWay for many years now. PCBWay fabricate PCBs at low cost, fast processing time for only 24 hours, and fast delivery time using any carrier options. This double side 10cmx10cm can be fabricate at only 5USD for 5 to 10pcs by PCBWay. It's a standard PCB with silk screen and solder mask.

A DIY dsPIC30F2010 and dsPIC30F1010 Prototype Board with Programmer
10 PCBs for only 5USD
 

For different size of PCB we can instantly quote on PCBWay website using a zip PCB Gerber file without account.

A DIY dsPIC30F2010 and dsPIC30F1010 Prototype Board with Programmer
PCBWay Instant Quote
 

There's on port left GPB. So I added one more keypad port.

ATMega644P TWI MCP23017 LCD Keypad
Two Keypad Ports

 Source Code:

  1. /*
  2. * 10-i2c_mcp23017_keypad_2.c
  3. *
  4. * Created: 2/5/2026 3:14:18 PM
  5. * Author : Admin
  6. */

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

  10. const char MCP23017_W=0x40;
  11. const char MCP23017_R=0x41;

  12. //IOCON.BANK=0
  13. enum BANK0{
  14. IODIRA=0,IODIRB,IPOLA,IPOLB,GPINTENA,GPINTENB,DEFVALA,
  15. DEFVALB,INTCONA,INTCONB,IOCON1,IOCON2,GPPUA,GPPUB,
  16. INTFA,INTFB,INTCAPA,INTCAPB,GPIOA,GPIOB,OLATA,OLATB
  17. };


  18. void mcp23017_write(char address,char data){
  19. twi_start();
  20. /*Select the write address*/
  21. twi_write(MCP23017_W);
  22. /*Select a register address*/
  23. twi_write(address);
  24. /*Send configuration data*/
  25. twi_write(data);
  26. twi_stop();
  27. }

  28. unsigned char mcp23017_read(char address){
  29. /*Select a specific address*/
  30. twi_start();
  31. twi_write(MCP23017_W);
  32. twi_write(address);
  33. twi_stop();
  34. /*Read data from the given address*/
  35. twi_start();
  36. twi_write(MCP23017_R);
  37. unsigned char i2cData=twi_read(1);
  38. twi_stop();
  39. return i2cData;
  40. }

  41. //KeyPad at GPA
  42. const char key_1[4][4]={'1','2','3','A',
  43. '4','5','6','B',
  44. '7','8','9','C',
  45. '*','0','#','D'};

  46. //KeyPad at GPB
  47. const char key_2[4][4]={'E','F','G','H',
  48. 'I','J','K','L',
  49. 'M','N','O','P',
  50. 'Q','R','S','T'};
  51. //KeyPad at GPA
  52. char keyScan_1(void){
  53. char data=0,temp,key;
  54. for(char i=0;i<4;i++){
  55. data=0xFF;
  56. data&=~(1<<i);
  57. mcp23017_write(OLATA,data);
  58. _delay_ms(5);
  59. data=mcp23017_read(GPIOA);
  60. data&=0xF0;
  61. if((data&0x10)==0) {temp=key_1[i][0]; break;}
  62. else if((data&0x20)==0){temp=key_1[i][1]; break;}
  63. else if((data&0x40)==0){temp=key_1[i][2]; break;}
  64. else if((data&0x80)==0){temp=key_1[i][3]; break;}
  65. else temp=0;
  66. _delay_ms(10);
  67. }
  68. return temp;
  69. }
  70. //KeyPad at GPB
  71. char keyScan_2(void){
  72. char data=0,temp,key;
  73. for(char i=0;i<4;i++){
  74. data=0xFF;
  75. data&=~(1<<i);
  76. mcp23017_write(OLATB,data);
  77. _delay_ms(5);
  78. data=mcp23017_read(GPIOB);
  79. data&=0xF0;
  80. if((data&0x10)==0) {temp=key_2[i][0]; break;}
  81. else if((data&0x20)==0){temp=key_2[i][1]; break;}
  82. else if((data&0x40)==0){temp=key_2[i][2]; break;}
  83. else if((data&0x80)==0){temp=key_2[i][3]; break;}
  84. else temp=0;
  85. _delay_ms(10);
  86. }
  87. return temp;
  88. }

  89. int main(void)
  90. {
  91. /* Replace with your application code */
  92. lcd_init();
  93. twi_init();
  94. lcd_text("ATMEGA644P TWI");
  95. lcd_xy(1,2);
  96. lcd_text("MCP23017 KeyPad");
  97. _delay_ms(5000);
  98. lcd_clear();
  99. //Key Pad Init
  100. mcp23017_write(IODIRA,0xF0);
  101. mcp23017_write(GPPUA,0xF0);
  102. mcp23017_write(IODIRB,0xF0);
  103. mcp23017_write(GPPUB,0xF0);
  104. char keyPad_1,keyPad_2,charCount=0,newLine=0,line=1;
  105. while (1)
  106. {
  107. keyPad_1=keyScan_1();
  108. if(keyPad_1!=0){
  109. lcd_data(keyPad_1);
  110. charCount++;
  111. _delay_ms(500);
  112. }
  113. keyPad_2=keyScan_2();
  114. if(keyPad_2!=0){
  115. lcd_data(keyPad_2);
  116. charCount++;
  117. _delay_ms(500);
  118. }
  119. if(charCount>16){
  120. newLine=1;
  121. charCount=0;
  122. line+=1;
  123. }
  124. if(newLine){
  125. newLine=0;
  126. if(line==2) lcd_xy(1,2);
  127. else{
  128. lcd_xy(1,1);
  129. lcd_command(0x01);
  130. _delay_ms(5);
  131. line=1;
  132. }
  133. }
  134. }
  135. }


Schematic:

ATMega644P TWI MCP23017 LCD Keypad
Schematic

 AVR Prototype Board:

ATMega644P TWI MCP23017 LCD Keypad
AVR Prototype Board
ATMega644P TWI MCP23017 LCD Keypad
AVR Prototype Board Experiment

 For a full ATMega644P tutorials please visit this page.


 

Search This Blog

Labels

23K256 (1) 24C16B (2) 25AA010A (2) 8051 (7) 93AA46B (1) ADC (34) Analog Comparator (1) Arduino (16) ARM (13) AT89C52 (7) ATMega32 (58) ATMega644P (27) AVR (87) Bootloader (1) CCS PICC (31) Change Notify Interrupt (CNI) (2) DAC (2) DHT11 (4) Display (133) Distance Sensor (3) ds1307 (10) DS18B20 (5) ds3231 (1) ds3232 (2) dsPIC (5) dsPIC30F1010 (3) dsPIC30F2010 (5) EEPROM (5) Environment Sensor (5) ESP32 (1) esp8266 (1) Graphical LCD (2) I2C (38) ILI9341 (1) Input/Output (75) Interrupt (22) Keil (5) Keypad (16) KS0108 (2) LCD (75) LM35 (3) Master/Slave (2) MAX7221 (1) MCP23017 (8) MCP23S17 (7) MCP4921 (1) MCP4922 (2) Meter (3) MikroC (2) Motor (15) MPLABX (73) Nokia 5110 LCD (4) OLED (2) One-Wire (7) Oscillator (8) PCB (10) PCD8544 (3) PCF8574 (10) PIC (108) PIC12F (3) PIC16F628A (3) PIC16F630 (2) PIC16F716 (4) PIC16F818 (11) PIC16F818/819 (3) PIC16F84A (16) PIC16F876A (2) PIC16F877A (9) PIC16F88 (2) PIC16F887 (60) PIC18 (19) PIC18F1220 (5) PIC18F2550 (5) PIC18F4550 (12) PICKit2 (1) Pin Change Interrupt (1) PWM (12) RTC (12) SBN0064G (1) Sensor (13) SH1106 (3) Shift Register (13) Shift Registers (10) Software TWI (2) SPI (39) ST7735 (1) STM32 (11) STM32 Black Pill (1) STM32 Blue Pill (12) STM32 HAL (5) STM32CubeIDE (13) STM32F103C8T6 (9) STM32F401CCU6 (1) SysTick (4) temperature sensor (13) TFT (1) TG12864A (1) Thermometer (22) Timer/Counter (32) TM1637 (2) twi (10) UART (8) Ultrasonic (4) Voltmeter (7) WDT (1) XC16 (2) XC8 (96)