Linux下的串口编程(FL2440实现串口接收发送)

前面已经了解了串口的基础知识,下面将介绍在Linux下如何编程。以下的程序是,直接串口读,读完写的例程。

串口编程思路:
打开串口,设置波特率,数据位,停止位,奇偶校验位;
读写串口;(直接用read,write函数)
关闭串口。

直接见代码
串口的头文件,先定义一个结构体,含有其串口必备的要设置的数据位,奇偶校验位,停止位,是否连接,波特率,设备名等。
声明串口初始化函数,设置端口,关闭串口,打开串口的函数。

/********************************************************************************
 *      Copyright:  (C) 2018 NULL
 *                  All rights reserved.
 *
 *       Filename:  comport.h
 *    Description:  This head file is for the common TTY/Serial port operator library. 
 *
 *        Version:  1.0.0(7/30/2018)
 *         Author:  DingHuanhuan <[email protected]>
 *      ChangeLog:  1, Release initial version on "2018年07月30日 11时16分20秒"
 *                 
 ********************************************************************************/


#ifndef _COMPORT_H
#define _COMPORT_H

#include <stdio.h>    /*standard input and output definition*/
#include <string.h>
#include <stdlib.h>   /*standard function library definition*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <unistd.h>   /*UNIX standard function definition*/
#include <termios.h>  /* PPSIX terminal control definition*/
#include <fcntl.h>    /*file control definition*/
#include <errno.h>    /*error number definition*/
#include <sys/wait.h>

#define DEVNAME_LEN   64
#define buf_size     4096
typedef struct _COM_PORT
{
  unsigned char databit,parity,stopbit,flowctrl,is_connect;
  char dev_name[DEVNAME_LEN];
  int fd;
  int frag_size;
  long baudrate;
} COM_PORT;

COM_PORT  *Comport_Init(const char *dev_name,unsigned long baudrate, const char *settings);
void Setting_Comport(COM_PORT *comport, const char *settings);
void Comport_close(COM_PORT *comport);
int Comport_open(COM_PORT *comport);




#endif

串口源文件详解

1.按照头文件声明的顺序来,先串口初始化函数,返回一个结构体指针;在初始化函数里含有设置端口函数,结构体指针作为设置端口函数的入口参数;

2.设置端口函数:根据传进来的参数来设置结构体的数据位,奇偶校验位和停止位;

3.关闭串口函数:关闭之前 的串口文件描述符并设置其连接状态为0;

4.打开串口函数:
先来介绍一个最重要的结构体:很多系统都支持POSIX终端(串口)接口.程序可以利用这个接口来改变终端的参数,比如,波特率,字符大小等等.要使用这个端口的话,你必须将

struct termios
      {
      tcflag_t  c_iflag;  //输入选项
      tcflag_t  c_oflag;  //输出选项
      tcflag_t  c_cflag;  //控制选项
      tcflag_t  c_lflag;  //行选项
      cc_t      c_cc[NCCS]; //控制字符
      };

这个结构中最重要的是c_cflag,通过对它赋值,用户可以设置数据传输率、字符大小、数据位、停止位、奇偶效验位和硬件流控等。另外c_iflag和c_cc也是比较常用的标志。
c_cflag支持很多常量名称,其中设置数据传输率为相应的数据传输率前要加上“B”。
c_cflag成员不能直接对其初始化,而要将其通过与、或操作使用其中的某些选项。
输入模式c_iflag成员控制端口接收端的字符输入处理;c_cc包含了超时参数和控制字符的定义。
其具体意义如下。
c_iflag:输入模式标志,控制终端输入方式,具体参数如表1所示。
表1 c_iflag参数表
这里写图片描述
c_oflag:输出模式标志,控制终端输出方式,具体参数如表2所示。
表2 c_oflag参数
这里写图片描述
c_cflag:控制模式标志,指定终端硬件控制信息,具体参数如表3所示。
表3 c_cflag参数
这里写图片描述
c_lflag:本地模式标志,控制终端编辑功能,具体参数如表4所示。
表4 c_lflag参数
这里写图片描述
c_cc[NCCS]:控制字符,用于保存终端驱动程序中的特殊字符,如输入结束符等。c_cc中定义了如表5所示的控制字符。
表5 c_cc支持的控制字符
这里写图片描述
1)先根据这段判断是否是 我们所要打开的串口。

 /* not a TTY device */
    if(!strstr(comport->dev_name, "tty"))
    {
        printf("open not tty device \"%s\".\n",comport->dev_name);
        comport->fd = open(comport->dev_name, O_RDWR);
        retval = comport->fd <0 ? -2 : comport->fd;
        goto CleanUp;
    }

2)打开串口,将串口的文件描述符赋值给先前定义的串口结构体中的fd
int tcgetattr(int fd, struct termios *termios_p);
用于获取与终端相关的函数,成功返0,失败返回非零,发生失败接口将设置errno错误标识
eg.保存原先串口配置 tcgetattr(fd,&old_cfg)
该函数得到有fd指向的终端的配置参数,并将它们保存于termios结构变量old_cfg中。若调试成功,函数返回值为0,若调试失败,函数返回值为-1.

    comport->fd = open(comport->dev_name,O_RDWR | O_NOCTTY | O_NONBLOCK);
    if(comport->fd <0)
    {
        retval = -3;
        goto CleanUp;
    }
    printf("open device \"%s\"\n",comport->dev_name);

    if(0 != tcgetattr(comport->fd, &old_cfg))
    {
        retval = -4;  /* failed to get com settings*/
        goto CleanUp;
    }

    memset(&new_cfg, 0, sizeof(new_cfg));

3)之后就是进行串口配置,之前Setting_Comport函数是将配置信息赋到串口结构体中,接下来这个是直接来改变终端的参数。

    /*  Configure comport */

    new_cfg.c_cflag &= ~CSIZE; /*character length is 0 */
    new_cfg.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    new_cfg.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
    new_cfg.c_oflag &= ~(OPOST);

    /* set the databit */
    switch(comport->databit)
    {
      case 0x07:
        new_cfg.c_cflag |= CS7;
        break;
      case 0x08:
      default:
        new_cfg.c_cflag |= CS8;
        break;
    }

    /* set the parity */
    switch(comport->parity)
    {
      case 0x01:   //Odd check
          new_cfg.c_cflag |= PARENB;
          new_cfg.c_iflag |= (INPCK | ISTRIP);
          new_cfg.c_cflag |= PARODD;
          break;
      case 0x02:  //Even check
          new_cfg.c_cflag |= PARENB;
          new_cfg.c_iflag |= (INPCK | ISTRIP);
          new_cfg.c_cflag &= ~PARODD;
          break;
      case 0x00:
      default:
          new_cfg.c_cflag &= ~PARENB;
          break;
    }

    /*  set stop bit */
    if(0x01 !=comport->stopbit)
        new_cfg.c_cflag != CSTOPB;
    else 
        new_cfg.c_cflag &= ~CSTOPB;

    switch(comport->baudrate)
    {
     case 115200:
        temp = B115200;
        break;
     case 9600:
        temp = B9600;
        break;
     case 4800:
        temp = B4800;
        break;
     case 2400:
        temp = B2400;
        break;
     case 1800:
        temp = B1800;
        break;
     case 1200:
        temp = B1200;
        break;
     default:
        temp = B115200;
        break;
    }
    cfsetispeed(&new_cfg, temp);
    cfsetospeed(&new_cfg, temp);

    /* Set the com port timeout settings  */
    new_cfg.c_cc[VMIN] = 0;
    new_cfg.c_cc[VTIME] = 0;
    tcflush(comport->fd, TCIFLUSH);

    if(0 != tcsetattr(comport->fd, TCSANOW, &new_cfg))
    {
        retval = -5; //failed to set device comport settings
        goto CleanUp;
    }

    printf("Open device \"%s\".\n", comport->dev_name);
    comport->is_connect = 0x01;
    retval = comport->fd;

全:串口源码

/*********************************************************************************
 *      Copyright:  (C) 2018 NULL
 *                  All rights reserved.
 *
 *       Filename:  comport.c
 *    Description:  It's the comport operate library.
 *                 
 *        Version:  1.0.0(7/30/2018)
 *         Author:  DingHuanhuan <[email protected]>
 *      ChangeLog:  1, Release initial version on "2018年07月30日 11时59分34秒"
 *                 
 ********************************************************************************/

#include "comport.h"

COM_PORT *Comport_Init(const char *dev_name, unsigned long baudrate, const char *settings)
{
    COM_PORT *comport = NULL;
    if(NULL == (comport = (COM_PORT *)malloc(sizeof(COM_PORT))))
    {
        return NULL;
    }
    memset(comport, 0, sizeof(COM_PORT));
    comport->is_connect = 0;
    comport->frag_size = 128;

    strncpy(comport->dev_name, dev_name, DEVNAME_LEN);
    comport->baudrate = baudrate;

    Setting_Comport(comport, settings);

    return comport;
}

void Setting_Comport(COM_PORT *comport, const char *settings)
{
    if(NULL == comport || NULL == settings)
       return;

    switch(settings[0])   /* databit */
    {
      case '7':
        comport->databit = 7;
        break;
      case '8':
        comport->databit = 8;
        break;
      default:
        comport->databit = 8;
        break;
    }


    switch(settings[1])  /*parity check*/
    {
      case 'O':    /*Odd check*/
      case 'o':
        comport->parity = 1;
        break;
      case 'E':    /* Even check */
      case 'e':
        comport->parity = 2;
        break;
      case 'N':   /* None parity check */
      case 'n':
      default:
        comport->parity = 0;
        break;
    }

    switch(settings[2])  /*stop bit*/
    {
      case '1':
        comport->stopbit = 1;
        break;
      case '2':
      default:
        comport->stopbit = 2;
        break;
    }
}

void Comport_close(COM_PORT *comport)
{
    if(0 != comport->fd)
      close(comport->fd);

    comport->is_connect = 0x00;
    comport->fd = -1;

}

int Comport_open(COM_PORT *comport)
{
    int retval = -1;
    struct termios old_cfg, new_cfg;
    long temp;

    if(NULL == comport)
        return -1;

    Comport_close(comport);

    /* not a TTY device */
    if(!strstr(comport->dev_name, "tty"))
    {
        printf("open not tty device \"%s\".\n",comport->dev_name);
        comport->fd = open(comport->dev_name, O_RDWR);
        retval = comport->fd <0 ? -2 : comport->fd;
        goto CleanUp;
    }
    comport->fd = open(comport->dev_name,O_RDWR | O_NOCTTY | O_NONBLOCK);
    if(comport->fd <0)
    {
        retval = -3;
        goto CleanUp;
    }
    printf("open device \"%s\"\n",comport->dev_name);

    if(0 != tcgetattr(comport->fd, &old_cfg))
    {
        retval = -4;  /* failed to get com settings*/
        goto CleanUp;
    }

    memset(&new_cfg, 0, sizeof(new_cfg));

    /*  Configure comport */

    new_cfg.c_cflag &= ~CSIZE; /*character length is 0 */
    new_cfg.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    new_cfg.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
    new_cfg.c_oflag &= ~(OPOST);

    /* set the databit */
    switch(comport->databit)
    {
      case 0x07:
        new_cfg.c_cflag |= CS7;
        break;
      case 0x08:
      default:
        new_cfg.c_cflag |= CS8;
        break;
    }

    /* set the parity */
    switch(comport->parity)
    {
      case 0x01:   //Odd check
          new_cfg.c_cflag |= PARENB;
          new_cfg.c_iflag |= (INPCK | ISTRIP);
          new_cfg.c_cflag |= PARODD;
          break;
      case 0x02:  //Even check
          new_cfg.c_cflag |= PARENB;
          new_cfg.c_iflag |= (INPCK | ISTRIP);
          new_cfg.c_cflag &= ~PARODD;
          break;
      case 0x00:
      default:
          new_cfg.c_cflag &= ~PARENB;
          break;
    }

    /*  set stop bit */
    if(0x01 !=comport->stopbit)
        new_cfg.c_cflag != CSTOPB;
    else 
        new_cfg.c_cflag &= ~CSTOPB;

    switch(comport->baudrate)
    {
     case 115200:
        temp = B115200;
        break;
     case 9600:
        temp = B9600;
        break;
     case 4800:
        temp = B4800;
        break;
     case 2400:
        temp = B2400;
        break;
     case 1800:
        temp = B1800;
        break;
     case 1200:
        temp = B1200;
        break;
     default:
        temp = B115200;
        break;
    }
    cfsetispeed(&new_cfg, temp);
    cfsetospeed(&new_cfg, temp);

    /* Set the com port timeout settings  */
    new_cfg.c_cc[VMIN] = 0;
    new_cfg.c_cc[VTIME] = 0;
    tcflush(comport->fd, TCIFLUSH);

    if(0 != tcsetattr(comport->fd, TCSANOW, &new_cfg))
    {
        retval = -5; //failed to set device comport settings
        goto CleanUp;
    }

    printf("Open device \"%s\".\n", comport->dev_name);
    comport->is_connect = 0x01;
    retval = comport->fd;

CleanUp:
    printf("open device \"%s\" %s.\n",comport->dev_name,retval >0 ? "successfully" : "failure");
    return retval;
}

main函数

int main(int argc,char **argv)
{
    char             *devname = "/dev/ttyS1";
    unsigned long      baudrate = 115200;
    COM_PORT *comport;

    char buf[buf_size];


    comport = Comport_Init(devname, baudrate, "8N1");
    if(NULL == comport)
    {   
        printf("init serial port failure\n");
        return -1;                           
    }   

    Comport_open(comport);
    if(comport->fd <0) 
    {   
         printf("open error :%s\n",strerror(errno)); 
         exit(1);
    }   

    printf("OPEN THE DEVICE\n");
    while(1)
    {   
        sleep(3);
        if(read(comport->fd,buf,buf_size)<0)
            return -2; 
        printf("read is ok\n");
        printf("read : %s\n",buf);
        write(comport->fd,buf,buf_size);
        printf("write is ok\n");
        sleep(3);
    }
    close(comport->fd);
    free(comport);
    return 0;
}

接下来使用Makefile编译

#This Makefile used to call function to compile all the C source in current folder and links all the objects file into a excutable binary file.  

PWD=$(shell pwd)

prom = comport

CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux-
export CC=${CROSS_COMPILE}gcc
export CXX=${CROSS_COMPILE}g++
export AR=${CROSS_COMPILE}ar
export AS=${CROSS_COMPILE}as
export RANLIB=${CROSS_COMPILE}ranlib
export STRIP=${CROSS_COMPILE}strip


VPATH= .
SRCS = $(wildcard ${VPATH}/*.c)
DEPS = $(shell find ${VPATH}/*.h)
OBJS = $(patsubst %.c,%.o,$(SRCS))


$(prom): $(OBJS)
    @$(CC) -o $(prom) $(OBJS)
    @rm -rf *.o
clean:
    @rm -rf *.o

make之后编译出可执行文件comport,下载到开发板(tftp -gr comport 192.168.0.137 )后,给以777的权限即可执行。
打开串口调试助手,就可以看到自己串口发送的字符,在SecureCRT(连的是开发板)上可以看到串口所接收的字符。
这里写图片描述

猜你喜欢

转载自blog.csdn.net/m0_38022615/article/details/81294028
今日推荐