PIC Development Board with PK3

hexreader

Joined Apr 16, 2011
619
What about writing to LCD before and after EEPROM write. To see if the code is hanging during write or read.
Maybe move the LCD print code around - to see where the code hangs (if it does)

The below code displays the text "tst EEPROM A" with EEPROM inserted into socket. It displays the text "tst EEPROM Z" with EEPROM removed from socket

C:
//
#define _XTAL_FREQ 20000000     // crystal 20MHz

// PIC18F45K80 Configuration Bit Settings
// CONFIG1L
#pragma config RETEN = ON       // VREG Sleep Enable bit (Ultra low-power regulator is Enabled (Controlled by SRETEN bit))
#pragma config INTOSCSEL = LOW  // LF-INTOSC Low-power Enable bit (LF-INTOSC in Low-power mode during Sleep)
// SOSCSEL = No Setting
#pragma config XINST = OFF      // Extended Instruction Set (Disabled)
// CONFIG1H
#pragma config FOSC = HS2       // HS oscillator (high power, 16 MHz-25 MHz
#pragma config PLLCFG = OFF     // PLL x4 Enable bit (Disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor (Disabled)
#pragma config IESO = OFF       // Internal External Oscillator Switch Over Mode (Disabled)
// CONFIG2L
#pragma config PWRTEN = ON      // Power Up Timer (Enabled)
#pragma config BOREN = OFF      // Brown Out Detect (Disabled in hardware, SBOREN disabled)
#pragma config BORV = 0         // Brown-out Reset Voltage bits (3.0V)
#pragma config BORPWR = LOW     // BORMV Power level (BORMV set to low power level)
// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer (WDT disabled in hardware; SWDTEN bit disabled)
#pragma config WDTPS = 1        // Watchdog Postscaler (1:1)
// CONFIG3H
#pragma config CANMX = PORTC    // ECAN Mux bit (ECAN TX and RX pins are located on RC6 and RC7, respectively)
#pragma config MSSPMSK = MSK5   // MSSP address masking (5 bit address masking mode)
#pragma config MCLRE = ON      // Master Clear Enable (MCLR Enabled, RE3 Disabled)
// CONFIG4L
#pragma config STVREN = OFF     // Stack Overflow Reset (Disabled)
#pragma config BBSIZ = BB1K     // Boot Block Size (1K word Boot Block size)
// CONFIG5L
#pragma config CP0 = ON         // Code Protect 00800-01FFF (Enabled)
#pragma config CP1 = ON         // Code Protect 02000-03FFF (Enabled)
#pragma config CP2 = ON         // Code Protect 04000-05FFF (Enabled)
#pragma config CP3 = ON         // Code Protect 06000-07FFF (Enabled)
// CONFIG5H
#pragma config CPB = ON         // Code Protect Boot (Enabled)
#pragma config CPD = ON         // Data EE Read Protect (Enabled)
// CONFIG6L
#pragma config WRT0 = ON        // Table Write Protect 00800-01FFF (Enabled)
#pragma config WRT1 = ON        // Table Write Protect 02000-03FFF (Enabled)
#pragma config WRT2 = ON        // Table Write Protect 04000-05FFF (Enabled)
#pragma config WRT3 = ON        // Table Write Protect 06000-07FFF (Enabled)
// CONFIG6H
#pragma config WRTC = ON        // Config. Write Protect (Enabled)
#pragma config WRTB = ON        // Table Write Protect Boot (Enabled)
#pragma config WRTD = ON        // Data EE Write Protect (Enabled)
// CONFIG7L
#pragma config EBTR0 = ON       // Table Read Protect 00800-01FFF (Enabled)
#pragma config EBTR1 = ON       // Table Read Protect 02000-03FFF (Enabled)
#pragma config EBTR2 = ON       // Table Read Protect 04000-05FFF (Enabled)
#pragma config EBTR3 = ON       // Table Read Protect 06000-07FFF (Enabled)
// CONFIG7H
#pragma config EBTRB = ON       // Table Read Protect Boot (Enabled)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#pragma warning disable 520

#include <xc.h>

unsigned char Result1;
unsigned char Result2;
unsigned char Result3;
unsigned char Result4;

// The code should set the R/W bit according to its function
#define EEPROM_ADDRESS      0xA0         //I2C slave address of 24c02 (8 bit format)
#define Word_Address1       0x00


#define LCD_RS              LATBbits.LATB4
#define LCD_TRIS_RS         TRISBbits.TRISB4
#define LCD_RW              LATBbits.LATB5
#define LCD_TRIS_RW         TRISBbits.TRISB5
#define LCD_E               LATBbits.LATB6
#define LCD_TRIS_E          TRISBbits.TRISB6

#define  LCDPORT            LATD
#define  LCDTRISD           LATD

void Port_Initialized (void);
void WriteNibble(unsigned char command);
void WaitLCDBusy(void);
void WriteCommand(unsigned char command);

void Port_Initialized (void)
{
// LATx registers
    LATA =  0x00;
    LATB =  0x00;
    LATC =  0x00;
    LATD =  0x00;
    LATE =  0x00;

//  TRISx registers
    TRISA = 0x00;    // All are output, Unused
    TRISB = 0x00;   // all are output, Unused
    TRISC = 0x18;    //
    TRISD = 0x00;   // all are output, Unused
    TRISE = 0x00;   // All are output, Unused
 
    ANCON0 = 0x00;    // digital port
    ANCON1 = 0x00;    // Set to digital port
    CM1CON = 0x00;      // Comparator off
    CM2CON = 0x00;      // Comparator off
    ADCON0 = 0x00;      // A/D conversion Disabled
    ADCON1 = 0x00;      // A/D conversion Disabled
    ADCON2 = 0x00;     // A/D conversion Disabled
}

void WaitLCDBusy(void)
{
    __delay_ms(5);
}

//Send a command to the LCD
void WriteCommand(unsigned char command)
{
    WaitLCDBusy();                        //wait until not busy
    LCD_RS = 0;                           //setup to send command
    WriteNibble(command);                 //write the high nibble
    WriteNibble( (unsigned char)(command<<4) ); //then the low nibble   
}

//Initialized  LCD
void LCD_Initialized()
{
    LCDTRISD &=0x0f;                //ensure data bits are output
    LCD_E=0;                        //clear enable
    LCD_RS = 0;                     //going to write command
    LCD_TRIS_E=0;                   //Set enable to output
    LCD_TRIS_RS=0;                  //set RS to output
    LCD_TRIS_RW=0;
    LCD_RW=0;
    __delay_ms(30);                 //delay for LCD to initialise.
    WriteNibble(0x30);              //Required for initialisation
    __delay_ms(5);                  //required delay
    WriteNibble(0x30);              //Required for initialisation
    __delay_ms(1);                  //required delay
    WriteCommand(0x20);             //set to 4 bit interface
    WriteCommand(0x2c);             //set to 4 bit interface, 2 line and 5*10 font
    WriteCommand(0x01);             //clear display
    WriteCommand(0x06);             //move cursor right after write
    WriteCommand(0x0C);             //turn on display
}

//Send a character to the LCD
void WriteChar(unsigned char chr)
{
    WaitLCDBusy();                         //wait until not busy
    LCD_RS=1;                              //Setup to send character
    WriteNibble(chr);                      //write the high nibble           
    WriteNibble( (unsigned char)(chr<<4)); //then the low nibble
}

//Send any 4 bits to the LCD
void WriteNibble(unsigned char command)
{
    LCDPORT &= 0x0f;                        //clear the data bits
    LCDPORT|=((command & 0xf0));            //or in the new data
    LCD_E = 1;                              //enable the LCD interface
    NOP();                                  //change to delay of 1uS
    NOP();
    NOP();
    LCD_E = 0;                              //disable it
}

void LCD_Data( unsigned char *string)
{
    while (*string != '\0')
    {
      WriteChar(*string);
        string++;
    }
}
//Initialize I2C in master mode
void I2C_Initialized(void)
{
    TRISCbits.TRISC4 = 0;                                                       // commenting needed - will do another day
    TRISCbits.TRISC3 = 0;
    LATCbits.LATC4 = 0;
    LATCbits.LATC3 = 0;
    __delay_ms(1);                                                              // added in desperation - may not be needed
    TRISCbits.TRISC4 = 1;
    TRISCbits.TRISC3 = 1;
    __delay_ms(1);                                                              // added in desperation - may not be needed
    SSPSTATbits.SMP = 0;
    SSPSTATbits.CKE = 0;
    SSPCON1 = 0x38;
 
    __delay_ms(1);                                                              // added in desperation - may not be needed
 
    SSPSTAT = 0x80;                                                             // Slew rate control is disabled for Standard Speed mode (100 kHz and 1 MHz)
    SSPCON1 = 0x28;                                                             // I2C Master mode, clock = FOSC/(4 * (SSPADD + 1))
    SSPCON2 = 0x00;
    SSPADD = 49;                                                                // 100kHz clock @ 20MHz Fosc SSPADD = ( (Fosc/4) / BiteRate )-1
                                                                                // SSPADD = ( 20MHz / 100KHz ) - 1 = 49 //
}
// Send an I2C START
// Return 0 if all ok, 1 if bus collision
__bit I2C_Start(void)
{
    BCLIF = 0;  //Clear 'Bus collision" flag
    SEN = 1;    //initiate a START cycle
    while (SEN);    //wait until it has been sent
    return BCLIF;   //return value of BCLIF flag
}
// Send an I2C STOP
void I2C_Stop(void)
{
    PEN = 1;    //initiate a STOP cycle
    while (PEN);    //wait until it has been sent
}
// Send an I2C REPEATED START
void I2C_Restart(void)
{
    RSEN = 1;    //initiate a REPEATED START cycle
    while (RSEN);    //wait until it has been sent
}
//Receive one byte. ackflag=0 to send ACK, or 1 to send NAK in reply
//Send one byte. Return 0 if ACK received, or 1 if NAK received
__bit I2C_Sendbyte(unsigned char dat)
{
    SSPBUF = dat;

    asm("nop");     // <<<--- wait a little for R_W to be set

    while (R_W);    //wait until byte sent and ACK/NAK received
    return ACKSTAT;
}

unsigned char I2C_Recvbyte(unsigned char ackflag)
{
    RCEN = 1;   // initiate a RECEIVE cycle
    ACKDT =(__bit)ackflag;    //specify if we should send ACK or NAK after receiving
    while (RCEN);   //wait until RECEIVE has completed
    ACKEN = 1;  //initiate an ACK cycle
    while (ACKEN);  //wait until it has completed
    return SSPBUF;
}
//Send an array of data to an I2C device.
//Return 0 if all OK, 1 if bus error, 2 if slave address NAK, 3 if slave register NAK, 4 if slave data NAK
unsigned char EEPROM_Write(unsigned char slave_address, unsigned char start_reg, unsigned char buflen, const unsigned char * bufptr)
{
    if (I2C_Start() )   //send a start, and check if it succeeded
        return 1;   //abort if bus collision
    //send the I2C slave address (force R/W bit low)
    if (I2C_Sendbyte(slave_address & 0xfe))  // <<---- Added AND to force R/W- low.  Comment said it but code didn't do it
    {
        I2C_Stop(); //if address was NAKed, terminate the cycle
        return 2;   //and return error code
    }
    //send the device register index
    if (I2C_Sendbyte(start_reg))
    {
        I2C_Stop(); //if register was NAKed, terminate the cycle
        return 3;   //and return error code
    }
    //send the data. buflen might be zero!
    for (; buflen>0; --buflen)
    {
        if (I2C_Sendbyte(*bufptr++))
        {
            I2C_Stop(); //if register was NAKed, terminate the cycle
            return 4;   //and return error code
        }
    }
    I2C_Stop();
    return 0;   //no error
}
//Receive an array of data from an I2C device.
//Return 0 if all OK, 1 if bus error, 2 if slave address NAK, 3 if slave register NAK
unsigned char EEPROM_Read(unsigned char slave_address, unsigned char start_reg, unsigned char buflen, unsigned char * bufptr)
{
    //do a dummy zero length write cycle to set the register address
    unsigned char retval = EEPROM_Write(slave_address, start_reg, 0, 0);
    if (retval)
    {
        return retval;  //abort if there was an error
    }
    //now start the READ cycle
    if (I2C_Start() )   //send a start, and check if it succeeded
        return 1;   //abort if bus collision
    //send the I2C slave address (force the R/W bit high)
    if (I2C_Sendbyte(slave_address | 0x01))
    {
        I2C_Stop(); //if address was NAKed, terminate the cycle
        return 2;   //and return error code
    }
    //receive the data.
    for (; buflen>0; --buflen)
    {
        unsigned char ackflag = (buflen == 1);   //1 if this is the last byte to receive => send NAK

        *bufptr++ = I2C_Recvbyte(ackflag);
    }
    I2C_Stop();
    return 0;   //no error
}
const unsigned char EEPROM_data[] =
{
    0x07,   // Count 7
    0x06,   // Count 6
    0x05,   // Count 5
    0x04,   // Count 4
    0x03,   // Count 3
    0x02,   // Count 2
    0x01,   // Count 1
};
unsigned char rd_buf[7];


// Test variable for one byte transfer
const unsigned char testchar = 'A';
unsigned char testchar_readback = 'Z';  // init to this to see difference after read

void main(void)
{
     unsigned char i = 0;
     unsigned char Data1 [10]="EEPROM   ";
     unsigned char Data2 [10]="tst ";

     Port_Initialized ();
     LCD_Initialized();
     I2C_Initialized();
     LCD_Data(Data2);
 
    // Write test buffer
     Result1 = EEPROM_Write(EEPROM_ADDRESS , Word_Address1 , sizeof(EEPROM_data), EEPROM_data);
     __delay_ms(10);
 
    // Read test buffer back
     Result2 = EEPROM_Read(EEPROM_ADDRESS, Word_Address1 , sizeof(rd_buf), rd_buf) ;
     __delay_ms(10);

    // Write ONE character to location 0x15
    Result3 = EEPROM_Write(EEPROM_ADDRESS, 0x15 , 1, &testchar);
     __delay_ms(10);

     // Read back ONE character from 0x15
     Result4 = EEPROM_Read(EEPROM_ADDRESS, 0x15 , 1, &testchar_readback);
    __delay_ms(10);

      Data1[7] = testchar_readback;   // testchar_readback should have changed 'Z' to 'A'  if read/write worked
      LCD_Data(Data1);

    while(1);   //endless loop to avoid exiting main() function)
}
 

hexreader

Joined Apr 16, 2011
619
Black squares suggests that LCD did not initialise correctly

Has a wire fallen off from your LCD? You had it working before.

I seem to remember that you had a bad jumper lead in the past. Did you throw it away? - or are you using it for your LCD?
 
Last edited:

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
Black squares suggests that LCD did not initialise correctly

Has a wire fallen off from your LCD? You had it working before.

I seem to remember that you had a bad jumper lead in the past. Did you throw it away? - or are you using it for your LCD?
I think I have figured out problem RB6/PGC pin required to program device. I have connected enable pin of LCD to RB6. When I power off the system and again I power on the system I see the text

1621596536755.png

Edit: sorry RB6 was connected with enable pin of LCD
 
Last edited:

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
As far as I can tell, there is a problem with the I2C init function.
This function is a mess, and I have no idea why it works and which statements are unnecessary. All that I know is that it makes your project work. (on my hardware at least)
@hexreader I don't seen any problem with I2C init function. I ran the code with below function and It's working fine.

C:
//Initialize I2C in master mode
void I2C_Initialized(void)
{
    SSPSTAT=0x80; //Slew rate control is disabled for Standard Speed mode (100 kHz and 1 MHz)
    SSPCON1=0x28; // I2C Master mode, clock = FOSC/(4 * (SSPADD + 1))
    SSPCON2=0x00;
    SSPADD = 49;  //100kHz clock @ 20MHz Fosc SSPADD = ( (Fosc/4) / BiteRate )-1
   // SSPADD = ( 20MHz / 100KHz ) - 1 = 49 //
}
 

hexreader

Joined Apr 16, 2011
619
Well, I did say that my understanding of I2C is poor....

As long as your code works, then all is well. If the simpler init routine works, then carry on using it.

Here are the EEPROM contents (initially all FF hex) after your latest code has run:

Code:
i2cEEPROM Monitor 20 May 2021
? for help

?

?                 List Commands
d mm hh w dd mm y write Date/time to 1307 RTC
f dd              Fill with dd i2cEEPROM
r                 Read i2cEEPROM
t                 read Time from 1307 RTC
w aaa dd          Write i2cEEPROM
z                 set fixed date/time to 1307 RTC

t
time from 1307 RTC
Fri 21-05-2021 12:53:38
r

EEPROM Contents...
0000 = 07 06 05 04 - 03 02 01 FF - FF FF FF FF - FF FF FF FF ................
0010 = FF FF FF FF - FF 41 FF FF - FF FF FF FF - FF FF FF FF .....A..........
0020 = FF FF FF FF - FF FF FF FF - FF FF FF FF - FF FF FF FF ................
0030 = FF FF FF FF - FF FF FF FF - FF FF FF FF - FF FF FF FF ................
0040 = FF FF FF FF - FF FF FF FF - FF FF FF FF - FF FF FF FF ................
0050 = FF FF FF FF - FF FF FF FF - FF FF FF FF - FF FF FF FF ................
0060 = FF FF FF FF - FF FF FF FF - FF FF FF FF - FF FF FF FF ................
0070 = FF FF FF FF - FF FF FF FF - FF FF FF FF - FF FF FF FF ................
0080 = FF FF FF FF - FF FF FF FF - FF FF FF FF - FF FF FF FF ................
0090 = FF FF FF FF - FF FF FF FF - FF FF FF FF - FF FF FF FF ................
00A0 = FF FF FF FF - FF FF FF FF - FF FF FF FF - FF FF FF FF ................
00B0 = FF FF FF FF - FF FF FF FF - FF FF FF FF - FF FF FF FF ................
00C0 = FF FF FF FF - FF FF FF FF - FF FF FF FF - FF FF FF FF ................
00D0 = FF FF FF FF - FF FF FF FF - FF FF FF FF - FF FF FF FF ................
00E0 = FF FF FF FF - FF FF FF FF - FF FF FF FF - FF FF FF FF ................
00F0 = FF FF FF FF - FF FF FF FF - FF FF FF FF - FF FF FF FF ................
 

hexreader

Joined Apr 16, 2011
619
I don't seen any problem with I2C init function. I ran the code with below function and It's working fine.
I did a little more research and now I agree, the init function that I provided has unnecessary steps.
My project just needed RC3 and RC4 set as inputs to fix the problems that I had.
I decided to leave the TRISC3 and TRISC4 settings within init, but could be done in general IO init function equally as well.

Here is what I finally settled on:

C:
// Initialise I2C in master mode - clock frequency is ignored - 100KHz only
void I2C1_Init(const unsigned long clock){
    
    TRISCbits.TRISC4 = 1;                                                       // SDA is input
    TRISCbits.TRISC3 = 1;                                                       // SCL is input
    SSPSTAT = 0x80;                                                             // Slew rate control is disabled for Standard Speed mode (100 kHz and 1 MHz)
    SSPCON1 = 0x28;                                                             // I2C Master mode, clock = FOSC/(4 * (SSPADD + 1))
    SSPCON2 = 0x00;
    SSPADD = 49;                                                                // 100kHz clock @ 20MHz Fosc SSPADD = ( (Fosc/4) / BiteRate )-1
                                                                                // SSPADD = ( 20MHz / 100KHz ) - 1 = 49 //
}
 

JohnInTX

Joined Jun 26, 2012
4,787
That's a lot of good work. Well done to both of you.

I would like to point out that Microchip recommends that r-m-w to the TRIS registers not be done. It's preferable to just assign the full 8 bit value. It is especially important when you are referring the TRIS register that is also shared by a peripheral that also changes the IO direction as I2C does. I can attest personally to problems doing just that and have written about it at length here on AAC. I can look some of that up but for now, it's best to avoid problems and just follow Microchip's recommendations.
TRISCbits.TRISC4 = 1; // SDA is input
TRISCbits.TRISC3 = 1; // SCL is input
Good stuff, though!
 

hexreader

Joined Apr 16, 2011
619
Thanks JohnInTX:)

I have learnt something new.
I have removed the two offending bit setting instructions in my i2cEEPROM Monitor project and put a single TRISC command in port initialisation code
That tends to be what I normally do anyway, but I did not know that RMW was a thing with TRIS

Many thanks
 

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
@hexreader I think its time to work with DS1307. I am struggling little bit to read minutes. I just want to show minutes on LCD just for testing purpose

Can you modify this program and check it on your board May be it can show the hardware fault in my board. I'm afraid I haven't damaged my DS1307
C:
//
#define _XTAL_FREQ 20000000     // crystal 20MHz

// PIC18F45K80 Configuration Bit Settings
// CONFIG1L
#pragma config RETEN = ON       // VREG Sleep Enable bit (Ultra low-power regulator is Enabled (Controlled by SRETEN bit))
#pragma config INTOSCSEL = LOW  // LF-INTOSC Low-power Enable bit (LF-INTOSC in Low-power mode during Sleep)
// SOSCSEL = No Setting
#pragma config XINST = OFF      // Extended Instruction Set (Disabled)
// CONFIG1H
#pragma config FOSC = HS2       // HS oscillator (high power, 16 MHz-25 MHz
#pragma config PLLCFG = OFF     // PLL x4 Enable bit (Disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor (Disabled)
#pragma config IESO = OFF       // Internal External Oscillator Switch Over Mode (Disabled)
// CONFIG2L
#pragma config PWRTEN = ON      // Power Up Timer (Enabled)
#pragma config BOREN = OFF      // Brown Out Detect (Disabled in hardware, SBOREN disabled)
#pragma config BORV = 0         // Brown-out Reset Voltage bits (3.0V)
#pragma config BORPWR = LOW     // BORMV Power level (BORMV set to low power level)
// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer (WDT disabled in hardware; SWDTEN bit disabled)
#pragma config WDTPS = 1        // Watchdog Postscaler (1:1)
// CONFIG3H
#pragma config CANMX = PORTC    // ECAN Mux bit (ECAN TX and RX pins are located on RC6 and RC7, respectively)
#pragma config MSSPMSK = MSK5   // MSSP address masking (5 bit address masking mode)
#pragma config MCLRE = ON      // Master Clear Enable (MCLR Enabled, RE3 Disabled)
// CONFIG4L
#pragma config STVREN = OFF     // Stack Overflow Reset (Disabled)
#pragma config BBSIZ = BB1K     // Boot Block Size (1K word Boot Block size)
// CONFIG5L
#pragma config CP0 = ON         // Code Protect 00800-01FFF (Enabled)
#pragma config CP1 = ON         // Code Protect 02000-03FFF (Enabled)
#pragma config CP2 = ON         // Code Protect 04000-05FFF (Enabled)
#pragma config CP3 = ON         // Code Protect 06000-07FFF (Enabled)
// CONFIG5H
#pragma config CPB = ON         // Code Protect Boot (Enabled)
#pragma config CPD = ON         // Data EE Read Protect (Enabled)
// CONFIG6L
#pragma config WRT0 = ON        // Table Write Protect 00800-01FFF (Enabled)
#pragma config WRT1 = ON        // Table Write Protect 02000-03FFF (Enabled)
#pragma config WRT2 = ON        // Table Write Protect 04000-05FFF (Enabled)
#pragma config WRT3 = ON        // Table Write Protect 06000-07FFF (Enabled)
// CONFIG6H
#pragma config WRTC = ON        // Config. Write Protect (Enabled)
#pragma config WRTB = ON        // Table Write Protect Boot (Enabled)
#pragma config WRTD = ON        // Data EE Write Protect (Enabled)
// CONFIG7L
#pragma config EBTR0 = ON       // Table Read Protect 00800-01FFF (Enabled)
#pragma config EBTR1 = ON       // Table Read Protect 02000-03FFF (Enabled)
#pragma config EBTR2 = ON       // Table Read Protect 04000-05FFF (Enabled)
#pragma config EBTR3 = ON       // Table Read Protect 06000-07FFF (Enabled)
// CONFIG7H
#pragma config EBTRB = ON       // Table Read Protect Boot (Enabled)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#pragma warning disable 520

#include <xc.h>

unsigned char Result1;
unsigned char Result2;
unsigned char Result3;
unsigned char Result4;

// The code should set the R/W bit according to its function
#define DS1307_ADDRESS      0xD0         //I2C slave address of DS1307 (8 bit format)
#define Word_Address        0x00


#define LCD_RS              LATBbits.LATB4
#define LCD_TRIS_RS         TRISBbits.TRISB4
#define LCD_RW              LATBbits.LATB5
#define LCD_TRIS_RW         TRISBbits.TRISB5
#define LCD_E               LATBbits.LATB6
#define LCD_TRIS_E          TRISBbits.TRISB6

#define  LCDPORT            LATD
#define  LCDTRISD           LATD

//Prototype function
void Port_Initialized (void);
void WriteNibble(unsigned char command);
void WaitLCDBusy(void);
void WriteCommand(unsigned char command);

void Port_Initialized (void)
{
// LATx registers
    LATA =  0x00;
    LATB =  0x00;
    LATC =  0x00;
    LATD =  0x00;
    LATE =  0x00;

//  TRISx registers
    TRISA = 0x00;    // All are output, Unused
    TRISB = 0x00;   // all are output, Unused
    TRISC = 0x18;    //
    TRISD = 0x00;   // all are output, Unused
    TRISE = 0x00;   // All are output, Unused

    ANCON0 = 0x00;    // digital port
    ANCON1 = 0x00;    // Set to digital port
    CM1CON = 0x00;      // Comparator off
    CM2CON = 0x00;      // Comparator off
    ADCON0 = 0x00;      // A/D conversion Disabled
    ADCON1 = 0x00;      // A/D conversion Disabled
    ADCON2 = 0x00;     // A/D conversion Disabled
}

void WaitLCDBusy(void)
{
    __delay_ms(5);
}

//Send a command to the LCD
void WriteCommand(unsigned char command)
{
    WaitLCDBusy();                        //wait until not busy
    LCD_RS = 0;                           //setup to send command
    WriteNibble(command);                 //write the high nibble
    WriteNibble( (unsigned char)(command<<4) ); //then the low nibble  
}

//Initialized  LCD
void LCD_Initialized()
{
    LCDTRISD &=0x0f;                //ensure data bits are output
    LCD_E=0;                        //clear enable
    LCD_RS = 0;                     //going to write command
    LCD_TRIS_E=0;                   //Set enable to output
    LCD_TRIS_RS=0;                  //set RS to output
    LCD_TRIS_RW=0;
    LCD_RW=0;
    __delay_ms(30);                 //delay for LCD to initialise.
    WriteNibble(0x30);              //Required for initialisation
    __delay_ms(5);                  //required delay
    WriteNibble(0x30);              //Required for initialisation
    __delay_ms(1);                  //required delay
    WriteCommand(0x20);             //set to 4 bit interface
    WriteCommand(0x2c);             //set to 4 bit interface, 2 line and 5*10 font
    WriteCommand(0x01);             //clear display
    WriteCommand(0x06);             //move cursor right after write
    WriteCommand(0x0C);             //turn on display
}

//Send a character to the LCD
void WriteChar(unsigned char chr)
{
    WaitLCDBusy();                         //wait until not busy
    LCD_RS=1;                              //Setup to send character
    WriteNibble(chr);                      //write the high nibble          
    WriteNibble( (unsigned char)(chr<<4)); //then the low nibble
}

//Send any 4 bits to the LCD
void WriteNibble(unsigned char command)
{
    LCDPORT &= 0x0f;                        //clear the data bits
    LCDPORT|=((command & 0xf0));            //or in the new data
    LCD_E = 1;                              //enable the LCD interface
    NOP();                                  //change to delay of 1uS
    NOP();
    NOP();
    LCD_E = 0;                              //disable it
}

void LCD_Data( unsigned char *string)
{
    while (*string != '\0')
    {
      WriteChar(*string);
        string++;
    }
}

//Initialize I2C in master mode
void I2C_Initialized(void)
{
    SSPSTAT=0x80; //Slew rate control is disabled for Standard Speed mode (100 kHz and 1 MHz)
    SSPCON1=0x28; // I2C Master mode, clock = FOSC/(4 * (SSPADD + 1))
    SSPCON2=0x00;
    SSPADD = 49;  //100kHz clock @ 20MHz Fosc SSPADD = ( (Fosc/4) / BiteRate )-1
   // SSPADD = ( 20MHz / 100KHz ) - 1 = 49 //
}

// Send an I2C START
// Return 0 if all ok, 1 if bus collision
__bit I2C_Start(void)
{
    BCLIF = 0;  //Clear 'Bus collision" flag
    SEN = 1;    //initiate a START cycle
    while (SEN);    //wait until it has been sent
    return BCLIF;   //return value of BCLIF flag
}
// Send an I2C STOP
void I2C_Stop(void)
{
    PEN = 1;    //initiate a STOP cycle
    while (PEN);    //wait until it has been sent
}
// Send an I2C REPEATED START
void I2C_Restart(void)
{
    RSEN = 1;    //initiate a REPEATED START cycle
    while (RSEN);    //wait until it has been sent
}
//Receive one byte. ackflag=0 to send ACK, or 1 to send NAK in reply
//Send one byte. Return 0 if ACK received, or 1 if NAK received
__bit I2C_Sendbyte(unsigned char dat)
{
    SSPBUF = dat;

    asm("nop");     // <<<--- wait a little for R_W to be set

    while (R_W);    //wait until byte sent and ACK/NAK received
    return ACKSTAT;
}

unsigned char I2C_Recvbyte(unsigned char ackflag)
{
    RCEN = 1;   // initiate a RECEIVE cycle
    ACKDT =(__bit)ackflag;    //specify if we should send ACK or NAK after receiving
    while (RCEN);   //wait until RECEIVE has completed
    ACKEN = 1;  //initiate an ACK cycle
    while (ACKEN);  //wait until it has completed
    return SSPBUF;
}
//Send an array of data to an I2C device.
//Return 0 if all OK, 1 if bus error, 2 if slave address NAK, 3 if slave register NAK, 4 if slave data NAK
unsigned char DS1307_Write(unsigned char slave_address, unsigned char start_reg, unsigned char buflen, const unsigned char * bufptr)
{
    if (I2C_Start() )   //send a start, and check if it succeeded
        return 1;   //abort if bus collision
    //send the I2C slave address (force R/W bit low)
    if (I2C_Sendbyte(slave_address & 0xfe))  // <<---- Added AND to force R/W- low.  Comment said it but code didn't do it
    {
        I2C_Stop(); //if address was NAKed, terminate the cycle
        return 2;   //and return error code
    }
    //send the device register index
    if (I2C_Sendbyte(start_reg))
    {
        I2C_Stop(); //if register was NAKed, terminate the cycle
        return 3;   //and return error code
    }
    //send the data. buflen might be zero!
    for (; buflen>0; --buflen)
    {
        if (I2C_Sendbyte(*bufptr++))
        {
            I2C_Stop(); //if register was NAKed, terminate the cycle
            return 4;   //and return error code
        }
    }
    I2C_Stop();
    return 0;   //no error
}
//Receive an array of data from an I2C device.
//Return 0 if all OK, 1 if bus error, 2 if slave address NAK, 3 if slave register NAK
unsigned char DS1307_Read(unsigned char slave_address, unsigned char start_reg, unsigned char buflen, unsigned char * bufptr)
{
    //do a dummy zero length write cycle to set the register address
    unsigned char retval = DS1307_Write(slave_address, start_reg, 0, 0);
    if (retval)
    {
        return retval;  //abort if there was an error
    }
    //now start the READ cycle
    if (I2C_Start() )   //send a start, and check if it succeeded
        return 1;   //abort if bus collision
    //send the I2C slave address (force the R/W bit high)
    if (I2C_Sendbyte(slave_address | 0x01))
    {
        I2C_Stop(); //if address was NAKed, terminate the cycle
        return 2;   //and return error code
    }
    //receive the data.
    for (; buflen>0; --buflen)
    {
        unsigned char ackflag = (buflen == 1);   //1 if this is the last byte to receive => send NAK

        *bufptr++ = I2C_Recvbyte(ackflag);
    }
    I2C_Stop();
    return 0;   //no error
}
const unsigned char DS1307_data[] =
{
    0x07,   // Count 7
    0x06,   // Count 6
    0x05,   // Count 5
    0x04,   // Count 4
    0x03,   // Count 3
    0x02,   // Count 2
    0x01,   // Count 1
};
unsigned char rd_buf[7];


// Test variable for one byte transfer
const unsigned char testchar = 'A';
unsigned char testchar_readback = 'Z';  // init to this to see difference after read

void main(void)
{
     unsigned char i = 0;
     unsigned char Data1 [10]="EEPROM   ";
     unsigned char Data2 [10]="tst ";

     Port_Initialized ();
     LCD_Initialized();
     I2C_Initialized();
     LCD_Data(Data2);

    // Write test buffer
     Result1 = DS1307_Write(DS1307_ADDRESS , Word_Address , sizeof(DS1307_data), DS1307_data);
     __delay_ms(10);

    // Read test buffer back
     Result2 = DS1307_Read(DS1307_ADDRESS, Word_Address , sizeof(rd_buf), rd_buf) ;
     __delay_ms(10);

    // Write Minutes 1 minute to location 0x1, size 1
    Result3 = DS1307_Write(DS1307_ADDRESS, 0x01 , 1, 1);
     __delay_ms(10);

     // Read back Minutes from 0x1
     Result4 = DS1307_Read(DS1307_ADDRESS, 0x1 , 1, &testchar_readback);
    __delay_ms(10);

      Data1[7] = testchar_readback;  
      LCD_Data(Data1);

    while(1);   //endless loop to avoid exiting main() function)
}
 

hexreader

Joined Apr 16, 2011
619
I will take a look..... May take a while

First observation is that you are trying to send ASCII character 01 to LCD. This is not a printable character.

Would you like my "spoiler" EEPROM and RTC test program now?
It makes reading and writing much, much easier as can be seen in example printout post #186
Needs RS232 serial port, but no LCD
 
Last edited:

hexreader

Joined Apr 16, 2011
619
Here is a very quick modification that sets sensible values of minutes, hours, day date.

I set 31 minutes, as 0x31 is a printable ASCII character '1'

but this really is no way to carry on

How about you write a function that converts a byte to two printable ASCII characters? ... or decimal if you prefer?

Code:
//
#define _XTAL_FREQ 20000000     // crystal 20MHz

// PIC18F45K80 Configuration Bit Settings
// CONFIG1L
#pragma config RETEN = ON       // VREG Sleep Enable bit (Ultra low-power regulator is Enabled (Controlled by SRETEN bit))
#pragma config INTOSCSEL = LOW  // LF-INTOSC Low-power Enable bit (LF-INTOSC in Low-power mode during Sleep)
// SOSCSEL = No Setting
#pragma config XINST = OFF      // Extended Instruction Set (Disabled)
// CONFIG1H
#pragma config FOSC = HS2       // HS oscillator (high power, 16 MHz-25 MHz
#pragma config PLLCFG = OFF     // PLL x4 Enable bit (Disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor (Disabled)
#pragma config IESO = OFF       // Internal External Oscillator Switch Over Mode (Disabled)
// CONFIG2L
#pragma config PWRTEN = ON      // Power Up Timer (Enabled)
#pragma config BOREN = OFF      // Brown Out Detect (Disabled in hardware, SBOREN disabled)
#pragma config BORV = 0         // Brown-out Reset Voltage bits (3.0V)
#pragma config BORPWR = LOW     // BORMV Power level (BORMV set to low power level)
// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer (WDT disabled in hardware; SWDTEN bit disabled)
#pragma config WDTPS = 1        // Watchdog Postscaler (1:1)
// CONFIG3H
#pragma config CANMX = PORTC    // ECAN Mux bit (ECAN TX and RX pins are located on RC6 and RC7, respectively)
#pragma config MSSPMSK = MSK5   // MSSP address masking (5 bit address masking mode)
#pragma config MCLRE = ON      // Master Clear Enable (MCLR Enabled, RE3 Disabled)
// CONFIG4L
#pragma config STVREN = OFF     // Stack Overflow Reset (Disabled)
#pragma config BBSIZ = BB1K     // Boot Block Size (1K word Boot Block size)
// CONFIG5L
#pragma config CP0 = ON         // Code Protect 00800-01FFF (Enabled)
#pragma config CP1 = ON         // Code Protect 02000-03FFF (Enabled)
#pragma config CP2 = ON         // Code Protect 04000-05FFF (Enabled)
#pragma config CP3 = ON         // Code Protect 06000-07FFF (Enabled)
// CONFIG5H
#pragma config CPB = ON         // Code Protect Boot (Enabled)
#pragma config CPD = ON         // Data EE Read Protect (Enabled)
// CONFIG6L
#pragma config WRT0 = ON        // Table Write Protect 00800-01FFF (Enabled)
#pragma config WRT1 = ON        // Table Write Protect 02000-03FFF (Enabled)
#pragma config WRT2 = ON        // Table Write Protect 04000-05FFF (Enabled)
#pragma config WRT3 = ON        // Table Write Protect 06000-07FFF (Enabled)
// CONFIG6H
#pragma config WRTC = ON        // Config. Write Protect (Enabled)
#pragma config WRTB = ON        // Table Write Protect Boot (Enabled)
#pragma config WRTD = ON        // Data EE Write Protect (Enabled)
// CONFIG7L
#pragma config EBTR0 = ON       // Table Read Protect 00800-01FFF (Enabled)
#pragma config EBTR1 = ON       // Table Read Protect 02000-03FFF (Enabled)
#pragma config EBTR2 = ON       // Table Read Protect 04000-05FFF (Enabled)
#pragma config EBTR3 = ON       // Table Read Protect 06000-07FFF (Enabled)
// CONFIG7H
#pragma config EBTRB = ON       // Table Read Protect Boot (Enabled)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#pragma warning disable 520

#include <xc.h>

unsigned char Result1;
unsigned char Result2;
unsigned char Result3;
unsigned char Result4;

// The code should set the R/W bit according to its function
#define DS1307_ADDRESS      0xD0         //I2C slave address of DS1307 (8 bit format)
#define Word_Address        0x00


#define LCD_RS              LATBbits.LATB4
#define LCD_TRIS_RS         TRISBbits.TRISB4
#define LCD_RW              LATBbits.LATB5
#define LCD_TRIS_RW         TRISBbits.TRISB5
#define LCD_E               LATBbits.LATB6
#define LCD_TRIS_E          TRISBbits.TRISB6

#define  LCDPORT            LATD
#define  LCDTRISD           LATD

//Prototype function
void Port_Initialized (void);
void WriteNibble(unsigned char command);
void WaitLCDBusy(void);
void WriteCommand(unsigned char command);

void Port_Initialized (void)
{
// LATx registers
    LATA =  0x00;
    LATB =  0x00;
    LATC =  0x00;
    LATD =  0x00;
    LATE =  0x00;

//  TRISx registers
    TRISA = 0x00;    // All are output, Unused
    TRISB = 0x00;   // all are output, Unused
    TRISC = 0x18;    //
    TRISD = 0x00;   // all are output, Unused
    TRISE = 0x00;   // All are output, Unused
 
    ANCON0 = 0x00;    // digital port
    ANCON1 = 0x00;    // Set to digital port
    CM1CON = 0x00;      // Comparator off
    CM2CON = 0x00;      // Comparator off
    ADCON0 = 0x00;      // A/D conversion Disabled
    ADCON1 = 0x00;      // A/D conversion Disabled
    ADCON2 = 0x00;     // A/D conversion Disabled
}

void WaitLCDBusy(void)
{
    __delay_ms(5);
}

//Send a command to the LCD
void WriteCommand(unsigned char command)
{
    WaitLCDBusy();                        //wait until not busy
    LCD_RS = 0;                           //setup to send command
    WriteNibble(command);                 //write the high nibble
    WriteNibble( (unsigned char)(command<<4) ); //then the low nibble   
}

//Initialized  LCD
void LCD_Initialized()
{
    LCDTRISD &=0x0f;                //ensure data bits are output
    LCD_E=0;                        //clear enable
    LCD_RS = 0;                     //going to write command
    LCD_TRIS_E=0;                   //Set enable to output
    LCD_TRIS_RS=0;                  //set RS to output
    LCD_TRIS_RW=0;
    LCD_RW=0;
    __delay_ms(30);                 //delay for LCD to initialise.
    WriteNibble(0x30);              //Required for initialisation
    __delay_ms(5);                  //required delay
    WriteNibble(0x30);              //Required for initialisation
    __delay_ms(1);                  //required delay
    WriteCommand(0x20);             //set to 4 bit interface
    WriteCommand(0x2c);             //set to 4 bit interface, 2 line and 5*10 font
    WriteCommand(0x01);             //clear display
    WriteCommand(0x06);             //move cursor right after write
    WriteCommand(0x0C);             //turn on display
}

//Send a character to the LCD
void WriteChar(unsigned char chr)
{
    WaitLCDBusy();                         //wait until not busy
    LCD_RS=1;                              //Setup to send character
    WriteNibble(chr);                      //write the high nibble           
    WriteNibble( (unsigned char)(chr<<4)); //then the low nibble
}

//Send any 4 bits to the LCD
void WriteNibble(unsigned char command)
{
    LCDPORT &= 0x0f;                        //clear the data bits
    LCDPORT|=((command & 0xf0));            //or in the new data
    LCD_E = 1;                              //enable the LCD interface
    NOP();                                  //change to delay of 1uS
    NOP();
    NOP();
    LCD_E = 0;                              //disable it
}

void LCD_Data( unsigned char *string)
{
    while (*string != '\0')
    {
      WriteChar(*string);
        string++;
    }
}

//Initialize I2C in master mode
void I2C_Initialized(void)
{
    SSPSTAT=0x80; //Slew rate control is disabled for Standard Speed mode (100 kHz and 1 MHz)
    SSPCON1=0x28; // I2C Master mode, clock = FOSC/(4 * (SSPADD + 1))
    SSPCON2=0x00;
    SSPADD = 49;  //100kHz clock @ 20MHz Fosc SSPADD = ( (Fosc/4) / BiteRate )-1
   // SSPADD = ( 20MHz / 100KHz ) - 1 = 49 //
}

// Send an I2C START
// Return 0 if all ok, 1 if bus collision
__bit I2C_Start(void)
{
    BCLIF = 0;  //Clear 'Bus collision" flag
    SEN = 1;    //initiate a START cycle
    while (SEN);    //wait until it has been sent
    return BCLIF;   //return value of BCLIF flag
}
// Send an I2C STOP
void I2C_Stop(void)
{
    PEN = 1;    //initiate a STOP cycle
    while (PEN);    //wait until it has been sent
}
// Send an I2C REPEATED START
void I2C_Restart(void)
{
    RSEN = 1;    //initiate a REPEATED START cycle
    while (RSEN);    //wait until it has been sent
}
//Receive one byte. ackflag=0 to send ACK, or 1 to send NAK in reply
//Send one byte. Return 0 if ACK received, or 1 if NAK received
__bit I2C_Sendbyte(unsigned char dat)
{
    SSPBUF = dat;

    asm("nop");     // <<<--- wait a little for R_W to be set

    while (R_W);    //wait until byte sent and ACK/NAK received
    return ACKSTAT;
}

unsigned char I2C_Recvbyte(unsigned char ackflag)
{
    RCEN = 1;   // initiate a RECEIVE cycle
    ACKDT =(__bit)ackflag;    //specify if we should send ACK or NAK after receiving
    while (RCEN);   //wait until RECEIVE has completed
    ACKEN = 1;  //initiate an ACK cycle
    while (ACKEN);  //wait until it has completed
    return SSPBUF;
}
//Send an array of data to an I2C device.
//Return 0 if all OK, 1 if bus error, 2 if slave address NAK, 3 if slave register NAK, 4 if slave data NAK
unsigned char DS1307_Write(unsigned char slave_address, unsigned char start_reg, unsigned char buflen, const unsigned char * bufptr)
{
    if (I2C_Start() )   //send a start, and check if it succeeded
        return 1;   //abort if bus collision
    //send the I2C slave address (force R/W bit low)
    if (I2C_Sendbyte(slave_address & 0xfe))  // <<---- Added AND to force R/W- low.  Comment said it but code didn't do it
    {
        I2C_Stop(); //if address was NAKed, terminate the cycle
        return 2;   //and return error code
    }
    //send the device register index
    if (I2C_Sendbyte(start_reg))
    {
        I2C_Stop(); //if register was NAKed, terminate the cycle
        return 3;   //and return error code
    }
    //send the data. buflen might be zero!
    for (; buflen>0; --buflen)
    {
        if (I2C_Sendbyte(*bufptr++))
        {
            I2C_Stop(); //if register was NAKed, terminate the cycle
            return 4;   //and return error code
        }
    }
    I2C_Stop();
    return 0;   //no error
}
//Receive an array of data from an I2C device.
//Return 0 if all OK, 1 if bus error, 2 if slave address NAK, 3 if slave register NAK
unsigned char DS1307_Read(unsigned char slave_address, unsigned char start_reg, unsigned char buflen, unsigned char * bufptr)
{
    //do a dummy zero length write cycle to set the register address
    unsigned char retval = DS1307_Write(slave_address, start_reg, 0, 0);
    if (retval)
    {
        return retval;  //abort if there was an error
    }
    //now start the READ cycle
    if (I2C_Start() )   //send a start, and check if it succeeded
        return 1;   //abort if bus collision
    //send the I2C slave address (force the R/W bit high)
    if (I2C_Sendbyte(slave_address | 0x01))
    {
        I2C_Stop(); //if address was NAKed, terminate the cycle
        return 2;   //and return error code
    }
    //receive the data.
    for (; buflen>0; --buflen)
    {
        unsigned char ackflag = (buflen == 1);   //1 if this is the last byte to receive => send NAK

        *bufptr++ = I2C_Recvbyte(ackflag);
    }
    I2C_Stop();
    return 0;   //no error
}
const unsigned char DS1307_data[] =
{
    0x07,   // seconds
    0x31,   // minutes
    0x08,   // hours
    0x07,   // day
    0x22,   // date
    0x05,   // month
    0x01,   // year
};
unsigned char rd_buf[7];


// Test variable for one byte transfer
const unsigned char testchar = 'A';
unsigned char testchar_readback = 'Z';  // init to this to see difference after read

void main(void)
{
     unsigned char i = 0;
     unsigned char Data1 [10]="EEPROM   ";
     unsigned char Data2 [10]="tst ";

     Port_Initialized ();
     LCD_Initialized();
     I2C_Initialized();
     LCD_Data(Data2);
 
    // Write test buffer
    Result1 = DS1307_Write(DS1307_ADDRESS , Word_Address , sizeof(DS1307_data), DS1307_data);
     __delay_ms(10);
 
    // Read test buffer back
     Result2 = DS1307_Read(DS1307_ADDRESS, Word_Address , sizeof(rd_buf), rd_buf) ;
     __delay_ms(10);

    // Write Minutes 1 minute to location 0x1, size 1
    //Result3 = DS1307_Write(DS1307_ADDRESS, 0x01 , 1, 31);
     __delay_ms(10);

     // Read back Minutes from 0x1
     Result4 = DS1307_Read(DS1307_ADDRESS, 0x1 , 1, &testchar_readback);
    __delay_ms(10);

      Data1[7] = testchar_readback;   
      LCD_Data(Data1);

    while(1);   //endless loop to avoid exiting main() function)
}
 

hexreader

Joined Apr 16, 2011
619
Running my test program shows that the above code does work

Code:
i2cEEPROM Monitor 20 May 2021
? for help

t
time from 1307 RTC
Sat 22-05-2021 08:31:27
You just need to work on displaying the results in a sensible way
 

hexreader

Joined Apr 16, 2011
619
Good decision - your life is about to get much easier..:)

C:
// Important Note: some of the code below  is based on example code that is copyright of  mikroE

// original code is copyright Djsarker - updated by amateur author who makes no claim to any copyright

// bad port of 1307 RTC and EEPROM test programs mixed in with other random code found on forum
//   - this has resulted in Frankenstein's Monster - I am not proud of the result :{
// messy and probably buggy code due to minimal effort made on port
// amateur code - use at your own risk - author accepts no responsibility for anything, anywhere, ever

//  Simple monitor program for PIC18F45K80 EasyPIC v7
//     - Put RX and TX UART switches Tx on RC6, Rx on RC7 (turn on SW1.1 and SW2.1)
//     - use terminal program on PC set to 9600,8,n,1
//     - turn on switches SW4.7 and SW4.8 to enable on-board EEPROM

//  SPECIAL NOTE:-  Code assumes EEPROM Write-Protect pin is connected to RC0, but not true of EasyPic 7 on-board EEPROM
//                  Ignore RC0 operation for on-board EEPROM - only EEPROM Click fitted to microBUS 1 socket uses WP

// status as of 20 May 2021....
//    - much tidying desperately needed
//    - backspace does not work correctly
//    - otherwise - seems to work

// PIC18F45K80 Configuration Bit Settings

// CONFIG1L
#pragma config RETEN = ON       // VREG Sleep Enable bit (Ultra low-power regulator is Enabled (Controlled by SRETEN bit))
#pragma config INTOSCSEL = LOW  // LF-INTOSC Low-power Enable bit (LF-INTOSC in Low-power mode during Sleep)
#pragma config SOSCSEL = HIGH   // SOSC Power Selection and mode Configuration bits (High Power SOSC circuit selected)
#pragma config XINST = OFF      // Extended Instruction Set (Disabled)

// CONFIG1H
#pragma config FOSC = HS2       // Oscillator (HS oscillator (High power, 16 MHz - 25 MHz))
#pragma config PLLCFG = OFF     // PLL x4 Enable bit (Disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor (Disabled)
#pragma config IESO = OFF       // Internal External Oscillator Switch Over Mode (Disabled)

// CONFIG2L
#pragma config PWRTEN = ON      // Power Up Timer (Enabled)
#pragma config BOREN = OFF      // Brown Out Detect (Disabled in hardware, SBOREN disabled)
#pragma config BORV = 0         // Brown-out Reset Voltage bits (3.0V)
#pragma config BORPWR = LOW     // BORMV Power level (BORMV set to low power level)

// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer (WDT disabled in hardware; SWDTEN bit disabled)
#pragma config WDTPS = 1        // Watchdog Postscaler (1:1)

// CONFIG3H
#pragma config CANMX = PORTC    // ECAN Mux bit (ECAN TX and RX pins are located on RC6 and RC7, respectively)
#pragma config MSSPMSK = MSK5   // MSSP address masking (5 bit address masking mode)
#pragma config MCLRE = ON       // Master Clear Enable (MCLR Enabled, RE3 Disabled)

// CONFIG4L
#pragma config STVREN = OFF     // Stack Overflow Reset (Disabled)
#pragma config BBSIZ = BB1K     // Boot Block Size (1K word Boot Block size)

// CONFIG5L
#pragma config CP0 = OFF        // Code Protect 00800-01FFF (Disabled)
#pragma config CP1 = OFF        // Code Protect 02000-03FFF (Disabled)
#pragma config CP2 = OFF        // Code Protect 04000-05FFF (Disabled)
#pragma config CP3 = OFF        // Code Protect 06000-07FFF (Disabled)

// CONFIG5H
#pragma config CPB = OFF        // Code Protect Boot (Disabled)
#pragma config CPD = OFF        // Data EE Read Protect (Disabled)

// CONFIG6L
#pragma config WRT0 = OFF       // Table Write Protect 00800-01FFF (Disabled)
#pragma config WRT1 = OFF       // Table Write Protect 02000-03FFF (Disabled)
#pragma config WRT2 = OFF       // Table Write Protect 04000-05FFF (Disabled)
#pragma config WRT3 = OFF       // Table Write Protect 06000-07FFF (Disabled)

// CONFIG6H
#pragma config WRTC = OFF       // Config. Write Protect (Disabled)
#pragma config WRTB = OFF       // Table Write Protect Boot (Disabled)
#pragma config WRTD = OFF       // Data EE Write Protect (Disabled)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protect 00800-01FFF (Disabled)
#pragma config EBTR1 = OFF      // Table Read Protect 02000-03FFF (Disabled)
#pragma config EBTR2 = OFF      // Table Read Protect 04000-05FFF (Disabled)
#pragma config EBTR3 = OFF      // Table Read Protect 06000-07FFF (Disabled)

// CONFIG7H
#pragma config EBTRB = OFF      // Table Read Protect Boot (Disabled)

#include <xc.h>

#define  _XTAL_FREQ 20000000

#define i2cEEPROM_WP LATCbits.LATC0                                             // connect EEPROM to RC0 or to ground

// function prototypes - for descriptions, see function code
void linein(char* pstring);
char getparams(char* tempstring);
void PrintHex(unsigned char i);
void PrintHexSp(unsigned char i);
void UART1_Init(unsigned long baud_rate);
char UART1_Read(void);
void UART1_Write(unsigned char message);
void UART1_Write_Text(char *p);
void cmdd(void);
void cmdf(void);
void cmdr(void);
void cmdt(void);
void cmdw(void);
void cmdz(void);
void I2C1_Init(const unsigned long clock);
unsigned short I2C1_Start(void);
void I2C1_Repeated_Start(void);
void I2C1_Stop(void);
unsigned short I2C1_Wr(unsigned short data_);
unsigned char I2C1_Rd(unsigned char ackflag);
void i2cEEPROM_WrSingle(unsigned int wAddr, unsigned char wData);
unsigned char i2cEEPROM_RdSingle(unsigned int rAddr);
void PrintHex(unsigned char ihex);
void PrintHexSp(unsigned char ihex);
char getparams(char* tempstring);
void linein(char* pstring);

// global variables
unsigned char newcmd;                                                           // save most recent command letter
char cmd;                                                                       // first letter of input line
char linebuff[257];                                                             // allow up to this many characters in input line
unsigned char param[8][20];                                                     // up to 8 parameters
unsigned int upar[8];                                                           // parameters as word
unsigned char nparams;                                                          // number of parameters
unsigned char EC_hdr;
unsigned char EC_tmp;
unsigned int EC_adr;                                                            // memory address
unsigned char EC_data;                                                          // memory data
unsigned int ee_addr;                                                           // EEPROM address
char ascii_string[18];                                                          // store ASCII string for "r" command
char sec, min1, hr, week_day, day, mn, year;                                    // store information read from 1307 RTC
char *txt, tnum[4];                                                             // buffers for 1307 RTC

//--------------------- Reads time and date information from RTC (DS1307)
void Read_Time(char *sec, char *min, char *hr, char *week_day, char *day, char *mn, char *year) {

    I2C1_Start();
    I2C1_Wr(0xD0);                                                              // RTC address 0x38 shifted left, r/w cleared for write
    I2C1_Wr(0);                                                                 // start from register 0
    I2C1_Repeated_Start();
    I2C1_Wr(0xD1);                                                              // RTC address 0x38, shifted left, r/w set for read
    *sec = I2C1_Rd(1);                                                          // register 0
    *min = I2C1_Rd(1);                                                          // register 1
    *hr = I2C1_Rd(1);                                                           // register 2
    *week_day = I2C1_Rd(1);                                                     // register 3
    *day = I2C1_Rd(1);                                                          // register 4
    *mn = I2C1_Rd(1);                                                           // register 5
    *year = I2C1_Rd(0);                                                         // register 6
    I2C1_Stop();
}

//-------------------- Formats date and time
void Transform_Time(char  *sec, char *min, char *hr, char *week_day, char *day, char *mn, char *year) {
    *sec  =  ((*sec & 0x70) >> 4)*10 + (*sec & 0x0F);
    *min  =  ((*min & 0xF0) >> 4)*10 + (*min & 0x0F);
    *hr   =  ((*hr & 0x30) >> 4)*10 + (*hr & 0x0F);
    *week_day =(*week_day & 0x07);
    *day  =  ((*day & 0xF0) >> 4)*10 + (*day & 0x0F);
    *mn   =  ((*mn & 0x10) >> 4)*10 + (*mn & 0x0F);
    *year =  ((*year & 0xF0)>>4)*10+(*year & 0x0F);
}

//-------------------- Output values to UART
void Display_Time(char sec, char min, char hr, char week_day, char day, char mn, char year) {

    UART1_Write_Text("\r");
    switch(week_day){
        case 1:
            txt = "Sun";
            break;
        case 2:
            txt = "Mon";
            break;
        case 3:
            txt = "Tue";
            break;
        case 4:
            txt = "Wed";
            break;
        case 5:
            txt = "Thu";
            break;
        case 6:
            txt = "Fri";
            break;
        case 7:
            txt = "Sat";
            break;
        default:
            txt = "Inv";
            break;
   }
   UART1_Write_Text(txt);

   UART1_Write(' ');
   UART1_Write((day / 10) + 48);                                                // Print tens digit of day variable
   UART1_Write((day % 10)   + 48);                                              // Print ones digit of day variable
   UART1_Write('-');
   UART1_Write((mn / 10) + 48);
   UART1_Write((mn % 10) + 48);
   UART1_Write_Text("-202");
   UART1_Write( year  + 48);                                                    // Print year

   UART1_Write(' ');
   UART1_Write((hr / 10)   + 48);
   UART1_Write((hr % 10)   + 48);
   UART1_Write(':');
   UART1_Write((min / 10) + 48);
   UART1_Write((min % 10) + 48);
   UART1_Write(':');
   UART1_Write((sec / 10) + 48);
   UART1_Write((sec % 10) + 48);
   if((sec > 59 ) || (min > 59 ) || (hr > 23 ) || (day > 31 ) || (mn > 12 )){
       UART1_Write_Text("  * Invalid ! *");
       UART1_Write_Text("\r\n  check 1307 RTC connections\r\n");
   }
}

// initialise UART 1 for 9600,8,n,1
// note that baud rate argument is currently completely ignored
void UART1_Init(unsigned long baud_rate){
    //TXSTAx TRANSMIT STATUS AND CONTROL REGISTER
    TXSTA1bits.CSRC = 0;                                                        // : Don?t care.
    TXSTA1bits.TX9 = 0;                                                         // Selects 8-bit transmission
    TXSTA1bits.TXEN = 1;                                                        // Transmit Enable
    TXSTA1bits.SYNC  = 0;                                                       // Asynchronous mode
    TXSTA1bits.SENDB = 0;
    TXSTA1bits.BRGH =  1;                                                       //  High speed mode
    TXSTA1bits.TX9D = 0;
    //RCSTAx: RECEIVE STATUS AND CONTROL REGISTER
    RCSTA1bits.SPEN  = 1 ;                                                      // Serial port enabled
    RCSTA1bits.RX9 = 0;                                                         // Selects 8-bit reception
    RCSTA1bits.SREN  = 1 ;                                                      // Don?t care.
    RCSTA1bits.CREN  = 1 ;                                                      // Enables receiver
    RCSTA1bits.ADDEN = 0;                                                       //
    RCSTA1bits.FERR  = 0 ;                                                      // No framing error
    RCSTA1bits.OERR  = 1 ;                                                      // Overrun error
    RCSTA1bits.RX9D   = 0 ;                                                     // Selects 8-bit reception

    SPBRGH1 = 0;
    SPBRG1 = 129;
}

// write a single character to UART 1 - blocking
void UART1_Write(unsigned char message){
    while(PIR1bits.TX1IF == 0 );                                                          // Wait till the transmitter register becomes empty
    TXREG1 = message;
}

// write a string to UART 1
void UART1_Write_Text(char *p){
    while(*p != '\0') {
        //__delay_ms(1);
        UART1_Write(*p);
        p++;
    }
}

// read a single charater from UART1
char UART1_Read(void){
  char temp;

    while(!PIR1bits.RC1IF);                                                     // blocking wait for character to arrive from terminal
    temp = RCREG1;                                                              // get the character
    return temp;
}

// Initialise I2C in master mode - clock frequency is ignored - 100KHz only
void I2C1_Init(const unsigned long clock){
 
    SSPSTAT = 0x80;                                                             // Slew rate control is disabled for Standard Speed mode (100 kHz and 1 MHz)
    SSPCON1 = 0x28;                                                             // I2C Master mode, clock = FOSC/(4 * (SSPADD + 1))
    SSPCON2 = 0x00;
    SSPADD = 49;                                                                // 100kHz clock @ 20MHz Fosc SSPADD = ( (Fosc/4) / BiteRate )-1
                                                                                // SSPADD = ( 20MHz / 100KHz ) - 1 = 49 //
}

// Send an I2C START
// Return 0 if all ok, 1 if bus collision
unsigned short I2C1_Start(void){
    PIR2bits.BCLIF = 0;  //Clear 'Bus collision" flag
    SSPCON2bits.SEN = 1;                                                        // initiate a START cycle
    while (SSPCON2bits.SEN);                                                    // wait until it has been sent
    return PIR2bits.BCLIF;                                                      // return value of BCLIF flag
}

// Send an I2C STOP
void I2C1_Stop(void){
    SSPCON2bits.PEN = 1;                                                        // initiate a STOP cycle
    while (SSPCON2bits.PEN);                                                    // wait until it has been sent
}

// Send an I2C REPEATED START
void I2C1_Repeated_Start(void){
    SSPCON2bits.RSEN = 1;                                                       // initiate a REPEATED START cycle
    while (SSPCON2bits.RSEN);                                                   // wait until it has been sent
}

// Receive one byte. ackflag=0 to send ACK, or 1 to send NAK in reply
// Send one byte. Return 0 if ACK received, or 1 if NAK received
unsigned short I2C1_Wr(unsigned short data_){
    SSPBUF = (unsigned char)data_;
    asm ("nop");                                                                // <<<--- wait a little for R_W to be set
    while (SSPSTATbits.R_W);                                                    // wait until byte sent and ACK/NAK received
    return SSPCON2bits.ACKSTAT;
}

unsigned char I2C1_Rd(unsigned char ackflag){
    SSPCON2bits.RCEN = 1;                                                       // initiate a RECEIVE cycle
    SSPCON2bits.ACKDT = !(ackflag & 0x01);                                      // specify if we should send ACK or NAK after receiving
    while (SSPCON2bits.RCEN);                                                   // wait until RECEIVE has completed
    SSPCON2bits.ACKEN = 1;                                                      // initiate an ACK cycle
    while (SSPCON2bits.ACKEN);                                                  // wait until it has completed
    return SSPBUF;
}


void main() {
    ADCON0 = 0;                                                                 // Configure PORT pins as digital
    TRISA = 0;
    TRISB  = 0;                                                                 // Configure PORT as output
    TRISC  = 0x98;                                                              // UART1 Rx, I2C SDA, SCL input, rest output
    TRISD  = 0;                                                                 // Configure PORT as output
    LATA = 0;
    LATB = 0x00;                                                                // clear all to Low
    LATC = 0x00;                                                                // clear all to Low
    LATD = 0x00;                                                                // clear all to Low

    __delay_ms(1000);                                                           // prevent double start when programming
    UART1_Init(9600);                                                           // Initialise UART 1
    __delay_ms(100);                                                            // Wait for UART modules to stabilise
    newcmd = '?';                                                               // default to help
    cmd = newcmd;

    UART1_Write_Text("\r\n\ni2cEEPROM Monitor 20 May 2021\r\n");                // introduction text
    UART1_Write_Text("? for help\r\n\n");                                         // introduction text

    i2cEEPROM_WP = 1;                                                           // start with EEPROM write protected
    I2C1_Init(100000);                                                          // initialise I2C communication
    __delay_ms(100);                                                            // allow I2C to settle

    while(1){
        linein(linebuff);                                                       // fetch a line of text
        newcmd = getparams(linebuff);                                           // read hex parameters
        switch(newcmd){                                                         // act upon command letter
            case 'D':
                cmdd();
                break;

            case 'F':
                cmdf();
                break;

            case 'R':
                cmdr();
                break;

            case 'T':
                cmdt();
                break;

            case 'W':
                cmdw();
                break;

            case 'Z':
                cmdz();
                break;

            case '?':
                UART1_Write_Text("\r\n");
                UART1_Write_Text("?                 List Commands\r\n");
                UART1_Write_Text("d mm hh w dd mm y write Date/time to 1307 RTC\r\n");
                UART1_Write_Text("f dd              Fill with dd i2cEEPROM\r\n");
                UART1_Write_Text("r                 Read i2cEEPROM\r\n");
                UART1_Write_Text("t                 read Time from 1307 RTC\r\n");
                UART1_Write_Text("w aaa dd          Write i2cEEPROM\r\n");
                UART1_Write_Text("z                 set fixed date/time to 1307 RTC\r\n");
                UART1_Write_Text("\r\n");
                break;
            default:{
                UART1_Write_Text("\r\ncommand not recognised\r\n");
                break;
            }
        }
    }
}

// write date to 1307 RTC
void cmdd(void){
    if(nparams < 2){                                                            // warn if wrong number of parameters, but allow anyway to default to old values
        UART1_Write_Text("\r\nneed at least 1 parameter...\r\nd mm hh w dd mm y\r\n");
        UART1_Write_Text("minute, hour, weekday 1=Sun, day, month, year 0-9\r\n\n");
    }
    else{
        I2C1_Start();                                                           // issue start signal
        I2C1_Wr(0xD0);                                                          // address DS1307  (0x68 shifted left by one)
        I2C1_Wr(0);                                                             // start from word at address (REG0)
        I2C1_Wr(0x80);                                                          // write $80 to REG0. (pause counter + 0 sec)
        I2C1_Wr(upar[1] & 0xff);                                                // write to minutes word to (REG1)
        if(nparams > 2){
            I2C1_Wr(upar[2] & 0xff);                                            // write to hours word (24-hours mode)(REG2)
            if(nparams > 3){
                I2C1_Wr(upar[3] & 0xff);                                        // write day (1 = Sunday) (REG3)
                if(nparams > 4){
                    I2C1_Wr(upar[4] & 0xff);                                    // write to date word (REG4)
                    if(nparams > 5){
                        I2C1_Wr(upar[5] & 0xff);                                // write to month word (REG5)
                        if(nparams > 6){
                            I2C1_Wr(upar[6] & 0xff);                            // write to year word (REG6)    
                        }
                    }
                }
            }
        }
        I2C1_Stop();                                                            // issue stop signal

        I2C1_Start();                                                           // issue start signal
        I2C1_Wr(0xD0);                                                          // address DS1307  (0x68 shifted left by one)
        I2C1_Wr(0);                                                             // start from word at address 0
        I2C1_Wr(0);                                                             // write 0 to REG0 (enable counting + 0 sec)
        I2C1_Stop();                                                            // issue stop signal
        UART1_Write_Text("new date/time set\r\n\n");
    }
}
 
// fill with dd EEPROM Click
// f dd      write data dd (hex) to address aaa (hex)
void cmdf(void){

    EC_data = upar[1] & 0xff;                                                   // parameter 1 is byte value to fill with
    i2cEEPROM_WP = 0;                                                           // WP write enable when low
    UART1_Write_Text("\r\nEEPROM Fill");

    if(nparams == 2){
        for(ee_addr = 0; ee_addr < 1024; ee_addr++){
            i2cEEPROM_WrSingle(ee_addr, EC_data);                               // write byte
            if((ee_addr & 0x1f) == 0){                                          // only print a dot every 32 bytes -
                UART1_Write_Text(".");                                          //    - to show that fill is still in progress
            }
        }
    }
    else{
        UART1_Write_Text("\r\nsyntax error - need...\r\nf dd\r\n");
    }
    i2cEEPROM_WP = 1;                                                           // WP write protect when high
    UART1_Write_Text("\r\ndone\r\n");
}

// read I2C EEPROM
void cmdr(void){

    i2cEEPROM_WP = 1;                                                           // WP write protect when high
    UART1_Write_Text("\r\nEEPROM Contents...");
    ascii_string[16] = 0;                                                       // null terminate ASCII string
    ascii_string[0] = 0;                                                        // no ASCII string for first line

    for(EC_adr = 0; EC_adr < 256; EC_adr++){                                    // 1k bytes in 24C08 I2C EEPROM, 256 bytes in 24C02 I2C EEPROM
        if(! (EC_adr & 0x0f)){                                                  // show address every 16th byte
            UART1_Write_Text(ascii_string);                                     // print ASCII string at end of line
            UART1_Write_Text("\r\n");
            PrintHex(EC_adr/256);                                               // print high address byte as hex
            PrintHex(EC_adr & 0xff);                                                   // print low address byte
            UART1_Write_Text(" = ");
        }
        else{
            if(! (EC_adr & 0x03)){                                              // show '-' after every fourth byte
                UART1_Write_Text("- ");
            }
        }
        EC_tmp = (EC_adr >> 8) & 0x03;                                          // get top 2 address bits
        EC_hdr = 0x50 + EC_tmp;                                                 // bare EEPROM i2c address + hi 2 bits EEPROM aggress
        EC_data = i2cEEPROM_RdSingle(EC_adr);                                   // read single byte (data address)
        PrintHexSp(EC_data);                                                    // print the data byte as hex
        if((EC_data > 31) && (EC_data < 128)){                                  // printable characters only
            ascii_string[EC_adr & 0x0f] = EC_data;                              // store ASCII for later print - limit pointer 0 to 0x0f
        }
        else{                                                                   // change non-printable character to dot
            ascii_string[EC_adr & 0x0f] = '.';                                  // store dot for later print - limit pointer 0 to 0x0f
        }
        __delay_ms(1);                                                          // slow down the display rate
    }
    UART1_Write_Text(ascii_string);                                             // print final ASCII string
    UART1_Write_Text("\r\n");
}

// read time from 1307 I2C RTC
void cmdt(void){
    UART1_Write_Text("time from 1307 RTC\r\n");
    Read_Time(&sec,&min1,&hr,&week_day,&day,&mn,&year);                         // read time from RTC(DS1307)
    Transform_Time(&sec,&min1,&hr,&week_day,&day,&mn,&year);                    // format date and time    
    Display_Time(sec, min1, hr, week_day, day, mn, year);                       // prepare and display on LCD
    UART1_Write_Text("\r\n");
}

// write to I2C EEPROM
// w aaa dd      write data dd (hex) to address aaa (hex)
void cmdw(void){

    EC_adr = upar[1];                                                           // parameter 1 is address 0 to 0x03ff
    EC_data = upar[2] & 0xff;                                                   // parameter 2 is data to write

    i2cEEPROM_WP = 0;                                                           // WP write enable when low
    UART1_Write_Text("\r\nEEPROM Write...");

    __delay_ms(100);                                                              // no idea why I put this here :(

    if(nparams == 3){
        i2cEEPROM_WrSingle(EC_adr, EC_data);                                    // write byte
    }
    else{
        UART1_Write_Text("syntax error - need...\r\nw aaa dd\r\n");
    }
    i2cEEPROM_WP = 1;                                                           // WP write protect when high
    UART1_Write_Text("\r\n");
}

// set fixed date/time to 1307 RT
void cmdz(void){
    I2C1_Start();                                                               // issue start signal
    I2C1_Wr(0xD0);                                                              // address DS1307  (0x68 shifted left by one)
    I2C1_Wr(0);                                                                 // start from word at address (REG0)
    I2C1_Wr(0x80);                                                              // write $80 to REG0. (pause counter + 0 sec)
    I2C1_Wr(0x34);                                                              // write to minutes word to (REG1)
    I2C1_Wr(0x12);                                                              // write to hours word (24-hours mode)(REG2)
    I2C1_Wr(0x05);                                                              // write day (1 = Sunday) (REG3)
    I2C1_Wr(0x20);                                                              // write to date word (REG4)
    I2C1_Wr(0x05);                                                              // write to month word (REG5)
    I2C1_Wr(0x01);                                                              // write to year word (REG6)
    I2C1_Stop();                                                                // issue stop signal

    I2C1_Start();                                                               // issue start signal
    I2C1_Wr(0xD0);                                                              // address DS1307  (0x68 shifted left by one)
    I2C1_Wr(0);                                                                 // start from word at address 0
    I2C1_Wr(0);                                                                 // write 0 to REG0 (enable counting + 0 sec)
    I2C1_Stop();                                                                // issue stop signal
    UART1_Write_Text("1307 date/time reset\r\n");
}

// display byte in hex
void PrintHex(unsigned char ihex) {
unsigned char hib,lob;

    hib = ihex & 0xF0;                                                          // high nibble
    hib = hib >> 4;
    hib = hib + '0';
    if (hib > '9') hib = hib + 7;
    lob = (ihex & 0x0F) + '0';                                                  // low nibble
    if (lob > '9') lob = lob+7;

    UART1_Write(hib);
    UART1_Write(lob);
}

// display byte in hex with trailing space
void PrintHexSp(unsigned char ihex) {
unsigned char hib,lob;

    hib = ihex & 0xF0;                                                          // high nibble
    hib = hib >> 4;
    hib = hib + '0';
    if (hib > '9') hib = hib + 7;
    lob = (ihex & 0x0F) + '0';                                                  // low nibble
    if (lob > '9') lob = lob + 7;

    UART1_Write(hib);
    UART1_Write(lob);
    UART1_Write(' ');
}

// get parameters from string
char getparams(char* tempstring){
  char oldcmd;                                                                  // remember old command letter
  int  n;                                                                       // counter
  char tempchar;                                                                // temp store
  char tempchar2;                                                               // temp store
  unsigned int pointer1 = 0;                                                    // pointer within string
  unsigned int pointer2 = 0;                                                    // pointer within string

    oldcmd = cmd;                                                               // remember old value
    nparams = 0;                                                                // initialise
    pointer1 = 0;                                                               // initialise

    for ( n = 0 ; n < 8 ; n++){                                                 // count 0 to 7
        // skip leading spaces
        tempchar=1;                                                             // init
        do {
            tempchar = tempstring[pointer1++];
        } while (tempchar == 0x20);
        pointer1--;                                                             // leave pointer after param

        // count parameters
        if ((tempchar != 0) && (nparams < 8)){
            nparams++;
        }

        if (n == 0){                                                            // only for param 0
            tempchar=tempstring[pointer1];                                      // get only first letter
            if ((tempchar > 0x60) && (tempchar < 0x7b)) {
                tempchar -= 0x20;                                               // to upper case
            }
            cmd=tempchar;
        }

        tempchar=1;                                                             // initialise
        if (nparams != 0){                                                      // only for non-blank line
            // get all characters
            pointer2=0;                                                         // initialise
            do {
                tempchar = tempstring[pointer1++];                              // get char
                if ((tempchar > 0x60) && (tempchar < 0x7b)) {
                    tempchar -= 0x20;                                           // to upper case
                }
                param[n][pointer2++] = tempchar;                                // and store it
            } while ((tempchar > 0x20) && (tempchar < 0x7f) && (pointer2 < 20)); // text
            param[n][pointer2-1]=0;                                             // zero terminate param string
            if((tempchar == 0)||(n == 9)){                                      // no more params if end of line
                break;
            }
        }
    }

    // convert parameter strings to hex longwords
    for (n = 0; n < nparams ; n++){                                             // parms are 0 to 7
        tempchar2=1;                                                            // initialise
        pointer1=0;                                                             // initialise
        upar[n]=0;                                                              // initialise
        do {
            tempchar = param[n][pointer1++];
            // read one character
            if ( tempchar != 0 ){
                upar[n] = upar[n] * 0x10;                                       // next most signicant hex digit
            }
            tempchar2 = tempchar;                                               // remember original character
            if ((tempchar < 0x30) || (tempchar > 0x46)) {
                tempchar = 0x00;                                                // non-hex to zero
            }
            if ((tempchar > 0x39) && (tempchar < 0x41)) {
                tempchar = 0x00;                                                // non-hex to zero
            }
            if ((tempchar > 0x40) && (tempchar < 0x47)) {
                tempchar -= 0x37;                                               // to bin
            }
            if ((tempchar > 0x2f) && (tempchar < 0x3a)) {
                tempchar -= 0x30;                                               // to bin
            }
            upar[n] += tempchar;
        } while (tempchar2 != 0);
    }

    if (nparams == 0) {
        cmd = oldcmd;
    }
    return cmd;
}

// get a string from UART1.
// Input: Buffer pointer.
// Output: updated buffer.
void linein(char* pstring){
  char inChar = 0;

    while(inChar != '\r'){                                                      // keep reading until CR

        //UART1 read
        if (PIR1bits.RC1IF){                                                    // if a character is received, then process it
            inChar = UART1_Read();                                              // get the character
            UART1_Write(inChar);                                                // echo the character
            if(inChar == '\r'){                                                 // CR
                UART1_Write('\n');                                              // send LF if CR received
                *pstring ++= '\0';                                              // null terminate the received string
            }
            else {
                if (inChar != 0x7f ){                                           // if not backspace
                    *pstring++ = inChar;                                        // add the new character to the receive string
                }
                if (inChar == 0x7f ){                                           // handle backspace (very crudely)
                    *--pstring = 0x00;                                          // move terninator back
                }
            }
        }
    }
}

//--------------- Writes data to I2C EEPROM - single location
void i2cEEPROM_WrSingle(unsigned int wAddr, unsigned char wData) {
  unsigned char hi_addr;                                                        // top two bits of address to bits 2,1

    wAddr &= 0x3ff;                                                             // force address to a valid address
    hi_addr = (wAddr >> 7) & 0x06;                                              // extract top two address bits to bits 2,1
    I2C1_Start();                                                               // issue I2C start signal
    I2C1_Wr(0xA0 | hi_addr);                                                    // send byte via I2C  (device address + W)
    I2C1_Wr(wAddr);                                                             // send byte (address of EEPROM location)
    I2C1_Wr(wData);                                                             // send data (data to be written)
    I2C1_Stop();                                                                // issue I2C stop signal
    __delay_ms(10);                                                             //  too lazy to work out how long to wait, so over-long wait
}

//--------------- Reads data from I2C EEPROM - single location (random)
unsigned char i2cEEPROM_RdSingle(unsigned int rAddr) {
  unsigned char result;
  unsigned char hi_addr;                                                        // top two bits of address to bits 2,1

    rAddr &= 0x3ff;                                                             // force address to a valid address
    hi_addr = (rAddr >> 7) & 0x06;                                              // extract top two address bits to bits 2,1
    I2C1_Start();                                                               // issue I2C start signal
    I2C1_Wr(0xA0 | hi_addr);                                                    // send byte via I2C  (device address + W)
    I2C1_Wr(rAddr);                                                             // send byte (data address)
    I2C1_Repeated_Start();                                                      // issue I2C signal repeated start
    I2C1_Wr(0xA1 | hi_addr);                                                    // send byte (device address + R)
    result = I2C1_Rd(0);                                                        // Read the data (NO acknowledge)
    I2C1_Stop();                                                                // issue I2C stop signal
    return result;
}
 
Last edited:

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
Good decision - your life is about to get much easier..
I just ran code Here is result on hyper terminal I will take a time to understand code but can you confirm ds1307 is working by looking result?. because my main focus is find that ds1307 is working with board.

If DS1307 is working then I will write my own code for real time clock
1621682784113.png
 

hexreader

Joined Apr 16, 2011
619
Good - UART transmit PIC to PC terminal is working
First test is to type ? (return)
You should get help text.
If not, there is a problem with UART receive

next type z (return)
then type t (return)
Code:
i2cEEPROM Monitor 20 May 2021
? for help

?

?                 List Commands
d mm hh w dd mm y write Date/time to 1307 RTC
f dd              Fill with dd i2cEEPROM
r                 Read i2cEEPROM
t                 read Time from 1307 RTC
w aaa dd          Write i2cEEPROM
z                 set fixed date/time to 1307 RTC

z
1307 date/time reset
t
time from 1307 RTC
Thu 20-05-2021 12:34:01
 

hexreader

Joined Apr 16, 2011
619
Wouldn't it be much easier just to run a jumper from RC7 to Rx or Tx - whichever one you have not already connected?
Turn off all handshaking on terminal program.

A monitor program will make much of your future development much easier
 

hexreader

Joined Apr 16, 2011
619
Seems you do not like my EEPROM monitor program.

Another option might be to use the code in post #192.
Hopefully you showed a '1' character on LCD.
You did not say whether you did or not show a '1' on LCD
That would be the "simple" example
 
Top