728x90

Showing posts with label OLED. Show all posts
Showing posts with label OLED. Show all posts

Saturday, January 20, 2024

PIC16F887 PCF8574AP I2C LCD Example using XC8

The PCF8574 could be used for a HD44780 based character LCD controlling using the 4-bit data transfer mode. The popular one's is an Arduino TWI LCD driving using this chip.

PIC16F887 PCF8574AP I2C LCD Example using XC8
A long hours running program


This chip has only 8 bits inputs/outputs. So it can interface with an 8-bit character LCD using the 4-bit data transfer mode. Using this method the micro-processor need to send the 8-bit command or data two time, first the higher nibble and then the lower nibble. For more information about using the PCF8574 please see this post.  If you are a beginner in micro-controller programming you can see this post about 4-bit LCD interfacing.

PIC16F887 PCF8574AP I2C LCD Example using XC8
Program Testing on Prototype Board

 I use use my own DIY PCF8574AP character LCD module. Its schematic is shown below.

PIC16F887 PCF8574AP I2C LCD Example using XC8
PCF8574AP Character LCD Module Schematic

Its slave address are 0x70 and 0x71.

PIC16F887 PCF8574AP I2C LCD Example using XC8
DIY PCF8574AP Character LCD Module

PIC16F887 PCF8574AP I2C LCD Example using XC8
DIY PCF8574AP Character LCD Module

You can use an Arduino PCF8574 LCD module with different address.

PIC16F887 PCF8574AP I2C LCD Example using XC8
Arduino PCF8574 LCD module

PIC16F887 PCF8574AP I2C LCD Example using XC8
Arduino PCF8574 LCD module

In this example, The micro-controller send a counter variable to the display. It updates for every 250ms. I use the I2C module of PIC16F887. The program written in C using MPLABX IDE and its XC8 C compiler. It's free to use.

  1. /*
  2.  * File: main.c
  3.  * Author: Admin
  4.  *
  5.  * Created on January 19, 2024, 3:36 PM
  6.  */
  7.  
  8. #include <xc.h>
  9. #include "config.h"
  10. #include "pcf8574.h"
  11. #include <stdio.h>
  12.  
  13. #define _XTAL_FREQ 8000000UL
  14.  
  15. #define RS 0
  16. #define RW 1
  17. #define EN 2
  18. #define BL 3
  19.  
  20. __bit backLight=0;
  21.  
  22. void i2c_lcdCommand(uint8_t command){
  23. uint8_t data;
  24. data=command&0xF0;
  25. pcf8574Write(data|(backLight<<BL)|(1<<EN));
  26. __delay_us(10);
  27. pcf8574Write(data|(backLight<<BL));
  28. __delay_us(50);
  29.  
  30. data=command<<4;
  31. pcf8574Write(data|(backLight<<BL)|(1<<EN));
  32. __delay_us(10);
  33. pcf8574Write(data|(backLight<<BL));
  34. __delay_us(50);
  35. }
  36.  
  37. void i2c_lcdData(uint8_t command){
  38. uint8_t data;
  39. data=command&0xF0;
  40. pcf8574Write(data|(backLight<<BL)|(1<<EN)|(1<<RS));
  41. __delay_us(10);
  42. pcf8574Write(data|(backLight<<BL)|(1<<RS));
  43. __delay_us(50);
  44.  
  45. data=command<<4;
  46. pcf8574Write(data|(backLight<<BL)|(1<<EN)|(1<<RS));
  47. __delay_us(10);
  48. pcf8574Write(data|(backLight<<BL)|(1<<RS));
  49. __delay_us(50);
  50. }
  51.  
  52. void i2c_lcdXY(int8_t x, int8_t y){
  53. int8_t addr[]={0x80,0xC0};
  54. i2c_lcdCommand(addr[y-1]+x-1);
  55. }
  56.  
  57. void i2c_lcdText(int8_t *txt){
  58. while(*txt) i2c_lcdData(*txt++);
  59. }
  60.  
  61. void i2c_lcdClear(void){
  62. i2c_lcdCommand(0x01);
  63. __delay_ms(5);
  64. }
  65.  
  66. void i2c_lcdInit(void){
  67. i2c_init(100000);
  68. __delay_us(10);
  69. pcf8574Write(0);
  70. __delay_ms(10);
  71. i2c_lcdCommand(0x33);
  72. __delay_us(10);
  73. i2c_lcdCommand(0x32);
  74. __delay_us(10);
  75. i2c_lcdCommand(0x28);
  76. __delay_us(10);
  77. i2c_lcdCommand(0x0F);
  78. __delay_us(10);
  79. i2c_lcdCommand(0x01);
  80. __delay_ms(5);
  81. i2c_lcdCommand(0x06);
  82. __delay_us(10);
  83. }
  84.  
  85. void main(void) {
  86. OSCCONbits.IRCF=7;
  87. i2c_lcdInit();
  88. backLight=1;
  89. __delay_ms(1000);
  90. i2c_lcdText(" PIC16F887 I2C");
  91. i2c_lcdXY(1,2);
  92. i2c_lcdText(" PCF8574AP LCD");
  93. long counter=0;
  94. uint8_t msg[10];
  95. __delay_ms(2000);
  96. i2c_lcdClear();
  97. i2c_lcdCommand(0x0C);
  98. i2c_lcdText("Counter Variable");
  99. while(1){
  100. sprintf(msg,"%u",counter);
  101. i2c_lcdXY(1,2);
  102. i2c_lcdText(msg);
  103. counter++;
  104. __delay_ms(250);
  105. }
  106. return;
  107. }
  108.  

I use Proteus VSM to design and simulating this program before it will be tested on a prototype board.

PIC16F887 PCF8574AP I2C LCD Example using XC8
Simulating Program in Proteus

PIC16F887 PCF8574AP I2C LCD Example using XC8
Simulating Program in Proteus


Click here to download this example from GitHub.

Tuesday, January 9, 2024

PIC16F887 SH1106 I2C OLED Display Example using XC8

Overview

An SH1106 is a 132x64 LED display driver with controller. This chip support 8-bit 6800-series parallel interface, 8-bit 8080-series parallel interface, Serial Peripheral Interface (SPI), and Inter Integrated Circuit (I2C) bus interface. It usually come with an 1.3 inches 128x64 OLED display module with an SPI or an I2C interface. 

PIC16F887 SH1106 I2C OLED Display Example using XC8
PIC16F887 OLED Display

Using this module with an Arduino is very popular. Some programmer creates a simple game console using this display. Arduino platform has a lot of libraries and graphic for this LCD module. 

PIC16F887 SH1106 I2C OLED Display Example using XC8

PIC16F887 SH1106 I2C OLED Display Example using XC8

PIC16F887 SH1106 I2C OLED Display Example using XC8
1.3 Inches 1106 128x64 IIC OLED Module

PIC16F887 SH1106 I2C OLED Display Example using XC8
1.3 Inches 1106 128x64 IIC OLED Module

 

Without Arduino we can check the LCD Wiki website for programming and interfacing with this device using different micro-processor.

PIC16F887 SH1106 I2C OLED Display Example using XC8
For full specification please check product datasheet. The LCD is mounted on a PCB with a ready to use I2C interface. Its supply voltage is 5VDC by default.

Here we will use a two-wire I2C bidirectional bus interface. This module has an on-board 10kΩ pull-up resistors. Its I2C write address is 0x78 by default. This chip could handle up to 40kHz serial clock frequency. But I use only 200kHz with PIC16F887 I2C module to prevent it from being halted.

PIC16F887 SH1106 I2C OLED Display Example using XC8
I2C System Configuration

Using only two-wire data bus the controller can communicate with multiple devices. This I2C display is writable and readable.

PIC16F887 SH1106 I2C OLED Display Example using XC8

The micro-processor writes command or data to this display. It begin by an I2C start bit, device address (eg. 0x78), Acknowledge bit (A), Control Byte, Data Byte, and an I2C stop bit. 

Data/Command (D/C) bit of the control byte determine between display RAM data and command as it's shown in the picture above.

Display RAM Data can also be read from this display module.

To use it properly we need to set its display commands using a command set below.

  1. Set Low Column Address: (00H - 0FH)
  2. Set Higher Column Address: (10H - 1FH)
  3. Set Pump voltage value: (30H - 33H)
  4. Set Display Start Line: (40H - 7FH)
  5. Set Contrast Control Register: (Double Bytes Command), The Contrast Control Mode Set (81H), Contrast Data Register Set (00H - FFH)
  6. Set Segment Re-map: (A0H - A1H)
  7. Set Entire Display OFF/ON: (A4H - A5H)
  8. Set Normal/Reverse Display: (A6H - A7H)
  9. Set Multiplex Ration: (Double Bytes Command), Multiplex Ration Mode Set: (A8H), Multiplex Ration Data Set: (00H - 3FH).
  10. Set DC-DC OFF/ON: (Double Bytes Command), DC-DC Control Mode Set: (ADH), DC-DC ON/OFF Mode Set: (8AH - 8BH).
  11. Display OFF/ON: (AEH - AFH)
  12. Set Page Address: (B0H - B7H)
  13. Set Common Output Scan Direction: (C0H - C8H)
  14. Set Display Offset: (Double Bytes Command), Display Offset Mode Set: (D3H), Display Offset Data Set: (00H - 3FH)
  15. Set Display Clock Divide Ratio/Oscillator Frequency: (Double Bytes Command), Divide Ratio/Frequency Mode Set: (D5H), Divide Ratio/Oscillator Frequency Data Set: (00H - FFH).
  16. Set Dis-Charge/Pre-Charge Period: (Double Bytes Command), Pre-charge Period Mode Set: (D9H), Dis-charge/Pre-charge Period Data Set: (00H - FFH)
  17. Set Common pads hardware configuration: (Double Bytes Command), Common Pads Hardware Configuration Mode Set: (DAH), Sequential/Alternative Mode Set: (02H - 12H).
  18. Set VCOM Deselect Level: (Double Bytes Command), VCOM Deselect Level Mode Set: (DBH), VCOM Deselect Level Data Set: (00H - FFH).
  19. Read-Modify-Write: (E0H)
  20. End: (EEH)
  21. NOP: (E3H)
  22. Write Display Data
  23. Read Status
  24. Read Display Data

For a fully explained text, you can check its datasheet. These command are summerized in a command table below.

PIC16F887 SH1106 I2C OLED Display Example using XC8
Command Table 1

PIC16F887 SH1106 I2C OLED Display Example using XC8
Command Table 2

We can see its user's manual include programming tutorial to get used to this display controller.

PIC16F887 MPLABX IDE and XC8 Programming

An 8-bit PIC16F887 is suitable for this display controller since it has a high speed I2C module inside. I configure this module with a clock frequency of 200kHz. The program will send a 8x16 character text to the display.

  1. /*
  2.  * File: main.c
  3.  * Author: Admin
  4.  *
  5.  * Created on January 8, 2024, 8:50 PM
  6.  */
  7.  
  8. #include <xc.h>
  9. #include "config.h"
  10. #include "sh1106.h"
  11.  
  12. #define _XTAL_FREQ 20000000UL
  13.  
  14. void main(void) {
  15. display_init();
  16. __delay_ms(100);
  17. display_clear(0);
  18. display_text_8x16(0,0,"SH1106 I2C OLED");
  19. display_text_8x16(0,1,"And PIC16F887");
  20. display_text_8x16(0,2,"Programming With");
  21. display_text_8x16(0,3,"MPLABX IDE XC8");
  22. __delay_ms(5000);
  23. display_clear(0);
  24. while(1){
  25. display_text_8x16(0,0,"PIC16F887 SH1106");
  26. __delay_ms(2500);
  27. uint8_t h=15;
  28. for(uint8_t i=0;i<10;i++) {
  29. display_char_8x16(h,1,'0'+i);
  30. h+=10;
  31. }
  32. __delay_ms(2500);
  33. h=0;
  34. for(uint8_t i=0;i<14;i++) {
  35. display_char_8x16(h,2,'A'+i);
  36. h+=10;
  37. }
  38. __delay_ms(2500);
  39. h=0;
  40. for(uint8_t i=0;i<14;i++) {
  41. display_char_8x16(h,3,'N'+i);
  42. h+=10;
  43. }
  44. __delay_ms(10000);
  45. display_clear(255);
  46. __delay_ms(10000);
  47. display_clear(0);
  48. __delay_ms(1000);
  49. }
  50. return;
  51. }
  52.  

Only text fonts requires a lot of program space. To get additional fonts and graphic we can add an SPI or an I2C EEPROM or even a Flash memory to store those data.

PIC16F887 SH1106 I2C OLED Display Example using XC8
Protues Simulation
Protues has an LCD module for SSD1306. It's very similar to the SH1106. However simulating this module in Protues is slower than a physical hardware.


PIC16F887 SH1106 I2C OLED Display Example using XC8
Running Program

PIC16F887 SH1106 I2C OLED Display Example using XC8
Running Program


 

Click here to download its source file.

We can use the ATMega32 or ATMega644P TWI or even software TWI to interface with this chip.



Search This Blog

Labels