728x90

Monday, February 12, 2024

PIC16F887 SPI SN74HC165 LCD XC8 Example

Overview

The SN74HC165 is an 8-bit parallel-load shift registers chip. It uses the SPI interface to shift data out from the register. This chip commonly use in keys reading in video system, printer/scanner, microwave oven, etc.

PIC16F887 SPI SN74HC165 LCD XC8 Example
Simulating Program in Proteus

This chip is very easy to use since it's a standard logic IC. It does not require any configuration like the MCP23S17 does.

PIC16F887 SPI SN74HC165 LCD XC8 Example
Pin Configuration and Functions

It has a Dual In Line Package (DIP) easing the electronics hobbyist prototyping. I don't have a physical chip here because it is hard to find at local store. But it has a model in Proteus VSM allowing us to simulate the behavior of this chip.

PIC16F887 SPI SN74HC165 LCD XC8 Example
Logic Diagram

The SN74HC165 contain standard logic gates and flip flop as shown in the diagram above. It can be cascaded to make a larger registers more than 8-bit inputs.

PIC16F887 SPI SN74HC165 LCD XC8 Example
Load Shift Sequence

To use the chip the microprocessor must activate the LOAD (LD) pin from high to low transition first. It will latch the 9-bit input data into the register. Then the 8 clock cycle input via CLK (clock) pin will shift the data out at SO (serial out) pin.

The CLK INH (clock inhabit) must be pulled low to enable this chip.

PIC16F887 SPI Programming

We can use the build-in SPI module of PIC16F887 to read data from this chip. The SPI module has the following pins,

  1. nCS - Chip Select (RC2 or other pins)
  2. SCK - Serial Clock (RC3)
  3. SDI - Serial Data In (RC4)
  4. SDO - Serial Data Out (RC5)

I use the nCS pin to load data into the SN74C165 first before the data shifts out. In this example, the PIC16F887 read data from the SN74HC165. The 8-bit data will show on a 16x2 character LCD in decimal, hexadecimal and binary value.

  1. /*
  2.  * File: main.c
  3.  * Author: Admin
  4.  *
  5.  * Created on February 12, 2024, 7:19 PM
  6.  */
  7.  
  8. #include <xc.h>
  9. #include <stdio.h>
  10. #include "config.h"
  11. #include "LCD4Bits.h"
  12. #include "spi.h"
  13.  
  14. #define _XTAL_FREQ 8000000UL
  15.  
  16. void putch(char data){
  17. lcdData(data);
  18. }
  19.  
  20. void dec_to_bin(uint8_t data){
  21. for(int8_t i=7;i>=0;i--){
  22. if((data&(1<<i))==0) putch('0');
  23. else putch('1');
  24. }
  25. }
  26.  
  27. void main(void) {
  28. uint8_t rc_data;
  29. OSCCONbits.IRCF=7;
  30. lcdInit();
  31. spi_init();
  32. lcdCommand(0x0C);
  33. nCS=1;
  34. while(1){
  35. nCS=0;
  36. __delay_us(10);
  37. nCS=1;
  38. rc_data=spi_receive();
  39. lcdXY(1,1);
  40. printf("DEC:%3d",rc_data);
  41. printf(" HEX:0x%02X",rc_data);
  42. lcdXY(1,2);
  43. printf("BIN: ");
  44. dec_to_bin(rc_data);
  45. __delay_ms(100);
  46. }
  47. return;
  48. }
  49.  

I putted the SPI driver in one package.

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 WRITE_ADDR 0x40
  11. #define READ_ADDR 0x41
  12.  
  13. #define nCS RC2
  14.  
  15. void spi_init(void);
  16. void spi_send(uint8_t data);
  17. uint8_t spi_receive(void);
  18.  
  19.  

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/64*/
  10. SSPCONbits.SSPM=2;
  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. }

Click here to download this example.

PIC16F887 SPI SN74HC165 LCD XC8 Example
Simulating Program in Proteus


We can use the PIC16F84A with SPI bit-banging to read the data from this chip. A larger AVR chip, the ATMega32 could use a software SPI to interface to this chip.

You can see the software SPI version of this example.



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.



Search This Blog