Serial Communication Problem


Closed Thread
Results 1 to 24 of 24

Hybrid View

  1. #1
    Join Date
    Apr 2005
    Location
    Virginia
    Posts
    65

    Question Serial Communication Problem

    Hello, I have been wrestling with this for days and thought I'd see if anyone could tell me what I'm doing wrong. I've Googled, gone through some excellent intro PIC books and read the forum here. The closest info I've found is here under the "serial string parsing" thread by billybobbins.

    To give you a picture of the end product:
    I am putting together a program that does four things: 1) Except a serial data stream of up to 40 bytes long, 2) execute commands based on data from the data stream, 3) re-transmit the data stream (nothing added or changed), and 4) count pulses from an encoder using an interrupt.

    My problem is with 1). For the life of me, I cannot get read a stream of serial data as I'd like. I'm trying to create a loop that looks for serial data coming in, reads and stores it into a variable array if any is present and goes onto to perform another function briefly before going back into the original loop.

    I'm in a Catch 22. If I don't use a timeout in the serin command, the program does nothing until data comes in, but when it comes in I have all of the bytes regardless of the size. If I do use a timeout either I get junk or a varying portion of the original data.

    My test data is sent via hyperterminal at 2400 baud 8N1. This is sent as a data file (notepad txt).

    Test data stream is: A00gfhgd00CR+
    where the + is used to identify the end of the stream. Eventually the baud will be 9600 and a line feed will be used to denote the end of a stream, just can't simulate a line feed in notepad.

    Here is the code with the results:

    All code has the following:

    include "modedefs.bas"

    Trisb = %00000000
    Trisc = %01000000
    Portb = %00000000
    Portc = %00000000

    a var byte
    b var byte
    c var byte
    d var byte
    RX var byte[40]
    TX var byte[40]
    i var byte
    dSize var byte
    f var byte
    PDA var byte
    InCheck var byte

    Yes, I have a few extra variables I'm not using in the current program.



    A) Using a for loop and a timeout

    Main:

    serin portc.7, T2400, 100, LED, RX[0]

    If RX[0] != 0 Then ReadPDA

    goto LED

    ReadPDA:

    For i = 1 to 40

    serin portc.7, T2400, RX[i]

    If RX[i] = "+" Then DataOut
    Next



    goto Error 'DataEnd


    LED:

    portb.0 = 1
    pause 10
    portb.0 = 0
    pause 10
    PDA = 0
    goto Main

    DataOut:

    for d = 0 to i
    serout portc.6, T2400, [RX[d]]
    next

    serout portc.6, T2400, [10, 13]

    goto Main

    Error:

    serout portc.6, T2400, ["Error"]

    goto Main

    And the results for five streams sent are:
    0gfhgd00CR+
    A00gfhgd00CR+
    ˜gfhgd00CR+
    A00gfhgd00CR+
    A00gfhgd00CR+

    Okay, not bad, but the first run didn't catch the A0 and the third not only lost the A00 but thought it saw a y with two dots over it instead.

    B) Using a while loop and a timeout


    Main:

    serin portc.7, T2400, 1, LED, RX[0]
    'pause 1
    If RX[0] != 0 Then ReadPDA
    'If RX[0] = 0 Then LED
    goto LED ' ReadPDA 'Error

    LED:

    portb.0 = 1
    pause 10
    portb.0 = 0
    pause 10
    PDA = 0
    goto Main

    ReadPDA:

    counter = 1

    while counter != 40 and RX[counter] != "+"
    serin portc.7,T2400, RX[counter]
    'if RX[counter] = 0 Then LED
    'pause 1
    counter = counter+1
    Wend

    If counter = 40 then Error

    goto DataOut



    DataOut:

    for i = 0 to counter
    serout portc.6, T2400, [RX[i]]
    next

    serout portc.6, T2400, [10, 13]

    goto Main


    Error:

    serout portc.6, T2400, ["Error", 10, 13]

    goto Main


    And the results for five streams sent are:
    00gfhgd00CR++
    : fhgd00CR++
    ‚þ0gfhgd00+
    ó0gfhgd00+
    Óöfhgd00CR+

    Again, if I remove the timeout, the data is perfect but the program doesn't move. I've seen some code with hserin and serin2, but I haven't played with those commands and haven't seen an advantage in using them in this application over serin, at least yet.

    Any help or advice is greatly appreciated! Thanks!

  2. #2
    Join Date
    Oct 2004
    Location
    Hangover, Germany
    Posts
    289


    Did you find this post helpful? Yes | No

    Default

    Oh yeah,

    The PIC is not fast enough to receive several bytes with software.
    You have to use assemblercode inside an Interrupt-Routine with a USART on the PIC.

    Tip: Counting signals is managed through Counters or Timers and you don't need Interrupts.

  3. #3
    Join Date
    Feb 2003
    Location
    Delaware
    Posts
    30


    Did you find this post helpful? Yes | No

    Default hardware UART is the way to go.

    Some advice. Always use a hardware UART when you can.

    I do bullet proof comms using an asm routine and a harware UART. However, if I had a small program and I didn't want to write an assembly interrupt service routine then I would simple poll the interrupt bit. This bit will set whenever a character has come in. It will clear when you remove the character.

    So what chip are you using? Does it have a UART? Can you use it?

    Hope this helps,

    Joe.

  4. #4
    Join Date
    Apr 2005
    Location
    Virginia
    Posts
    65


    Did you find this post helpful? Yes | No

    Question Counters and polling

    Thank you both for the info. Sorry I forgot to mention it earlier, I am using a 18F2525 which has a USART. Now I must admit that my knowledge is extremely limited at this time because I know next to nil about assembly except that it's not a lot of fun and quite complicated when I did try learning it a couple years ago.

    I haven't played with interrupts yet, but I'll be starting with those next week if not today. When you say poll the interrupt bit, bare with me, you mean set portb.2, for example, as an interrupt, read in the character when one is detected into a byte of my array (in this case RX[#]) and continue doing so until I get the last character? Also, I presume I can use another interrupt and hopefully set one as a higher priority than the other?

    Is there an example somewhere on using the counter on the PIC? Haven't had a lot of luck searching on the Net. Or is that used in conjunction with the COUNT command? I want to make sure that any time I receive a pulse from the encoder that it gets counted, this will be a priority over everything else.

    Again, thank you both for your advice.

  5. #5
    Join Date
    Oct 2004
    Location
    Italy
    Posts
    695


    Did you find this post helpful? Yes | No

    Default

    Hi!

    =============================================
    The PicBasic Pro SERIN2 command has an optional
    flow control pin. The SERIN2 command does this
    handshaking flow control on a byte by byte basis.
    Some computers may send several bytes before
    they even check the status of their handshaking lines.
    ==============================================


    The idea below does not use the flow control pin.

    Define first the data frames.

    START character
    The start character is present only one time in
    the data frame. (The first byte). If you use
    Notepad, the START character has to be printable.

    END character
    The end character is present only one time in
    the data frame. (The last byte). If you use
    Notepad, the END character has to be printable.

    DUMMY character(s)
    The DUMMY character is present one or more times
    in the data frame. The frame can have
    from 0 to 42 DUMMY characters.(See example below).
    If you use Notepad, the DUMMY characters need to
    be printable.

    DATA character(s)
    Any value except the values used for the
    START, END and DUMMY characters.
    The frame can have from 1 to 40 DATA
    characters. If you use Notepad, the DATA characters
    need to be printable.

    When you choose the character for START, END
    and DUMMY, choose characters that you will never
    use in the DATA characters. Maybe one day you
    will send DATA to an LCD display, so don't
    waste useful ASCII characters.

    * * *

    Example data frames in a Notepad file:

    S = Start character
    X = DATA character(s)
    E = END character
    D = DUMMY character(s)

    <START><DATA><DUMMY><END>

    The DUMMY character(s) is (are) used only if
    DATA is less than 40 bytes or if you need
    to send DUMMY data frames to the PIC.
    While the PC sends out the dummy data frames
    the PIC has time to do something else.
    (Remember we don't use any flow control).


    The following 5 lines are the Notepad file:

    SXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXE
    SXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXDE
    DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
    SXXXXXXXXXXDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDE
    SXDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDE

    Where:

    The first line is a data frame with 40 bytes of data.
    The second line is a data frame with 39 bytes of data.
    The third line is a dummy frame.
    The fourth line is a data frame with 10 bytes of data.
    The fifth line is a data frame with 1 byte of data.

    * * * *

    At 9600 baud the PC sends 960 bytes per second.
    (Terminal 8N1, raw ASCII file send).

    The data frames are always 42 bytes long plus the
    two bytes that Notepad will put at the end of
    each line. (CR and LF).
    To send out 44 bytes the PC will need 46 ms
    at 9600 baud.

    * * *

    If the above idea is compatible with your design, I will
    help you with the PicBasic Pro code.


    Best regards,


    Luciano
    Last edited by Luciano; - 28th April 2005 at 19:45.

  6. #6
    Join Date
    Feb 2003
    Location
    Delaware
    Posts
    30


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by elec_mech

    I haven't played with interrupts yet, but I'll be starting with those next week if not today. When you say poll the interrupt bit, bare with me, you mean set portb.2, for example, as an interrupt, read in the character when one is detected into a byte of my array (in this case RX[#]) and continue doing so until I get the last character? Also, I presume I can use another interrupt and hopefully set one as a higher priority than the other?
    Thats not quite what I mean. A pic has a few different interrupts. Things like timer0, received character, and portb.0 are all things that can interrupt the processor. Portb.0 is an external interrupt.

    Now on the 16F devices when an interrupt occurs the program jumps to a set mem location (this is in assembly...not PBP) if you have enabled the interrupt (ie it is not masked). It is up to the programmer to test which interrupt caused the program to jump to the interrupt vector. The programmer also needs to save a bunch of stuff (context saving) upon entering the ISR and then needs to restore it all when leaving the ISR. I am only a little familiar with the 18F parts but I know that they have even more registers associated with interrupts. Now this sounds like alot of work. But there is a trick.

    You see interrupt bits toggle regardless of if you have set up any interrupt registers! This means that if you start a timer and it overflows the timer overflow (TMRIF) bit gets set. So if you where to find out what register and bit will toggle when your event occurs then you poll that bit by doing a compare inside of your loop. Something like :

    Code:
    loop:
    'do some stuff here
    'and some more here
    
    if TMRIF = 1 then                    'now check to see if the timer over flowed
         TMRIF = 0                         'it did so reset the bit
         My_counter = My_counter + 1   'increment the counter
    endif
    
    goto loop
    For this to work you would create an alias to the timers interrupt flag and call it TMRIF. You would also need to start the harware timer by setting the appropriate bit in the appropriate register.

    Now if you where to use the UART you would get a bit set (RCIF, received character interrupt flag) whenever a character came in! And all you would need to do would be to load the character into a variable to reset the bit. This would look something like this:

    Code:
    loop:
    'do some stuff here
    'and some more here
    
    if RCIF = 1 then char_in = RCV_IN
    
    goto loop
    For this example to work you would need to create an alias for the received character interrupt flag and name it RCIF and an alias for the buffer that holds the received character and name it RCV_IN. Also you would need to set up the comms parameters.

    Hope this helps.

    Joe.

    Edit....You REALLY need the data sheet for your PIC!

  7. #7
    Join Date
    Oct 2004
    Location
    Italy
    Posts
    695


    Did you find this post helpful? Yes | No

    Default

    Microchip Application Notes:

    AN774 Asynchronous Communications with the PICmicro® USART
    http://ww1.microchip.com/downloads/e...tes/00774a.pdf

    AN774 Source Code (PIC16, PIC17, PIC18).
    http://ww1.microchip.com/downloads/e...otes/00774.zip


    From Source code ZIP file, Readme18.txt

    There are five code examples for the PIC18F452.
    They can be applied to any PIC18 part, with minor changes.
    Each file has a brief functional description in the header
    at the top of the file. They all receive data and transmit
    the data back, but do so in different ways to demonstrate
    typical applications of the USART.

    Here is a summary of the features of each code example:

    P18_TIRI.ASM Use interrupts for transmit and receive, Circular buffers, Eight bit data
    P18_TPRP.ASM Poll for transmit and receive, Simple buffers, Eight bit data
    P18_TWRP.ASM Poll to receive, Wait to transmit, No buffers, Eight bit data
    P18_2STP.ASM Poll to receive, Wait to transmit, No buffers, Eight bit data, Two stop bits
    P18_PRTY.ASM Poll to receive, Wait to transmit, No buffers, Eight bit data, Even parity bit

    Best regards,

    Luciano

  8. #8
    Join Date
    Feb 2005
    Location
    Essex, UK
    Posts
    154


    Did you find this post helpful? Yes | No

    Default

    With some of these examples using USART, do you have to use a MAX232 IC or can the PICs ports be connected straight to the DB9 serial connector?

    Better still, does anyone have an example connection schematic.

    Many thanks,

    Steve

Similar Threads

  1. Replies: 18
    Last Post: - 4th July 2017, 14:26
  2. serial communication problem
    By kindaichi in forum Serial
    Replies: 13
    Last Post: - 11th March 2010, 16:37
  3. Replies: 5
    Last Post: - 20th March 2006, 01:34
  4. Problem in Serial Communication
    By uuq1 in forum mel PIC BASIC Pro
    Replies: 2
    Last Post: - 5th June 2005, 07:17
  5. Replies: 8
    Last Post: - 11th November 2004, 20:08

Members who have read this thread : 2

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts