In previous example, I use the MCP23S17 to drive an HD44780 based 20x4 character LCD using the 4-bit data transfer mode. This chip has two GPIO ports. So it can interface to various types of digital I/O devices including a dot matrix display, a multiplexing 7-Segment display, a matrix keypad, etc.
Simulating Program in Proteus |
In this example, I use a 20x4 character LCD and a 4x4 matrix keypad. They are controlled by the MCP23S17 GPIO extender chip. This chip uses the SPI interface that controlled by a PIC16F887 micro-controller.
A 4x4 membrane matrix keypad is suitable for most of hobbyist electronics projects |
I add a key pad scanning routine in the C main file. It's very simple, and light weight. The founded key is an ASCII character that directly show on the LCD, otherwise it return 0 value.
/* * File: main.c * Author: Admin * * Created on February 11, 2024, 10:42 AM */ #include <xc.h> #include "config.h" #include "mcp23S17.h" #define _XTAL_FREQ 8000000UL /*MCP23S17 4x4 KeyPad Scan Function*/ const uint8_t key_ascii[][4]={ '7','8','9','/', '4','5','6','*', '1','2','3','-', 'x','0','=','+' }; uint8_t get_key(void); void main(void) { uint8_t key=0,char_count=0, new_line=0,line_num=1; OSCCONbits.IRCF=7; lcd_init(); lcd_text("PIC16F887 MCP23S17"); lcd_xy(1,2); lcd_text("Character LCD KeyPad"); lcd_xy(1,3); lcd_text("Example Using MPLABX"); lcd_xy(1,4); lcd_text("IDE And XC8 Compiler"); __delay_ms(3000); lcd_clear(); while(1){ key=get_key(); if(key!=0){ lcd_data(key); __delay_ms(250); char_count+=1; } if(char_count>=20){char_count=0; new_line=1;} if(new_line){ new_line=0; line_num+=1; switch(line_num){ case 2: lcd_xy(1,2); break; case 3: lcd_xy(1,3); break; case 4: lcd_xy(1,4); break; case 5: lcd_clear(); line_num=1; break; } } } } uint8_t get_key(void){ uint8_t data,key_value=0; for(uint8_t i=0;i<4;i++){ mcp23S17_send(OLATB,1<<i); __delay_ms(10); data=mcp23S17_receive(GPIOB); data=data>>4; if(data==0x01) {key_value=key_ascii[i][0]; break;} else if(data==0x02) {key_value=key_ascii[i][1]; break;} else if(data==0x04) {key_value=key_ascii[i][2]; break;} else if(data==0x08) {key_value=key_ascii[i][3]; break;} else key_value=0; } return key_value; }
I wrote a driver for the MCP23S17 that use the SPI driver within the project file.
The mcp23S17.h C header file:
/* * File: mcp23S17.h * Author: Admin * * Created on February 9, 2024, 3:54 PM */ #include <xc.h> #include "spi.h" /*MCP23S17 Registers Definition*/ #define IODIRA 0x00 #define IODIRB 0x01 #define IPOLA 0x02 #define IPOLB 0x03 #define GPINTENA 0x04 #define GPINTENB 0x05 #define DEFVALA 0x06 #define DEFVALB 0x07 #define INTCONA 0x08 #define INTCONB 0x09 #define IOCONA 0x0A #define IOCONB 0x0B #define GPPUA 0x0C #define GPPUB 0x0D #define INTFA 0x0E #define INTFB 0x0F #define INTCAPA 0x10 #define INTCAPB 0x11 #define GPIOA 0x12 #define GPIOB 0x13 #define OLATA 0x14 #define OLATB 0x15 /*MCP23S17 Address*/ #define WRITE_ADDR 0x40 #define READ_ADDR 0x41 /*MCP23S17 Read and Write Functions*/ void mcp23S17_send(uint8_t address, uint8_t data); uint8_t mcp23S17_receive(uint8_t address); /*MCP23S17 Character LCD Functions*/ #define RS 0 #define EN 2 void lcd_command(uint8_t command); void lcd_data(uint8_t myChar); void lcd_xy(uint8_t x, uint8_t y); void lcd_text(uint8_t *txt); void lcd_clear(void); void lcd_init(void);
The mcp23S17.c C source file:
#include "mcp23S17.h" /*MCP23S17 Input Output Functions*/ void mcp23S17_send(uint8_t address, uint8_t data){ nCS=0; spi_send(WRITE_ADDR); spi_send(address); spi_send(data); nCS=1; } uint8_t mcp23S17_receive(uint8_t address){ uint8_t data; nCS=0; spi_send(READ_ADDR); spi_send(address); data=spi_receive(); nCS=1; return data; } /*MCP23S17 Character LCD Functions*/ void delay(uint16_t count){ while(count>0) count--; } void lcd_command(uint8_t command){ uint8_t data; data=command&0xF0; mcp23S17_send(OLATA, data|(1<<EN)); delay(50); mcp23S17_send(OLATA, data); delay(50); data=command<<4; mcp23S17_send(OLATA, data|(1<<EN)); delay(50); mcp23S17_send(OLATA, data); delay(50); } void lcd_data(uint8_t myChar){ uint8_t data; data=myChar&0xF0; mcp23S17_send(OLATA, data|(1<<RS)|(1<<EN)); delay(50); mcp23S17_send(OLATA, data); delay(50); data=myChar<<4; mcp23S17_send(OLATA, data|(1<<RS)|(1<<EN)); delay(50); mcp23S17_send(OLATA, data|(1<<RS)); delay(50); } void lcd_xy(uint8_t x, uint8_t y){ /*20x4 Character LCD*/ uint8_t tbe[]={0x80,0xC0,0x94,0xD4}; lcd_command(tbe[y-1]+x-1); } void lcd_text(uint8_t *txt){ while(*txt) lcd_data(*txt++); } void lcd_init(void){ spi_init(); nCS=1; /*LCD PORT*/ mcp23S17_send(IODIRA,0x00); mcp23S17_send(OLATA,0x00); /*KeyPad PORT*/ mcp23S17_send(IODIRB,0xF0); lcd_command(0x33); lcd_command(0x32); lcd_command(0x28); lcd_command(0x0F); lcd_command(0x01); delay(500); lcd_command(0x06); } void lcd_clear(void){ lcd_command(0x01); delay(500); }
Simulating Program |
Click here to download its source file.
No comments:
Post a Comment