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.
| 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":
- /*
- * 12-spi_sn74hc165_sn74hc595n_keypad.c
- *
- * Created: 2/18/2026 2:03:34 PM
- * Author : Admin
- */
- #include <avr/io.h>
- #include <util/delay.h>
- #define F_CPU 16000000UL
- #define DDR_SPI DDRB
- #define PRT_SPI PORTB
- #define DD_SH 3
- #define DD_SS 4
- #define DD_MOSI 5
- #define DD_MISO 6
- #define DD_SCK 7
- void SPI_MasterInit(void)
- {
- /* Set MOSI and SCK output, all others input */
- DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
- /* Enable SPI, Master, set clock rate fck/16 */
- SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
- }
- void SPI_MasterTransmit(char cData)
- {
- /* Start transmission */
- SPDR = cData;
- /* Wait for transmission complete */
- while(!(SPSR & (1<<SPIF)))
- ;
- }
- void SPI_SlaveInit(void)
- {
- /* Set MISO output, all others input */
- DDR_SPI = (1<<DD_MISO);
- /* Enable SPI */
- SPCR = (1<<SPE);
- }
- char SPI_SlaveReceive(void)
- {
- /* Wait for reception complete */
- while(!(SPSR & (1<<SPIF)))
- ;
- /* Return Data Register */
- return SPDR;
- }
- const char key_16[4][8]={'1','2','3','4','5','6','7','8',
- '9','0','A','B','C','D','E','F',
- 'G','H','I','J','K','L','M','N',
- 'O','P','Q','R','S','T','U','V'};
- char key_scan(void){
- char data=0,temp,key;
- for(char i=0;i<8;i++){
- SPI_MasterTransmit(1<<i);
- PRT_SPI&=~(1<<DD_SS);
- _delay_us(10);
- PRT_SPI|=(1<<DD_SS);
- _delay_ms(5);
- PRT_SPI&=~(1<<DD_SH);
- PRT_SPI|=(1<<DD_SH);
- SPI_MasterTransmit(0);
- data=SPI_SlaveReceive();
- if(data==0x01) {temp=key_16[0][i]; break;}
- else if(data==0x02) {temp=key_16[1][i]; break;}
- else if(data==0x04){temp=key_16[2][i]; break;}
- else if(data==0x08){temp=key_16[3][i]; break;}
- else temp=0;
- _delay_ms(10);
- }
- return temp;
- }
- int main(void)
- {
- /* Replace with your application code */
- SPI_MasterInit();
- lcd_init();
- DDR_SPI|=(1<<DD_SH);
- char data=0;
- char temp,charCount=0,newLine=0,line=1;
- lcd_text("ATMega644P SPI");
- lcd_xy(1,2);
- lcd_text("MATRIX KEYPAD");
- _delay_ms(5000);
- lcd_clear();
- while (1)
- {
- temp=key_scan();
- if(temp!=0){
- lcd_data(temp);
- charCount++;
- _delay_ms(500);
- }
- if(charCount>16){
- newLine=1;
- charCount=0;
- line+=1;
- }
- if(newLine){
- newLine=0;
- if(line==2) lcd_xy(1,2);
- else{
- lcd_xy(1,1);
- lcd_command(0x01);
- _delay_ms(5);
- line=1;
- }
- }
- _delay_ms(100);
- }
- }
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.
| 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.
No comments:
Post a Comment