Menu

Adskeeper - header widge

728x90

Search This Blog

468x60

Navbar

AdsKeeper - IAB Display Standard Ad Unit

Sunday, October 18, 2026

PIC18F4550 and HD44780 LCD Interfacing Example using MikroC

Overview

The HD44780 alphanumeric display has been using for many years now. In early years, it is commonly found in some electronic and control system, laser printers, etc. At that time, interfacing this LCD with an 8-bit micro-controller and programming in Assembly language was common. This display controller uses the Motorola 6800 data bus with three control signals, Register Select (RS), Read/Write (R/W), and Enable (E). However it support a 4-bit data transfer mode that split the 8-bit data into higher nibble and lower nibble, in which the higher nibble sent and latched first.

 

PIC18F4550 and HD44780 LCD Interfacing Example using MikroC
A Blue Back LED 16x2 Character LCD


PIC18F4550 and HD44780 LCD Interfacing Example using MikroC
A Blue Back LED 16x2 Character LCD

 

Currently, this display controller still in used. It is very popular among students, engineer, hobbyists, and small electronic control projects. There are a lot of replacement controllers available at very low cost and riches in dimensions. Using this LCD with and Arduino is very popular due to its ready-to-use module and libraries. This display can be converted into a serial communication interface such as I2C or SPI.

 

PIC18F4550 and a 16x2 LCD Example

MikroC has a lot of hardware libraries even in free mode. We can follow its example programs in its reference manual. To get started, I repeat an example code in its Lcd Libary. There are some library functions that we need to know especially the LCD pins declaration.

Library Routines

The LCD pins declaration such as R/S, E, and D7:4 must be putted first at the head of C source code before these functions can be called. For more information please see its Help file in the compiler IDE. 

Schematic

 

PIC18F4550 and HD44780 LCD Interfacing Example using MikroC
Schematic

 

 

MikroC Source Code




  1. // LCD module connections
  2. sbit LCD_RS at RD2_bit;
  3. sbit LCD_EN at RD3_bit;
  4. sbit LCD_D4 at RD4_bit;
  5. sbit LCD_D5 at RD5_bit;
  6. sbit LCD_D6 at RD6_bit;
  7. sbit LCD_D7 at RD7_bit;

  8. sbit LCD_RS_Direction at TRISD2_bit;
  9. sbit LCD_EN_Direction at TRISD3_bit;
  10. sbit LCD_D4_Direction at TRISD4_bit;
  11. sbit LCD_D5_Direction at TRISD5_bit;
  12. sbit LCD_D6_Direction at TRISD6_bit;
  13. sbit LCD_D7_Direction at TRISD7_bit;
  14. // End LCD module connections

  15. char txt1[] = "mikroElektronika";
  16. char txt2[] = "EasyPIC6";
  17. char txt3[] = "Lcd4bit";
  18. char txt4[] = "example";

  19. char i; // Loop variable

  20. void Move_Delay() { // Function used for text moving
  21. Delay_ms(500); // You can change the moving speed here
  22. }

  23. void main(){


  24. Lcd_Init(); // Initialize LCD

  25. Lcd_Cmd(_LCD_CLEAR); // Clear display
  26. Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off
  27. Lcd_Out(1,6,txt3); // Write text in first row

  28. Lcd_Out(2,6,txt4); // Write text in second row
  29. Delay_ms(2000);
  30. Lcd_Cmd(_LCD_CLEAR); // Clear display

  31. Lcd_Out(1,1,txt1); // Write text in first row
  32. Lcd_Out(2,5,txt2); // Write text in second row

  33. Delay_ms(2000);

  34. // Moving text
  35. for(i=0; i<4; i++) { // Move text to the right 4 times
  36. Lcd_Cmd(_LCD_SHIFT_RIGHT);
  37. Move_Delay();
  38. }

  39. while(1) { // Endless loop
  40. for(i=0; i<8; i++) { // Move text to the left 7 times
  41. Lcd_Cmd(_LCD_SHIFT_LEFT);
  42. Move_Delay();
  43. }

  44. for(i=0; i<8; i++) { // Move text to the right 7 times
  45. Lcd_Cmd(_LCD_SHIFT_RIGHT);
  46. Move_Delay();
  47. }
  48. }
  49. }

 

DIY PIC18F4550 Prototype Board

I tested this example on my DIY PIC18F4550 Prototype Board.

 

PIC18F4550 and HD44780 LCD Interfacing Example using MikroC
PIC18F4550 Prototype Board


PIC18F4550 and HD44780 LCD Interfacing Example using MikroC
PIC18F4550 Prototype Board


 


 

On-board Switches and LCD Example

In this example, when one of two on-board push buttons is pressed it will shows its state - Press or Released. The schematic is shown in the example above.

MikroC Source Code

 




  1. #define SW4 RB4_bit
  2. #define SW5 RB5_bit

  3. // LCD module connections
  4. sbit LCD_RS at RD2_bit;
  5. sbit LCD_EN at RD3_bit;
  6. sbit LCD_D4 at RD4_bit;
  7. sbit LCD_D5 at RD5_bit;
  8. sbit LCD_D6 at RD6_bit;
  9. sbit LCD_D7 at RD7_bit;

  10. sbit LCD_RS_Direction at TRISD2_bit;
  11. sbit LCD_EN_Direction at TRISD3_bit;
  12. sbit LCD_D4_Direction at TRISD4_bit;
  13. sbit LCD_D5_Direction at TRISD5_bit;
  14. sbit LCD_D6_Direction at TRISD6_bit;
  15. sbit LCD_D7_Direction at TRISD7_bit;
  16. // End LCD module connections


  17. void main(){

  18. /// PORTB AS INPUT
  19. PORTB = 0;
  20. LATB = 0;
  21. TRISB = (1<<5)|(1<<4);
  22. // ENABLE PORTB PULL-UP
  23. INTCON2 &=~(1<<7);
  24. // DISABLE ANALOG INPUTS
  25. ADCON1 = 0x0F;
  26. Lcd_Init(); // Initialize LCD

  27. Lcd_Cmd(_LCD_CLEAR); // Clear display
  28. Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off

  29. Lcd_Out(1,1,"PIC18F4550 LCD");
  30. Lcd_out(2,1,"Buttons Example");

  31. Delay_ms(7000);
  32. Lcd_Cmd(_LCD_CLEAR); // Clear display
  33. Lcd_Out(1,1, "Press on SW4.");
  34. Lcd_Out(2,1, "Press on SW5.");
  35. while(1){
  36. if(SW4==0){
  37. Lcd_Out(1,1, "SW4 is Pressed.");
  38. while(SW4 == 0);
  39. Lcd_Out(1,1, "SW4 is Released.");
  40. }
  41. if(SW5==0){
  42. Lcd_Out(2,1, "SW5 is Pressed.");
  43. while(SW5 == 0);
  44. Lcd_Out(2,1, "SW5 is Released.");
  45. }
  46. }
  47. }

 

Example Pictures

I tested this example on my DIY PIC18F4550 Prototype Board.

 

PIC18F4550 and HD44780 LCD Interfacing Example using MikroC
My DIY PIC18F4550 Prototype Board


PIC18F4550 and HD44780 LCD Interfacing Example using MikroC
My DIY PIC18F4550 Prototype Board


PIC18F4550 and HD44780 LCD Interfacing Example using MikroC
My DIY PIC18F4550 Prototype Board

 

 


 

  

Saturday, October 17, 2026

PIC18F4550 LED and Switch Interfacing using MikroC

Introduction

PIC18F4550 is a high performance 8-bit PIC micro-controller produced by Microchip Technology nearly two decades now. It's a USB micro-controller since it has a USB interface that supports up to USB 2.0. It operates up to 48MHz by enable its Phase Lock Loop (PLL) with pre-scaler and post-scaler settings.

 

PIC18F4550 LED and Switch Interfacing using MikroC
A DIY PIC18F4550 Prototype Board

 

It has up to 5 I/O ports ranging from PORTA to PORTE. They are digital programmable input output ports. Some ports have an alternative functions such as ADC inputs, PWM output, SPI, I2C, interrupt capture, etc.

PIC18F4550 LED and Switch Interfacing using MikroC
PIC18F4550-I/P I stock and its pin diagram

 

This 8-bit chip is very easy to program since there are a lot of compilers including Assembly and C. Using Assembly is free since the manufacture offer this feature with it MPLABX IDE compiler.  

Today, using a high level programming language is common since modern micro-controllers have a large RAM and Flash memory space. The XC8 C compiler is free of charge with some limited C language features. Some commercial C compiler for this chip are CCS PICC, Mikroelektronika MikroC, IAR Embedded Workbench for PIC18, etc. 

However Mikroelektronika offers a free version of its compiler for evaluation without limiting any features. But the compiling code is not larger than 2KB. It's suitable for any small control project, students and hobbyists.

 

PIC18F4550 LED Blinking using MikroC

I test the oscillator and on-board LED of my DIY PIC18F4550 prototype board by blinking an LED connects to RD0.

The on-board crystal clock frequency is 20MHz. So need to do additional configurations to get a 48MHz clock frequency. It's useful to drive the USB hardware clock of this micro-controller. 

After creating a new project, go to Project menu and click on Edit Project as show in the picture below.

 

PIC18F4550 LED and Switch Interfacing using MikroC
Edit Project to set a 48MHz clock frequency.


Schematic

 

PIC18F4550 LED and Switch Interfacing using MikroC
Schematic

 

 

MikroC Source Code


  1. #define LED LATD0_bit

  2. void main() {
  3. PORTD = 0;
  4. LATD = 0;
  5. TRISD = 0;
  6. while(1){
  7. LED = 0;
  8. Delay_ms(1000);
  9. LED = 1;
  10. Delay_ms(1000);
  11. }
  12. }

 

 Hardware Test

 

PIC18F4550 LED and Switch Interfacing using MikroC
LED Blinking at RD0


 We can do the LED blinking using MPLABX XC8 or CCS PICC Compiler with the same chip.

 

PIC18F4550 LED and Button Test using MikroC

There two on-board user buttons for testing the input of RB4 and RB5 pin. RB4 has an alternative analog input function. So we need to disable analog input at this pin, or even all analog input pins. By clearing the PCFG3:PCFG0 nibble of the ADCON1, all analog input function will disabled.

Unlike the mid-range 8-bit PIC microcontroller, the high end 8-bit PIC micro-controllers have an additional output data latch port registers (LATx). We use this register for data output. 

Most of PORTB of any 8-bit PIC micro-controllers have an optional PortB Pull-Up (nRBPU). In PIC18F4550, we just clear the nRBPU bit of the INTCON1 register to enable this feature. 

In this example, I tested the input from RB5:RB4 of PORTB that will toggle the output LATD7:LATD6 LED. 

 

Schematic

 

PIC18F4550 LED and Switch Interfacing using MikroC
Schematic

 

 

MikroC Source Code


  1. #define SW4 RB4_bit
  2. #define SW5 RB5_bit
  3. #define LED4 LATD6_bit
  4. #define LED5 LATD7_bit

  5. const millis = 500;

  6. void main() {
  7. /// PORTB AS INPUT
  8. PORTB = 0;
  9. LATB = 0;
  10. TRISB = (1<<5)|(1<<4);
  11. // PORTD AS OUTPUT
  12. PORTD = 0;
  13. LATD = 0;
  14. TRISD = 0;
  15. // ENABLE PORTB PULL-UP
  16. INTCON2 &=~(1<<7);
  17. // DISABLE ANALOG INPUTS
  18. ADCON1 = 0x0F;
  19. // TEST LED
  20. LED4=1;
  21. LED5=1;
  22. Delay_ms(5000);
  23. LED4 = 0;
  24. LED5 = 0;
  25. while(1){
  26. if(SW4==0){
  27. Delay_ms(millis);
  28. LED4^=1;
  29. }
  30. if(SW5==0){
  31. Delay_ms(millis);
  32. LED5^=1;
  33. }
  34. }
  35. }

  

PIC18F4550 DIY Prototype Board 

 

PIC18F4550 LED and Switch Interfacing using MikroC
DIY PIC18F4550 Prototype Board

PIC18F4550 LED and Switch Interfacing using MikroC
DIY PIC18F4550 Prototype Board

PIC18F4550 LED and Switch Interfacing using MikroC
DIY PIC18F4550 Prototype Board

 

 I tested this example on my DIY PIC18F4550 Prototype Board.

 

Thursday, October 15, 2026

dsPIC30F2010 Software I2C LCD and RTC

Introduction

A dedicated I2C module of a micro-controller including the dsPIC30F2010 is fixed. For instance the I2C1 port pins of the dsPIC30F2010 are RF2(SDA) and RF3(SCL). These pins share with other communication module such as ICSP and UART1. So we need to disconnect them first before setting up a proper communication port connection. However, some modern micro-controllers have a port remapping for communication interface pins.  

 

dsPIC30F2010 Software I2C LCD and RTC
PCF8574T Software I2C Character LCD

 

On the other hand, the I2C communication protocol is very easy to emulate via software bit-banging method using Assembly, C, or even other high level programming languages. Mikro C offers both hardware and software I2C library routines. We can check its user's manual for details. Here I cut only some key-points:

External dependencies of Software I²C Library

The following variables must be defined in all projects using Software I²C Library: Description : Example :
extern sbit Soft_I2C_Scl; Soft I²C Clock line. sbit Soft_I2C_Scl at RB11_bit;
extern sbit Soft_I2C_Sda; Soft I²C Data line. sbit Soft_I2C_Sda at RB12_bit;
extern sbit Soft_I2C_Scl_Direction; Direction of the Soft I²C Clock pin. sbit Soft_I2C_Scl_Direction at TRISB11_bit;
extern sbit Soft_I2C_Sda_Direction; Direction of the Soft I²C Data pin. sbit Soft_I2C_Sda_Direction at TRISB12_bit;

Library Routines

 

The Soft_I2C_Scl and Soft_I2C_Sda must be declared first before we can use the Soft_I2C_Init function. The Software I2C operates at lower clock speed and need more program space (ROM) since it's a purely software communication protocol.

 

dsPIC30F2010 Interfacing and Programming using MikroC

 

We can select any pins of the dsPIC30F2010 to operates a software I2C communication protocol. Here I use RD0 for SCL and RD1 for SDA. I'm not sure about its SCL clock frequency since I don't have an oscilloscope.

Schematic:

 

dsPIC30F2010 Software I2C LCD and RTC
Schematic

 

In this example a PCF8574T character LCD and a DS3231 Real Time Clock (RTC) chip use a single I2C bus to communication with the master MCU.  The MCU continuous read the RTC data from DS3231 and shows it on the I2C character LCD. The DS3231 timing is very precise since it uses its internal calibrated RC oscillator.


dsPIC30F2010 Software I2C LCD and RTC
PCF8574T Arduino TWI HD44780 LCD Module

 

dsPIC30F2010 Software I2C LCD and RTC
Arduino DS3231 High Precision Real Time Clock Module

dsPIC30F2010 Software I2C LCD and RTC
Arduino DS3231 High Precision Real Time Clock Module

 

The PCF8574T and DS3231 Arduino module are widely used among students and hobbyists due to its low cost and less complexity. 

MikroC Source Code:




  1. // Software I2C connections
  2. sbit Soft_I2C_Scl at RD0_bit;
  3. sbit Soft_I2C_Sda at RD1_bit;
  4. sbit Soft_I2C_Scl_Direction at TRISD0_bit;
  5. sbit Soft_I2C_Sda_Direction at TRISD1_bit;
  6. // End Software I2C connections

  7. const char PCF8574_W=0x40;
  8. const char PCF8574_R=0x41;
  9. const char PCF8574T_LCD_W=0x4E;
  10. const char PCF8574T_LCD_R=0x4F;
  11. const char PCF8574A_W=0x70;
  12. const char PCF8574A_R=0x71;

  13. void pcf8574_write(char _data){
  14. Soft_I2C_Start(); // issue I2C start signal
  15. Soft_I2C_Write(PCF8574T_LCD_W); // send byte via I2C (device address + W)
  16. Soft_I2C_Write(_data); // send byte (data address)
  17. Soft_I2C_Stop(); // issue I2C stop signal
  18. }

  19. /*TWI LCD Driver*/
  20. #define RS 0
  21. #define RW 1
  22. #define EN 2
  23. #define BL 3

  24. #define i2c_lcd_cursor_off() i2c_lcd_command(0x0C)
  25. #define i2c_lcd_line_1() i2c_lcd_command(0x80)
  26. #define i2c_lcd_line_2() i2c_lcd_command(0xC0)

  27. char backLight=1;

  28. void i2c_lcd_command(char command){
  29. char _data;
  30. _data=command&0xF0;
  31. pcf8574_write(_data|(backLight<<BL)|(1<<EN));
  32. //_delay_us(10);
  33. pcf8574_write(_data|(backLight<<BL));
  34. //_delay_us(50);

  35. _data=command<<4;
  36. pcf8574_write(_data|(backLight<<BL)|(1<<EN));
  37. //_delay_us(10);
  38. pcf8574_write(_data|(backLight<<BL));
  39. //_delay_us(50);
  40. }

  41. void i2c_lcd__data(char command){
  42. char _data;
  43. _data=command&0xF0;
  44. pcf8574_write(_data|(backLight<<BL)|(1<<EN)|(1<<RS));
  45. Delay_us(10);
  46. pcf8574_write(_data|(backLight<<BL)|(1<<RS));
  47. Delay_us(50);

  48. _data=command<<4;
  49. pcf8574_write(_data|(backLight<<BL)|(1<<EN)|(1<<RS));
  50. Delay_us(10);
  51. pcf8574_write(_data|(backLight<<BL)|(1<<RS));
  52. Delay_us(50);
  53. }

  54. void i2c_lcd_xy(char x, char y){
  55. char addr[]={0x80,0xC0};
  56. i2c_lcd_command(addr[y-1]+x-1);
  57. }

  58. void i2c_lcd_text(char *txt){
  59. while(*txt) i2c_lcd__data(*txt++);
  60. }

  61. void i2c_lcd_clear(void){
  62. i2c_lcd_command(0x01);
  63. Delay_ms(5);
  64. }

  65. void i2c_lcd_init(void){
  66. pcf8574_write(0);
  67. Delay_ms(10);
  68. i2c_lcd_command(0x33);
  69. Delay_us(10);
  70. i2c_lcd_command(0x32);
  71. Delay_us(10);
  72. i2c_lcd_command(0x28);
  73. Delay_us(10);
  74. i2c_lcd_command(0x0F);
  75. Delay_us(10);
  76. i2c_lcd_command(0x01);
  77. Delay_ms(10);
  78. i2c_lcd_command(0x06);
  79. Delay_us(10);
  80. }

  81. void rtc_set(void){
  82. char rtc[7]={0x35,0x12,0x17,0x05,0x15,0x10,0x26};
  83. char i=0;
  84. Soft_I2C_Start(); // issue I2C start signal
  85. Soft_I2C_Write(0xD0); // send byte via I2C (device address + W)
  86. Soft_I2C_Write(0); // send byte (data address)
  87. while(i<7){
  88. Soft_I2C_Write(rtc[i]);
  89. i++;
  90. }
  91. Soft_I2C_Stop();
  92. }
  93. void main(){
  94. char temp[7], i = 0, text[16];
  95. Soft_I2C_Init(); // Initialize Soft I2C communication

  96. Delay_ms(10);
  97. //rtc_set();
  98. i2c_lcd_init();
  99. Delay_ms(10);
  100. i2c_lcd_clear();

  101. i2c_lcd_text("Software I2C");
  102. i2c_lcd_line_2();
  103. i2c_lcd_text("PCF8574T DS3231");
  104. i2c_lcd_cursor_off();
  105. Delay_ms(5000);
  106. i2c_lcd_clear();
  107. while(1){
  108. for(i = 0; i < 7; i++){
  109. Soft_I2C_Start(); // issue I2C start signal
  110. Soft_I2C_Write(0xD0); // send byte via I2C (device address + W)
  111. Soft_I2C_Write(i); // send byte (data address)
  112. Soft_I2C_Stop();
  113. Soft_I2C_Start();
  114. Soft_I2C_Write(0xD1); // send byte (device address + R)
  115. temp[i] = Soft_I2C_Read(0u); // Read the data (NO acknowledge)
  116. Soft_I2C_Stop(); // issue I2C stop signal
  117. }
  118. sprintf(text,"Date: %2X/%2X/20%2X",temp[4],temp[5],temp[6]);
  119. i2c_lcd_line_1();
  120. i2c_lcd_text(text);
  121. sprintf(text,"Time: %2X/%2X/%2X",temp[2],temp[1],temp[0]);
  122. i2c_lcd_line_2();
  123. i2c_lcd_text(text);
  124. Delay_ms(800);
  125. }
  126. }


The sprintf function uses a lot of memory space. We can process the ASCII data one-by-one to save memory space of the MCU.

 

dsPIC30F2010 Software I2C LCD and RTC
DS3231 and PCF8574T Software I2C Programming

dsPIC30F2010 Software I2C LCD and RTC
DS3231 and PCF8574T Software I2C Programming

 

I tested this program on my DIY dsPIC30F2010 Prototype Board. 

 


 

For a full software TWI programming examples please see this post. 

 

 

 


Adskeep- Standard Ads

Electronics and Programming Tutorials

336x280

DIY Electronic Projects And Instruments

AdsKeeper - 2091654

Labels

23K256 (1) 24C16B (2) 25AA010A (2) 8051 (7) 93AA46B (1) ADC (40) Analog Comparator (1) Arduino (16) ARM (32) AT89C52 (7) ATMega32 (59) ATMega644P (27) AVR (88) AVR PCB (2) Bootloader (1) CCS PICC (31) Change Notify Interrupt (CNI) (2) DAC (2) DHT11 (5) Display (157) Distance Sensor (3) dot matrix (1) ds1307 (10) DS18B20 (6) ds3231 (2) ds3232 (2) dsPIC (16) dsPIC30F1010 (3) dsPIC30F2010 (15) EEPROM (5) Environment Sensor (6) ESP32 (1) esp8266 (1) Graphical LCD (3) HD44780 (13) I2C (40) ILI9341 (1) Input/Output (85) Interrupt (22) IoT PCB (1) Keil (5) Keypad (16) KS0108 (3) LCD (88) LM35 (4) Master/Slave (2) MAX7221 (1) MCP23017 (8) MCP23S17 (7) MCP4921 (1) MCP4922 (2) Meter (3) MikroC (2) MikroC ARM (1) MikroC dsPIC (11) MikroC PIC (2) Module PCB (2) Motor (15) MPLABX (73) Nokia 5110 LCD (5) OLED (2) One-Wire (7) Oscillator (8) PCB (13) PCD8544 (3) PCF8574 (13) PIC (122) PIC12F (3) PIC16 (105) PIC16F628A (3) PIC16F630 (2) PIC16F716 (4) PIC16F818 (11) PIC16F818/819 (3) PIC16F84A (16) PIC16F876A (2) PIC16F877A (9) PIC16F88 (2) PIC16F887 (60) PIC18 (19) PIC18F1220 (5) PIC18F2550 (5) PIC18F4550 (14) PICKit2 (1) PICMicro PCB (4) Pin Change Interrupt (1) PLL (1) PWM (12) RTC (13) SBN0064G (1) Sensor (15) SH1106 (3) Shift Register (15) Shift Registers (19) SN74HC595N (9) Software SPI (1) Software TWI (3) SPI (44) sprinf (3) ST7735 (1) STM32 (29) STM32 Black Pill (1) STM32 Blue Pill (12) STM32 HAL (23) STM32CubeIDE (32) STM32F103C8T6 (9) STM32F103R6 (18) STM32F401CCU6 (1) SysTick (7) temperature sensor (15) TFT (1) TG12864A (1) Thermometer (22) Timer/Counter (32) TM1637 (2) twi (10) UART (11) Ultrasonic (4) Voltmeter (7) WDT (1) XC16 (2) XC8 (96)