Microchip PIC16F1829 Serial Communication

pic16f1829_serial_isr_0

I’m writing code for a Microchip PIC16F1829 and thought I’d share the serial communication routine.  I’ve completed the schematic capture and PCB layout for the servo motor controller design.  But it’s a good idea to get some code written before moving forward with the PCB prototype production.  I’ve written a good chunk of the code for this design.  When the design is complete we’ll open source the files and place them on our web site (including the firmware for the microcontroller).

I’m writing the code using Microchip’s free C compiler xc8 and using their IDE MPLAB X.  To test the code with hardware I’ve connected a PICkit3 to a breadboarded DIP package of the PIC16F1829.  A serial port is connected to the PIC16F1829 through our USB to serial converter breakout board (BM010, will be listed on our web site Dec-2012).

Early in the code, after the power on reset, I configure the serial related registers and set up a timer that will timeout after 20+ bit periods (two bytes ~2ms).  Not shown in this code is the fact that I’ve also configured the TX line as an output and the RX line as an input.  These serial port hardware connections default to pins RB7 and RB5 respectively, but there are alternate pins you can select if you want to.  Also not shown are two buffer arrays I’ve defined (intRXBuffer[40] and intTXBuffer[40]).

I use the “int” prefix to remind me that these are used primarily by the interrupt routines.  I should probably use something else so their not confused with integer variable types.  Later maybe.
pic16f1829_serial_ISR_1

The design makes heavy use of interrupts.  Serial data reception interrupts are enabled at power up.  Once a serial data byte is received the TMR0 interrupt is enabled.   Every time a byte is received I reset the TMR0 timer.  If no byte is received within 20 bit periods the serial receive timer is turned off, the TMR0 is turned off, and a flag is set indicating data is ready for processing.  This allows serial data reception to occur in the background so you don’t have to worry about coordinating it with other program timing.  The serial data transmission routine is also interrupt driven, but I’ll get to that a little later.

Here’s the function where the serial reception interrupt is enabled.

pic16f1829_serial_isr_1b

Once the interrupt is enabled the ISR (interrupt service routine) will be entered when any byte is received.  The byte is shoved into a buffer, and the timer I mentioned earlier (TMR0) is cleared and its interrupt is enabled.  If another byte is received before the timer elapses the ISR will just keep sticking bytes into the buffer and resetting the timer.  As soon as the timer elapses the receive and timer interrupts are disabled, and a flag is set telling which is checked in the main program loop.  Note that if the number of bytes received exceeds the buffer size the pointer is reset to 0.  This will prevent an overrun of data that corrupts program RAM.

pic16f1829_serial_isr_2

In the main program I check for the data ready flag roughly every 4ms.  This is my program loop period.  This causes the response time to a serial command to also be 4ms.  Since I’m still writing this code I have not completed the serial communication protocol.   Currently my serial communication handling  routine just takes the data in the receive buffer and copies it to the transmit buffer.  It then enables the transmit interrupt causing the data to be transmitted on the serial port automatically.  I also re-enable the serial receive interrupt here and reset pointers to the beginning of my serial buffer.

Later I’ll actually check the serial data in the buffer and implement write, read, and other commands.  Currently, this interrupt driven serial communication simply mirrors data back to me.  If I type “I love circuits” into a terminal program I will receive that back.
pic16f1829_serial_isr_3

There’s another issue you need to handle when using the PIC’s serial port features.  You can have framing and overrun errors.  An overrun error occurs when the PIC’s FIFO buffer receives more than 2 full bytes before the RCREG is read.  This error is dreadful because if you don’t clear the error the serial port will not receive any new data.  A power on reset is necessary if you don’t handle this error in your code.  Since I’m using interrupts this shouldn’t be an issue, but let’s be safe.  The function below is called every 4ms and checks for serial port errors.  If it sees one it resets everything to a default state.

pic16f1829_serial_isr_4

That’s the gist of it.  A few functions to set things up, and all of your serial data reception and transmission occurs in the background.

It’s not finished, or completely tested.  I’m sure there’s some typos and a logic error here and there.  But it probably 80% there, and good enough to share.

Comments

  1. Younguk Chang says:

    Hi.
    It is really good information.
    I’m playing with Microchip’s BodyCom kit.
    It has PIC16LF1829 chip.
    I’m trying to do com port serial communication.
    So far I have no idea how it works.
    Could you share your code file with me?
    It will help me a lot to understande the communication.
    Thanks.
    p.s: My email is timchang1212@gmail.com

    • I should post the source code to our web site in the next week or two. The serial communication firmware was used in two new products and we’ll make available an MPLABX project with all source c ode as those products are produced.

      Lon

  2. Eduardo says:

    Hi!
    Where can I download the source code? It would be great! I am trying to do serial communication as well.

    Thanks.

    Eduardo (cartola@gmail.com)

  3. Hej,
    It is very good information you write about serial communication and coding with XC8. I am trying to convert your code to PIC18F2420. One thing in your code i did not understand is this :
    COMM.Bits.RXREADY?? Is this your own bit definition? Would you please write the definition of this line and where you define it. Thanks
    Salam

    • Hi Salam,

      That’s a bit structure I defined. You can use any kind of flag as long as it is public. The flag gets set in the serial ISR when the timer times out (see code block for ISR, in section with label “Handle TMR0 interrupts”). It gets cleared after the data is collected.

      Lon

Speak Your Mind

*