精华内容
下载资源
问答
  • linux C串口数据解析

    2020-08-31 17:06:01
    @解析串口数据 串口初始化及配置 下面展示一些 串口相关初始化。 /相关初始化/ pthread_t pSerial; static const char *device = "/dev/ttyS1"; static int uartFd = 0; int speed_arr[] = { B921600, B460800, B...

    @解析串口数据

    串口初始化及配置

    下面展示一些 串口相关初始化
    /相关初始化/

    pthread_t pSerial;
    static const char *device = "/dev/ttyS1";
    static int uartFd = 0;
    int speed_arr[] = {
        B921600, B460800, B230400, B115200, B57600, B38400, B19200,
        B9600, B4800, B2400, B1200, B300,
    };
    int name_arr[] = {
        921600, 460800, 230400, 115200, 57600, 38400,  19200,
        9600,  4800,  2400,  1200,  300,
    };
    

    /设置串口速度/

    void set_speed(int fd, int speed)
    {
        int   i;
        int   status;
        struct termios   Opt;
        tcgetattr(fd, &Opt);
    
        for ( i= 0;  i < (int)(sizeof(speed_arr) / sizeof(int));  i++) {
            if  (speed == name_arr[i])	{
                tcflush(fd, TCIOFLUSH);
                cfsetispeed(&Opt, speed_arr[i]);
                cfsetospeed(&Opt, speed_arr[i]);
                status = tcsetattr(fd, TCSANOW, &Opt);
                if  (status != 0)
                    perror("tcsetattr fd1");
                return;
            }
            tcflush(fd,TCIOFLUSH);
        }
    
        if (i == 12){
            printf("\tSorry, please set the correct baud rate!\n\n");
        }
    }
    

    /串口相关设置,停止位,校验位…/

    int set_Parity(int fd,int databits,int stopbits,int parity)
    {
        struct termios options;
        if  ( tcgetattr( fd,&options)  !=  0) {
            perror("SetupSerial 1");
            return(FALSE);
        }
        options.c_cflag &= ~CSIZE ;
        switch (databits) /*脡猫脰脙脢媒戮脻脦禄脢媒*/ {
        case 7:
            options.c_cflag |= CS7;
            break;
        case 8:
            options.c_cflag |= CS8;
            break;
        default:
            fprintf(stderr,"Unsupported data size\n");
            return (FALSE);
        }
    
        switch (parity) {
        case 'n':
        case 'N':
            options.c_cflag &= ~PARENB;   /* Clear parity enable */
            options.c_iflag &= ~INPCK;     /* Enable parity checking */
            break;
        case 'o':
        case 'O':
            options.c_cflag |= (PARODD | PARENB);  /* 脡猫脰脙脦陋脝忙脨搂脩茅*/
            options.c_iflag |= INPCK;             /* Disnable parity checking */
            break;
        case 'e':
        case 'E':
            options.c_cflag |= PARENB;     /* Enable parity */
            options.c_cflag &= ~PARODD;   /* 脳陋禄禄脦陋脜录脨搂脩茅*/
            options.c_iflag |= INPCK;       /* Disnable parity checking */
            break;
        case 'S':
        case 's':  /*as no parity*/
            options.c_cflag &= ~PARENB;
            options.c_cflag &= ~CSTOPB;
            break;
        default:
            fprintf(stderr,"Unsupported parity\n");
            return (FALSE);
        }
        /* 脡猫脰脙脥拢脰鹿脦禄*/
        switch (stopbits) {
        case 1:
            options.c_cflag &= ~CSTOPB;
            break;
        case 2:
            options.c_cflag |= CSTOPB;
            break;
        default:
            fprintf(stderr,"Unsupported stop bits\n");
            return (FALSE);
        }
        /* Set input parity option */
        if (parity != 'n')
            options.c_iflag |= INPCK;
        options.c_cc[VTIME] = 1; // 15 seconds
        options.c_cc[VMIN] = 128;
        options.c_lflag &= ~(ECHO | ICANON);
        options.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
        options.c_oflag &= ~OPOST;
        options.c_cflag |= CLOCAL | CREAD;
        options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    
        tcflush(fd,TCIFLUSH); /* Update the options and do it NOW */
        if (tcsetattr(fd,TCSANOW,&options) != 0) {
            perror("SetupSerial 3");
            return (FALSE);
        }
        return (TRUE);
    }
    

    /打开串口/linux下查看串口 /dev/ttyS*

    int OpenDev(const char *Dev)
    {
        int fd = open( Dev, O_RDWR | O_NOCTTY | O_NDELAY);
        if (-1 == fd)
        {
            perror("Can't Open Serial Port");
            return -1;
        } else
            return fd;
    }
    
    *这里就是初始化串口一些信息调用以上的函数* __
    void InitCom(const char *SeriName)
    {
        //    pthread_t pSerial;
        uartFd = OpenDev(SeriName);
        if (uartFd > 0)
        {
            set_speed(uartFd, 19200);
            if (set_Parity(uartFd,8,1,'N')== FALSE)
            {
                fprintf(stderr, "Set Parity Error\n");
                close(uartFd);
                return;
            }
            pthread_create(&pSerial,NULL,ReadComData,NULL);
        }
        else
        {        printf("Open %s Falied!\r\n",device);
            return;
        }
    }
    

    串口数据的解析

    *启动线程接收* __
    void InitCom(const char *SeriName)
    {
        //    pthread_t pSerial;
        uartFd = OpenDev(SeriName);
        if (uartFd > 0)
        {
            set_speed(uartFd, 19200);
            if (set_Parity(uartFd,8,1,'N')== FALSE)
            {
                fprintf(stderr, "Set Parity Error\n");
                close(uartFd);
                return;
            }
            pthread_create(&pSerial,NULL,ReadComData,NULL);/*线程函数在下面*/
        }
        else
        {        printf("Open %s Falied!\r\n",device);
            return;
        }
    }
    

    下面展示一些 接收串口数据解析

    void * ReadComData(void *arg)
    {
        printf("%s is running\r\n",__FUNCTION__);
        (void)arg;
        char buf[128];
        int rtn;
        int index = 0;
        char c;
        while(1)
        {
            rtn = read(uartFd,&c,1);
            if(rtn > 0)
            {
            /*接收到的数据开头为A*/
                if('A' == c)
                {
                    index = 1;
                    buf[0] = c;
                }
                /*以换行结束,也就是在输入如:A123456\r,\r是在串口界面上输入发送信息的时候键盘上的回车*/
                else if('\r' == c)
                {
                    buf[index] = '\0';
                    if('>' == buf[0])
                    {
                        printf("Recv data is:%s\r\n",buf);
                        /**/
                    }
                    index = 0;
                }
                /*没找到继续找*/
                else
                {
                    buf[index] = c;
                    index++;
                    if(index >= 128)
                        index = 0;
                }
            }
        }
        return NULL;
    }
    
    展开全文
  • Linux串口读取与解析

    2021-02-02 10:27:10
    串口协议包的接收及解析处理 对于串口接收问题前面之前有文章介绍过串口缓存机制的应用。当然这里不应用缓存机制也是完全可行的。这里我们讲解基于不带串口缓存机制的处理。对于串口接收我们最常用的方式就是在串口...

    串口协议包的接收及解析处理

    对于串口接收问题前面之前有文章介绍过串口缓存机制的应用。当然这里不应用缓存机制也是完全可行的。这里我们讲解基于不带串口缓存机制的处理。对于串口接收我们最常用的方式就是在串口中断中接收数据。

    利用串口接收数据包信息大致分为下面三种情况:

    1. 接收一帧数据,对帧数据进行处理(可以利用串口接收非空中断和串口空闲中断实现)
    2. 中断中边接收边处理存储,并将有效数据存储起来,再对有效数据进行解析。
    3. 将接收到的数据全部存入缓存,从缓存中提取数据并做处理。

    第11课.串口(UART)的使用

    1.UART连线图

    S3C2440有3个独立通道的UART
    

    2.数据传输流程

    1.平时数据线处于“空闲”状态(1状态)
    2.当要发送数据时,UART改变TxD数据线的状态(变为0状态),并维持1位的时间,这样接收方检测到开始位后,在等待1.5位的时间就开始一位一位的检测数据线的状态得到所传输的数据
    3.UART一帧中可以有5,6,7或8位的数据,发送方一位一位的改变数据线的状态将它们发送出去。首先发送最低位
    4.如果使用校验功能,UART在发送完数据位后,还要发送1个校验位。有两种校验方法:奇校验,偶校验——数据位连同校验位,“1”的数目等于奇数或偶数
    5.最后,发送停止位。数据线恢复到“空闲”状态(1状态)。停止位的长度有3种:1位,1.5位,2位

     正是由于这种机制,没有干扰的情况下,发送每个字节都能读到。

    Linux读取串口数据

    问题背景

        大致为:有一个发送端周期性的往本机串口上发送数据,本机需要定时读取串口数据,解析,获取自己想要的信息。实际描述为:由于是做智能驾驶的,需要读取车辆速度,通过OBD设备读取并解析车辆速度,然后通过蓝牙发送给PC串口(也是通过一个蓝牙模块接收),PC端串口定时接收串口数据并解析。

        在上述过程中,有一个问题需要注意:发送方是周期性的不停的发送数据,也就是说PC机串口一直有数据进来,最常见的是发送端频率比接收端频率高,即准备读取串口数据时总可以读取的数据,但也也导致了另一个问题,那就是怎么处理接收端串口缓冲,因为你每次的读取操作都必须要把当前串口缓冲区中数据全部读取出来,不能只读一部分,不然发送端一直有数据进来,而你每次都不读玩,就会造成缓冲区溢出。

     

    串口的实质是什么

        但凡接触过Linux系统知识或者了解计算机系统原理,那你一定通过一句话“在任何操作系统下,一切都是文件”,Linux系统就是这句话的最完美的实现,即在Linux系统下,你完全可以把所有东西当成是一个文件、即所有东西都可以按照“打开——设置——读写——关闭”的模式进行,同样,在Linux下串口也可以看成是一种文件(其实任何操作系统下都可以这样认为),你要读写串口数据,就必须先打开、设置串口,然后读写,读写完毕,就必须要关闭串口。

    从串口缓冲区里读数据,其实和打开txt文件读数据一样,可以一次读几个字节,也可以全读出来。

     

    (1)打开串口:

        在ReadCarSpeed.cpp文件中,OpenCom()函数负责打开和设置串口,这里有一点需要啰嗦一下:myCom->setTimeout(50);延时设置函数,我这里设置的是50ms,对于这个延时,我的理解是本机串口的接收频率,注意这个接收频率是不同于你读取的频率的,这里的接收频率是本机串口缓冲区接收数据的延时,即没50ms就有一个数据进去接收缓冲区队列(要理解数据缓冲区实际就是一个队列,先进先出),而你读取的频率是你调用readAll()函数的频率,如我的读取频率就是主控程序的频率(大约为500ms),所以每次大约读取10个速度信息。

    缓冲区(buffer)与缓存(cache)

    一、什么是缓冲区

    缓冲区(buffer),它是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区,显然缓冲区是具有一定大小的。

    缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区。

    二、为什么要引入缓冲区

    我们为什么要引入缓冲区呢?

    高速设备与低速设备的不匹配,势必会让高速设备花时间等待低速设备,我们可以在这两者之间设立一个缓冲区。

    缓冲区的作用:

    1.可以解除两者的制约关系,数据可以直接送往缓冲区,高速设备不用再等待低速设备,提高了计算机的效率。例如:我们使用打印机打印文档,由于打印机的打印速度相对较慢,我们先把文档输出到打印机相应的缓冲区,打印机再自行逐步打印,这时我们的CPU可以处理别的事情。

    2.可以减少数据的读写次数,如果每次数据只传输一点数据,就需要传送很多次,这样会浪费很多时间,因为开始读写与终止读写所需要的时间很长,如果将数据送往缓冲区,待缓冲区满后再进行传送会大大减少读写次数,这样就可以节省很多时间。例如:我们想将数据写入到磁盘中,不是立马将数据写到磁盘中,而是先输入缓冲区中,当缓冲区满了以后,再将数据写入到磁盘中,这样就可以减少磁盘的读写次数,不然磁盘很容易坏掉。

    简单来说,缓冲区就是一块内存区,它用在输入输出设备和CPU之间,用来存储数据。它使得低速的输入输出设备和高速的CPU能够协调工作,避免低速的输入输出设备占用CPU,解放出CPU,使其能够高效率工作。

    小草手把手教你 LabVIEW 串口仪器控制——VISA 串口配置

    串口有个缓冲区,存在计算机内存里,VISA 读取,就是从缓冲区读取数据,读完之后,读取的就不存在缓冲区里了。如果你没读取,那就一直在缓冲区里,直到缓冲区溢出。其实就好比一个水桶,写 VISA 是往水桶进水,读 VISA 是出水。你也可以想想队列的原理,差不多的。

    手把手教你学51单片机-C语言版.pdf

    UART (Universal Asynchronous Receiver/Transmitter,即通用异步收发器)串行通信是单片机最常用的一种通信技术,通常用于单片机和电脑之间以及单片机和单片机之间的通信。 

    11.1 串行通信的初步认识  

    当单片机 1 想给单片机 2 发送数据时,比如发送一个 0xE4 这个数据,用二进制形式表 示就是 0b11100100,在 UART 通信过程中,是低位先发,高位后发的原则,那么就让 TXD 首先拉低电平,持续一段时间,发送一位 0,然后继续拉低,再持续一段时间,又发送了一 位 0,然后拉高电平,持续一段时间,发了一位 1……一直到把 8 位二进制数字 0b11100100 全部发送完毕。这里就涉及到了一个问题,就是持续的这“一段时间”到底是多久?由此便引入了通信中的一个重要概念——波特率,也叫做比特率。

    波特率就是发送二进制数据位的速率,习惯上用 baud 表示,即我们发送一位二进制数据 的持续时间=1/baud。在通信之前,单片机 1 和单片机 2 首先都要明确的约定好它们之间的通 信波特率,必须保持一致,收发双方才能正常实现通信,这一点大家一定要记清楚。

    约定好速度后,我们还要考虑第二个问题,数据什么时候是起始,什么时候是结束呢? 不管是提前接收还是延迟接收,数据都会接收错误。在 UART 通信的时候,一个字节是 8 位, 规定当没有通信信号发生时,通信线路保持高电平,当要发送数据之前,先发一位 0 表示起 始位,然后发送 8 位数据位,数据位是先低后高的顺序,数据位发完后再发一位 1 表示停止 位。这样本来要发送一个字节的 8 位数据,而实际上我们一共发送了 10 位,多出来的两位 其中一位起始位,一位停止位。而接收方呢,原本一直保持的高电平,一旦检测到了一位低 电平,那就知道了要开始准备接收数据了,接收到 8 位数据位后,然后检测到停止位,再准 备下一个数据的接收。我们图示看一下,如图 11-2 所示。

     

    图 11-2 串口数据发送示意图,实际上是一个时域示意图,就是信号随着时间变化的对应 关系。比如在单片机的发送引脚上,左边的是先发生的,右边的是后发生的,数据位的切换 时间就是波特率分之一秒,如果能够理解时域的概念,后边很多通信的时序图就很容易理解 了。 

    11.4 IO 口模拟 UART 串口通信

    这一节对理解串口的高低电平发送与接收特别有帮助,具体看  第11章 UART 串口通信(手把手教你学51单片机pdf部分)

    11.5.2 UART 模块介绍

    IO 口模拟串口通信,让大家了解了串口通信的本质,但是我们的单片机程序却需要不停 的检测扫描单片机 IO 口收到的数据,大量占用了单片机的运行时间。这时候就会有聪明人 想了,其实我们并不是很关心通信的过程,我们只需要一个通信的结果,最终得到接收到的 数据就行了。这样我们可以在单片机内部做一个硬件模块,让它自动接收数据,接收完了, 通知我们一下就可以了,我们的 51 单片机内部就存在这样一个 UART 模块,要正确使用它, 当然还得先把对应的特殊功能寄存器配置好。

    展开全文
  • }catch(IOException ex) {//"关闭串口失败"; } } } TempHumidity tempHumidity= newTempHumidity();private List fValue = new ArrayList(); //温度值//char[] hex2char = hex.toCharArray(); int[] buffer = new ...

    packageClientDemo;importgnu.io.CommPort;importgnu.io.CommPortIdentifier;importgnu.io.NoSuchPortException;importgnu.io.PortInUseException;importgnu.io.SerialPort;importgnu.io.SerialPortEvent;importgnu.io.SerialPortEventListener;importgnu.io.UnsupportedCommOperationException;import staticcom.jeecg.common.DateUtil.getNowDate;importjava.io.IOException;importjava.io.InputStream;importjava.io.OutputStream;importjava.text.DecimalFormat;importjava.util.ArrayList;importjava.util.Date;importjava.util.Enumeration;importjava.util.HashMap;importjava.util.HashSet;importjava.util.Iterator;importjava.util.List;importjava.util.Observable;importjava.util.TooManyListenersException;importorg.apache.log4j.Logger;importorg.jeecgframework.web.system.service.SystemService;importorg.springframework.beans.factory.annotation.Autowired;importcom.jeecg.pdwsn.entity.ChannelsEntity;importcom.jeecg.pdwsn.entity.DataEntity;importcom.jeecg.pdwsn.entity.DevicesEntity;importcom.jeecg.pdwsn.entity.SensorsEntity;importcom.jeecg.pdwsn.entity.WarningEntity;importcom.jeecg.pdwsn.service.DevicesServiceI;importcom.jeecg.pdwsn.service.SensorsServiceI;importcom.jeecg.pdwsn.service.impl.DevicesServiceImpl;public class serialReader extends Observable implementsRunnable,

    SerialPortEventListener {private static final Logger logger = Logger.getLogger(DevicesServiceImpl.class);staticCommPortIdentifier portId;int delayRead = 100;int numBytes; // private static byte[] readBuffer = new byte[1024]; //

    //private static char[] readBuffer = new char[1024];

    staticEnumeration portList;

    InputStream inputStream;

    OutputStream outputStream;staticSerialPort serialPort;

    HashMap serialParams;

    Thread readThread;boolean isOpen = false;public static final String PARAMS_DELAY = "delay read"; // public static final String PARAMS_TIMEOUT = "timeout"; //超时时间

    public static final String PARAMS_PORT = "port name"; //端口名称

    public static final String PARAMS_DATABITS = "data bits"; // public static final String PARAMS_STOPBITS = "stop bits"; // public static final String PARAMS_PARITY = "parity"; //奇偶校验

    public static final String PARAMS_RATE = "rate"; // private HashMapmap;public booleanisOpen() {returnisOpen;

    }/*** 初始化端口操作的参数.

    *

    *@throwsSerialPortException

    *

    *@see

    */

    publicserialReader() {

    isOpen= false;

    }public void open(HashMap params) throwsNoSuchPortException,

    PortInUseException, IOException, UnsupportedCommOperationException,

    TooManyListenersException {

    serialParams=params;if(isOpen) {

    close();

    }/*try {*/

    //参数初始

    int timeout =Integer.parseInt(serialParams.get(PARAMS_TIMEOUT)

    .toString());int rate =Integer.parseInt(serialParams.get(PARAMS_RATE).toString());int dataBits =Integer.parseInt(serialParams.get(PARAMS_DATABITS)

    .toString());int stopBits =Integer.parseInt(serialParams.get(PARAMS_STOPBITS)

    .toString());int parity =Integer.parseInt(serialParams.get(PARAMS_PARITY)

    .toString());

    delayRead=Integer.parseInt(serialParams.get(PARAMS_DELAY).toString());

    String port=serialParams.get(PARAMS_PORT).toString();//打开端口

    portId =CommPortIdentifier.getPortIdentifier(port);

    serialPort= (SerialPort) portId.open("SerialReader", timeout);

    inputStream=serialPort.getInputStream();

    serialPort.addEventListener(this);

    serialPort.notifyOnDataAvailable(true);

    serialPort.setSerialPortParams(rate, dataBits, stopBits, parity);

    isOpen= true;/** } catch (PortInUseException e) { //

    * 端口"+serialParams.get( PARAMS_PORT ).toString()+"已经被占�?;

    *

    * } catch (TooManyListenersException e) { // "端口"+serialParams.get(

    * PARAMS_PORT ).toString()+"监听者过�?; } catch

    * (UnsupportedCommOperationException e) { // "端口操作命令不支�?; } catch

    * (NoSuchPortException e) { // "端口"+serialParams.get( PARAMS_PORT

    * ).toString()+"不存�?; } catch (IOException e) { //

    * "打开端口"+serialParams.get( PARAMS_PORT ).toString()+"失败"; }*/serialParams.clear();/*Thread readThread = new Thread(this);

    readThread.start();*/}public voidrun() {try{

    Thread.sleep(50);

    }catch(InterruptedException e) {

    }

    }public voidstart() {try{

    outputStream=serialPort.getOutputStream();

    }catch(IOException e) {

    }try{

    readThread= new Thread(this);

    readThread.start();

    }catch(Exception e) {

    }

    }//start() end

    public void run(byte[] message) {try{

    Thread.sleep(4);

    }catch(InterruptedException e) {

    }try{if (message != null) {

    System.out.println("run message:" +message);

    outputStream.write(message);

    }

    }catch(IOException e) {

    }

    }public voidclose() {if(isOpen) {try{

    serialPort.notifyOnDataAvailable(false);

    serialPort.removeEventListener();

    inputStream.close();

    serialPort.close();

    isOpen= false;

    }catch(IOException ex) {//"关闭串口失败";

    }

    }

    }

    TempHumidity tempHumidity= newTempHumidity();private List fValue = new ArrayList(); //温度值//char[] hex2char = hex.toCharArray();

    int[] buffer = new int[8192];int[] bufTmp = new int[2048]; //接收数据缓冲区2

    int dataLen = 0; //接收数据的总长度

    int step = 0; //解析步骤

    int readBytes=0;

    List splitt=new ArrayList();

    @Overridepublic voidserialEvent(SerialPortEvent event) {//TODO Auto-generated method stub

    try{

    Thread.sleep(delayRead);

    }catch(InterruptedException e) {

    e.printStackTrace();

    }switch(event.getEventType()) {case SerialPortEvent.BI: //10

    case SerialPortEvent.OE: //7

    case SerialPortEvent.FE: //9

    case SerialPortEvent.PE: //8

    case SerialPortEvent.CD: //6

    case SerialPortEvent.CTS: //3

    case SerialPortEvent.DSR: //4

    case SerialPortEvent.RI: //5

    case SerialPortEvent.OUTPUT_BUFFER_EMPTY: //2

    break;case SerialPortEvent.DATA_AVAILABLE: //1

    int len=readBuffer.length;int count=0;try{//多次读取,将所有数据读

    while (inputStream.available() > 0) {

    count++;

    readBuffer= new byte[inputStream.available()];

    numBytes=inputStream.read(readBuffer);//readBuffer

    System.out.println("readBuffer"+new char[inputStream.available()]+"SSsssssssssssssss"+numBytes);

    }//打印接收到的字节数据//System.out.println("长度"+readBuffer[]+"readBuffer.toString();"+readBuffer.toString());

    int[] iBuffer = new int[8192];for (int i = 0; i < numBytes; i++) {//System.out.println();

    /*changeMessage(readBuffer, numBytes);*/

    //iBuffer[i] = ((byte)readBuffer[i] & 0xff);

    buffer[dataLen]= ((byte)readBuffer[i] & 0xff);

    System.out.println("原始数据\t\t\t"+buffer[dataLen]);

    logger.info("原始数据\t\t\t"+buffer[dataLen]);switch(step)

    {case 0://AA=170

    if (0xAA == buffer[0])

    {

    step++;

    dataLen++;

    }else{

    step= 0;

    dataLen= 0;

    }break;case 1:

    step++;

    dataLen++;break;case 2:

    dataLen++;if (dataLen >= buffer[1] + 2)

    {

    step++;

    }break;case 3://bb 十进制187

    if (0xBB ==buffer[dataLen])

    {//0f =15 十进制//System.out.println("温度湿度"+buffer[1]);

    if (buffer[1] < 0x0F)

    {//温湿度

    for (int j = 0; j < buffer[1]-4; j++)

    {

    bufTmp[j]= buffer[j + 4];//System.out.println("温度湿度"+buffer[j + 4]);

    }

    System.out.println("进入温湿度");

    AnalysisWenShiDu(8);//logger.info( "完整数据3 1"+iBuffer[i]);//logger.log(null, "AnalysisWenShiDu");//System.out.println("AnalysisWenShiDu");

    }else{//电缆数据

    for (int j = 0; j < buffer[1] - 2; j++)

    {

    bufTmp[j]= buffer[j + 2];//除去包头、长度、尾的数据//System.out.println(buffer[j + 2]+"除去包头、长度、尾的数据");

    }//System.out.println( "当前次数"+bufTmp[2]+"bufTmpbufTmpbufTmp\t\t "+bufTmp[i] );

    logger.info("当前次数"+bufTmp[2]+"bufTmpbufTmpbufTmp\t\t "+bufTmp[i]);//System.out.println( "bufTmpbufTmpbufTmp222\t\t "+bufTmp[2] );

    AnalysisData(bufTmp,bufTmp[2]);if (bufTmp[2] == 8)

    {//第八条电缆数据

    ///插入数据;

    StringBuffer sssss=newStringBuffer();for (int j = 0; j < splitt.size(); j++) {

    sssss.append(splitt.get(j)+";");

    }

    HttpPostUtil.getHanYuanUtils("http://localhost:8080/jeecg/rest/webshishishuju/fasong?sssss="+sssss);

    splitt.clear();

    splitt= newArrayList();

    dataLen= 0;

    }

    }

    }

    step= 0;

    dataLen= 0;break;default:

    step= 0;

    dataLen= 0;break;

    }

    }

    }catch(IOException e) {

    e.printStackTrace();

    }break;

    }

    }int cou=0;

    @Autowired

    DevicesServiceI devicesService;

    @AutowiredprivateSystemService systemService;

    @AutowiredprivateSensorsServiceI sensorsServiceI;/*public List diaoyong() {

    return splitt;

    }*/

    private List AnalysisData(int [] bufTmp2,intcurGP)

    {try{//System.out.println("bufTmp2[1]原始数据"+bufTmp2[1]);//bufTmp2[4] == 20

    int len = bufTmp2[4] * 2;int temp = 0;

    Double ftemp= 0.0;//长度40

    for (int i = 5; i < len +5; i++)

    {if (i % 2 == 1)

    {

    temp= bufTmp2[i] << 8;

    temp+= bufTmp2[i + 1];//System.out.println("bufTmp2[i]"+bufTmp2[i]);//System.out.println("temp"+temp);

    int st =temp;//System.out.println("ststst"+st);

    if (st > 0)

    {

    ftemp= st * 0.0625;

    }else if (st < 0)

    {

    ftemp= -(~st + 1) * 0.0625;

    }else if (st == 0)

    {

    ftemp= 0.0;

    }

    System.out.println(ftemp+"ftemp");

    splitt.add(Double.parseDouble(new DecimalFormat("0.00").format(ftemp)));

    i+= 1;

    }

    }

    }catch(Exception e)

    {

    }returnfValue;

    }//List wd=new ArrayList();

    private List AnalysisWenShiDu(intlen)

    {//仓内温湿度(T1H T1L H1H H1L)//仓外温湿度(T2H T2L H2H H2L)

    tempHumidity.in_temp = GetFloat1(bufTmp[0], bufTmp[1]);

    tempHumidity.in_humidity= GetFloat1(bufTmp[2], bufTmp[3]);double a=GetFloat1(bufTmp[0], bufTmp[1]);double b=GetFloat1(bufTmp[2], bufTmp[3]);double c=GetFloat1(bufTmp[4], bufTmp[5]);double d=GetFloat1(bufTmp[6], bufTmp[7]);

    System.out.println("a温度"+a+"b湿度"+b);

    tempHumidity.out_temp= GetFloat1(bufTmp[4], bufTmp[5]);

    tempHumidity.out_humidity= GetFloat1(bufTmp[6], bufTmp[7]);

    splitt.add(Double.parseDouble(new DecimalFormat("0.00").format(a)));

    splitt.add(Double.parseDouble(new DecimalFormat("0.00").format(b)));

    splitt.add(Double.parseDouble(new DecimalFormat("0.00").format(c)));

    splitt.add(Double.parseDouble(new DecimalFormat("0.00").format(d)));returnsplitt;

    }public static voidmain(String[] args) {int temp=0;

    temp= 170 << 8;//System.out.println(temp+"temp");

    }private float GetFloat1(int bufTmp2,intbufTmp3)

    {int temp = 0;float ftemp =0f;

    temp= bufTmp2 << 8;

    temp+=bufTmp3;int st =temp;if (st > 0)

    {

    ftemp= st * 0.1f;

    }else if (st < 0)

    {

    ftemp= (0xFFFF - temp) * 0.1f;

    }else if (st == 0)

    {

    ftemp= 0;

    }//System.out.println("温度湿度!!!!!!!!!!!!!!!!!!!!!!!!!"+ftemp);

    returnftemp;

    }//通过observer pattern将收到的数据给observer//将buffer中的空字节删除后再发送更新消息通知观察者

    public void changeMessage(byte[] message, intlength) {boolean flag = false;byte type = message[3];

    setChanged();

    notifyObservers(message);

    }static voidlistPorts() {

    Enumeration portEnum=CommPortIdentifier.getPortIdentifiers();while(portEnum.hasMoreElements()) {

    CommPortIdentifier portIdentifier=(CommPortIdentifier) portEnum

    .nextElement();

    }

    }static String getPortTypeName(intportType) {switch(portType) {caseCommPortIdentifier.PORT_I2C:return "I2C";caseCommPortIdentifier.PORT_PARALLEL:return "Parallel";caseCommPortIdentifier.PORT_RAW:return "Raw";caseCommPortIdentifier.PORT_RS485:return "RS485";caseCommPortIdentifier.PORT_SERIAL:return "Serial";default:return "unknown type";

    }

    }public HashSet getAvailableSerialPorts()//本来static

    {

    HashSet h = new HashSet();

    Enumeration thePorts=CommPortIdentifier.getPortIdentifiers();while(thePorts.hasMoreElements()) {

    CommPortIdentifier com=(CommPortIdentifier) thePorts

    .nextElement();switch(com.getPortType()) {caseCommPortIdentifier.PORT_SERIAL:try{

    CommPort thePort= com.open("CommUtil", 50);

    thePort.close();

    h.add(com);

    }catch(PortInUseException e) {

    System.out.println("Port, " +com.getName()+ ", is in use.");

    }catch(Exception e) {

    System.out.println("Failed to open port " +com.getName()+e);

    }

    }

    }returnh;

    }public classTempHumidity

    {public float in_temp; //舱内温度

    public float in_humidity; //舱内湿度

    public floatout_temp;public floatout_humidity;

    }

    }

    展开全文
  • Linux串口驱动解析

    千次阅读 2013-11-05 15:55:26
    串口驱动有3个核心数据结构,它们都定义在 1、uart_driver uart_driver包含了串口设备名、串口驱动名、主次设备号、串口控制台(可选)等信息,还封装了tty_driver(底层串口驱动无需关心tty_driver)。 struct uart...

    原文

    一、核心数据结构

    串口驱动有3个核心数据结构,它们都定义在<#include linux/serial_core.h>

    1、uart_driver

    uart_driver包含了串口设备名、串口驱动名、主次设备号、串口控制台(可选)等信息,还封装了tty_driver(底层串口驱动无需关心tty_driver)。
    struct uart_driver {
        struct module     *owner;           /* 拥有该uart_driver的模块,一般为THIS_MODULE */
        const char        *driver_name;     /* 串口驱动名,串口设备文件名以驱动名为基础 */
        const char        *dev_name;        /* 串口设备名 */
        int                major;           /* 主设备号 */
        int                minor;           /* 次设备号 */
        int                nr;              /* 该uart_driver支持的串口个数(最大) */
        struct console    *cons;            /* 其对应的console.若该uart_driver支持serial console,否则为NULL */
    
        /*
         * these are private; the low level driver should not
         * touch these; they should be initialised to NULL
         */
        struct uart_state *state;
        struct tty_driver *tty_driver;
    };

    2、uart_port

    uart_port用于描述串口端口的I/O端口或I/O内存地址、FIFO大小、端口类型、串口时钟等信息。实际上,一个uart_port实例对应一个串口设备。
    struct uart_port {
        spinlock_t             lock;           /* 串口端口锁 */
        unsigned int           iobase;         /* IO端口基地址 */
        unsigned char __iomem *membase;        /* IO内存基地址,经映射(如ioremap)后的IO内存虚拟基地址 */
        unsigned int           irq;            /* 中断号 */
        unsigned int           uartclk;        /* 串口时钟 */
        unsigned int           fifosize;       /* 串口FIFO缓冲大小 */
        unsigned char          x_char;         /* xon/xoff字符 */
        unsigned char          regshift;       /* 寄存器位移 */
        unsigned char          iotype;         /* IO访问方式 */
        unsigned char          unused1;
    
    #define UPIO_PORT        (0)               /* IO端口 */
    #define UPIO_HUB6        (1)
    #define UPIO_MEM         (2)               /* IO内存 */
    #define UPIO_MEM32       (3)
    #define UPIO_AU          (4)               /* Au1x00 type IO */
    #define UPIO_TSI         (5)               /* Tsi108/109 type IO */
    #define UPIO_DWAPB       (6)               /* DesignWare APB UART */
    #define UPIO_RM9000      (7)               /* RM9000 type IO */
    
        unsigned int        read_status_mask;  /* 关心的Rx error status */
        unsigned int        ignore_status_mask;/* 忽略的Rx error status */
        struct uart_info      *info;           /* pointer to parent info */
        struct uart_icount     icount;         /* 计数器 */
    
        struct console        *cons;           /* console结构体 */
    #ifdef CONFIG_SERIAL_CORE_CONSOLE
        unsigned long         sysrq;           /* sysrq timeout */
    #endif
    
        upf_t                 flags;
    
    #define UPF_FOURPORT         ((__force upf_t) (1 << 1))
    #define UPF_SAK              ((__force upf_t) (1 << 2))
    #define UPF_SPD_MASK         ((__force upf_t) (0x1030))
    #define UPF_SPD_HI           ((__force upf_t) (0x0010))
    #define UPF_SPD_VHI          ((__force upf_t) (0x0020))
    #define UPF_SPD_CUST         ((__force upf_t) (0x0030))
    #define UPF_SPD_SHI          ((__force upf_t) (0x1000))
    #define UPF_SPD_WARP         ((__force upf_t) (0x1010))
    #define UPF_SKIP_TEST        ((__force upf_t) (1 << 6))
    #define UPF_AUTO_IRQ         ((__force upf_t) (1 << 7))
    #define UPF_HARDPPS_CD       ((__force upf_t) (1 << 11))
    #define UPF_LOW_LATENCY      ((__force upf_t) (1 << 13))
    #define UPF_BUGGY_UART       ((__force upf_t) (1 << 14))
    #define UPF_MAGIC_MULTIPLIER ((__force upf_t) (1 << 16))
    #define UPF_CONS_FLOW        ((__force upf_t) (1 << 23))
    #define UPF_SHARE_IRQ        ((__force upf_t) (1 << 24))
    #define UPF_BOOT_AUTOCONF    ((__force upf_t) (1 << 28))
    #define UPF_FIXED_PORT       ((__force upf_t) (1 << 29))
    #define UPF_DEAD             ((__force upf_t) (1 << 30))
    #define UPF_IOREMAP          ((__force upf_t) (1 << 31))
    
    #define UPF_CHANGE_MASK      ((__force upf_t) (0x17fff))
    #define UPF_USR_MASK         ((__force upf_t) (UPF_SPD_MASK|UPF_LOW_LATENCY))
    
        unsigned int             mctrl;        /* 当前的moden设置 */
        unsigned int             timeout;      /* character-based timeout */        
        unsigned int             type;         /* 端口类型 */
        const struct uart_ops   *ops;          /* 串口端口操作函数集 */
        unsigned int             custom_divisor;
        unsigned int             line;         /* 端口索引 */
        resource_size_t          mapbase;      /* IO内存物理基地址,可用于ioremap */
        struct device           *dev;          /* 父设备 */
        unsigned char            hub6;         /* this should be in the 8250 driver */
        unsigned char            suspended;
        unsigned char            unused[2];
        void                    *private_data; /* 端口私有数据,一般为platform数据指针 */
    };
    uart_iconut为串口信息计数器,包含了发送字符计数、接收字符计数等。在串口的发送中断处理函数和接收中断处理函数中,我们需要管理这些计数。
    struct uart_icount {
        __u32    cts;
        __u32    dsr;
        __u32    rng;
        __u32    dcd;
        __u32    rx;      /* 发送字符计数 */
        __u32    tx;      /* 接受字符计数 */
        __u32    frame;   /* 帧错误计数 */
        __u32    overrun; /* Rx FIFO溢出计数 */
        __u32    parity;  /* 帧校验错误计数 */
        __u32    brk;     /* break计数 */
        __u32    buf_overrun;
    };
    uart_info有两个成员在底层串口驱动会用到:xmit和tty。用户空间程序通过串口发送数据时,上层驱动将用户数据保存在xmit;而串口发送中断处理函数就是通过xmit获取到用户数据并将它们发送出去。串口接收中断处理函数需要通过tty将接收到的数据传递给行规则层。(未找到)
    /* uart_info实例仅在串口端口打开时有效,它可能在串口关闭时被串口核心层释放。因此,在使用uart_port的uart_info成员时必须保证串口已打开。底层驱动和核心层驱动都可以修改uart_info实例。
     * This is the state information which is only valid when the port
     * is open; it may be freed by the core driver once the device has
     * been closed. Either the low level driver or the core can modify
     * stuff here.
     */
    struct uart_info {
        struct tty_struct     *tty;
        struct circ_buf        xmit;
        uif_t                  flags;
    
    /*
     * Definitions for info->flags. These are _private_ to serial_core, and
     * are specific to this structure. They may be queried by low level drivers.
     */
    #define UIF_CHECK_CD        ((__force uif_t) (1 << 25))
    #define UIF_CTS_FLOW        ((__force uif_t) (1 << 26))
    #define UIF_NORMAL_ACTIVE    ((__force uif_t) (1 << 29))
    #define UIF_INITIALIZED        ((__force uif_t) (1 << 31))
    #define UIF_SUSPENDED        ((__force uif_t) (1 << 30))
    
        int                     blocked_open;
    
        struct tasklet_struct   tlet;
    
        wait_queue_head_t       open_wait;
        wait_queue_head_t       delta_msr_wait;
    };

    3、uart_ops

    uart_ops涵盖了串口驱动可对串口设备进行的所有操作。
    /*
     * This structure describes all the operations that can be
     * done on the physical hardware.
     */
    struct uart_ops {
        unsigned int (*tx_empty)(struct uart_port *); /* 串口的Tx FIFO缓存是否为空 */
        void         (*set_mctrl)(struct uart_port *, unsigned int mctrl); /* 设置串口modem控制 */
        unsigned int (*get_mctrl)(struct uart_port *); /* 获取串口modem控制 */
        void         (*stop_tx)(struct uart_port *); /* 禁止串口发送数据 */
        void         (*start_tx)(struct uart_port *); /* 使能串口发送数据 */
        void         (*send_xchar)(struct uart_port *, char ch);/* 发送xChar */
        void         (*stop_rx)(struct uart_port *); /* 禁止串口接收数据 */
        void         (*enable_ms)(struct uart_port *); /* 使能modem的状态信号 */
        void         (*break_ctl)(struct uart_port *, int ctl); /* 设置break信号 */
        int          (*startup)(struct uart_port *); /* 启动串口,应用程序打开串口设备文件时,该函数会被调用 */
        void         (*shutdown)(struct uart_port *); /* 关闭串口,应用程序关闭串口设备文件时,该函数会被调用 */
        void         (*set_termios)(struct uart_port *, struct ktermios *new, struct ktermios*old); /* 设置串口参数 */
        void         (*pm)(struct uart_port *, unsigned int state,
                 unsigned int oldstate); /* 串口电源管理 */
        int          (*set_wake)(struct uart_port *, unsigned int state); /*  */
        const char  *(*type)(struct uart_port *); /* 返回一描述串口类型的字符串 */
        void         (*release_port)(struct uart_port *); /* 释放串口已申请的IO端口/IO内存资源,必要时还需iounmap */
        int          (*request_port)(struct uart_port *); /* 申请必要的IO端口/IO内存资源,必要时还可以重新映射串口端口 */
        void         (*config_port)(struct uart_port *, int); /* 执行串口所需的自动配置 */
        int          (*verify_port)(struct uart_port *, struct serial_struct *); /* 核实新串口的信息 */
        int          (*ioctl)(struct uart_port *, unsigned int, unsigned long); /* IO控制 */
    };

    二、串口驱动API

    drivers/tty/serial/serial_core.c
    1、uart_register_driver

    2、uart_unregister_driver

    3、uart_add_one_port

    4、uart_remove_one_port

    5、uart_write_wakeup

    6、uart_suspend_port

    7、uart_resume_port

    8、uart_get_baud_rate

    9、uart_get_divisor

    10、uart_update_timeout

    11、uart_match_port

    12、uart_console_write


    三、串口驱动例子

    该串口驱动例子是我针对s3c2410处理器的串口2(uart2)独立开发的。因为我通过博创2410s开发板的GRPS扩展板来测试该驱动(已通过测试),所以我叫该串口为gprs_uart。该驱动将串口看作平台(platform)设备。platform可以看作一伪总线,用于将集成于片上系统的轻量级设备与Linux设备驱动模型联系到一起,它包含以下两部分(有关platform的声明都在#include <linux/platform_device.h>,具体实现在drivers/base/platform.c):
    1、platform设备。我们需要为每个设备定义一个platform_device实例
    struct platform_device {
        const char      *name;         /* 设备名 */
        int              id;           /* 设备的id号 */
        struct device    dev;          /* 其对应的device */
        u32              num_resources;/* 该设备用有的资源数 */
        struct resource *resource;     /* 资源数组 */
    };
    为我们的设备创建platform_device实例有两种方法:①填充一个platform_device结构体后platform_device_register(一次注册一个)或②platform_add_devices(一次可以注册多个platform设备)platform_device注册到内核;更简单的是使用platform_device_register_simple来建立并注册我们的platform_device。
    2、platform驱动。platform设备由platform驱动进行管理。当设备加入到系统中时,platform_driver的probe方法会被调用来见对应的设备添加或者注册到内核;当设备从系统中移除时,platform_driver的remove方法会被调用来做一些清理工作,如移除该设备的一些实例、注销一些已注册到系统中去的东西。
    struct platform_driver {
        int  (*probe)(struct platform_device *);
        int  (*remove)(struct platform_device *);
        void (*shutdown)(struct platform_device *);
        int  (*suspend)(struct platform_device *, pm_message_t state);
        int  (*suspend_late)(struct platform_device *, pm_message_t state);
        int  (*resume_early)(struct platform_device *);
        int  (*resume)(struct platform_device *);
        struct device_driver driver;
    };

    例子驱动中申请和释放IO内存区的整个过程如下:

    insmod gprs_uart.kogprs_init_module()uart_register_driver()gprs_uart_probe() uart_add_one_port()gprs_uart_config_port()gprs_uart_request_port()request_mem_region()

    rmmod gprs_uart.kogprs_exit_module()uart_unregister_driver()gprs_uart_remove()uart_remove_one_port()gprs_uart_release_port()release_mem_region()

    例子驱动中申请和释放IRQ资源的整个过程如下:

    open /dev/gprs_uartgprs_uart_startup()request_irq()

    close /dev/gprs_uartgprs_uart_shutdown()free_irq()

    想了解更详细的调用过程可以在驱动模块各函数头插入printk(KERN_DEBUG "%s\n", __FUNCTION__);并在函数尾插入printk(KERN_DEBUG "%s done\n", __FUNCTION__);

    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/kernel.h>       /* printk() */
    #include <linux/slab.h>         /* kmalloc() */
    #include <linux/fs.h>           /* everything... */
    #include <linux/errno.h>        /* error codes */
    #include <linux/types.h>        /* size_t */
    #include <linux/fcntl.h>        /* O_ACCMODE */
    #include <asm/system.h>         /* cli(), *_flags */
    #include <asm/uaccess.h>        /* copy_*_user */
    #include <linux/ioctl.h>
    #include <linux/device.h>
    
    #include <linux/platform_device.h>
    #include <linux/sysrq.h>
    #include <linux/tty.h>
    #include <linux/tty_flip.h>
    #include <linux/serial_core.h>
    #include <linux/serial.h>
    #include <linux/delay.h>
    #include <linux/clk.h>
    #include <linux/console.h>
    #include <asm/io.h>
    #include <asm/irq.h>
    #include <asm/hardware.h>
    #include <asm/plat-s3c/regs-serial.h>
    #include <asm/arch/regs-gpio.h>
    
    
    #define DEV_NAME            "gprs_uart"     /* 设备名 */
    /* 这里将串口的主设备号设为0,则串口设备编号由内核动态分配;你也可指定串口的设备编号 */
    #define GPRS_UART_MAJOR        0            /* 主设备号 */
    #define GPRS_UART_MINOR        0            /* 次设备号 */
    #define GPRS_UART_FIFO_SIZE    16           /* 串口FIFO的大小 */
    #define RXSTAT_DUMMY_READ    (0x10000000)
    #define MAP_SIZE             (0x100)        /* 要映射的串口IO内存区大小 */
    
    /* 串口发送中断号 */
    #define TX_IRQ(port) ((port)->irq + 1)
    /* 串口接收中断号 */
    #define RX_IRQ(port) ((port)->irq)
    
    /* 允许串口接收字符的标志 */
    #define tx_enabled(port) ((port)->unused[0])
    /* 允许串口发送字符的标志 */
    #define rx_enabled(port) ((port)->unused[1])
    
    /* 获取寄存器地址 */
    #define portaddr(port, reg) ((port)->membase + (reg))
    
    /* 读8位宽的寄存器 */
    #define rd_regb(port, reg) (ioread8(portaddr(port, reg)))
    /* 读32位宽的寄存器 */
    #define rd_regl(port, reg) (ioread32(portaddr(port, reg)))
    /* 写8位宽的寄存器 */
    #define wr_regb(port, reg, val) \
        do { iowrite8(val, portaddr(port, reg)); } while(0)
    /* 写32位宽的寄存器 */        
    #define wr_regl(port, reg, val) \
        do { iowrite32(val, portaddr(port, reg)); } while(0)
    
    
    /* 禁止串口发送数据 */
    static void gprs_uart_stop_tx(struct uart_port *port)
    {
        if (tx_enabled(port))            /* 若串口已启动发送 */
        {        
            disable_irq(TX_IRQ(port));   /* 禁止发送中断 */
            tx_enabled(port) = 0;        /* 设置串口为未启动发送 */
        }
    }
    
    /* 使能串口发送数据 */
    static void gprs_uart_start_tx(struct uart_port *port)
    {
        if (!tx_enabled(port))           /* 若串口未启动发送 */
        {
            enable_irq(TX_IRQ(port));    /* 使能发送中断 */
            tx_enabled(port) = 1;        /* 设置串口为已启动发送 */
        }    
    }
    
    /* 禁止串口接收数据 */
    static void gprs_uart_stop_rx(struct uart_port *port)
    {
        if (rx_enabled(port))            /* 若串口已启动接收 */
        {
            disable_irq(RX_IRQ(port));   /* 禁止接收中断 */
            rx_enabled(port) = 0;        /* 设置串口为未启动接收 */
        }
    }
    
    /* 使能modem的状态信号 */
    static void gprs_uart_enable_ms(struct uart_port *port)
    {
    }
    
    /* 串口的Tx FIFO缓存是否为空 */
    static unsigned int gprs_uart_tx_empty(struct uart_port *port)
    {
        int ret = 1;
        unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT);
        unsigned long ufcon = rd_regl(port, S3C2410_UFCON);
    
        if (ufcon & S3C2410_UFCON_FIFOMODE)    /* 若使能了FIFO */
        {
            if ((ufstat & S3C2410_UFSTAT_TXMASK) != 0 ||    /* 0 <FIFO <=15 */
                    (ufstat & S3C2410_UFSTAT_TXFULL))       /* FIFO满 */
                ret = 0;
        }
        else    /* 若未使能了FIFO,则判断发送缓存和发送移位寄存器是否均为空 */
        {
            ret = rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE;
        }
                
        return ret;
    }
    
    /* 获取串口modem控制,因为uart2无modem控制,所以CTS、DSR直接返回有效 */
    static unsigned int gprs_uart_get_mctrl(struct uart_port *port)
    {
        return (TIOCM_CTS | TIOCM_DSR | TIOCM_CAR);
    }
    
    /* 设置串口modem控制 */
    static void gprs_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
    {
    
    }
    
    /* 设置break信号 */
    static void gprs_uart_break_ctl(struct uart_port *port, int break_state)
    {
        unsigned long flags;
        unsigned int ucon;
    
        spin_lock_irqsave(&port->lock, flags);
    
        ucon = rd_regl(port, S3C2410_UCON);
    
        if (break_state)
            ucon |= S3C2410_UCON_SBREAK;
        else
            ucon &= ~S3C2410_UCON_SBREAK;
    
        wr_regl(port, S3C2410_UCON, ucon);
    
        spin_unlock_irqrestore(&port->lock, flags);
    }
    
    /* 返回Rx FIFO已存多少数据 */
    static int gprs_uart_rx_fifocnt(unsigned long ufstat)
    {
        /* 若Rx FIFO已满,返回FIFO的大小 */
        if (ufstat & S3C2410_UFSTAT_RXFULL)
            return GPRS_UART_FIFO_SIZE;
    
        /* 若FIFO未满,返回Rx FIFO已存了多少字节数据 */
        return (ufstat & S3C2410_UFSTAT_RXMASK) >> S3C2410_UFSTAT_RXSHIFT;
    }
    
    #define S3C2410_UERSTAT_PARITY (0x1000)
    
    /* 串口接收中断处理函数,获取串口接收到的数据,并将这些数据递交给行规则层 */
    static irqreturn_t gprs_uart_rx_chars(int irq, void *dev_id)
    {
        struct uart_port *port = dev_id;
        struct tty_struct *tty = port->info->tty;
        unsigned int ufcon, ch, flag, ufstat, uerstat;
        int max_count = 64;
    
        /* 循环接收数据,最多一次中断接收64字节数据 */
        while (max_count-- > 0)
        {
            ufcon = rd_regl(port, S3C2410_UFCON);
            ufstat = rd_regl(port, S3C2410_UFSTAT);
    
            /* 若Rx FIFO无数据了,跳出循环 */
            if (gprs_uart_rx_fifocnt(ufstat) == 0)
                break;
    
            /* 读取Rx error状态寄存器 */
            uerstat = rd_regl(port, S3C2410_UERSTAT);
            /* 读取已接受到的数据 */
            ch = rd_regb(port, S3C2410_URXH);
    
            /* insert the character into the buffer */
            /* 先将tty标志设为正常 */
            flag = TTY_NORMAL;
            /* 递增接收字符计数器 */
            port->icount.rx++;
    
            /* 判断是否存在Rx error
             * if (unlikely(uerstat & S3C2410_UERSTAT_ANY))等同于
             * if (uerstat & S3C2410_UERSTAT_ANY)
             * 只是unlikely表示uerstat & S3C2410_UERSTAT_ANY的值为假的可能性大一些
             * 另外还有一个likely(value)表示value的值为真的可能性更大一些
             */
            if (unlikely(uerstat & S3C2410_UERSTAT_ANY))
            {
                /* 若break错误,递增icount.brk计算器 */
                if (uerstat & S3C2410_UERSTAT_BREAK)
                {
                    port->icount.brk++;
                    if (uart_handle_break(port))
                     goto ignore_char;
                }
    
                /* 若frame错误,递增icount.frame计算器 */
                if (uerstat & S3C2410_UERSTAT_FRAME)
                    port->icount.frame++;
                /* 若overrun错误,递增icount.overrun计算器 */
                if (uerstat & S3C2410_UERSTAT_OVERRUN)
                    port->icount.overrun++;
    
                /* 查看我们是否关心该Rx error
                 * port->read_status_mask保存着我们感兴趣的Rx error status
                 */
                uerstat &= port->read_status_mask;
    
                /* 若我们关心该Rx error,则将flag设置为对应的error flag */
                if (uerstat & S3C2410_UERSTAT_BREAK)
                    flag = TTY_BREAK;
                else if (uerstat & S3C2410_UERSTAT_PARITY)
                    flag = TTY_PARITY;
                else if (uerstat & ( S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_OVERRUN))
                    flag = TTY_FRAME;
            }
    
            /* 处理sys字符 */
            if (uart_handle_sysrq_char(port, ch))
                goto ignore_char;
    
            /* 将接收到的字符插入到tty设备的flip缓冲 */
            uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, ch, flag);
    
    ignore_char:
            continue;
        }
        
        /* 刷新tty设备的flip缓冲,将接受到的数据传给行规则层 */
        tty_flip_buffer_push(tty);
    
        return IRQ_HANDLED;
    }
    
    /* 串口发送中断处理函数,将用户空间的数据(保存在环形缓冲xmit里)发送出去 */
    static irqreturn_t gprs_uart_tx_chars(int irq, void *dev_id)
    {
        struct uart_port *port = dev_id;
        struct circ_buf *xmit = &port->info->xmit;        /* 获取环线缓冲 */
        int count = 256;
    
        /* 若设置了xChar字符 */
        if (port->x_char)
        {
            /* 将该xChar发送出去 */
            wr_regb(port, S3C2410_UTXH, port->x_char);
            /* 递增发送计数 */
            port->icount.tx++;
            /* 清除xChar */        
            port->x_char = 0;
            /* 退出中断处理 */        
            goto out;
        }
    
        /* 如果没有更多的字符需要发送(环形缓冲为空),
         * 或者uart Tx已停止,
         * 则停止uart并退出中断处理函数
         */
        if (uart_circ_empty(xmit) || uart_tx_stopped(port))
        {
            gprs_uart_stop_tx(port);
            goto out;
        }
    
        /* 循环发送数据,直到环形缓冲为空,最多一次中断发送256字节数据 */
        while (!uart_circ_empty(xmit) && count-- > 0)
        {
            /* 若Tx FIFO已满,退出循环 */
            if (rd_regl(port, S3C2410_UFSTAT) & S3C2410_UFSTAT_TXFULL)
                break;
    
            /* 将要发送的数据写入Tx FIFO */
            wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
            /* 移向循环缓冲中下一要发送的数据 */
            xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
            port->icount.tx++;
        }
    
        /* 如果环形缓冲区中剩余的字符少于WAKEUP_CHARS,唤醒上层 */    
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
            uart_write_wakeup(port);
    
        /* 如果环形缓冲为空,则停止发送 */
        if (uart_circ_empty(xmit))
            gprs_uart_stop_tx(port);
    
     out:
        return IRQ_HANDLED;
    }
    
    /* 启动串口端口,在打开该驱动的设备文件时会调用该函数来申请串口中断,并设置串口为可接受,也可发送 */
    static int gprs_uart_startup(struct uart_port *port)
    {
        unsigned long flags;
        int ret;
        const char *portname = to_platform_device(port->dev)->name;
    
        /* 设置串口为不可接受,也不可发送 */
        rx_enabled(port) = 0;
        tx_enabled(port) = 0;
    
        spin_lock_irqsave(&port->lock, flags);
    
        /* 申请接收中断 */
        ret = request_irq(RX_IRQ(port), gprs_uart_rx_chars, 0, portname, port);
        if (ret != 0)
        {
            printk(KERN_ERR "cannot get irq %d\n", RX_IRQ(port));
            return ret;
        }    
    
        /* 设置串口为允许接收 */
        rx_enabled(port) = 1;
    
        /* 申请发送中断 */
        ret = request_irq(TX_IRQ(port), gprs_uart_tx_chars, 0, portname, port);
        if (ret)
        {
            printk(KERN_ERR "cannot get irq %d\n", TX_IRQ(port));
            rx_enabled(port) = 0;
            free_irq(RX_IRQ(port), port);
            goto err;
        }    
        
        /* 设置串口为允许发送 */
        tx_enabled(port) = 1;
    
    err:
        spin_unlock_irqrestore(&port->lock, flags);
        return ret;
    }
    
    /* 关闭串口,在关闭驱动的设备文件时会调用该函数,释放串口中断 */
    static void gprs_uart_shutdown(struct uart_port *port)
    {
        rx_enabled(port) = 0;                /* 设置串口为不允许接收    */
        free_irq(RX_IRQ(port), port);        /* 释放接收中断    */
        tx_enabled(port) = 0;                /* 设置串口为不允许发送    */
        free_irq(TX_IRQ(port), port);        /* 释放发送中断    */
    }
    
    /* 设置串口参数 */
    static void gprs_uart_set_termios(struct uart_port *port,
                     struct ktermios *termios,
                     struct ktermios *old)
    {
        unsigned long flags;
        unsigned int baud, quot;
        unsigned int ulcon, ufcon = 0;
    
        /* 不支持moden控制信号线
         * HUPCL:    关闭时挂断moden
         * CMSPAR:    mark or space (stick) parity
         * CLOCAL:    忽略任何moden控制线
         */
        termios->c_cflag &= ~(HUPCL | CMSPAR);
        termios->c_cflag |= CLOCAL;
    
        /* 获取用户设置的串口波特率,并计算分频数(串口波特率除数quot) */
        baud = uart_get_baud_rate(port, termios, old, 0, 115200*8);
        if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
            quot = port->custom_divisor;
        else
            quot = port->uartclk / baud / 16 - 1;
    
        /* 设置数据字长 */
        switch (termios->c_cflag & CSIZE)
        {
        case CS5:
            ulcon = S3C2410_LCON_CS5;
            break;
        case CS6:
            ulcon = S3C2410_LCON_CS6;
            break;
        case CS7:
            ulcon = S3C2410_LCON_CS7;
            break;
        case CS8:
        default:
            ulcon = S3C2410_LCON_CS8;
            break;
        }
    
        /* 是否要求设置两个停止位(CSTOPB) */        
        if (termios->c_cflag & CSTOPB)
            ulcon |= S3C2410_LCON_STOPB;
    
        /* 是否使用奇偶检验 */
        if (termios->c_cflag & PARENB)
        {
            if (termios->c_cflag & PARODD)  /* 奇校验 */
                ulcon |= S3C2410_LCON_PODD;
            else                            /* 偶校验 */
                ulcon |= S3C2410_LCON_PEVEN;
        }
        else                                /* 无校验 */
        {
            ulcon |= S3C2410_LCON_PNONE;
        }
    
        if (port->fifosize > 1)
            ufcon |= S3C2410_UFCON_FIFOMODE | S3C2410_UFCON_RXTRIG8;
    
        spin_lock_irqsave(&port->lock, flags);
    
        /* 设置FIFO控制寄存器、线控制寄存器和波特率除数寄存器 */
        wr_regl(port, S3C2410_UFCON, ufcon);
        wr_regl(port, S3C2410_ULCON, ulcon);
        wr_regl(port, S3C2410_UBRDIV, quot);
    
        /* 更新串口FIFO的超时时限 */
        uart_update_timeout(port, termios->c_cflag, baud);
    
        /* 设置我们感兴趣的Rx error */
        port->read_status_mask = S3C2410_UERSTAT_OVERRUN;
        if (termios->c_iflag & INPCK)
            port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY;
    
        /* 设置我们忽略的Rx error */
        port->ignore_status_mask = 0;
        if (termios->c_iflag & IGNPAR)
            port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN;
        if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
            port->ignore_status_mask |= S3C2410_UERSTAT_FRAME;
    
        /* 若未设置CREAD(使用接收器),则忽略所有Rx error*/
        if ((termios->c_cflag & CREAD) == 0)
            port->ignore_status_mask |= RXSTAT_DUMMY_READ;
    
        spin_unlock_irqrestore(&port->lock, flags);
    }
    
    /* 获取串口类型 */
    static const char *gprs_uart_type(struct uart_port *port)
    {/* 返回描述串口类型的字符串指针 */
        return port->type == PORT_S3C2410 ? "gprs_uart:s3c2410_uart2" : NULL;
    }
    
    /* 申请串口一些必要的资源,如IO端口/IO内存资源,必要时还可以重新映射串口端口 */
    static int gprs_uart_request_port(struct uart_port *port)
    {
        struct resource *res;
        const char *name = to_platform_device(port->dev)->name;
    
        /* request_mem_region请求分配IO内存,从开始port->mapbase,大小MAP_SIZE
         * port->mapbase保存当前串口的寄存器基地址(物理)
         * uart2: 0x50008000
         */
        res = request_mem_region(port->mapbase, MAP_SIZE, name);
        if (res == NULL)
        {
            printk(KERN_ERR"request_mem_region error: %p\n", res);
            return -EBUSY;
        }
        
        return 0;
    }
    
    /* 释放串口已申请的IO端口/IO内存资源,必要时还需iounmap */
    static void gprs_uart_release_port(struct uart_port *port)
    {
        /* 释放已分配IO内存 */
        release_mem_region(port->mapbase, MAP_SIZE);
    }
    
    /* 执行串口所需的自动配置 */
    static void gprs_uart_config_port(struct uart_port *port, int flags)
    {    
        int retval;
    
        /* 请求串口 */
        retval = gprs_uart_request_port(port);
        /* 设置串口类型 */
        if (flags & UART_CONFIG_TYPE && retval == 0)
            port->type = PORT_S3C2410;
    }
    
    /* The UART operations structure */
    static struct uart_ops gprs_uart_ops = {
        .start_tx        = gprs_uart_start_tx,      /* Start transmitting */
        .stop_tx        = gprs_uart_stop_tx,        /* Stop transmission */
        .stop_rx        = gprs_uart_stop_rx,        /* Stop reception */
        .enable_ms        = gprs_uart_enable_ms,    /* Enable modem status signals */
        .tx_empty        = gprs_uart_tx_empty,      /* Transmitter busy? */
        .get_mctrl        = gprs_uart_get_mctrl,    /* Get modem control */
        .set_mctrl        = gprs_uart_set_mctrl,    /* Set modem control */
        .break_ctl        = gprs_uart_break_ctl,    /* Set break signal */
        .startup        = gprs_uart_startup,        /* App opens GPRS_UART */
        .shutdown        = gprs_uart_shutdown,      /* App closes GPRS_UART */
        .set_termios    = gprs_uart_set_termios,    /* Set termios */
        .type            = gprs_uart_type,          /* Get UART type */
        .request_port    = gprs_uart_request_port,  /* Claim resources associated with a GPRS_UART port */
        .release_port    = gprs_uart_release_port,  /* Release resources associated with a GPRS_UART port */
        .config_port    = gprs_uart_config_port,    /* Configure when driver adds a GPRS_UART port */
    };
    
    /* Uart driver for GPRS_UART */
    static struct uart_driver gprs_uart_driver = {
        .owner = THIS_MODULE,                /* Owner */
        .driver_name = DEV_NAME,             /* Driver name */
        .dev_name = DEV_NAME,                /* Device node name */
        .major = GPRS_UART_MAJOR,            /* Major number */
        .minor = GPRS_UART_MINOR,            /* Minor number start */
        .nr = 1,                             /* Number of UART ports */
    };
    
    /* Uart port for GPRS_UART port */
    static struct uart_port gprs_uart_port = {
            .irq        = IRQ_S3CUART_RX2,           /* IRQ */
            .fifosize    = GPRS_UART_FIFO_SIZE,      /* Size of the FIFO */
            .iotype        = UPIO_MEM,               /* IO memory */
            .flags        = UPF_BOOT_AUTOCONF,       /* UART port flag */
            .ops        = &gprs_uart_ops,            /* UART operations */
            .line        = 0,                        /* UART port number */
            .lock        = __SPIN_LOCK_UNLOCKED(gprs_uart_port.lock),
    };
    
    /* 初始化指定串口端口 */
    static int gprs_uart_init_port(struct uart_port *port, struct platform_device *platdev)
    {
        unsigned long flags;
        unsigned int gphcon;
        
        if (platdev == NULL)
            return -ENODEV;
    
        port->dev        = &platdev->dev;
    
        /* 设置串口波特率时钟频率 */
        port->uartclk    = clk_get_rate(clk_get(&platdev->dev, "pclk"));
    
        /* 设置串口的寄存器基地址(物理): 0x50008000 */
        port->mapbase    = S3C2410_PA_UART2;
        
        /* 设置当前串口的寄存器基地址(虚拟): 0xF5008000 */        
        port->membase    = S3C24XX_VA_UART + (S3C2410_PA_UART2 - S3C24XX_PA_UART);
    
        spin_lock_irqsave(&port->lock, flags);
    
        wr_regl(port, S3C2410_UCON, S3C2410_UCON_DEFAULT);
        wr_regl(port, S3C2410_ULCON, S3C2410_LCON_CS8 | S3C2410_LCON_PNONE);
        wr_regl(port, S3C2410_UFCON, S3C2410_UFCON_FIFOMODE
            | S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_RESETBOTH);
    
        /* 将I/O port H的gph6和gph7设置为TXD2和RXD2 */
        gphcon = readl(S3C2410_GPHCON);
        gphcon &= ~((0x5) << 12);
        writel(gphcon, S3C2410_GPHCON);
        
        spin_unlock_irqrestore(&port->lock, flags);
        
        return 0;
    }
    
    /* Platform driver probe */
    static int __init gprs_uart_probe(struct platform_device *dev)
    {
        int ret;
        
        /* 初始化串口 */
        ret = gprs_uart_init_port(&gprs_uart_port, dev);
        if (ret < 0)
        {
            printk(KERN_ERR"gprs_uart_probe: gprs_uart_init_port error: %d\n", ret);
            return ret;
        }    
    
        /* 添加串口 */
        ret = uart_add_one_port(&gprs_uart_driver, &gprs_uart_port);
        if (ret < 0)
        {
            printk(KERN_ERR"gprs_uart_probe: uart_add_one_port error: %d\n", ret);
            return ret;    
        }
    
        /* 将串口uart_port结构体保存在platform_device->dev->driver_data中 */
        platform_set_drvdata(dev, &gprs_uart_port);
    
        return 0;
    }
    
    /* Called when the platform driver is unregistered */
    static int gprs_uart_remove(struct platform_device *dev)
    {
        platform_set_drvdata(dev, NULL);
    
        /* 移除串口 */
        uart_remove_one_port(&gprs_uart_driver, &gprs_uart_port);
        return 0;
    }
    
    /* Suspend power management event */
    static int gprs_uart_suspend(struct platform_device *dev, pm_message_t state)
    {
        uart_suspend_port(&gprs_uart_driver, &gprs_uart_port);
        return 0;
    }
    
    /* Resume after a previous suspend */
    static int gprs_uart_resume(struct platform_device *dev)
    {
        uart_resume_port(&gprs_uart_driver, &gprs_uart_port);
        return 0;
    }
    
    /* Platform driver for GPRS_UART */
    static struct platform_driver gprs_plat_driver = {
        .probe = gprs_uart_probe,                /* Probe method */
        .remove = __exit_p(gprs_uart_remove),    /* Detach method */
        .suspend = gprs_uart_suspend,            /* Power suspend */
        .resume = gprs_uart_resume,              /* Resume after a suspend */
        .driver = {
            .owner    = THIS_MODULE,
            .name = DEV_NAME,                    /* Driver name */
        },
    };
    
    /* Platform device for GPRS_UART */
    struct platform_device *gprs_plat_device; 
    
    static int __init gprs_init_module(void)
    {
        int retval;
    
        /* Register uart_driver for GPRS_UART */
        retval = uart_register_driver(&gprs_uart_driver);
        if (0 != retval)
        {
            printk(KERN_ERR "gprs_init_module: can't register the GPRS_UART driver %d\n",retval);
            return retval;
        }
    
        /* Register platform device for GPRS_UART. Usually called
        during architecture-specific setup */
        gprs_plat_device = platform_device_register_simple(DEV_NAME, 0, NULL, 0);
        if (IS_ERR(gprs_plat_device)) 
        {
            retval = PTR_ERR(gprs_plat_device);
            printk(KERN_ERR "gprs_init_module: can't register platform device %d\n", retval);
            goto fail_reg_plat_dev;
        }
    
        /* Announce a matching driver for the platform
        devices registered above */
        retval = platform_driver_register(&gprs_plat_driver);
        if (0 != retval)
        {
            printk(KERN_ERR "gprs_init_module: can't register platform driver %d\n", retval);
            goto fail_reg_plat_drv;
        }
    
        return 0; /* succeed */
    
    fail_reg_plat_drv:
        platform_device_unregister(gprs_plat_device);
    fail_reg_plat_dev:
        uart_unregister_driver(&gprs_uart_driver);
        return retval;
    }
    
    static void __exit gprs_exit_module(void)
    {
        /* The order of unregistration is important. Unregistering the
        UART driver before the platform driver will crash the system */
    
        /* Unregister the platform driver */
        platform_driver_unregister(&gprs_plat_driver);
    
        /* Unregister the platform devices */
        platform_device_unregister(gprs_plat_device);
    
        /* Unregister the GPRS_UART driver */
        uart_unregister_driver(&gprs_uart_driver);
    }
    
    module_init(gprs_init_module);
    module_exit(gprs_exit_module);
    
    MODULE_AUTHOR("lingd");
    MODULE_LICENSE("Dual BSD/GPL");


    展开全文
  • Linux串口接收

    2013-01-05 11:38:30
    linux串口初始化以及数据解析的例子。
  • 09-14上周的时候,发了篇文章,关于linux串口的【当然程序师转别人的(还是发布在IBM开发者社区的嘞)】,虽然当时能跑的通,但这周在用的时候却发现不行了,于是决定仔细研究下linux下串口这东西!当然那个程序有...
  • 串口数据解析总结

    2018-03-27 19:21:00
    linux下编写串口通讯程序,采用select监听串口的可读事件,一旦可读,调用read。但是我们会发现,read一次得到的数据通常不是完整的一个数据帧。 比如完整数据帧为 但是实际上需要read多次才能完全读到。 ...
  • 1.首先应公司要求再 com 口本来使用 .net 由于 .net 适用 linux 太麻烦 改为...主要讲述linux 系统使用串口(windows 比 linux 更简单) 话不多说直接上代码 @RequestMapping(value = "/porttest",method ={Re...
  • 本文从一个简单例子 —— 51 单片机上的串口命令解析器程序出发,对比过程式与对象式思维差异,分享自己对 OO 的一点浅薄看法。本文是学习宋宝华老师的《C语言大型软件设计的面向对象》课程后的一些收获。前言传统...
  • 今天做USB的Gsensor程序发现读到的数据总是校验不过,无法进一步解析数据,而在Windows下通过工具读出来的数据均是正常的。 于是做出了串口读上来的数据有加过工的可能,因为该Sensor是以二进制形式进行数据上报的,...
  • Linux 串口编程之GPS

    千次阅读 2018-07-19 21:26:42
    此代码中涉及到串口初始化、串口操作的打开、关闭、读写,还涉及到GPS相关协议的解析,如接收到的GPS数据如何处理,如何发送数据到GPS模块等。协议采用的是SIM68VB NMEA协议。  1、 串口初始化代码如下:  此...
  • 解析串口-接收完整数据

    万次阅读 2016-05-23 16:48:35
    linux下编写串口通讯程序,采用select监听串口的可读事件,一旦可读,调用read。但是我们会发现,read一次得到的数据通常不是完整的一个数据帧。比如完整数据帧为但是实际上需要read多次才能完全读到。程序实际...
  • 前面的文章分析了串口的一些基本知识,在工业应用中,串口通信比较常用的协议就是Modbus RTU,freemodbus是一款微型... 我们知道Modbus通信的重点一方面是数据解析,另一方面就是串口的 不定长 数据接收,因为modb...
  • system("sttyerase^H);system("stty-F/dev/ttyS0-icrnl-ixon-ixoff-opost-isig-icanon-echo");//enterintonon-canonical(raw)mode这将是不充分的代码(以及每个POSIX约定的不良编码实践)将...C和Linux中最简单的方法...
  • linux操作系统下,运用串口通信,来实现GPS的接收与定位数据解析
  • Linux系统编程:串口编程Linux下的串口概述Linux串口编程代码解析编译和测试代码中的常量介绍 Linux下的串口概述 常见的数据通信的基本方式分为并行通信和串行通信。 1.并行通信:利用多条数据传输线将一个资料的...
  • void GasmeterManager::run() { std::string accrbuff; std::string accrstr;.../*优化方案:此处将串口每一句作为一个节点保存到链表中,另一个线程去以此取节点解析*/ pthread_setcancelstate(PTHREAD_CA
  • 本文系转载,著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。作者: 邵国际
  • Linux应用编程之串口

    2017-06-16 10:40:27
    数据能正常接收,也能正常解析,唯独不能长时间运行,也就是没有将数据处理好的问题,这由不得不温故一下串口通信的一些知识。比如串口的配置(配置信息的含义,也去做了相应的了解,解决这种隐形的
  • C——Linux下的串口编程

    万次阅读 多人点赞 2017-06-06 19:30:50
    在前篇也说到,我们将会自己写程序来对GPS数据进行解析,而这些数据正是靠串口来传输的。所以,本篇博文将进行关于串口通信的学习。一、串口接头首先我们得知道串口长什么样,常用的串口接头有两种,一种是9针串口...
  • linux下的I/O操作定义:在我看来,I/O是指数据流的操作,比如说网络编程的I/O操作,串口的读写等等可以称为I/O操作。在linux系统中一共有下面五种I/O操作模式。 阻塞I/O(blocking I/O) 非阻塞I/O (nonblocking I...
  • 字节流数据解析

    2019-12-26 13:43:49
    近期在做linux串口数据通讯时,发生了让人头疼的丢包,后分析解析代码发现一旦数据段中含有帧头便会解析不到数据,通过一上午的调试,写了一个新的解析。 #include <stdio.h> //帧头 长度 命令 数据 ...

空空如也

空空如也

1 2 3 4 5 6
收藏数 111
精华内容 44
关键字:

linux串口解析数据

linux 订阅