This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Serial i/o programming using keil c

Hi. I'm working on a project involving a java program and the micro controller NXP P89v664.

The java program which utilises the RXTX package, outputs to the serial port a string of characters to be deciphered by the micro controller.

My java program is completed and outputs correctly as checked by virtual com ports and a c program.

I have written a keil c program to receive the input but I somehow receive random inputs instead.

I used the _getkey() fuction to receive the input and putchar() function to check the output.

I'm new to keil c can anyone shed some light on this pls?

Thanks.

Parents
  • Hi All. Thanks for the replies. I will test the output from an oscilloscope soon. However i do suspect that my formula for calculating the baudrate is at fault.

    I lifted this code for initializing the serial port and setting baudrate to 9600

    void com_initialize (void)
    { /*------------------------------------------------
    Setup TIMER1 to generate the proper baud rate.
    ------------------------------------------------*/
    com_baudrate (9600);

    /*------------------------------------------------
    Clear com buffer indexes.
    ------------------------------------------------*/
    EA = 0; /* Disable Interrupts */

    t_in = 0;
    t_out = 0;
    t_disabled = 1;

    r_in = 0;
    r_out = 0;

    /*------------------------------------------------
    Setup serial port registers.
    ------------------------------------------------*/
    SM0 = 0; SM1 = 1; /* serial port MODE 1 */
    SM2 = 0;
    REN = 1; /* enable serial receiver */

    TI = 0; /* clear transmit interrupt */
    RI = 0; /* clear receiver interrupt */

    ES0 = 1; /* enable serial interrupts */
    PS0 = 0; /* set serial interrupts to low priority */

    EA = 1; /* Enable Interrupts */
    }

    void com_baudrate (unsigned baudrate)
    { EA = 0; /* Disable Interrupts */

    /*------------------------------------------------
    Clear transmit interrupt and buffer.
    ------------------------------------------------*/ TI = 0; /* clear transmit interrupt */ t_in = 0; /* empty transmit buffer */ t_out = 0; t_disabled = 1; /* disable transmitter */

    /*------------------------------------------------
    Set timer 1 up as a baud rate generator.
    ------------------------------------------------*/ TR1 = 0; /* stop timer 1 */ ET1 = 0; /* disable timer 1 interrupt */

    PCON |= 0x80; /* 0x80=SMOD: set serial baudrate doubler */

    TMOD &= ~0xF0; /* clear timer 1 mode bits */ TMOD |= 0x20; /* put timer 1 into MODE 2 */

    TH1 = (unsigned char) (256 - (18432000 / (16L * 12L * baudrate))); //18432000=Crystal freq set in the project options

    TR1 = 1; /* start timer 1 */

    EA = 1; /* Enable Interrupts */
    }

    Thanks for the help everyone!

Reply
  • Hi All. Thanks for the replies. I will test the output from an oscilloscope soon. However i do suspect that my formula for calculating the baudrate is at fault.

    I lifted this code for initializing the serial port and setting baudrate to 9600

    void com_initialize (void)
    { /*------------------------------------------------
    Setup TIMER1 to generate the proper baud rate.
    ------------------------------------------------*/
    com_baudrate (9600);

    /*------------------------------------------------
    Clear com buffer indexes.
    ------------------------------------------------*/
    EA = 0; /* Disable Interrupts */

    t_in = 0;
    t_out = 0;
    t_disabled = 1;

    r_in = 0;
    r_out = 0;

    /*------------------------------------------------
    Setup serial port registers.
    ------------------------------------------------*/
    SM0 = 0; SM1 = 1; /* serial port MODE 1 */
    SM2 = 0;
    REN = 1; /* enable serial receiver */

    TI = 0; /* clear transmit interrupt */
    RI = 0; /* clear receiver interrupt */

    ES0 = 1; /* enable serial interrupts */
    PS0 = 0; /* set serial interrupts to low priority */

    EA = 1; /* Enable Interrupts */
    }

    void com_baudrate (unsigned baudrate)
    { EA = 0; /* Disable Interrupts */

    /*------------------------------------------------
    Clear transmit interrupt and buffer.
    ------------------------------------------------*/ TI = 0; /* clear transmit interrupt */ t_in = 0; /* empty transmit buffer */ t_out = 0; t_disabled = 1; /* disable transmitter */

    /*------------------------------------------------
    Set timer 1 up as a baud rate generator.
    ------------------------------------------------*/ TR1 = 0; /* stop timer 1 */ ET1 = 0; /* disable timer 1 interrupt */

    PCON |= 0x80; /* 0x80=SMOD: set serial baudrate doubler */

    TMOD &= ~0xF0; /* clear timer 1 mode bits */ TMOD |= 0x20; /* put timer 1 into MODE 2 */

    TH1 = (unsigned char) (256 - (18432000 / (16L * 12L * baudrate))); //18432000=Crystal freq set in the project options

    TR1 = 1; /* start timer 1 */

    EA = 1; /* Enable Interrupts */
    }

    Thanks for the help everyone!

Children
  • Check it here: http://www.keil.com/c51/baudrate.asp

    Then start with a simple "Hello, World" embedded application sending to the serial port, and check that Hyperterminal (or whatever) received the output correctly...

    And pay attention to the clearly-stated instructions for posting source code:

    www.danlhenry.com/.../keil_code.png

  • TH1 = (unsigned char) (256 - (18432000 / (16L * 12L * baudrate))); //18432000=Crystal freq set in the project options.
    


    Interesting line. So you want 16 and 12 to be long constants. But does 18432000 seem like it fits in a 16-bit int?

  • Hi. I have checked the value and used the value TH1=0xF6 but the results are the same. I'm receiving funny stuff from the micro controller like before.

    I used a simple program to test but the results are the same as my other program.

    SEND: 0x01 0x02 0x03 0x04
    RECEIVE: 0xFD 0xFB 0xFB 0xF7

  • Hi. Can you send me more examples of your output that is generated?
    Send ...
    Receive...

  • Hi everyone. Sorry for the late reply. Have been testing with different crystals and baudrate.

    Microcontroller: NXP P89v664
    Flash Program: Flash Magic

    Crystal: 14.74756
    Baud: 38400
    TH1: 0xFE

    Results in hyper terminal:

    Input: 0 1 2 3 4 5 6 7 8 9
    Output: ðþ ñþ òþ óþ ôþ õþ öþ ÷þ øþ ùþ

    Results in another program:

    Input(HEX): 01 02 03 04 05 06 07 08 09 10 20 30 40
    Output(HEX): E1 E2 E3 E4 E5 E6 E7 E8 E9 F0 E0FE(Sometimes FE) F0FE(Sometimes FE) E0FF(Sometimes FF)

    Input(HEX): 81 82 83 84 85 86 87 88 89 90 A0
    Output(HEX): E1 E2 E3 E4 E5 E6 E7 E8 E9 F0 E0FE(Sometimes FE)

    Input(HEX): D1 D2 D3 E1 E2 E3 E4 E5 E6 E7 E8 E9 F0 F1 F2 F3
    Output(HEX): F1 F2 F3 E1 E2 E3 E4 E5 E6 E7 E8 E9 F0 F1 F2 F3

  • Using this code:

    /*------------------------------------------------------------------------------
    MAIN.C:  Interrupt Driver SIO Using printf.
    
    Copyright 1995-2002 KEIL Software, Inc.
    ------------------------------------------------------------------------------*/
    
    #include <reg51.h>
    #include <stdio.h>
    #include "sio.h"
    
    /*------------------------------------------------------------------------------
    _getkey waits until a character is received from the serial port.  This may not
    be the exact desired operation (for example if the buffer is empty, this
    function hangs waiting for a character to be received).
    ------------------------------------------------------------------------------*/
    char _getkey (void)
    {
    int k;
    
    do
      {
      k = com_getchar ();
      }
    while (k == -1);
    
    return ((unsigned char) k);
    }
    
    /*------------------------------------------------------------------------------
    ------------------------------------------------------------------------------*/
    char putchar (char c)
    {
    volatile unsigned int i;
    
    while (com_putchar (c) != 0)
      {
      for (i=0; i<1000; i++)
        {
        /*** DO NOTHING ***/
        }
      }
    
    return (c);
    }
    
    /*------------------------------------------------------------------------------
    Note that the two function above, _getkey and putchar, replace the library
    functions of the same name.  These functions use the interrupt-driven serial
    I/O routines in SIO.C.
    ------------------------------------------------------------------------------*/
    code char message [] =
      "This is a test to see if the interrupt driven serial I/O routines really work.";
    
    void main (void)
    {
    com_initialize ();              /* initialize interrupt driven serial I/O */
    com_baudrate (38400);            /* setup for 1200 baud */
    
    EA = 1;                         /* Enable Interrupts */
    
    //printf ("Interrupt-driver Serial I/O Example\r\n\r\n");
    
    while (1)
      {
      unsigned char c;
    
     //printf ("Press a key.\r\n");
      c = _getkey();
            putchar(c);
    
     // printf ("\r\n");
    // printf ("You pressed '%c'.\r\n\r\n", c);
      }
    }
    
    

  • /*------------------------------------------------------------------------------
    SIO.C:  Serial Communication Routines.
    
    Copyright 1995-2002 KEIL Software, Inc.
    ------------------------------------------------------------------------------*/
    
    #include <reg51.h>
    #include <string.h>
    #include "sio.h"
    
    /*------------------------------------------------------------------------------
    Notes:
    
    The length of the receive and transmit buffers must be a power of 2.
    
    Each buffer has a next_in and a next_out index.
    
    If next_in = next_out, the buffer is empty.
    
    (next_in - next_out) % buffer_size = the number of characters in the buffer.
    ------------------------------------------------------------------------------*/
    #define TBUF_SIZE   2           /*** Must be one of these powers of 2 (2,4,8,16,32,64,128) ***/
    #define RBUF_SIZE   8           /*** Must be one of these powers of 2 (2,4,8,16,32,64,128) ***/
    
    #define TBUF_SPACE  idata       /*** Memory space where the transmit buffer resides ***/
    #define RBUF_SPACE  idata       /*** Memory space where the receive buffer resides ***/
    
    #define CTRL_SPACE  data        /*** Memory space for the buffer indexes ***/
    
    /*------------------------------------------------------------------------------
    ------------------------------------------------------------------------------*/
    #if TBUF_SIZE < 2
    #error TBUF_SIZE is too small.  It must be larger than 1.
    #elif TBUF_SIZE > 128
    #error TBUF_SIZE is too large.  It must be smaller than 129.
    #elif ((TBUF_SIZE & (TBUF_SIZE-1)) != 0)
    #error TBUF_SIZE must be a power of 2.
    #endif
    
    #if RBUF_SIZE < 2
    #error RBUF_SIZE is too small.  It must be larger than 1.
    #elif RBUF_SIZE > 128
    #error RBUF_SIZE is too large.  It must be smaller than 129.
    #elif ((RBUF_SIZE & (RBUF_SIZE-1)) != 0)
    #error RBUF_SIZE must be a power of 2.
    #endif
    
    /*------------------------------------------------------------------------------
    ------------------------------------------------------------------------------*/
    static TBUF_SPACE unsigned char tbuf [TBUF_SIZE];
    static RBUF_SPACE unsigned char rbuf [RBUF_SIZE];
    
    static CTRL_SPACE unsigned char t_in = 0;
    static CTRL_SPACE unsigned char t_out = 0;
    
    static CTRL_SPACE unsigned char r_in = 0;
    static CTRL_SPACE unsigned char r_out = 0;
    
    static bit ti_restart = 0;  /* NZ if TI=1 is required */
    
    
    /*------------------------------------------------------------------------------
    ------------------------------------------------------------------------------*/
    static void com_isr (void) interrupt 4
    {
    /*------------------------------------------------
    Received data interrupt.
    ------------------------------------------------*/
    if (RI != 0)
      {
      RI = 0;
    
      if (((r_in - r_out) & ~(RBUF_SIZE-1)) == 0)
        {
        rbuf [r_in & (RBUF_SIZE-1)] = SBUF;
        r_in++;
        }
      }
    
    /*------------------------------------------------
    Transmitted data interrupt.
    ------------------------------------------------*/
    if (TI != 0)
      {
      TI = 0;
    
      if (t_in != t_out)
        {
        SBUF = tbuf [t_out & (TBUF_SIZE-1)];
        t_out++;
        ti_restart = 0;
        }
      else
        {
        ti_restart = 1;
        }
      }
    
    }
    
    /*------------------------------------------------------------------------------
    ------------------------------------------------------------------------------*/
    #pragma disable
    
    void com_initialize (void)
    {
    /*------------------------------------------------
    Setup TIMER1 to generate the proper baud rate.
    ------------------------------------------------*/
    com_baudrate (1200);
    
    /*------------------------------------------------
    Clear com buffer indexes.
    ------------------------------------------------*/
    t_in = 0;
    t_out = 0;
    
    r_in = 0;
    r_out = 0;
    
    /*------------------------------------------------
    Setup serial port registers.
    ------------------------------------------------*/
    SM0 = 0; SM1 = 1;   /* serial port MODE 1 */
    SM2 = 0;
    REN = 1;            /* enable serial receiver */
    
    RI = 0;             /* clear receiver interrupt */
    TI = 0;             /* clear transmit interrupt */
    ti_restart = 1;
    
    ES = 1;             /* enable serial interrupts */
    PS = 0;             /* set serial interrupts to low priority */
    }
    
    /*------------------------------------------------------------------------------
    ------------------------------------------------------------------------------*/
    #pragma disable
    
    void com_baudrate (
      unsigned baudrate)
    {
    /*------------------------------------------------
    Clear transmit interrupt and buffer.
    ------------------------------------------------*/
    TI = 0;             /* clear transmit interrupt */
    t_in = 0;           /* empty transmit buffer */
    t_out = 0;
    
    /*------------------------------------------------
    Set timer 1 up as a baud rate generator.
    ------------------------------------------------*/
    TR1 = 0;            /* stop timer 1 */
    ET1 = 0;            /* disable timer 1 interrupt */
    
    PCON |= 0x80;       /* 0x80=SMOD: set serial baudrate doubler */
    
    TMOD &= ~0xF0;      /* clear timer 1 mode bits */
    TMOD |= 0x20;       /* put timer 1 into MODE 2 */
    
    TH1 = 0xFE;//(unsigned char) (256 - (XTAL / (16L * 12L * baudrate)));
    
    TR1 = 1;            /* start timer 1 */
    }
    
    /*------------------------------------------------------------------------------
    ------------------------------------------------------------------------------*/
    #pragma disable
    
    char com_putchar (
      unsigned char c)
    {
    /*------------------------------------------------
    If the buffer is full, return an error value.
    ------------------------------------------------*/
    if (com_tbuflen () >= TBUF_SIZE)
      return (-1);
    
    /*------------------------------------------------
    Add the data to the transmit buffer.  If the
    transmit interrupt is disabled, then enable it.
    ------------------------------------------------*/
    tbuf [t_in & (TBUF_SIZE - 1)] = c;
    t_in++;
    
    if (ti_restart)
      {
      ti_restart = 0;
      TI = 1;               /* generate transmit interrupt */
      }
    
    return (0);
    }
    
    /*------------------------------------------------------------------------------
    ------------------------------------------------------------------------------*/
    #pragma disable
    
    int com_getchar (void)
    {
    if (com_rbuflen () == 0)
      return (-1);
    
    return (rbuf [(r_out++) & (RBUF_SIZE - 1)]);
    }
    
    /*------------------------------------------------------------------------------
    ------------------------------------------------------------------------------*/
    #pragma disable
    
    unsigned char com_rbuflen (void)
    {
    return (r_in - r_out);
    }
    
    /*------------------------------------------------------------------------------
    ------------------------------------------------------------------------------*/
    #pragma disable
    
    unsigned char com_tbuflen (void)
    {
    return (t_in - t_out);
    }
    
    /*------------------------------------------------------------------------------
    ------------------------------------------------------------------------------*/
    

  • but what do you see with an oscilloscope?

  • Hi. I dont think i have done the oscilloscope test correctly. I only get 50Hz at the output.

    Anyway I am able to get the correct echo of the characters after i transferred the hex file without pressing the reset button on the microcontroller.

    After pressing the reset button, I get the funny characters as shown above.

  • i have need of this software, so please procede me.

  • /*------------------------------------------------
    Received data interrupt.
    ------------------------------------------------*/
    if (RI != 0)
      {
      RI = 0;
    
      if (((r_in - r_out) & ~(RBUF_SIZE-1)) == 0)
        {
        rbuf [r_in & (RBUF_SIZE-1)] = SBUF;
        r_in++;
        }
      }
    

    the above looks 'strange' and i think wrong,
    the 'normal' way is

    /*------------------------------------------------
    Received data interrupt.
    ------------------------------------------------*/
    if (RI)
      {
      RI = 0;
      rbuf [r_in] = SBUF;
      r_in++;
      r_in &= (RBUF_SIZE-1); // works only if RBUF_SIZE is a power of 2
      }
    

    Erik

  • As long as r_in and r_out are integers of size 2^n, and the buffer is of size 2^m where m is smaller than n, you don't need to clip them everytime r_in or r_out are incremented.

    That means that (r_in - r_out) == 0 represents an empty buffer.
    And that (r_in - r_out) != 0 represents a non-empty buffer.
    And that ((r_in - r_out) & ~(RBUF_SIZE-1)) == 0 represents a non-full buffer.
    And that ((r_in - r_out) & ~(RBUF_SIZE-1)) != 0 represents a full buffer.

    So the code checks if there is room to insert (at least) one more character.
    Since r_in are incremented without a clip, the insert code must do the clipping instead:
    rbuf[r_in & (RBUF_SIZE-1)]

    The advantage with clipping/masking when indexing the array, instead of when incrementing the indices, is that you can fill the array completely full.

    If you do clip r_in and r_out directly when they are incremented, you must never fill the ring buffer 100% full or you get into a situation where r_in == r_out means either full or empty.