• AVR Freaks

Hot!I2C Interfacing XC8 PIC16F877A

Page: 123 > Showing page 1 of 3
Author
delfindelfin
Super Member
  • Total Posts : 296
  • Reward points : 0
  • Joined: 2017/01/19 12:32:58
  • Location: Mexico
  • Status: offline
2019/05/03 18:20:59 (permalink)
0

I2C Interfacing XC8 PIC16F877A

Hello, this is the first time I use I2C. I found this code on internet and I am trying to adapt it and understand it. 
 
I2C Master:
 

 
 
 
// Including C Standard Libraries
#include <stdint.h>
// Including XC8 Compiler Library
#include <xc.h>
// Including User's Libraties
#include "i2c.h"
 
// Defining Oscillator Frequency
#define _XTAL_FREQ 8000000
 
// Setting Configuration Bits
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT enabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
 
void main()
{

// Setting Direction Registers /////////////////////////////////////////////////////

nRBPU = 0; // Enable PORTB internal pull up resistor
TRISB = 0xFF; // PORTB as input
TRISD = 0x00; // PORTD as output
PORTD = 0x00; // All LEDs OFF

// I2C Initiation //////////////////////////////////////////////////////////////////

I2C_Master_Init(100000); // I2C Master with clock in Standard Mode (100 kbps)

// Main Function ///////////////////////////////////////////////////////////////////

while(1)
{

//// I2C Writing ///////////////////////////////////////////////////////////////

I2C_Master_Start(); // Start condition
I2C_Master_Write(0x30); // 7 bit address + Write
I2C_Master_Write(PORTB); // Write data
I2C_Master_Stop(); // Stop condition
__delay_ms(200);

//// I2C Reading ///////////////////////////////////////////////////////////////

I2C_Master_Start(); // Start condition
I2C_Master_Write(0x31); // 7 bit address + Read
PORTD = I2C_Master_Read(0); // Read + Acknowledge
I2C_Master_Stop(); // Stop condition
__delay_ms(200);
}
}
 
 
 

 
Header:

 
 
 
#ifndef I2C_H
#define I2C_H
 
//// Master Configurations ///////////////////////////////////////////////////////
 
void I2C_Master_Init(const unsigned long c);
void I2C_Master_Wait();
void I2C_Master_Start();
void I2C_Master_RepeatedStart();
void I2C_Master_Stop();
void I2C_Master_Write(unsigned d);
 
//// Slave Configurations ////////////////////////////////////////////////////////
 
unsigned short I2C_Master_Read(unsigned short a);
//void interrupt I2C_Slave_Read();
void I2C_Slave_Init(short address);
 
#endif
 
 
 

 
Library

 
 
 
// Including XC8 Compiler Library
#include <xc.h>
// Including User's Libraties
#include "i2c.h"
 
// Defining Oscillator Frequency
#define _XTAL_FREQ 8000000
 
//// Master Configurations ///////////////////////////////////////////////////////
 
void I2C_Master_Init(const unsigned long c)
{
SSPCON = 0b00101000; // 00101000 (Enabling Serial Port, Master Mode)
SSPCON2 = 0; // 00000000 ()
SSPADD = (_XTAL_FREQ/(4*c))-1; // I2C Bits per Second
SSPSTAT = 0; // 0000 0000 (High Speed Mode, Disable SMBus)

TRISC3 = 1; // Setting Serial Clock (SCL) as input
TRISC4 = 1; // Setting Serial Data (SDA) as input
}
 
void I2C_Master_Wait()
{
while ((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));
}
 
void I2C_Master_Start()
{
I2C_Master_Wait();
SEN = 1;
}
 
void I2C_Master_RepeatedStart()
{
I2C_Master_Wait();
RSEN = 1;
}
 
void I2C_Master_Stop()
{
I2C_Master_Wait();
PEN = 1;
}
 
void I2C_Master_Write(unsigned d)
{
I2C_Master_Wait();
SSPBUF = d;
}
 
unsigned short I2C_Master_Read(unsigned short a)
{
unsigned short temp;
I2C_Master_Wait();
RCEN = 1;
I2C_Master_Wait();
temp = SSPBUF;
I2C_Master_Wait();
ACKDT = (a)?0:1;
ACKEN = 1;
return temp;
}
 
//// Slave Configurations ////////////////////////////////////////////////////////
 
/*
short z;
 
void interrupt I2C_Slave_Read()
{
if(SSPIF == 1)
{
SSPCONbits.CKP = 0;
 
if ((SSPCONbits.SSPOV) || (SSPCONbits.WCOL))
{
z = SSPBUF; // Read the previous value to clear the buffer
SSPCONbits.SSPOV = 0; // Clear the overflow flag
SSPCONbits.WCOL = 0; // Clear the collision bit
SSPCONbits.CKP = 1;
}
 
if(!SSPSTATbits.D_nA && !SSPSTATbits.R_nW)
{
z = SSPBUF;
while(!BF);
PORTD = SSPBUF;
SSPCONbits.CKP = 1;
}
else if(!SSPSTATbits.D_nA && SSPSTATbits.R_nW)
{
z = SSPBUF;
BF = 0;
SSPBUF = PORTB ;
SSPCONbits.CKP = 1;
while(SSPSTATbits.BF);
}
 
SSPIF = 0;
}
}
 
void I2C_Slave_Init(short address)
{
SSPSTAT = 0x80; //
SSPADD = address; //
SSPCON = 0x36; //
SSPCON2 = 0x01; //
TRISC3 = 1; // Setting Serial Clock (SCL) as input
TRISC4 = 1; // Setting Serial Data (SDA) as input
GIE = 1;
PEIE = 1;
SSPIF = 0;
SSPIE = 1;
}

*/
 
 
 

 
I am still studying it, I commented some lines since it was not compiling, but I would appreciate suggestions about i2c and what approach should I follow. Thanks
 
 
post edited by delfindelfin - 2019/05/03 18:22:15

Attached Image(s)


MPLAB X IDE v5.05
XC8 2.00
#1

54 Replies Related Threads

    qhb
    Superb Member
    • Total Posts : 9998
    • Reward points : 0
    • Joined: 2016/06/05 14:55:32
    • Location: One step ahead...
    • Status: offline
    Re: I2C Interfacing XC8 PIC16F877A 2019/05/03 18:40:17 (permalink)
    +1 (1)
    Why do you keep doing
    void main()
    instead of
    void main(void)
    as the XC8 manual tells you? I've personally told you at least twice previously.


     
    You need pullup resistors on SDA and SCL. Try 4.7k
     
    Your read code is bad. You should send a NAK with the last byte you read, not an ACK.
    You really need to understand the I2C protocol to use it. Start at https://en.wikipedia.org/wiki/I%C2%B2C
     

    Nearly there...
    #2
    katela
    Super Member
    • Total Posts : 1279
    • Reward points : 0
    • Joined: 2013/06/11 05:25:18
    • Location: South Africa
    • Status: offline
    Re: I2C Interfacing XC8 PIC16F877A 2019/05/03 18:41:22 (permalink)

    Free online Microcontroller Tutorials and Projects for Hobbyists and students. From beginners to advanced. Website: www.studentcompanion.co.za
    YouTube Tutorials: https://www.youtube.com/StudentCompanionSA
    #3
    PStechPaul
    Super Member
    • Total Posts : 2290
    • Reward points : 0
    • Joined: 2006/06/27 16:11:32
    • Location: Cockeysville, MD, USA
    • Status: offline
    Re: I2C Interfacing XC8 PIC16F877A 2019/05/03 22:17:03 (permalink)
    +1 (1)
    I was struggling with I2C code for driving an LCD display a little over a year ago. Some of that discussion might help:
    https://www.microchip.com/forums/m1044807.aspx

     
    #4
    delfindelfin
    Super Member
    • Total Posts : 296
    • Reward points : 0
    • Joined: 2017/01/19 12:32:58
    • Location: Mexico
    • Status: offline
    Re: I2C Interfacing XC8 PIC16F877A 2019/06/23 16:26:38 (permalink)
    0
    How do you set the slave address?

    I2C_Master_Write(0x30);

     I have the address 0x30 .. But I don't understand how it was selected
     
    Edit: I think it is in SSPADD of the Slave Device.. Does all the devices that support this Protocol have an SSPADD register?
    post edited by delfindelfin - 2019/06/23 16:48:38

    MPLAB X IDE v5.05
    XC8 2.00
    #5
    ric
    Super Member
    • Total Posts : 22654
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: offline
    Re: I2C Interfacing XC8 PIC16F877A 2019/06/23 16:42:07 (permalink)
    0
    The "slave address" is determined by the slave.
    If you're trying to interface to an I2C device, you read the documentation that came with the device.
    You just have to determine if they are telling you a full 8 bit address (which 0x30 must be), or just the 7 bit address (before left shifting and combining with the R/W bit), which in this case would have been 0x18.
     
     

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #6
    delfindelfin
    Super Member
    • Total Posts : 296
    • Reward points : 0
    • Joined: 2017/01/19 12:32:58
    • Location: Mexico
    • Status: offline
    Re: I2C Interfacing XC8 PIC16F877A 2019/06/23 19:03:08 (permalink)
    +1 (1)
    I am trying to interface a BMP180 Pressure Sensor ... So, in this case it would be 0xEF (read) and 0xEE (write) as an 8 bit address
     
     

    Attached Image(s)


    MPLAB X IDE v5.05
    XC8 2.00
    #7
    ric
    Super Member
    • Total Posts : 22654
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: offline
    Re: I2C Interfacing XC8 PIC16F877A 2019/06/23 19:06:46 (permalink)
    0
    Yes

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #8
    delfindelfin
    Super Member
    • Total Posts : 296
    • Reward points : 0
    • Joined: 2017/01/19 12:32:58
    • Location: Mexico
    • Status: offline
    Re: I2C Interfacing XC8 PIC16F877A 2019/07/01 12:22:54 (permalink)
    0
    In this function:

    uint8_t I2C_Master_Read(uint8_t ack)
    {
    unsigned short incoming;
    I2C_Master_Hold(); // Hold the program if I2C is busy
    RCEN = 1; // Enabling Receiving mode for I2C
     
    I2C_Master_Hold(); // Hold the program if I2C is busy
    incoming = SSPBUF; // Getting the data saved in SSPBUF
     
    I2C_Master_Hold(); // Hold the program if I2C is busy
    ACKDT = (ack)?0:1; // Check if ack bit received
    ACKEN = 0; // Initiate Acknowledge sequence on SDA and SCL pins and transmit ACKDT data bit
     
    return incoming; // Returning Data Read
    }

    How is it called this line?:

    ACKDT = (ack)?0:1; // Check if ack bit received 

    This is the first time I see this expressión: "(ack)?0:1"

    MPLAB X IDE v5.05
    XC8 2.00
    #9
    pcbbc
    Super Member
    • Total Posts : 1090
    • Reward points : 0
    • Joined: 2014/03/27 07:04:41
    • Location: 0
    • Status: offline
    Re: I2C Interfacing XC8 PIC16F877A 2019/07/01 13:19:45 (permalink)
    0
    It’s the ternary conditional operator.

    It’s the same as...
    if (ack) {
    ACKDT = 0;
    } else {
    ACKDT = 1;
    }

    ...except that it is an in-line expression version.

    Basically thing to the left of the ? operator is evaluated and tested. If it is non-zero (true) the expression to the left of the : is evaluated and returned, otherwise if zero (false) the expression to the right of the : is used.
    post edited by pcbbc - 2019/07/01 13:22:48
    #10
    ric
    Super Member
    • Total Posts : 22654
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: offline
    Re: I2C Interfacing XC8 PIC16F877A 2019/07/01 13:20:53 (permalink)
    0
    delfindelfin
    This is the first time I see this expressión: "(ack)?0:1"

    Have you ever read a C textbook?
    "?" is the "ternary" operator.
    https://en.wikipedia.org/wiki/%3F:#C
     

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #11
    PStechPaul
    Super Member
    • Total Posts : 2290
    • Reward points : 0
    • Joined: 2006/06/27 16:11:32
    • Location: Cockeysville, MD, USA
    • Status: offline
    Re: I2C Interfacing XC8 PIC16F877A 2019/07/01 14:45:49 (permalink)
    0
    I was unfamiliar with the ternary operator for C until fairly recently, and I don't think I've used it in any of my code. There has been some discussion about the efficiency of its compiled code, as well as readability and ease of maintenance:
     
    https://embeddedgurus.com...-the-ternary-operator/

     
    #12
    jtemples
    عُضْوٌ جَدِيد
    • Total Posts : 11208
    • Reward points : 0
    • Joined: 2004/02/13 12:31:19
    • Location: Southern California
    • Status: offline
    Re: I2C Interfacing XC8 PIC16F877A 2019/07/01 15:52:29 (permalink)
    +2 (2)
    While it is "a" ternary operator, it is actually "the" conditional operator.  The C standard does not refer to it as a ternary operator.
    #13
    ric
    Super Member
    • Total Posts : 22654
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: offline
    Re: I2C Interfacing XC8 PIC16F877A 2019/07/01 16:02:37 (permalink)
    +1 (1)
    Thanks for the correction John. I suspected my terminology wasn't strictly correct. :)

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #14
    delfindelfin
    Super Member
    • Total Posts : 296
    • Reward points : 0
    • Joined: 2017/01/19 12:32:58
    • Location: Mexico
    • Status: offline
    Re: I2C Interfacing XC8 PIC16F877A 2019/07/03 10:24:16 (permalink)
    0
    In the algorithm to compute the temperature. What does it mean to multiply by a long? ... If I am correct. according to the XC8 User's Guide, a signed long has a size of 32 bits ..
    https://i.imgur.com/g7ZMtWE.png
    So, the values to compute B3 are: AC1=408, oss=0, X3=57 .. The result without considering the long aspect multiplication is 422.75 ... Altough according to the image, the result has to be 422.. What does it mean that operation: (long)AC1
     
    Edit: Altough .. I think it is just a convertion to a long type ... But I am still not sure 

    post edited by delfindelfin - 2019/07/03 12:27:24

    MPLAB X IDE v5.05
    XC8 2.00
    #15
    ric
    Super Member
    • Total Posts : 22654
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: offline
    Re: I2C Interfacing XC8 PIC16F877A 2019/07/03 13:14:44 (permalink)
    0
    That is "casting" a value to 32 bits, so the multiplication will be done using 32 bit arithmetic.

    The result without considering the long aspect multiplication is 422.75 ... Altough according to the image, the result has to be 422..

    This is integer arithmetic, you cannot get fractions.

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #16
    delfindelfin
    Super Member
    • Total Posts : 296
    • Reward points : 0
    • Joined: 2017/01/19 12:32:58
    • Location: Mexico
    • Status: offline
    Re: I2C Interfacing XC8 PIC16F877A 2019/07/03 15:13:16 (permalink)
    0
    But .. Temperature data word UT  is supposed to be 16 bit .. So, why do I have to use a long data type (32 bit)

    MPLAB X IDE v5.05
    XC8 2.00
    #17
    ric
    Super Member
    • Total Posts : 22654
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: offline
    Re: I2C Interfacing XC8 PIC16F877A 2019/07/03 15:17:59 (permalink)
    +1 (1)
    Because you are about to multiply it by a value that will give a result bigger than 16 bits.
    The multiply would overflow if you didn't force it to use 32 bit arithmetic. Casting one of the arguments to 32 bits makes that happen. It does not change the actual value.
     
     
    Just to be very clear, if the penny has not dropped yet. When you do a mathematical operation on two arguments in C, it is done using the size of the larger of the two variables. So, if one is 16 bit and one is 32 bit, it will be done using 32 bit arithmetic.
    If you use two 16 bit variables, then it's done using 16 bit arithmetic, and if the result is too big for a 16 bit variable, it will overflow. This is a fundamental feature of arithmetic in C, so you need to get your head around it.
    post edited by ric - 2019/07/03 15:33:08

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #18
    cobusve
    Super Member
    • Total Posts : 492
    • Reward points : 0
    • Joined: 2012/04/02 16:15:40
    • Location: Chandler
    • Status: offline
    Re: I2C Interfacing XC8 PIC16F877A 2019/07/04 12:26:55 (permalink)
    +1 (1)
    And just to be 100% clear on that, you have to think not only of the final answer but all the intermediary values as well. If you are going to do x *100 /99 then you have to be able to store x*100 so that you can divide it down by 99 in the last step, so even if your answer will be small the intermediary value will be large.
     
    In your example (AC1*4 + X3 << oss) can be larger than 16 bits, so you need a larger container to store the value for the calculation.
     
    Not being aware of data type sizes and when they will overflow or what the rules are the compiler will use to do the math is a very common source of errors in C code. These errors can be extremely tricky as the math could work out fine for some values you test with and not for other values that come up during later use.

    Also take a look at https://www.microforum.cc/ - a great resource for information on PIC and AVR microcontrollers and embedded programming in general. You can also post questions to the experts there.
    #19
    delfindelfin
    Super Member
    • Total Posts : 296
    • Reward points : 0
    • Joined: 2017/01/19 12:32:58
    • Location: Mexico
    • Status: offline
    Re: I2C Interfacing XC8 PIC16F877A 2019/07/04 14:09:30 (permalink)
    0
    There are also negative numbers in the Calibration Constants .. I am unable to find that information in the datasheet .. But, do I have to assume that negative numbers are in Signed Magnitude, One's Complement or Two's Complement Represantation?  I think that is important since I don't understand what is it the real difference between int8_t and uint8_t when it comes to save bits on a register  
     
    Datasheet:
    https://cdn-shop.adafruit...ST-BMP180-DS000-09.pdf
     
    The datasheet doesn't say neither the range of the temperature .. unless is the range of the 16 bit value ..
    post edited by delfindelfin - 2019/07/04 15:15:00

    MPLAB X IDE v5.05
    XC8 2.00
    #20
    Page: 123 > Showing page 1 of 3
    Jump to:
    © 2019 APG vNext Commercial Version 4.5