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.
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.
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.
/* * File: main.c * Author: Admin * * Created on February 9, 2024, 3:47 PM */ #include <xc.h> #include "config.h" #include "mcp23S17.h" #define _XTAL_FREQ 8000000UL #define RS 0 #define EN 2 void lcd_command(uint8_t command){ uint8_t data; data=command&0xF0; mcp23S17_send(OLATA, data|(1<<EN)); __delay_us(50); mcp23S17_send(OLATA, data); __delay_us(50); data=command<<4; mcp23S17_send(OLATA, data|(1<<EN)); __delay_us(50); mcp23S17_send(OLATA, data); __delay_us(50); } void lcd_data(uint8_t myChar){ uint8_t data; data=myChar&0xF0; mcp23S17_send(OLATA, data|(1<<RS)|(1<<EN)); __delay_us(50); mcp23S17_send(OLATA, data); __delay_us(50); data=myChar<<4; mcp23S17_send(OLATA, data|(1<<RS)|(1<<EN)); __delay_us(50); mcp23S17_send(OLATA, data|(1<<RS)); __delay_us(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; mcp23S17_send(IODIRA,0x00); mcp23S17_send(OLATA,0x00); lcd_command(0x33); lcd_command(0x32); lcd_command(0x28); lcd_command(0x0F); lcd_command(0x01); __delay_ms(5); lcd_command(0x06); } void main(void) { OSCCONbits.IRCF=7; lcd_init(); lcd_xy(2,1); lcd_text("PIC16F887 MCP23S17"); lcd_xy(2,2); lcd_text("SPI GPIO Extender"); lcd_xy(2,3); lcd_text("Example With MPLABX"); lcd_xy(1,4); lcd_text("And XC8 C Compiler.."); while(1){ } return; }
I putted the SPI driver in separated files.
- The spi.h header file
/* * File: spi.h * Author: Admin * * Created on February 9, 2024, 9:13 AM */ #include <xc.h> #define nCS RC2 void spi_init(void); void spi_send(uint8_t data); uint8_t spi_receive(void);
- The spi.c source file
#include "spi.h" void spi_init(void){ /*SPI Mode Clock Low To High*/ SSPCONbits.CKP=0; SSPSTATbits.CKE=1; SSPSTATbits.SMP=0; /*SPI Master Mode Clock = Fosc/4*/ SSPCONbits.SSPM=0; /*Turn On The Module*/ SSPCONbits.SSPEN=1; SSPSTATbits.BF=1; PORTC=0; TRISC=0; /*SPI SDI Pin Input*/ TRISC4=1; } void spi_send(uint8_t data){ SSPSTATbits.BF==1; SSPBUF=data; while(SSPSTATbits.BF==0); SSPSTATbits.BF==1; } uint8_t spi_receive(void){ uint8_t data; spi_send(0x00); data=SSPBUF; return data; }
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
/* * 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);
- The mcp23S17.c source file
#include "mcp23S17.h" 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; }
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