Thread: C and RS232 problem

  1. #1
    Registered User
    Join Date
    Nov 2009

    C and RS232 problem

    Hi all,

    I'm in troubles in writing C drivers for a device using RS232 port.
    I cannot establish any communications between my linux box and that device! On the other hand I'm sure the RS232 on the device is working properly because using a hyperterminal on another Windows machine everything works fine.

    Here is what is reported in the manual of the device:

    "The RS232 communication parameters are:
    9600 BAUD, 8 BIT, NO PARITY, 1 STOP BIT (8N1)
    Each command is an ASCII string, and must be terminated by a Carriage Return character[...] The responses are terminated by a Carriage Return character."

    Here is my code:

    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <termios.h>
    #include <stdlib.h>
    int open_port(char *port)
      int fd;
      if (!port)
        return -1;
      if ((fd=open(port,O_RDWR | O_NOCTTY | O_NDELAY))<0)
        return -2;
      return fd;
    void configure_port(int fd)
      struct termios newtio;
      newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD ;
      newtio.c_iflag = IGNPAR | ICRNL;
    int main (int argc, char **argv)
      int fd;
      char PORT[]="/dev/ttyUSB0";
      int status;
      char buffer[255];
      if ((fd=open_port(PORT))<0)
          printf("Error in opening serial port fd=%d\n",fd);
          return -1;
      if ((status=write(fd,"SE\r",3))<3)
          printf("Error in writing on serial port\n");
          return -1;
       return 0;
    This code is compiled without any errors or warnings but unfortunately I cannot read correct values from the device (the device should respond 2 digits ASCII
    code terminated with Carriage Return character to the command SE).
    In particular sometimes it happens to read "SE\r" (so exactly the same command I write on the RS232 from the pc) and in some other cases the read values are wrong in format and in length.
    I cannot figure out where the problem is. I guess it is a rs232 configuration problem because as I told you using hyperterminal on Windows everything is ok but I really did not realize what is going wrong.
    Maybe the problem is that I'm using a serial to usb converter and it needs further configuration I'm missing? (The same converter works with hyperterminal).
    By the way here is the output of my linux box when I plug in the converter:

    usb 2-1: new full speed USB device using uhci_hcd and address 13
    usb 2-1: configuration #1 chosen from 1 choice
    pl2303 2-1:1.0 pl2303 converter detected
    usb 2-1: pl2303 converter now attached to ttyUSB0

    Any suggestions?

    Any help is really appreciated.

    Thank you for your attention.


  2. #2
    Registered User
    Join Date
    Nov 2009
    Sorry. I have realized that in my previous post I did not include the line:
    #define BAUDRATE B9600
    that is present in my code.


  3. #3
    {Jaxom,Imriel,Liam}'s Dad Kennedy's Avatar
    Join Date
    Aug 2006
    First, make sure that you can do the same thing from Linux using minicom (you'll have to remap \n to \r to make this happen, but that is not hard to do either. Next, in your code I see that you blow away the termio configuration. This is not always a good idea as the driver may have set something specific to the device in this structure. The better way to do this is to read the termio settings, then modify and write your changes back -- I've had to do this before with USB<->serial adapters.

    Hope this helps!

  4. #4
    Registered User
    Join Date
    Nov 2009
    Thanks a lot for your suggestions!

    I already have made a very quick try to communicate to the device using minicom but without luck. Probalby this is due to two different things:
    1) the device I have to communicate to is not a modem and probably further minicom configuration is needed (I understood minicom is mainly used with modem or similar devices)
    2) I was not able to figure out how to configure minicom to map \n in \r (as also you suggested). I thought this is not possible.

    On Monday I will try to overcome these two problems and I will also include your suggestion in my code. I will let you know.

    Thanks again

  5. #5
    Registered User
    Join Date
    Nov 2009
    Hi all!

    I have made some progresses in writing my drivers.

    First of all I have used a new PC equipped with a rs232 port and I do not use the serial to usb converter anymore.

    At least now I'm able to communicate with my device! Anyway there are some points that are still cryptic to me.

    The device is designed to not respond to all commands.

    Here is the code I use to issue commands for which the device responds:

    1.   #include <termios.h>
    2.   #include <stdio.h>
    3.   #include <stdlib.h>
    4.   #include <unistd.h>
    5.   #include <fcntl.h>
    6.   #include <sys/signal.h>
    7.   #include <sys/stat.h>
    8.   #include <sys/types.h>
    9.   #include <string.h>
    11. #define BAUDRATE B9600
    12. #define MODEMDEVICE "/dev/ttyS0"
    14. #define FALSE 0
    15. #define TRUE 1
    17. volatile int STOP=FALSE;
    18. void signal_handler_IO(int status);
    19. int wait_flag=TRUE;
    21. int main()
    22. {
    23.    int fd,c,res;
    24.    struct termios oldtio,newtio;
    25.    struct sigaction saio;
    26.    char buf[255];
    28.   fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
    29.   if (fd <0) {perror(MODEMDEVICE); exit(-1); }
    31.    saio.sa_handler=signal_handler_IO;
    32.    saio.sa_flags=0;
    33.    saio.sa_restorer=NULL;
    34.    sigaction(SIGIO,&saio,NULL);
    36.    fcntl(fd,F_SETOWN,getpid());
    37.    fcntl(fd,F_SETFL,FASYNC);
    39.   tcgetattr(fd,&oldtio); 
    40.   bzero(&newtio,sizeof(newtio));
    41.   newtio.c_cflag = BAUDRATE |   CS8 | CLOCAL | CREAD;
    42.   newtio.c_iflag = IGNPAR | ICRNL;
    43.   newtio.c_oflag = 0;
    44.   newtio.c_lflag = ICANON;
    45.   newtio.c_cc[VMIN]=1;
    46.   newtio.c_cc[VTIME]=0;
    47.   tcflush(fd, TCIFLUSH);
    48.   tcsetattr(fd,TCSANOW,&newtio);
    50.   printf("Send command SE\n");
    51.   if ((res=write(fd,"SE\r",3))!=3)  
    52.          return -1;
    53.   printf("Done! Status=%d\n",res);
    54.   res=read(fd,buf,255);
    56.   while (STOP==FALSE)
    57.    {
    58.    if (wait_flag==FALSE)
    59.       {
    60.         res=read(fd,buf,255);
    61.         buf[res]=0;
    62.         printf(":%s:%d\n",buf,res);
    63.         STOP=TRUE;
    64.          wait_flag=TRUE;
    65.       }
    66.   }
    68.   tcsetattr(fd,TCSANOW,&oldtio);
    69.  return 0;
    70. }
    72. void signal_handler_IO(int status)
    73. {
    74.   printf("received SIGIO signal\n");
    75.   wait_flag=FALSE;
    76. }
    This code works but I cannot understand why it needs the line 54. More precisely without line 54 the values read at line 60 sometimes are correct and sometimes not. With the line 54 the values read at line 60 are always correct! Why?!?

    Similar behavior is observed when I use commands to which the device does not respond at all:
      printf("Send command ST 1\n");
      if ((res=write(fd,"ST 1\r",5))!=5)
          return -1;
      printf("Done! Status=%d\n",res);
    Also in that case even if I don't have to read anything from the device I have to include a read() call to write the data correctly to the device! Why?!?

    Thanks in advance for your help.

Popular pages Recent additions subscribe to a feed