PIC 16F1503 16x2 LCD I2C Communication issues - Page 1
Forum section: electronics / general

author: sumithcmohan
author_rank: Newbie
timestamp: January 09, 2019, 09:46:58 am
content: Code:PIC 16F1503Clock: Internal 10MHzCompiler: MPLAB XC8Simulation: Proteus 8 ProfessionalI am trying to show a text "Hello world" in my LCD via PIC I2C communication. Tried sevaral codes but fails everytime.Here is the LCD details in proteus.Code:Part value: JHD-2X16-I2C{MODDLL=LCDALPHA}{PRIMITIVE=DIGITAL,I2C}{NUMCOLS=16}{NUMROWS=2}CLOCK=100kHz{ROW1=80-8F}{ROW2=C0-CF}{DVCADDR=$7C}{TRACE=1}Below shows the code in PIC 16F1503Code:// PIC16F1503 Configuration Bit Settings// 'C' source line config statements// CONFIG1#pragma config FOSC = INTOSC // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin)#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)#pragma config MCLRE = OFF // MCLR Pin Function Select (MCLR/VPP pin function is digital input)#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)#pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled)#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)// CONFIG2#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)#pragma config LPBOR = OFF // Low-Power Brown Out Reset (Low-Power BOR is disabled)#pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)#include <xc.h>#include <stdint.h>#include <stdio.h>#define _XTAL_FREQ 10000000void I2C_init (uint32_t clock){SSPADD = (_XTAL_FREQ/(4*clock))-1; // here clock is the BR/clock speedSSP1CON1 = 0b00101000; //first 4 bits I2c master mode , 6th bit is SSPEN enables the scl and sda line//Set/Reset: S, P, SSPxSTAT, WCOL, SSPOVSSP1CON2 |= 0x00; //Reset SEN, PEN (SSPxCON2)SSP1IF = 1; BCL1IF = 1;//Set SSPxIF, BCLxIFSSP1STAT = 0;TRISC0 = 1;TRISC1 = 1;}I2C_wait (void){while ((SSPSTAT & 0x04) || (SSPCON2 & 0x1F)); // wait for start bit to clear in SSPSTAT and bits 0 to 4 in SSPCON2}void I2C_start (void){I2C_wait ();SSPCON2 |= 0x01; // SEN=1 -> initiate the START condition on SDA and SCL pins}void I2C_repeated_start (void){I2C_wait();SSPCON2 |= 0x02; // RSEN=1 -> initiate REPEATED START condition on SDA and SCL pins}void I2C_stop (void){I2C_wait ();SSPCON2 |= 0x04; // PEN=1 -> initiate the STOP condition on SDA and SCL pins}void I2C_write (uint8_t data){I2C_wait ();SSPBUF = data; // load data into SSPBUF register}uint8_t I2C_read (uint8_t ack){uint8_t temp;I2C_wait();RCEN = 1; // enable receive mode for I2cI2C_wait();temp = SSPBUF; // load data from Buffer to the tempI2C_wait();ACKDT = (ack); // 0-- not ACK , 1-- ACKACKEN = 1; // Send Acknowledgementreturn temp;}#define SLAVE_ADDRESS_LCD 0x40 // change this according to ur setupvoid lcd_send_data (unsigned char data){unsigned char data_l, data_u;data_l = (data<<4)&0xf0; //select lower nibble by moving it to the upper nibble positiondata_u = data&0xf0; //select upper nibbleI2C_start();I2C_write (SLAVE_ADDRESS_LCD);I2C_write (data_u|0x0D); //enable=1 and rs =1I2C_write (data_u|0x09); //enable=0 and rs =1I2C_write (data_l|0x0D); //enable =1 and rs =1I2C_write (data_l|0x09); //enable=0 and rs =1I2C_stop();}void lcd_send_cmd (unsigned char data){unsigned char data_l, data_u;data_l = (data<<4)&0xf0; //select lower nibble by moving it to the upper nibble positiondata_u = data&0xf0; //select upper nibbleI2C_start();I2C_write (SLAVE_ADDRESS_LCD);I2C_write (data_u|0x0C); //enable=1 and rs =0I2C_write (data_u|0x08); //enable=0 and rs =0I2C_write (data_l|0x0C); //enable =1 and rs =0I2C_write (data_l|0x08); //enable=0 and rs =0I2C_stop();}void lcd_init (void){lcd_send_cmd (0x02);lcd_send_cmd (0x28);lcd_send_cmd (0x0c);lcd_send_cmd (0x80);}void lcd_send_string (char *str){while (*str) lcd_send_data (*str++);}//void lcd_send_float (float data, int numberofdigits)//{//char xg_char;//snprintf (xg_char, 8, "%f", data);//for (int i=0; i<numberofdigits; i++)//{//lcd_send_data (xg_char);//}//}int main (){I2C_init (100000);lcd_init ();lcd_send_string ("h");while (1){}}Please help on this issue. I am trying for last 2 weeks.

author: JoeP
author_rank: Contributor
timestamp: January 12, 2019, 01:13:48 pm
content: I'm not familiar with proteus, but it could help you diagnose the problem better if you look at the waveforms on the SDA and SCL lines; I'm also having trouble with I2C, and using a dual-channel oscilloscope it revealed that the slave device wasn't sending an acknowledge bit when I transmitted its address.

author: sumithcmohan
author_rank: Newbie
timestamp: January 12, 2019, 02:08:46 pm
content: Do you have any workable code for 16F1503 for I2C ?In my code I am getting good wave form from SDA and SCL. I will share the screen shot on Monday. Need some guidance about how to know “Aknowledge receipt “ from slave.Also I am doubt about the device address asper the example code for 16F877A it’s 0x28 but it’s not work with 16F1503 and LCD I2C display.

author: JoeP
author_rank: Contributor
timestamp: January 12, 2019, 06:33:15 pm
content: Before I go any further, I should probably mention that I've never actually got I2C working - though I do know the basic principles. I'm not the most qualified person to answer this question.Are you familiar with what is going on on the SDA and CLK lines in a working I2C communication? If not, there are plenty of guides online, so it would be a good idea to get accustomed with it.To begin to analyse the waveforms, first look for the start bit. Then look at the logic level of SDA at each preceding falling edge. The first 7 of these bits form the device address. The bit after that determines whether the master intends to read (1) or write to (0) the slave device. The bit after that is the acknowledge bit. If this is low, then the slave has received the address and is ready to continue the communication. If not, something's going wrong.The line in your codeCode:#define SLAVE_ADDRESS_LCD 0x40would be an obvious mistake if, as you say, the LCD address is actually 0x28.

author: @rt
author_rank: Super Contributor
timestamp: January 13, 2019, 03:22:43 am
content: You should delay for about a second before sending to any HD44780 compatible display (which I assume this is after the I2C decoder).For some it doesn’t matter, but for others it will never initialise, and never come good for the rest of the power cycle.

author: newbrain
author_rank: Super Contributor
timestamp: January 13, 2019, 08:50:53 pm
content: Not being a PICky person, I won't comment on the I2C and other PIC specific stuff.BUT:Code:void lcd_init (void){lcd_send_cmd (0x02);lcd_send_cmd (0x28);lcd_send_cmd (0x0c);lcd_send_cmd (0x80);}This does not look like a correct initialization sequence for a HD44870 based display.The sequence can be found at page 68here.I see at least two problems:Not following the described sequence with the specified delays.This is the major one: the code send the commands in two nibbles, that's OK only if the controller isalreadyin 4 bit mode.At initialization, it will default to 8 bit mode: only the most significant nibble must be sent (the commands to set interface width do not have meaningful bits in the lower nibble).