ADXL345 Accelerometer and 18F4550 in Hi-Tech C

ClydeCrashKop

Well-Known Member
Most Helpful Member
This program displays the 3 axis output from an ADXL345 Accelerometer and 18F4550 in Hi-Tech C. Specifically the little GY-291 board available cheap on eBay. There are pull-ups on the board to solve the 3 volt problem.
I got some info from Ngoc Chung Hoang using CCS compiler ADXL345 + Pic 16f877a If you ask nice and leave your email, he will send the source code.
and his Balancing robot
I use Nigel Goodwin's tutorials in asm... as a starting place for C programs and subroutines.
Thank you Nigel and Ian.
You are welcome to leave your 18F4550 code in this thread.

C:
// ADXL345 Accelerometer and 18F4550 in Hi-Tech C
// Using the hardware MSSP I2C port on RB0 & RB1 and LCD on port D
 
/*   Using HI-TECH C for PIC18 MCU Family.
 
  LCD on D  ICSP is on Port B6 and B7.
  The wiring for the LCD using Hitachi HD44780 is at
  http://www.winpicprog.co.uk/pic_tutorial_lcd_board.htm
*/
//#include <pic18f4550.h>
#include <pic18.h>
#include <htc.h>
#include <stdlib.h>
#include <stdio.h>
 
/* Configuration words for a PIC18F4450
* with a 20 MHz crystal oscillator
*/
__CONFIG(1,USBPLL&PLLDIV5&CPUDIV4&HSPLL&FCMEN&IESOEN);
__CONFIG(2,VREGDIS&PWRTEN&BORDIS&BORV42&WDTDIS&WDTPS32K);
__CONFIG(3,PBDIGITAL&LPT1DIS&MCLREN);
__CONFIG(4,XINSTDIS&STVRDIS&LVPDIS&ICPORTDIS&DEBUGDIS);
__CONFIG(5,UNPROTECT);
__CONFIG(6,UNPROTECT);
__CONFIG(7,UNPROTECT);
 
 
char  IDDV =0;
#define  BW_RATE            44    //0x2C
#define  POWER_CTL          45    //0x2D
#define  DATA_FORMAT        49    //0x31
#define  DATAX0             50    //0x32
#define  DATAX1             51    //0x33
#define  DATAY0             52    //0x34
#define  DATAY1             53    //0x35
#define  DATAZ0             54    //0x36
#define  DATAZ1             55    //0x37
#define  FIFO_CTL           56    //0x38            ADXL1345    1010011   0x53   Device
#define CHIP_Write    0xA6        // adxl345 address for writing    10100110  0xA6   Write
#define CHIP_Read    0xA7        // and reading                    10100111  0xA7   Read
 
 
#define _XTAL_FREQ  20000000        // Xtal speed
 
#define LCD_PORT PORTD            // constants
#define LCD_TRIS TRISD            //
#define LCD_RS     LATD4        // It didn't like RD4?
#define LCD_RW    LATD6
#define LCD_E    LATD7
 
 
        // Required prototypes.. each function needs to be declared
        // if called BEFORE definition.
 
void LCD_init(void), LCD_cmd(unsigned char ch);
void LCD_goto(char line, char column), LCD_clr(void);
void LCD_cur(unsigned char ch), pulse_E(void);
void LCD_char(unsigned char ch), LCD_charD(unsigned char ch);
void LCD_printC(const char *str), LCD_printR(char *str);
void delayMs(int x);
 
// Hardware I2C functions
void I2CInit(void);
void I2CStart();
void I2CStop();
void I2CRestart();
void I2CAck();
void I2CNak();
void I2CWait();
void I2CSend(unsigned char dat);
unsigned char I2CRead(void);
char E_Write(int addr, unsigned char ch);
unsigned char E_Read(int addr);
 
 
 
void ini_adxl345()
{
E_Write(FIFO_CTL,0x9f);
__delay_ms(10);    
E_Write(DATA_FORMAT,0x09);
__delay_ms(10);  
E_Write(BW_RATE,0x0d);
__delay_ms(10);        
E_Write(POWER_CTL,0x08);  // activate  
}
 
unsigned char LCDbuffer[17];
char ErrFlags;            // Read error. (I don't use it, but you might!)
    
 
 
/* our main program loop */
void main(void)
{
    CMCON = 0x07;                        // Comparitors off
 
    int index = 0;                        // text variable
    unsigned char ch;
    LCD_TRIS = 0b00000000;            // LCD port as outputs
    LCD_PORT = 0b00000000;            // Clear LCD port
    delayMs(150);                    // let LCD stabilise
    LCD_init();                        // Initalise screen
 
//    LCD_goto(1,0);    // line 1.
//    LCD_printC("Hi World");
 
    // Initialize I2C Port
    I2CInit();
    // Initialize ADXL345 Accelerometer
    ini_adxl345();
 
/*    LCD_goto(1,0);
      int id, pow, bw_rate;
      id= E_Read(IDDV);  // should be 229 for ADXL1345
     __delay_ms(10);
      pow=E_Read(0x2D);  //should be 8 to activate
     __delay_ms(10);
      bw_rate =E_Read(0x2C);  //BW_RATE 0x2C is 13
        sprintf(LCDbuffer,"id=%3d pow=%3d BW_RATE=%3d",id,pow,bw_rate);
        LCD_printR(LCDbuffer);        // use sprintf to format
*/
 
    signed long x,y,z;
    signed long xhi,xlo,yhi,ylo,zhi,zlo;
    signed long Xaccumulate, Yaccumulate, Zaccumulate;
    signed long Xaverage, Yaverage, Zaverage;
    int i;
 
 
  while(1) {
 
    Xaccumulate = Yaccumulate = Zaccumulate = 0;
 
    for (i=0; i<16; i++) {  // Read sequentially 16 times then get an average.
 
 
    ErrFlags = 0;                                    // Clear error
    I2CStart();
    I2CSend(CHIP_Write);
    I2CSend(DATAX0);    // DATAX0 is the first of 6 bytes
    I2CRestart();
    I2CSend(CHIP_Read);                            //
    xlo = I2CRead();                                // read character
    I2CAck();
    xhi = I2CRead();                                // read character
    I2CAck();
    ylo = I2CRead();                                // read character
    I2CAck();
    yhi = I2CRead();                                // read character
    I2CAck();
    zlo = I2CRead();                                // read character
    I2CAck();
    zhi = I2CRead();                                // read character
    I2CNak();
    I2CStop();
 
 
    Xaccumulate += ((xhi<<8) | xlo); //Xaccumulate = Xaccumulate + (xhi*256 + xlo)
    Yaccumulate += ((yhi<<8) | ylo);
    Zaccumulate += ((zhi<<8) | zlo);
 
  }  // for loop
 
//    x= (xhi<<8) | xlo;
//    y= (yhi<<8) | ylo;
//    z= (zhi<<8) | zlo;
 
// Calculate average accelerometer readings over last 16 samples
 
/* *** Other methods of dividing gave me results in the +/- thousands ***
DIV   From Hi-Tech C manual
Synopsis
#include <stdlib.h>
div_t div (int numer, int demon)
Description
The div() function computes the quotient and remainder of the numerator divided by the denominator.
Example
#include <stdlib.h>
#include <stdio.h>
void
main (void)
{
div_t x;
x = div(12345, 66);
printf("quotient = %d, remainder = %d\n", x.quot, x.rem);
}
See Also
udiv(), ldiv(), uldiv()
Return Value
Returns the quotient and remainder into the div_t structure.
*/
 
div_t xavg ; // div_t is a structure explained above
div_t yavg ;
div_t zavg ;
 
xavg = div(Xaccumulate, 16);
yavg = div(Yaccumulate, 16);
zavg = div(Zaccumulate, 16);
 
LCD_goto(1,0);
        sprintf(LCDbuffer,"X=%5d",xavg.quot);
        LCD_printR(LCDbuffer);        // use sprintf to format
 
LCD_goto(1,9);
        sprintf(LCDbuffer,"Y=%5d",yavg.quot);
        LCD_printR(LCDbuffer);        // use sprintf to format
 
LCD_goto(2,4);    
sprintf(LCDbuffer,"Z=%5d",zavg.quot);
        LCD_printR(LCDbuffer);        // use sprintf to format
__delay_ms(25);
 
 
 
/*
// This reads byte registers one at a time.
   x=(E_Read(DATAX1)*256) | (E_Read(DATAX0));
   y=(E_Read(DATAY1)*256) | (E_Read(DATAY0));
   z=(E_Read(DATAZ1)*256) | (E_Read(DATAZ0));
 
LCD_goto(1,0);
        sprintf(LCDbuffer,"x=%5d",x);
        LCD_printR(LCDbuffer);        // use sprintf to format
 
LCD_goto(1,12);
        sprintf(LCDbuffer,"y=%5d",y);
        LCD_printR(LCDbuffer);        // use sprintf to format
 
LCD_goto(2,0);    
sprintf(LCDbuffer,"z=%5d",z);
        LCD_printR(LCDbuffer);        // use sprintf to format
*/
 
               }   // while loop
}  // Main
 
 
 
 
 
/*
Function: I2CInit
Return:
Arguments:
Description: Initialize I2C in master mode, Sets the required baudrate
*/
void I2CInit(void)
{
    TRISBbits.TRISB0 = 1; /* SDA and SCL as input pin */
     TRISBbits.TRISB1 = 1; /* these pins can be configured either i/p or o/p */
    SSPSTAT |= 0x80; /* Slew rate disabled */
    SSPCON1 = 0x28;//Enable SDA and SCL, I2C Master mode, clock = FOSC/(4 * (SSPADD + 1))
                /* SSPEN = 1, I2C Master mode, clock = FOSC/(4 * (SSPADD + 1)) */
    SSPCON2 = 0x00;      // Reset MSSP Control Register
    SSPADD = 49;      //20000000 / 4= 5000000, 5000000/ 100000= 50 50-1=49
    PIR1bits.SSPIF=0;    // Clear MSSP Interrupt Flag
    PIR2bits.BCLIF=0;
/* *** For different Frequencies ***
FOSC     FCY  SSPADD Value  FCLOCK
40 MHz 10 MHz     63h         100 kHz
32 MHz     8 MHz    4Fh         100 kHz
20 MHz     5 MHz    31h, 49d     100 kHz
16 MHz     4 MHz     27h         100 kHz
8 MHz     2 MHz     13h, 19d    100 kHz
4 MHz     1 MHz     09h         100 kHz
*/
}
 
 
/*
Function: I2CStart
Return:
Arguments:
Description: Send a start condition on I2C Bus
*/
void I2CStart()
{
    SEN = 1;         /* Start condition enabled */
    while(SEN);      /* automatically cleared by hardware */
                     /* wait for start condition to finish */
}
 
/*
Function: I2CStop
Return:
Arguments:
Description: Send a stop condition on I2C Bus
*/
void I2CStop()
{
    PEN = 1;         /* Stop condition enabled */
    while(PEN);      /* Wait for stop condition to finish */
                     /* PEN automatically cleared by hardware */
}
 
/*
Function: I2CRestart
Return:
Arguments:
Description: Sends a repeated start condition on I2C Bus
*/
void I2CRestart()
{
    RSEN = 1;        /* Repeated start enabled */
    while(RSEN);     /* wait for condition to finish */
}
 
/*
Function: I2CAck
Return:
Arguments:
Description: Generates acknowledge for a transfer
*/
void I2CAck()
{
    ACKDT = 0;       /* Acknowledge data bit, 0 = ACK */
    ACKEN = 1;       /* Ack data enabled */
    while(ACKEN);    /* wait for ack data to send on bus */
}
 
/*
Function: I2CNck
Return:
Arguments:
Description: Generates Not-acknowledge for a transfer
*/
void I2CNak()
{
    ACKDT = 1;       /* Acknowledge data bit, 1 = NAK */
    ACKEN = 1;       /* Ack data enabled */
    while(ACKEN);    /* wait for ack data to send on bus */
}
 
/*
Function: I2CWait
Return:
Arguments:
Description: wait for transfer to finish
*/
void I2CWait()
{
    while ((SSPCON2 & 0x1F ) || ( SSPSTAT & 0x04 ) );
    /* wait for any pending transfer */
}
 
/*
Function: I2CSend
Return:
Arguments: dat - 8-bit data to be sent on bus
           data can be either address/data byte
Description: Send 8-bit data on I2C bus
*/
void I2CSend(unsigned char dat)
{
    SSPBUF = dat;    /* Move data to SSPBUF */
    while(BF);       /* wait till complete data is sent from buffer */
    I2CWait();       /* wait for any pending transfer */
}
 
/*
Function: I2CRead
Return:    8-bit data read from I2C bus
Arguments:
Description: read 8-bit data from I2C bus
*/
unsigned char I2CRead(void)
{
    unsigned char temp;
/* Reception works if transfer is initiated in read mode */
    RCEN = 1;        /* Enable data reception */
    while(!BF);      /* wait for buffer full */
    temp = SSPBUF;   /* Read serial buffer and store in temp register */
    I2CWait();       /* wait to check any pending transfer */
    return temp;     /* Return the read data from bus */
}
 
 
// This is random writing. Write to a specified address
char E_Write(int addr, unsigned char ch)
    {
    /* Send Start condition */
    I2CStart();
    /* Send ADXL1345 slave address with write operation */
    I2CSend(CHIP_Write);
    /* Send subaddress, we are writing to this location */
    I2CSend(addr);
    /* send I2C data one by one */
    I2CSend(ch);
    /* Send a stop condition - as transfer finishes */
    I2CStop();
    return 1;                                        // All went well
    }
 
// The function takes an address and Returns a character
// This is random reading. Read from a specified addess
unsigned char E_Read(int addr)
    {
    unsigned char byte;
    unsigned char ch;
    ErrFlags = 0;                                    // Clear error
    /* Send Start condition */
    I2CStart();
    /* Send ADXL1345 slave address with write operation */
    I2CSend(CHIP_Write);
    /* this address is actually where we are going to read from */
    I2CSend(addr);
    /* Send a repeated start, after a dummy write to start reading */
    I2CRestart();
    /* send slave address with read bit set */
    I2CSend(CHIP_Read);
 
    ch = I2CRead();                                // read character
    I2CNak();
    I2CStop();
    return ch;
    }
 
 
 
 
// This may take calculated delay times. Don't use for LCD
void delayMs(int x)
    {
    while(x--)
        __delay_ms(1);
    }
 
void LCD_printC(const char * str)    // This passes the start a ROM character array
    {                                // by default the pointer points to data section
    while(*str != 0)                // while the character pointed to isn't 0
        LCD_char(*str++);            // print out the character, then increment
    }                                // the pointer down the array
 
void LCD_printR(char * str)             // This passes the start of a RAM character array
    {                                // by default the pointer points to data section
    while(*str != 0)                // while the character pointed to isn't 0
        LCD_char(*str++);            // print out the character, then increment
    }
 
void LCD_init()
    {
    LCD_cmd(0x20);                    // 4 bit
    LCD_cmd(0x28);                    // display shift
    LCD_cmd(0x6);                    // character mode
    LCD_cmd(0xc);                    // display on / off and cursor
    LCD_clr();                        // clear display
    }
 
void LCD_goto(char line, char column)        // combines line and lineW
    {
    unsigned char data = 0x80;                // default to 1
    if(line == 2)data = 0xc0;                // change to 2
    data += column;                            // add in  column
    LCD_cmd(data);
    }
 
void LCD_clr()
    {
    LCD_cmd(1);                                // Clr screen
    }
 
void LCD_cur(char on)
    {
    unsigned char cur = 0xc;                // cursor off
    if(on) cur = 0xd;                        // cursor on
    LCD_cmd(cur);
    }
 
void LCD_cmd(unsigned char ch)
    {
    LCD_PORT = ch >> 4 & 0xf;            // write high nibble
    LCD_RS = 0;
    pulse_E();
    LCD_PORT = ch & 0xf;                // write low nibble
    LCD_RS = 0;
    pulse_E();
    __delay_ms(5);
    }
 
void LCD_charD(unsigned char ch)
    {
    ch+=0x30;
    LCD_char(ch);                        // convert to ascii
    }
 
void LCD_char(unsigned char ch)
    {
    LCD_PORT = ch >> 4 & 0xf;            // High nibble
    LCD_RS = 1;
    pulse_E();
    LCD_PORT = ch & 0xf;                // low nibble
    LCD_RS = 1;
    pulse_E();
    __delay_ms(5);
    }
 
void pulse_E()
    {
    LCD_E = 1;
    __delay_us(1);
    LCD_E = 0;
    }
 

Attachments

Last edited:
Here it is again for the 16F628A

C:
// ADXL345 Accelerometer and 16F628a in Hi-Tech C
// Using Bit Bang I2C on RA6 & RA7 and LCD on port B
// This uses up all but 167 bytes of program memory
// the div_t averaging routine uses 414 bytes
// The wiring for the LCD using Hitachi HD44780 is at
// http://www.winpicprog.co.uk/pic_tutorial_lcd_board.htm
 
 
#include <pic.h>                // pic specific identifiers
#include <stdlib.h>
#include <stdio.h>
#define _XTAL_FREQ  4000000        // Xtal speed
__CONFIG(0x3D38);                // Config bits
 
char  IDDV =0;
#define  BW_RATE            44    //0x2C
#define  POWER_CTL          45    //0x2D
#define  DATA_FORMAT        49    //0x31
#define  DATAX0             50    //0x32
#define  DATAX1             51    //0x33
#define  DATAY0             52    //0x34
#define  DATAY1             53    //0x35
#define  DATAZ0             54    //0x36
#define  DATAZ1             55    //0x37
#define  FIFO_CTL           56    //0x38                        1010011   0x53   Device
#define CHIP_Write    0xA6        // adxl345 address for writing    10100110  0xA6   Write
#define CHIP_Read    0xA7        // and reading                    10100111  0xA7   Read
//#define DEVICE1 (0x53)
 
#define LCD_PORT    PORTB            //
#define LCD_TRIS    TRISB
#define LCD_RS        RB4
#define LCD_RW        RB6
#define LCD_E        RB7
 
#define I2C_PORT    PORTA            // I2C port configuration
#define I2C_TRIS    TRISA
#define SDAI        RA7
#define SCLI        RA6
#define SDA            TRISA7        // in C  we can control the input / output
#define SCL            TRISA6        // by one simple command.
 
 
        // Required prototypes
 
void LCD_init(void), LCD_cmd(unsigned char ch), LCD_busy(void);
void LCD_printC(const char *str), LCD_printR(char *str);
void LCD_goto(char line, char column), LCD_clr(void);
void LCD_cur(unsigned char ch), pulse_E(void), LCD_hex(int value);
void LCD_char(unsigned char ch), LCD_charD(unsigned char ch);
void convert(int numb);
 
unsigned char HEX_Table[] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
                            0x37, 0x38, 0x39, 0x41, 0x42, 0x43,
                            0x44, 0x45, 0x46};
// variables
unsigned char TenK, Thou, Hund, Tens, Ones;
 
 
void I2C_Sendnack(void), I2C_ack(void), I2C_Stop(void), clock(void);
void I2C_Start(void), I2C_Write(unsigned char ch);
char I2C_nack(), E_Write(int addr, unsigned char ch);
unsigned char I2C_Read(void);
unsigned char E_Read(int addr);
 
 
void ini_adxl345()
{
E_Write(FIFO_CTL,0x9f);    
E_Write(DATA_FORMAT,0x09); 
E_Write(BW_RATE,0x0d);     
E_Write(POWER_CTL,0x08);  // activate 
}
 
unsigned char LCDbuffer[17];// a screen buffer big enough for 16 chars + terminator
char ErrFlags;            // Read error. (I don't use it, but you might!)
   
// The SDA and SCL pins are ALWAYS set at 0 we use tristated pins to
// control the control.. while SDA and SCL are inputs the external pullup
// resistors give a high conditon whilst when SDA or SCL are outputs
// the control lines are pulled low.
 
 
void main(void)                            // program entry
    {
    int index = 0;                        // text variable
    OPTION_REG = 0x88;                        // timer pre-scaler
    CMCON = 0x7;                        // Comparitors off
    LCD_TRIS = 0b00000000;                // LCD port as outputs
    I2C_TRIS = 0b11111111;                // I2C port as inputs
    __delay_ms(150);
    RA6 = 0;                // SDC clock
    RA7 = 0;                // SDA Data
    I2C_PORT = 0;
    LCD_init();                            // Initalise screen
    ini_adxl345();                        // Initalise Accelerometer
    __delay_ms(30);                        // Helps Initalise screen
//    LCD_goto(1,0);
//    LCD_printC("Writing..");
/*
    LCD_goto(1,0);
      int id, pow, bw_rate;
      id= E_Read(IDDV);  // should be 229
     __delay_ms(10);
      pow=E_Read(0x2D);  //should be 8 to activate
     __delay_ms(10);
      bw_rate =E_Read(0x2C);  //BW_RATE 0x2C is 13
        sprintf(LCDbuffer,"id=%3d pow=%3d BW_RATE=%3d",id,pow,bw_rate);
        LCD_printR(LCDbuffer);        // use sprintf to format
*/
 
    signed long x,y,z;
    signed long xhi,xlo,yhi,ylo,zhi,zlo;
    signed long Xaccumulate, Yaccumulate, Zaccumulate;
    signed long Xaverage, Yaverage, Zaverage;
    int i;
    while(1)                            // endless Loop
        {
 
    Xaccumulate = Yaccumulate = Zaccumulate = 0;
 
    for (i=0; i<16; i++) {  // Read sequentially 16 times then get an average.
    ErrFlags = 0;                                    // Clear error
    I2C_Start();
    I2C_Write(CHIP_Write);
    if(!I2C_nack()) ErrFlags = 1;                        // Whoops!! problems
 
    I2C_Write((unsigned char) DATAX0 & 0xff);    // DATAX0 is the first of 6 bytes
    if(!I2C_nack()) ErrFlags = 1;                // to read sequentially
    I2C_Start();
    I2C_Write(CHIP_Read);                            //
    if(!I2C_nack()) ErrFlags = 1;
 
    xlo = I2C_Read();                                // read character
    I2C_ack();
    xhi = I2C_Read();                                // read character
    I2C_ack();
    ylo = I2C_Read();                                // read character
    I2C_ack();
    yhi = I2C_Read();                                // read character
    I2C_ack();
    zlo = I2C_Read();                                // read character
    I2C_ack();
    zhi = I2C_Read();                                // read character
    I2C_Sendnack();
    I2C_Stop();
 
    Xaccumulate += ((xhi<<8) | xlo); //Xaccumulate = Xaccumulate + (xhi*256 + xlo)
    Yaccumulate += ((yhi<<8) | ylo);
    Zaccumulate += ((zhi<<8) | zlo);
 
  }  // for loop
 
//    x= (xhi<<8) | xlo;
//    y= (yhi<<8) | ylo;
//    z= (zhi<<8) | zlo;
 
// Calculate average accelerometer readings over last 16 samples
 
/* *** Other methods of dividing gave me results in the +/- thousands ***
DIV   From Hi-Tech C manual
Synopsis
#include <stdlib.h>
div_t div (int numer, int demon)
Description
The div() function computes the quotient and remainder of the numerator divided by the denominator.
Example
#include <stdlib.h>
#include <stdio.h>
void
main (void)
{
div_t x;
x = div(12345, 66);
printf("quotient = %d, remainder = %d\n", x.quot, x.rem);
}
See Also
udiv(), ldiv(), uldiv()
Return Value
Returns the quotient and remainder into the div_t structure.
*/
 
div_t xavg ; // div_t is a structure explained above
div_t yavg ;
div_t zavg ;
 
xavg = div(Xaccumulate, 16);
yavg = div(Yaccumulate, 16);
zavg = div(Zaccumulate, 16);
 
LCD_goto(1,0);
        sprintf(LCDbuffer,"X=%5d",xavg.quot);
        LCD_printR(LCDbuffer);        // use sprintf to format
 
LCD_goto(1,9);
        sprintf(LCDbuffer,"Y=%5d",yavg.quot);
        LCD_printR(LCDbuffer);        // use sprintf to format
 
LCD_goto(2,4);   
sprintf(LCDbuffer,"Z=%5d",zavg.quot);
        LCD_printR(LCDbuffer);        // use sprintf to format
//__delay_ms(25);
__delay_ms(250);  // Just so the numbers don't change too fast.
 
 
/*
// This reads byte registers one at a time.
   x=(E_Read(DATAX1)*256) | (E_Read(DATAX0));
   y=(E_Read(DATAY1)*256) | (E_Read(DATAY0));
   z=(E_Read(DATAZ1)*256) | (E_Read(DATAZ0));
 
LCD_goto(1,0);
        sprintf(LCDbuffer,"x=%5d",x);
        LCD_printR(LCDbuffer);        // use sprintf to format
 
LCD_goto(1,12);
        sprintf(LCDbuffer,"y=%5d",y);
        LCD_printR(LCDbuffer);        // use sprintf to format
 
LCD_goto(2,0);   
sprintf(LCDbuffer,"z=%5d",z);
        LCD_printR(LCDbuffer);        // use sprintf to format
*/
 
 
        } //while
    } //main(void)
 
// Write to eeprom this returns a 0 if it fails or a 1 if all gooes well
// For byte eeproms and RTC devices.. comment out the Hi address byte
// and the I2C_nack() that follows it in both these functions.
 
// This is random writing. Write to a specified address
 
char E_Write(int addr, unsigned char ch)
    {
    I2C_Start();                                    // Send a start condition
    I2C_Write(CHIP_Write);                            // chip write address
    if(!I2C_nack()) return 0;                        // wait for ack
//    I2C_Write((unsigned char) (addr >> 8 & 0xff));    // Comment out if single byte addess
//    if(!I2C_nack()) return 0;                        // wait for ack
    I2C_Write((unsigned char) addr & 0xff);            // low address
    if(!I2C_nack()) return 0;                        // wait for ack
    I2C_Write(ch);                                    // Write values to Eeprom
    if(!I2C_nack()) return 0;
    I2C_Stop();                                        // Send a stop.
    return 1;                                        // All went well
    }
 
 
// The function takes an address and Returns a character
 
// This is random reading. Read from a specified addess
unsigned char E_Read(int addr)
    {
    unsigned char byte;
    unsigned char ch;
    ErrFlags = 0;                                    // Clear error
    I2C_Start();
    I2C_Write(CHIP_Write);
    if(!I2C_nack()) return  1;                        // Whoops!! problems
//    I2C_Write((unsigned char)( addr >> 8 & 0xff));    // Comment out if single byte addess
//    if(!I2C_nack()) return  1;
    I2C_Write((unsigned char) addr & 0xff);            //
    if(!I2C_nack()) return 1;
    I2C_Start();
    I2C_Write(CHIP_Read);                            //
    if(!I2C_nack()) return  1;
    ch = I2C_Read();                                // read character
    I2C_Sendnack();
    I2C_Stop();
    return ch;
    }
 
void I2C_Start()        //  start combo
    {
    SDA = 1;
    SCL = 1;
    SDA = 0;            // bring SDA low while SCL is high
    SCL = 0;
    }
 
void I2C_Stop()            // stop combo
    {
    SCL = 0;
    SDA = 0;
    SCL = 1;
    SDA = 1;            // bring SDA high while SCL is high
    }
 
unsigned char I2C_Read()
    {
    char index;
    unsigned char byte = 0;                        // initialize in byte
    for(index = 0x80; index > 0 ;index>>=1)        // using index as a mask
        {                                        // cycles through bit 7 to bit 0
        if(SDAI) byte += index;                    // read in the SDA line
        clock();
        }
    return byte;                                // 8 bits in...
    }
 
void I2C_Write(unsigned char ch)
    {
    char index;
 
    for(index = 0x80; index > 0 ;index>>=1)        // using index as mask
        {
        if(ch & index)                             // bit high or low
            SDA = 1;
        else
            SDA = 0;
        clock();
        }
    }
 
void I2C_ack()                            // generate an ack
    {
    SDA = 0;
    clock();
    SDA = 1;
    }
 
void I2C_Sendnack()                        // generate a not ack
    {
    SDA = 1;
    clock();
    }
 
char I2C_nack()                            // recive a not ack
    {
    unsigned char timeout = 255;
    SDA = 1;
    SCL = 1;
    while(SDAI)                            // wait till SDA goes low
        {
        if(timeout-- == 0) return 0;    // whoops!! no ack recieved
        }
    SCL = 0;
    return 1;
    }
 
void clock()                            // Might work without the nop
    {
    SCL=1;
    asm("nop");
    SCL=0;
    }
 
void convert(int numb)                // Takes a interger number
    {                                // and converts to single
    TenK = numb / 10000;            // decimal numbers.
    Thou = (numb % 10000)/ 1000;    //
    Hund = (numb % 1000) / 100;
    Tens = (numb % 100) / 10;
    Ones = numb % 10;
    }
 
// In C we can use Pointers, Pointers are advanced programming
// and can tie you in knots. The simplest pointer to use is the
// array pointer using "rom char" allows the pointer to
// point to constant character in code section.
 
void LCD_printC(const char * str)    // This passes the start a ROM character array
    {                                // by default the pointer points to data section
    while(*str != 0)                // while the character pointed to isn't 0
        LCD_char(*str++);            // print out the character, then increment
    }                                // the pointer down the array
 
void LCD_printR(char * str)             // This passes the start of a RAM character array
    {                                // by default the pointer points to data section
    while(*str != 0)                // while the character pointed to isn't 0
        LCD_char(*str++);            // print out the character, then increment
    }                                // the pointer down the array
 
 
void LCD_init()
    {
    LCD_cmd(0x20);                    // 4 bit
    LCD_cmd(0x28);                    // display shift
    LCD_cmd(0x6);                    // character mode
    LCD_cmd(0xc);                    // display on / off and cursor
    LCD_clr();                        // clear display
    }
 
void LCD_hex(int value)
    {
    char data;
    data = value >> 4 & 0xf;
    data = HEX_Table[data];                 // send upper nibble
    LCD_char(data);
    data = value & 0xf;                        // send lower nibble
    data = HEX_Table[data];
    LCD_char(data);
    }
 
void LCD_goto(char line, char column)        // combines line and lineW
    {
    unsigned char data = 0x80;                // default to 1
    if(line == 2)data = 0xc0;                // change to 2
    data += column;                            // add in  column
    LCD_cmd(data);
    }
 
void LCD_clr()
    {
    LCD_cmd(1);                                // Clr screen
    }
 
void LCD_cur(char on)
    {
    unsigned char cur = 0xc;                // cursor off
    if(on) cur = 0xd;                        // cursor on
    LCD_cmd(cur);
    }
 
void LCD_busy()
    {
    unsigned char BUSY = 0;
    while(1)
        {
        LCD_TRIS = 0x0f;                    // port to read mode
        LCD_RS = 0x0;
        LCD_RW = 0x1;                        // set to read
        LCD_E = 0x1;
        BUSY = LCD_PORT & 0xf;                // high byte comes first
        __delay_us(5);                        // so busy flag is on bit 3
        LCD_E = 0x0;
        LCD_E = 0x1;
        __delay_us(5);                        // dummy read
        LCD_E = 0x0;
        LCD_RW = 0x0;                        // set to write
        LCD_TRIS = 0x00;                    // port to write mode
        if(!(BUSY & 0x8 )) return;            // AND with bit 3
        }
    }
 
void LCD_cmd(unsigned char ch)
    {
    LCD_PORT = ch >> 4 & 0xf;
    LCD_RS = 0;
    pulse_E();
    LCD_PORT = ch & 0xf;
    LCD_RS = 0;
    pulse_E();
    __delay_ms(5);
    }
 
void LCD_charD(unsigned char ch)
    {
    ch+=0x30;
    LCD_char(ch);
    }
 
void LCD_char(unsigned char ch)
    {
    LCD_PORT = ch >> 4 & 0xf;
    LCD_RS = 1;
    pulse_E();
    LCD_PORT = ch & 0xf;
    LCD_RS = 1;
    pulse_E();
    __delay_ms(5);;
    }
 
void pulse_E()
    {
    LCD_E = 1;
    __delay_us(1);
    LCD_E = 0;
    }
 

Attachments

Last edited:
I just discovered something while setting up another computer for programming PICs.
HI-TECH C version 9.83 uses OPTION_REG and compacts programs better.
HI-TECH C version 9.65 uses OPTION and at least on this program uses 110 bytes more memory than the 16F628a has.
That explains why I have always had to change OPTION to OPTION_REG in Ian's programs.
Use HI-TECH C version 9.83 or better for this program.
 
Hi, thx for the information..
I have 2 questions
1.why u use portb for the i2c, isn't is supposed to be portc? As it written in the data sheet
2. Did u grounded sd0 pin in the adxl345?
 
Last edited:
In the program:
ADXL345 0x53 is the alternate Device address
#define CHIP_Write 0xA6
#define CHIP_Read 0xA7
Yes SD0 is grounded with a 4.7 K ohm resistor on this board. 3 Axis Accelerometer, Raspberry Pi, Arduino Compatible Sensor https://www.mpja.com/3-Axis-Acceler...rduino-Compatible-Sensor/productinfo/31583+MP

This pinout shows the I2C SCL & SDA on port B
 
Hi,
When I try to initiate adxl345
The sspbuff loaded with 0xA6
And the it stuck in endless loop at
While(BF)
In my pic 18f452 it's written while(SSPBUF)

Any idea why?
 
I haven’t used an 18F452. I see that the pinout is different and you are right that it uses port C for I2C. Use RC3 on pin 18 for SCL & RC4 on pin 23 for SDA and change them in the program. The configuration is probably different & you will probably have to set up port C instead or port B for I2C.

When first getting it to work, uncomment this section. id should be 53 Hex or 83 Decimal. If it is, you know that you are communicating.

/* LCD_goto(1,0);
int id, pow, bw_rate;
id= E_Read(IDDV); // should be 53 Hex or 83 Decimal for ADXL345
__delay_ms(10);
pow=E_Read(0x2D); //should be 8 to activate
__delay_ms(10);
bw_rate =E_Read(0x2C); //BW_RATE 0x2C is 13
sprintf(LCDbuffer,"id=%3d pow=%3d BW_RATE=%3d",id,pow,bw_rate);
LCD_printR(LCDbuffer); // use sprintf to format
*/
 
Last edited:
now I run ur comment , id,pow,bwrate=FF
any idea?

changed something
now its ALL 0xE5
 
Last edited:
I haven’t used an 18F452.
The pinout is in the Datasheet, along with info on using I2C on that chip.
PIC18FXX2 Data Sheet - Microchip
https://ww1.microchip.com/downloads/en/DeviceDoc/39564c.pdf

It may not be easy to migrate a program for an 18F4550 to an 18F452. I had to do it entirely different for a 16F628A. (Bitbang) If you can't find the answer in the datasheet, you should start a new thread in the Microcontrollers section where everyone will see it.
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…