New ICD2 (In-Circuit Debugger 2) to program and debug pics! Testing PIC 16F690 PWM 4 multiplexed channels
2008 01 Feb

I have now completed my I2C Master/Slave communication test. Quite happy with the results! Before getting started I needed to refresh my memory on I2C protocol, how Master and Slave devices would communicate, how data flow between devices. Found this nice tutorial on the web:

As I previously referred on other posts, the PIC 16F690 will now support I2C protocol by hardware for the slave device, meaning that Interrupt Service Routine will be available, serving I2C Master whenever necessary without the necessity to pool the I2C bus. This also will permit Slave PIC to run other tasks like acquiring data from Analog-to-Digital inputs, control outputs, read inputs, etc, and still server PIC Slave without causing any delay on I2C bus. Unfortunately I2C Master is not supported by hardware for this PIC (I2C Master mode is also supported, please check datasheet: page 197 -> 13.13 Master Mode). Not a problem, Master PIC will receive commands from PC (Via RS232 interface - serial communication) that will be stored on buffer to be processed whenever possible!

For the test I’ve used 2 PICs 16F690 @ 4Mhz and 1 RS232 interface for debug. Master PIC will connect to Lab PC by RS232 (COM1) for debugging purpose and to Slave PIC by I2C bus.

PIC I2C Master/Slave communication

Just picked some examples for I2C communication and found the most common example ‘how to communicate with IC2 eeprom’ and decided to simulate this with my PICs. For my test the Master PIC will send 16 bytes of data to Slave PIC that will store in memory for later request. Before sending data Master PIC need to ‘address’ the bus with the Slave ID and after this will send the 2 bytes. The 1st byte will be interpreted by Slave PIC has ‘internal memory address’ and the 2nd byte has generic data. This process will be repeated 16 times with different ‘internal memory address’ and data. The next step Master PIC will request 1 byte to Slave PIC of a specific ‘internal memory address’. Please check code to see how easy it is!

Note: Master Pic will use I2C master mode emulated by software, using CCSInfo internal routines and so it should be expected that pins from Master and Slave device to be different! The main objective (robot infrastructure) was only to get the PIC 16F690 I2C Slave mode working with the hardware, I2C Master mode would then be implemented by a bigger PIC such as 16F877. During the tests decided to use the same pic to make it a bit simpler and focus the work on the Slave device!

Master PIC:

  1. #include <16F690.h>
  2. #use delay(clock=4000000)
  4. //————————————————————————————————————————————————————————————
  5. #use i2c(Master, sda=PIN_C2, scl=PIN_C3) // I2C by software
  6. //————————————————————————————————————————————————————————————
  7. #use rs232(baud=9600, parity=N, xmit=PIN_B7, rcv=PIN_B5, bits=8, errors)
  8. //————————————————————————————————————————————————————————————
  9. // PORTC.2 [RC2 pin14]  -> I2C SDA (I2C Serial Data)
  10. // PORTC.3 [RC3 pin7]   -> I2C SCL (I2C Serial Clock)
  11. //————————————————————————————————————————————————————————————
  12. // PORTB.5 [RB5 pin12]  -> PicRX (RS232 input)
  13. // PORTB.7 [RB7 pin10]  -> PicTX (RS232 output)
  14. //————————————————————————————————————————————————————————————
  15. int x;
  17. BYTE result;void main()
  18. {
  19.   delay_ms(200); // power up delay
  20.   setup_adc_ports(NO_ANALOGS | VSS_VDD);
  21.   setup_comparator(NC_NC_NC_NC);
  22.   setup_oscillator(OSC_4MHZ);
  23.   set_tris_a(0b11111111);
  24.   set_tris_b(0b01111111 ); // Port B 00110000 ( Bit5/7 - RS232- Rx/tx)
  25.   set_tris_c(0b10110011);
  27.   while(1)
  28.   {
  29.     printf("\r\nI2C Master - Started!\r\n"); // debug to PC serial port - RS232
  30.     output_low(PIN_C6); // Led for visual debug
  31.     delay_ms(500);
  32.     delay_ms(500);
  33.     delay_ms(500);
  34.     delay_ms(500);
  35.     delay_ms(500);
  36.     output_high(PIN_C6);
  37.     delay_ms(500);
  38.     delay_ms(500);
  39.     delay_ms(500);
  40.     delay_ms(500);
  41.     delay_ms(500);
  42.     output_low(PIN_C6);
  44.     for(x=0;x<=15;x++)
  45.     {
  46.       i2c_start ();        // init I2C protocol
  47.       i2c_write (0xA0); // slave device address
  48.       i2c_write (x);      // slave ‘internal memory address’ [0;15]
  49.       i2c_write(15-x);  // data
  50.       i2c_stop();         // stop communication with slave
  51.       delay_ms(50);
  52.       i2c_start ();       // init I2C protocol
  53.       i2c_write (0xA1); // slave device address
  54.       result = i2c_read(0); // read slave last received data
  55.       i2c_stop ();        // stop communication with slave
  56.       printf("Result[%d]=%d\r\n",x,result); // debug data
  57.       delay_ms(50);
  58.     }
  60. // test
  61.       i2c_start ();
  62.       i2c_write (0xA0);
  63.       i2c_write (5); // request slave ‘internal memory address’ 0×05
  64.       i2c_stop();
  65.       delay_ms(50);
  66.       i2c_start ();
  67.       i2c_write (0xA1);
  68.       result = i2c_read(0); // read slave data
  69.       i2c_stop ();
  70.       printf("ReadAddress(5)=%d\r\n",result);
  71.       delay_ms(50);
  72.    }
  73. }
  74. //————————————————————————————————————————————————————————————

Slave PIC:

  1. #include <16F690.h>
  2. #use delay(clock=4000000)
  4. //————————————————————————————————————————————————————————————
  5. #use i2c(SLAVE, SDA=PIN_B4, SCL=PIN_B6, address=0xA0, FORCE_HW) // I2C by Hardware
  6. //————————————————————————————————————————————————————————————
  7. // PORTC.2 [RC2 pin14]  -> I2C SDA (I2C Serial Data)
  8. // PORTC.3 [RC3 pin7]   -> I2C SCL (I2C Serial Clock)
  9. //————————————————————————————————————————————————————————————
  10. BYTE incoming, state; // I2C vars
  11. BYTE address, buffer[0×10]; // Address and Array of Bytes
  13. #INT_SSP
  14. void ssp_interupt ()
  15. {
  16.   state = i2c_isr_state();
  18.   if(state < 0×80) //Master is sending data
  19.   {
  20.     if(state == 0)
  21.     {
  22.     }
  23.     if(state == 1)  //First received byte is address
  24.     {
  25.       incoming = i2c_read();
  26.       address = incoming;
  27.     }
  28.     if(state == 2)  //Second received byte is data
  29.     {
  30.       incoming = i2c_read();
  31.       buffer[address] = incoming;
  32.     }
  33.   }
  34.   if(state == 0×80)  //Master is requesting data
  35.   {
  36.     i2c_write (buffer[address]);
  37.   }
  38. }
  39. //————————————————————————————————————————————————————————————
  40. void main()
  41. {
  42.   delay_ms(200); // power up delay
  43.   setup_comparator(NC_NC_NC_NC);
  44.   setup_vref(FALSE);
  45.   set_tris_A ( 0b11111111 );      // Port A 11111111
  46.   set_tris_B ( 0b01111111 );      // Port B 00110000 ( Bit5/7 - RS232- Rx/tx)
  47.   set_tris_C ( 0b11111111 );      // Port C 11111111
  49.   enable_interrupts(INT_SSP);
  50.   enable_interrupts(GLOBAL);
  52.   while(TRUE)
  53.   {
  54.     // main code here …
  55.   }
  56. }
  57. //————————————————————————————————————————————————————————————

PC Serial Port output - Master PIC Debug

  1. I2C Master - Started!
  2. Result[0]=15
  3. Result[1]=14
  4. Result[2]=13
  5. Result[3]=12
  6. Result[4]=11
  7. Result[5]=10
  8. Result[6]=9
  9. Result[7]=8
  10. Result[8]=7
  11. Result[9]=6
  12. Result[10]=5
  13. Result[11]=4
  14. Result[12]=3
  15. Result[13]=2
  16. Result[14]=1
  17. Result[15]=0
  18. ReadAddress(5)=10

After this successfully test only need to make one more before getting the modules all together. Still need to test how to make PWM pulse available on 2 distinct outputs to control H-Bridge. I need to switch between outputs in order to change engine direction …

23 Responses to “Testing Pic code for I2C Master/Slave communication”

  1. Luc Bonnet Says:

    Very nice design!
    Please give me a description of your software development setup, so I will try to get the same tools as you.
    Until now, I use 8051 with Keil compiler, and I want to use PIC’s as I2C slaves.
    Thanks in advance.


  2. Nelson Neves Says:

    Hi Luc,

    thank you for your post! You can check for my software development setup in this post:

    and I’ve just acquired a new PIC programmer/debugger :

    Please notice that the PIC C compiler is not free, there are some good tools that are free, but I am more comfortable to work with this tool (CCSinfo) because I found it easy and quick to develop. They have a big community and you can check some problems and solutions in their forum! (you can find lots off source code there, it helps to see how things work)

    Also used 8051 some years ago, and really loved to work with it, but found that Microchip pics are very chip and don’t require much of external components to make it work.

    Please feel free to check other opensource and free PIC C compilers! There are very good tools out there! I haven’t had time to test it :(

  3. Ben Says:

    Hi Nelson,
    First, congratulation for your blog. It’s clear and practical.
    By the other hand, I have searched what type of C have you used for the PICs. I think that could be MikroC, but you are using function that are not implemented with the MikroC. Could do you say me what Pic C are you using in your projects? (at the pwm, and i2c projects)

  4. Nelson Neves Says:

    Hi Ben,

    thank you for your interest! The C compiler that I am using is CCSInfo PICC PCWH Compiler 4.016. Unfortunately it is a payed tool, but very well supported and have a very good library. Most of the functions in my code are from the tool’s library. Please check my Lab tools to get more info:

    I finally decided to use PIC 16F690 for the PWM and I2C support. You can find more details on PIC datasheet:

    I have another post that explains why I have changed from PIC 16F628A to 16F690 due to issues with PWM and H-Bridge interface:

    I’m quite busy at the moment doing other projects but hope to get back to my robot ASAP. ;)

  5. Ukri8051 Says:

    Maybe this way is more easy, slaves, eeproms, expand ports………

    // function i2c.c

    #include “i2c.h”

    /* Description : START Bit-Pattern Generate
    —-|________ SDA
    ——-|_____ SCL

    void GEN_START()
    P1 |= SDA_H;Delay(1); //SDA HIGH
    P1 |= SCL_H;Delay(1); //SCL HIGH
    P1 &= SDA_L;Delay(1); //SDA LOW
    P1 &= SCL_L;Delay(1); //SCL LOW

    Description : END Bit-Pattern Generate
    ______|—– SDA
    ___|——– SCL

    void GEN_STOP()
    P1 &= SCL_L;Delay(1); // SCL LOW
    P1 &= SDA_L;Delay(1); // SDA LOW
    P1 |= SCL_H;Delay(1); // SCL HIGH;
    P1 |= SDA_H;Delay(1); // SDA HIGH;

    Description : Send ACK or NACK Signal
    Argument : ack - ACK or NACK (INPUT)
    Note : It’s sent ACK and NACK by MCU.

    void SEND_ACK(char ack)
    P1 &= SCL_L;Delay(1); // Send ACK(LOW) or NACK(HIGH) and Generate SCL clock.
    if(ack == ACK) // If ACK?
    P1 &= SDA_L;
    else // If NACK?
    P1 |= SDA_H;
    P1 |= SCL_H;Delay(1); // SCL Clock
    P1 &= SCL_L;Delay(1);

    Description : Wait ACK or NACK Siganl
    Return Value : ACK or NACK
    Note : It’s sent ACK or NACK by Device interfaced using i2C with MCU.That is, MCU wait for ACK or NACK signal.

    char WAIT_ACK()
    char ack; // Wait for ACK or NACK
    P1 &= SCL_L;Delay(1);
    P1 |= SCL_H;Delay(1);
    if(P1 & SDA_H) // If Signal is HIGH,then NACK, else if LOW,then ACK
    ack = NACK;
    ack = ACK;
    P1 &= SCL_L;Delay(1);
    return ack;

    Description : Write Byte via I2C
    Argument : b - To be writted a byte value

    void WriteByte(char b)
    char i =0;
    for( ; i < 8 ; i++) // Send data by SCL from MSB to LSB by SDA on I2C BUS.
    P1 &= SCL_L;Delay(1); //SCL LOW

    /* Read by shift each 1 Bit from MSB in Data ‘b’. */
    if( ((b < ‘High’ to SDA
    P1 |= SDA_H;
    else // If ‘0′-> ‘Low’ to SDA
    P1 &= SDA_L;
    P1 |= SCL_H;Delay(1); //SCL HIGH
    P1 &= SCL_L;Delay(1); // SCL LOW

    Description : Read a Byte via I2C, Read data by SCL from MSB to LSB by SDA on I2C BUS..
    Return Value : Read Byte Value

    char ReadByte()
    char ret;
    char i = 0;
    ret = 0;
    P1 &= SCL_L;Delay(1); // SCL LOW
    for(; i<8 ; i++)
    P1 |= SCL_H;Delay(1); // SCL HIGH
    ret = (ret << 1);
    if(P1 & SDA_H) ret++;
    P1 &= SCL_L;Delay(1); // SCL LOW
    return ret;

    void Delay(int i)
    int j;
    for(; i != 0 ; i–)
    for( j = 0;j < 512;j++);


    i2c.h function

    #ifndef __I2C
    #define __I2C
    #define SDA_H 0×08 // SDA HIGH
    #define SDA_L ~(SDA_H) // SDA LOW

    #define SCL_H 0×10 // SCL HIGH — SDA Valid
    #define SCL_L ~(SCL_H) // SCL LOW — SDA Changable

    #define ACK 0×00 // ACK Signal
    #define NACK 0X01 // NACK Signal
    void GEN_START(); // START Bit-Patten Generate

    void GEN_STOP(); // END Bit-Pattern Generate

    void SEND_ACK(char ack); // Send ACK or NACK Signal

    char WAIT_ACK(); // Wait ACK or NACK Siganl

    void WriteByte(char b); // Write Byte via I2C

    char ReadByte(); // Read Byte via I2C

    void Delay(int i); // Delay Func.


  6. gaurav tyagi Says:

    so nice examples…..

  7. Nelson Neves Says:

    Thanks gaurav tyagi! I’ve been quite busy with other projects but hope to get back to my robot ASAP.

  8. Paul Says:

    HI Nelson

    You are such an intelligent person! Im stuck with my microcontroller project.. Im just wondering if u can give me some help about this?
    Make a microcontroller (Master) to communicate with another microcontroller (Slave):
    1. You need 4 wires linked between the Master and the Slave.
    2. You need to have a common ground between the Master and the Slave.
    3. You need to ensure Master and Slave having a 5 V DC power.
    4. Switch 1 and 2 are pre-set a statement of LED 1-4 as Table 1:

    Table 1 Statement of LEDs

    LED 1, 2, 3, 4 is on
    Other LEDs are off

    Switch 1 logic 0 0 1 1
    Switch 2 logic 0 1 0 1

    5. Switch 3 is normally logic 0.
    a. When Switch 3 is logic 0, LED statements are not updated.
    b. When Switch 3 is logic 1, LED statements are updated and presented as Table 1.

    Nelson if You cant understand the table, can you give me your email so I can give you the exact explanation


  9. Nelson Neves Says:

    I will contact you by email! Thanks for your interest on my site!

  10. Sunspot Says:

    Nelson - thanks for getting me started on “PIC as slave” !!
    I have some project notes at
    that may interest others who come here.

  11. Nelson Neves Says:

    Hi Graham, quite impressed with your work! It’s always a pleasure to help! Keep up the good work!

  12. ChelseaC Says:

    I have to do a project for a class using I2C Master Slave communication within the next few weeks so your post caught my eye in my research. I have not fully gotten into the project yet as I have another robot due first.

    I also have a senior design project to work on and I was wondering if maybe you would have some knowledge on the subject.

    I am working in a group on a design project which uses electrodes to track eye movement. The voltages from the electrodes will be filtered and then input into an A/D converter on a microcontroller. The micro will be connected to a PC via USB and will act as a USB mouse, moving according to the different voltages. I was advised to use the PIC18F4550. Is this a good suggestion? Is there anything in particular I may have overlooked or should consider (I am a beginner at programming micros)? Are there any places (besides of course the manual) I should look for help?


  13. Nelson Neves Says:

    That is really an interesting project!

    I’ve used the PIC 18F4550 to communicate with a device via SPI and it worked quite well. I was supposed to connect the PIC to the PC via USB (virtual serial port - COMx) in order to send commands that would control the SPI device. Never really finished the USB part, just used normal RS232 interface (PIC serial port connected to a PC with driver level shifter MAX232).

    I’ve selected this pic because it’s quite powerful and versatile, usb support, lots of external connectivity (serial port, SPI, I2C, etc), lots or RAM, 13 ADC channels (10-bit), eeprom to save you configurations, etc!

    Regarding the ADC modules you need to check if the acquisition time will suite your project, Microchip has a formula in the datasheet that will help you calculate that, or just googleit:

    From the mouse emulation don’t think that will be a problem, you can find some examples on the net and even at Microchip’s website, they also have a special USB framework that you can use, please have a look:

    I also found this demoboard (I’m not using this one, just googleit for the code) with code examples HID mouse support for the PIC 18F4550:
    (HID Mouse code)

    Regarding the PIC C Compiler, I’m now using CCSInfo because I’m already used to it, but Microchip has one also. Note that these 2 are payed compilers, and the last one quite expensive :( . You can always use it for evaluation purposes:

    I’ve been tempted to test Hi-Tech free C compiler, it looks quite good, I think it’s a good alternative (Hi-Tech was bought by Microchip but will maintain is products), it’s FREE!

    Where can you start to program Pics? My advise would be to try it on the compiler, it has lots of demo code, and you can always post/search on compiler forums. I always start with basic tasks like, blink a led then go on and try SPI, serial and I2C communication, ADCs, etc. Create some sort of small howto so that I can pick them up in future!

    Bottom line, I only used a minimal part of this device, so you need to take that in consideration and please ask for a 2nd opinion, but in my modest opinion I think the PIC 18F4550 will suite all of your needs.

    Good luck you your project and please don’t forget to keep me posted about your work!

    ps: USB article that may be useful to understand microcontroller limitations:

  14. Chelsea C Says:

    Have you tried out Mikroelectronica’s MiKroC compiler? It was what I was thinking of using but I am open to suggestions. (I’m currently looking into the ones you suggested)

  15. Nelson Neves Says:

    Sorry, completely forgot about that one! Damn!

    That was referenced to me by a colleague and He is quite happy with it! It seems to be very similar to CCSInfo, you will get a good discount if you also buy a demoboard! I’ve been tempted to buy a kit from them, demoboard and C compiler but was waiting on a business proposal for that and had no luck!

    If you are going for a payed solution I think this one has a really good price/quality.

  16. Chelsea C Says:

    In my first post, I mentioned a project I have to do for a class using I2C Master Slave communication within the next few weeks. I am about to embark on that project, although I have to choose a project to do given requirements that it has to fit. I have spent a lot of time on the internet, searching for projects ideas. I am not sure what project would be good because I don’t have a very good knowlege of the protocol we have to use for this project yet.

    I was hoping you could help steer me and my potential group in the right direction. Thank you very much for your time and help.

    Main resources:
    two gear motors
    24FC256 I2C memory chip
    two PIC16F690 chips and PICKIT2 programmer kit
    photocell (resistance changes when light is on the photocell so our professor said we could use this property in a voltage divider to change voltage)
    digital potentiometer

    I think we are supposed to use:

    Requirements and grading scale for Project 3

    This project is worth 40 points (40%). It is possible to get more than 40 points. The grading will be based on a base score that is multiplied by various factors.

    The base system is worth 15 points. Base system should consist of two processors that communicate with each other and with shared responsibility to achieve one or more tasks. You should be able to start the system
    using a remote control (TV remote with IR receiver or a flash light with a photo cell, tuned audio receiver and a dog whistle). Please pick up some photocells from me when you have the chance.
    Feature Multiplier
    Serial communication more complex than a simple start/stop 1.1
    Two way serial communication 1.1
    I2C communication 1.1
    SPI Communication 1.1
    SPI Communication - Bit Banged 1.2
    Analog input with A/D conversion 1.1
    Two way communication using I/O pins 1.1

    Additional Multipliers

    I reserve two more multipliers, one a factor of 1.2 for any well thought out feature(s) or doing something not directly covered in the class (for example using hardware PWM, or designing a mixed analog/digital
    component), and another a factor of 1.33 for what I call as a WOW factor.

    It is possible for a group to have a common base system and different students in the group may have additional features that they want to implement. Your report should document it by having a common report with separate appendices where each group member may want to add additional items.

  17. Ivon Says:

    Thx at last a practical and easy example using I2C, Nice blog i’ll keep visiting it, again thx for share :)

  18. Nelson Neves Says:

    Thanks for your visit, I’m glad for the feedback ;)

  19. Chelsea C Says:

    I completed the project I asked you about in my last post. We ended up using electronic dice made with LEDs controlled by a PIC16F690 micro. We used serial to communicate with another pic, I2C to store dice values, SPI to start a motor if either of the die values was a 6 and A/D to start the entire system (using a photocell in a voltage divider circuit). Perhaps that can give other students ideas for PIC projects.

    I am back to my EOG mouse project. I need to understand detail on USB specifications. I’m doing a lot of research but a direct explaination would be nice. Is there anything you can tell me about why a PIC18F4550 is good for USB compatability spec-wise? I know you said you didn’t get much into USB interfacing with this.

    So far, I have the fact that the PIC is capable of operating at a full speed rate of 12mbits/s which is supported by all USB hubs and it supports 16 bidirectional endpoints (which I don’t know if this is important to mention?).

    I know you’re busy but small advice on what is important to know and understand would be helpful.


  20. Nelson Neves Says:

    Glad to ear that you made it out! Sorry for the lack of feedback from me, but as I told you I’m a bit busy doing some Linux Embedded hardware testing for bifferboard! Thanks for sharing your project idea, It is actually very complete!

    Unfortunately I haven’t advanced in my USB studies and I’m afraid that I can’t help you to decide If the PIC 18F4550 will meat your needs. Have you read this article: (Open the PDF)

    You can also check for Microchip USB Framework, will probably get extra info:

    Some Microchp interesting USB Appnotes:


  21. Sebastien Says:

    Congratulation for your posts and sharing your knowledge. I am currently working on a similar project (two 16F690 talking to each other through I2C). I have one question about why you make use of 2 “PORT C” lines to drive the I2C bus. I thought that both chips should be connected through SDA and SCL on PORT B4/6, and the master should switch the TRISB state to drive the bus. Am I wrong about that ?

  22. Nelson Neves Says:

    Hi Sebastian,

    It’s been a while since my tests, I may probably wrongly assumed that PIC 16F690 would only support I2C Slave mode by hardware (and not Master mode) and so used the master emulated by software (using the CCSInfo internal libraries) and that is the main reason why the Pins don’t match! RC2 and RC3 from Master are being used for I2C master emulation.

    Reviewing the datasheet I have now noticed that PIC 16F690 also supports I2C Master mode by software:
    (page 197: 13.13 Master Mode).

    My apologies for this wrongly assumption! Thank you for making this important notice!

    I’m a bit busy testing some other projects based on Linux Embedded devices and will not have the available time to test this as it should, if you are interested in sharing your tests please feel free to post a link for your work!

    Once again, thank you for your comment,


  23. Sebastien Says:

    Well as you noticed, Master mode is only available through software operations, but parts of the hardware should help in building it. In fact, the code you use should (in theory) works perfectly using the same PIN, configured in I2C mode. The main difference should be that some of the operations are of no use (for example : enforcing the state of pins is not required, as in I2C mode only the TRIS needs to be changed).
    Despite this…I am currently trying to obtain a result using this approach, but can’t succeed in it. Surely I am missing something. I will probably have a try with a much powerfull device that has hardware support of Master Mode, in order to make my 16F690 SLAVE CODE running well, and then try to do the master with another 16F690. But my final goal for my current project is not to use 16F690 as the Master…will keep you informed of any new results.

Leave a Reply