Sunday, February 11, 2024

PIC16F887 SPI MCP23S17 Character LCD and KeyPad XC8 Example

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.

PIC16F887 SPI MCP23S17 Character LCD and KeyPad XC8 Example
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. 

PIC16F887 SPI MCP23S17 Character LCD and KeyPad XC8 Example
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.

  1. /*
  2.  * File: main.c
  3.  * Author: Admin
  4.  *
  5.  * Created on February 11, 2024, 10:42 AM
  6.  */
  7.  
  8. #include <xc.h>
  9. #include "config.h"
  10. #include "mcp23S17.h"
  11.  
  12. #define _XTAL_FREQ 8000000UL
  13.  
  14. /*MCP23S17 4x4 KeyPad Scan Function*/
  15. const uint8_t key_ascii[][4]={
  16. '7','8','9','/',
  17. '4','5','6','*',
  18. '1','2','3','-',
  19. 'x','0','=','+'
  20. };
  21. uint8_t get_key(void);
  22.  
  23. void main(void) {
  24. uint8_t key=0,char_count=0, new_line=0,line_num=1;
  25. OSCCONbits.IRCF=7;
  26. lcd_init();
  27. lcd_text("PIC16F887 MCP23S17");
  28. lcd_xy(1,2); lcd_text("Character LCD KeyPad");
  29. lcd_xy(1,3); lcd_text("Example Using MPLABX");
  30. lcd_xy(1,4); lcd_text("IDE And XC8 Compiler");
  31. __delay_ms(3000);
  32. lcd_clear();
  33. while(1){
  34. key=get_key();
  35. if(key!=0){
  36. lcd_data(key);
  37. __delay_ms(250);
  38. char_count+=1;
  39. }
  40. if(char_count>=20){char_count=0; new_line=1;}
  41. if(new_line){
  42. new_line=0;
  43. line_num+=1;
  44. switch(line_num){
  45. case 2: lcd_xy(1,2); break;
  46. case 3: lcd_xy(1,3); break;
  47. case 4: lcd_xy(1,4); break;
  48. case 5: lcd_clear(); line_num=1; break;
  49. }
  50. }
  51. }
  52. }
  53.  
  54. uint8_t get_key(void){
  55. uint8_t data,key_value=0;
  56. for(uint8_t i=0;i<4;i++){
  57. mcp23S17_send(OLATB,1<<i);
  58. __delay_ms(10);
  59. data=mcp23S17_receive(GPIOB);
  60. data=data>>4;
  61. if(data==0x01) {key_value=key_ascii[i][0]; break;}
  62. else if(data==0x02) {key_value=key_ascii[i][1]; break;}
  63. else if(data==0x04) {key_value=key_ascii[i][2]; break;}
  64. else if(data==0x08) {key_value=key_ascii[i][3]; break;}
  65. else key_value=0;
  66. }
  67. return key_value;
  68. }

I wrote a driver for the MCP23S17 that use the SPI driver within the project file.

The mcp23S17.h C header file:

  1. /*
  2.  * File: mcp23S17.h
  3.  * Author: Admin
  4.  *
  5.  * Created on February 9, 2024, 3:54 PM
  6.  */
  7.  
  8. #include <xc.h>
  9. #include "spi.h"
  10.  
  11. /*MCP23S17 Registers Definition*/
  12. #define IODIRA 0x00
  13. #define IODIRB 0x01
  14. #define IPOLA 0x02
  15. #define IPOLB 0x03
  16. #define GPINTENA 0x04
  17. #define GPINTENB 0x05
  18. #define DEFVALA 0x06
  19. #define DEFVALB 0x07
  20. #define INTCONA 0x08
  21. #define INTCONB 0x09
  22. #define IOCONA 0x0A
  23. #define IOCONB 0x0B
  24. #define GPPUA 0x0C
  25. #define GPPUB 0x0D
  26. #define INTFA 0x0E
  27. #define INTFB 0x0F
  28. #define INTCAPA 0x10
  29. #define INTCAPB 0x11
  30. #define GPIOA 0x12
  31. #define GPIOB 0x13
  32. #define OLATA 0x14
  33. #define OLATB 0x15
  34.  
  35. /*MCP23S17 Address*/
  36. #define WRITE_ADDR 0x40
  37. #define READ_ADDR 0x41
  38.  
  39. /*MCP23S17 Read and Write Functions*/
  40. void mcp23S17_send(uint8_t address, uint8_t data);
  41. uint8_t mcp23S17_receive(uint8_t address);
  42.  
  43. /*MCP23S17 Character LCD Functions*/
  44. #define RS 0
  45. #define EN 2
  46. void lcd_command(uint8_t command);
  47. void lcd_data(uint8_t myChar);
  48. void lcd_xy(uint8_t x, uint8_t y);
  49. void lcd_text(uint8_t *txt);
  50. void lcd_clear(void);
  51. void lcd_init(void);
  52.  
  53.  

The mcp23S17.c C source file:

  1.  
  2. #include "mcp23S17.h"
  3.  
  4. /*MCP23S17 Input Output Functions*/
  5. void mcp23S17_send(uint8_t address, uint8_t data){
  6. nCS=0;
  7. spi_send(WRITE_ADDR);
  8. spi_send(address);
  9. spi_send(data);
  10. nCS=1;
  11. }
  12.  
  13. uint8_t mcp23S17_receive(uint8_t address){
  14. uint8_t data;
  15. nCS=0;
  16. spi_send(READ_ADDR);
  17. spi_send(address);
  18. data=spi_receive();
  19. nCS=1;
  20. return data;
  21. }
  22.  
  23. /*MCP23S17 Character LCD Functions*/
  24. void delay(uint16_t count){
  25. while(count>0) count--;
  26. }
  27. void lcd_command(uint8_t command){
  28. uint8_t data;
  29. data=command&0xF0;
  30. mcp23S17_send(OLATA, data|(1<<EN));
  31. delay(50);
  32. mcp23S17_send(OLATA, data);
  33. delay(50);
  34.  
  35. data=command<<4;
  36. mcp23S17_send(OLATA, data|(1<<EN));
  37. delay(50);
  38. mcp23S17_send(OLATA, data);
  39. delay(50);
  40. }
  41.  
  42. void lcd_data(uint8_t myChar){
  43. uint8_t data;
  44. data=myChar&0xF0;
  45. mcp23S17_send(OLATA, data|(1<<RS)|(1<<EN));
  46. delay(50);
  47. mcp23S17_send(OLATA, data);
  48. delay(50);
  49.  
  50. data=myChar<<4;
  51. mcp23S17_send(OLATA, data|(1<<RS)|(1<<EN));
  52. delay(50);
  53. mcp23S17_send(OLATA, data|(1<<RS));
  54. delay(50);
  55. }
  56.  
  57. void lcd_xy(uint8_t x, uint8_t y){
  58. /*20x4 Character LCD*/
  59. uint8_t tbe[]={0x80,0xC0,0x94,0xD4};
  60. lcd_command(tbe[y-1]+x-1);
  61. }
  62.  
  63. void lcd_text(uint8_t *txt){
  64. while(*txt) lcd_data(*txt++);
  65. }
  66.  
  67. void lcd_init(void){
  68. spi_init();
  69. nCS=1;
  70. /*LCD PORT*/
  71. mcp23S17_send(IODIRA,0x00);
  72. mcp23S17_send(OLATA,0x00);
  73. /*KeyPad PORT*/
  74. mcp23S17_send(IODIRB,0xF0);
  75.  
  76. lcd_command(0x33);
  77. lcd_command(0x32);
  78. lcd_command(0x28);
  79. lcd_command(0x0F);
  80. lcd_command(0x01);
  81. delay(500);
  82. lcd_command(0x06);
  83. }
  84.  
  85. void lcd_clear(void){
  86. lcd_command(0x01);
  87. delay(500);
  88. }
  89.  
  90.  

PIC16F887 SPI MCP23S17 Character LCD and KeyPad XC8 Example
Simulating Program

Click here to download its source file.



No comments:

Post a Comment

Search This Blog

Labels

25AA010A (1) 8051 (7) 93AA46B (1) ADC (30) Analog Comparator (1) Arduino (15) ARM (6) AT89C52 (7) ATMega32 (56) AVR (57) CCS PICC (28) DAC (1) DHT11 (2) Display (105) Distance Sensor (3) DS18B20 (3) dsPIC (2) dsPIC30F1010 (2) EEPROM (5) Environment Sensor (4) esp8266 (1) I2C (29) Input/Output (67) Interrupt (19) Keil (5) Keypad (10) LCD (47) Master/Slave (1) MAX7221 (1) MCP23017 (5) MCP23S17 (4) Meter (3) MikroC (2) Motor (15) MPLABX (71) Nokia 5110 LCD (3) OLED (2) One-Wire (6) Oscillator (8) PCB (6) PCD8544 (3) PCF8574 (5) PIC (107) PIC12F (2) PIC16F628A (2) PIC16F630 (1) PIC16F716 (3) PIC16F818 (10) PIC16F818/819 (2) PIC16F84A (15) PIC16F876A (1) PIC16F877A (9) PIC16F88 (1) PIC16F887 (60) PIC18 (19) PIC18F1220 (4) PIC18F2550 (3) PIC18F4550 (12) PWM (11) RTC (8) Sensor (10) SH1106 (1) Shift Register (11) Shift Registers (3) SPI (24) STM32 (6) STM32 Blue Pill (6) STM32CubeIDE (6) STM32F103C8T6 (6) SysTick (3) temperature sensor (11) Thermometer (21) Timer/Counter (31) TM1637 (2) UART (7) Ultrasonic (4) Voltmeter (7) WDT (1) XC16 (2) XC8 (94)