Friday, February 9, 2024

PIC16F887 SPI MCP23S17 and Character LCD XC8 Example

In previous post I use the SPI interface of PIC16F887 to communicate with the MCP23S17 to read and write data from its I/O ports. The I/O port of MCP23S17 could be used for many input output purposes, relays driving, input sensor reading, etc.

PIC16F887 SPI MCP23S17 and Character LCD XC8 Example
Program Simulation in Proteus

In this example, I use GPIOA of MCP23S17 to control an HD44780 based character LCD module using its 4-bit data transfer mode. The MCP23S17 just need to write the 8-bit command or data to the LCD without concerning about reading the data back.

PIC16F887 SPI MCP23S17 and Character LCD XC8 Example
MCP23S17 DIP-28

The 8-bit LCD data will transfer the LCD controller twice. The higher nibble is sent first and then the lower nibble of the data byte. So the data byte must be latched into the LCD controller twice. Data latching is activated at falling edge of Enable (E) pin of the LCD.

I use the internal RC oscillator of PIC16F887 of 8MHz. The SPI clock frequency is Fosc/4. So the transfer rate is slower compare to direct I/O port driving. However we can use the external 20MHz crystal to get a higher frequency.

  1. /*
  2.  * File: main.c
  3.  * Author: Admin
  4.  *
  5.  * Created on February 9, 2024, 3:47 PM
  6.  */
  7.  
  8. #include <xc.h>
  9. #include "config.h"
  10. #include "mcp23S17.h"
  11.  
  12. #define _XTAL_FREQ 8000000UL
  13.  
  14. #define RS 0
  15. #define EN 2
  16.  
  17. void lcd_command(uint8_t command){
  18. uint8_t data;
  19. data=command&0xF0;
  20. mcp23S17_send(OLATA, data|(1<<EN));
  21. __delay_us(50);
  22. mcp23S17_send(OLATA, data);
  23. __delay_us(50);
  24.  
  25. data=command<<4;
  26. mcp23S17_send(OLATA, data|(1<<EN));
  27. __delay_us(50);
  28. mcp23S17_send(OLATA, data);
  29. __delay_us(50);
  30. }
  31.  
  32. void lcd_data(uint8_t myChar){
  33. uint8_t data;
  34. data=myChar&0xF0;
  35. mcp23S17_send(OLATA, data|(1<<RS)|(1<<EN));
  36. __delay_us(50);
  37. mcp23S17_send(OLATA, data);
  38. __delay_us(50);
  39.  
  40. data=myChar<<4;
  41. mcp23S17_send(OLATA, data|(1<<RS)|(1<<EN));
  42. __delay_us(50);
  43. mcp23S17_send(OLATA, data|(1<<RS));
  44. __delay_us(50);
  45. }
  46.  
  47. void lcd_xy(uint8_t x, uint8_t y){
  48. /*20x4 Character LCD*/
  49. uint8_t tbe[]={0x80,0xC0,0x94,0xD4};
  50. lcd_command(tbe[y-1]+x-1);
  51. }
  52.  
  53. void lcd_text(uint8_t *txt){
  54. while(*txt) lcd_data(*txt++);
  55. }
  56.  
  57. void lcd_init(void){
  58. spi_init();
  59. nCS=1;
  60. mcp23S17_send(IODIRA,0x00);
  61. mcp23S17_send(OLATA,0x00);
  62.  
  63. lcd_command(0x33);
  64. lcd_command(0x32);
  65. lcd_command(0x28);
  66. lcd_command(0x0F);
  67. lcd_command(0x01);
  68. __delay_ms(5);
  69. lcd_command(0x06);
  70. }
  71.  
  72. void main(void) {
  73. OSCCONbits.IRCF=7;
  74. lcd_init();
  75. lcd_xy(2,1);
  76. lcd_text("PIC16F887 MCP23S17");
  77. lcd_xy(2,2);
  78. lcd_text("SPI GPIO Extender");
  79. lcd_xy(2,3);
  80. lcd_text("Example With MPLABX");
  81. lcd_xy(1,4);
  82. lcd_text("And XC8 C Compiler..");
  83.  
  84. while(1){
  85.  
  86. }
  87. return;
  88. }
  89.  

I putted the SPI driver in separated files. 

  • The spi.h header file

  1. /*
  2.  * File: spi.h
  3.  * Author: Admin
  4.  *
  5.  * Created on February 9, 2024, 9:13 AM
  6.  */
  7.  
  8. #include <xc.h>
  9.  
  10. #define nCS RC2
  11.  
  12. void spi_init(void);
  13. void spi_send(uint8_t data);
  14. uint8_t spi_receive(void);
  15.  
  16.  
  • The spi.c source file
  1.  
  2. #include "spi.h"
  3.  
  4. void spi_init(void){
  5. /*SPI Mode Clock Low To High*/
  6. SSPCONbits.CKP=0;
  7. SSPSTATbits.CKE=1;
  8. SSPSTATbits.SMP=0;
  9. /*SPI Master Mode Clock = Fosc/4*/
  10. SSPCONbits.SSPM=0;
  11. /*Turn On The Module*/
  12. SSPCONbits.SSPEN=1;
  13. SSPSTATbits.BF=1;
  14. PORTC=0;
  15. TRISC=0;
  16. /*SPI SDI Pin Input*/
  17. TRISC4=1;
  18. }
  19.  
  20. void spi_send(uint8_t data){
  21. SSPSTATbits.BF==1;
  22. SSPBUF=data;
  23. while(SSPSTATbits.BF==0);
  24. SSPSTATbits.BF==1;
  25. }
  26.  
  27. uint8_t spi_receive(void){
  28. uint8_t data;
  29. spi_send(0x00);
  30. data=SSPBUF;
  31. return data;
  32. }

I wrote a driver for the MCP23S17 to send and received the data from this chip. It uses the SPI driver above.

  • The MCP23S17.h 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.  
  • The mcp23S17.c source file
  1.  
  2. #include "mcp23S17.h"
  3.  
  4. void mcp23S17_send(uint8_t address, uint8_t data){
  5. nCS=0;
  6. spi_send(WRITE_ADDR);
  7. spi_send(address);
  8. spi_send(data);
  9. nCS=1;
  10. }
  11.  
  12. uint8_t mcp23S17_receive(uint8_t address){
  13. uint8_t data;
  14. nCS=0;
  15. spi_send(READ_ADDR);
  16. spi_send(address);
  17. data=spi_receive();
  18. nCS=1;
  19. return data;
  20. }

The MPLABX IDE version is v6.15 and the XC8 C compiler version is v2.36. You can use the latest version of C compiler as you prefer. 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)