linux串口调试

在第一次调试Linux串口驱动的时候,一定要保证与Linux串口通信的器件是没有问题可以使用的,然后我们再进行串口操作的学习,否则也许可能碰到问题的时候不知如何处理了。

好了,在保证硬件已经没有问题的情况下,我们开始学习串口驱动模块的使用。

PC上的串口不比嵌入式,你可以在了解了寄存器之后操作寄存器就可以实现串口的功能了。

PC都是基于操作系统的,操作系统在用户模式是不能随便操作硬件,只有用户将内核模块加载,让内核模块去操作硬件,在Linux下就是使用这样的方式操作模块的。

在Linux下目录/dev/ 下就是一些硬件的驱动模块,对应串口的是名称为ttyS(数字)的模块,比如ttyS0就是串口1(COM1),ttyS1就是串口2,以此类推。

Linux下对硬件的操作就像是对文件的操作一样,唯一的区别就是文件不是流操作,可以在文件内部来回移动,串口以及其他硬件都是流操作,读取过了的数据是没有办法恢复的。

在了解了这些之后,我们开始学习串口的访问函数。

首先我们从头文件开始:

#include <stdio.h> //标准输入输出定义
#include <string.h> //字符串功能定义
#include <unistd.h> //UNIX标准函数定义
#include <fctl.h>     //文件控制定义
#include <errno.h> //错误码定义
#include <termios.h> //POSIX终端控制定义

#include <stdlib.h> //exit函数
#include <sys/time.h> //时间函数
#include <sys/types.h> //pid_t 多线程
#include <sys/ioctl.h> //ioctl

以上就是我们串口调试所用到的所有头文件,当然很多头文件应该用不上,但是我们一次性包含进来,用的时候就不用那样的找了。

下面是串口的打开操作:

串口打开用 open 函数,具体为:
       fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
这个函数返回-1就表示打开错误,有可能是被占用。后门的标志位O_RDWR 表示读写,O_NOCTTY表示改程序不会成为此程序的控制终端,与O_NDELAY,表示不等的DCD信号,一直处于等待数据接收状态。

在打开成功后,在最后添加函数 fcntl(fd, F_SETFL, 0);表示执行read命令的时候,如果没有数据会阻塞进程。

串口关闭操作,
串口关闭使用close函数,
      close(fd); 即可关闭,没有返回值。

串口写数据使用write函数
write(fd,W_buf,n)

串口读操作使用read函数
len=read(fd,W_buf,n)

如果串口设置fcntl(fd,F_SETFL,FNDELAY);
read函数将不会阻塞,如果没有数据将会直接返回0

在我们知道如何操作串口之后,我们只能操作一个适合我们使用的串口,
串口属性的设置就是我们首先要解决的问题了。
1 波特率
2400        B2400
4800        B4800
9600        B9600
19200      B19200
38400      B38400
57600       B57600
115200    B115200

其中9600是默认波特率,用的比较多,ARM芯片使用的波特率比较高,是115200。

设置波特率使用函数cfsetispped和cfsetospeed设置输入波特率和输出波特率,一般情况下我们使用的输入和输出都是同一个波特率。

2 设置控制模式

设置流控制:
不使用流控制:termios_new.c_cflag &= ~CRTSCTS
使用硬件流控:termios_new.c_cflag |= CRTSCTS
使用软件流控:termios_new.c_iflag |= IXON | IXOFF | IXANY

设置字符大小:
termios_new.c_cflag &= ~CSIZE;
termios_new.c_cflag |= CS8;
termios_new.c_cflag |= CS7;
termios_new.c_cflag |= CS6;
termios_new.c_cflag |= C5;

设置奇偶校验:
无校验:termios_new.c_cflag &= ~PARENB;
奇校验:termios_new.c_cflag |= PARENB;
               termios_new.c_cflag &= ~PARODD;
偶校验:termios_new.c_cflag |= PARENB;
              termios_new.c_cflag |= PARODD;

以上就是串口通信的一些基础知识。

下面开始看程序:

MyCom.h
typedef struct
{
char prompt;   //prompt agter reciving data
int baudrate; //baudrate
char databit;   //data bits, 5 6 7 8
char debug;   //debug mode ,0:none,1:debug
char echo;    //echo mode ,0:none,1:echo
char fctl;    //flow control,0:none,1:hardware,2:software
char tty;    //tty:0,1,2,3,4,5,6,7
char parity;   //parity 0:none,1:odd,2:even
char stopbit;   //stop bits,1,2
const int reserved;
}portinfo_t;

typedef portinfo_t *pportinfo_t;

int PortOpen(pportinfo_t pportinfo);
int PortSet(int fdcom,const pportinfo_t pportinfo);
void PortClose(int fdcom);
int PortSend(int fdcom, char *data, int datalen);
int PortRecv(int fdcom, char *data, int datalen, int baudrate);

MyCom.c
/*
MyCom.c
*/

#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/times.h>
#include <sys/types.h>
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "MyCom.h"

#define TTY_DEV "/dev/ttyS"

#define TIMEOUT_SEC(buflen,baud) (buflen*20/baud+2)
#define TIMEOUT_USEC 0

char *get_ptty(pportinfo_t pportinfo)
{
char *ptty;
switch(pportinfo->tty)
{
   case '0':
   {
    ptty=TTY_DEV"0";
   }break;

   case '1':
   {
    ptty=TTY_DEV"1";
   }break;
  
   case '2':
   {
    ptty=TTY_DEV"2";
   }break;
}
return ptty;
}

int convbaud(unsigned long int baudrate)
{
switch(baudrate)
{
   case 2400:
    return B2400;
   case 4800:
    return B4800;
   case 9600:
    return B9600;
   case 19200:
    return B19200;
   case 38400:
    return B38400;
   case 57600:
    return B57600;
   case 115200:
    return B115200;
   default:
    return B9600;
}
}

int PortSet(int fdcom, const pportinfo_t pportinfo)
{
struct termios termios_old, termios_new;
int baudrate,tmp;
char databit, stopbit, parity, fctl;

bzero(&termios_old,sizeof(termios_old));
bzero(&termios_new,sizeof(termios_new));
cfmakeraw(&termios_new);
tcgetattr(fdcom, &termios_old);

baudrate = convbaud(pportinfo->baudrate);
cfsetispeed(&termios_new,baudrate);
cfsetispeed(&termios_new,baudrate);
termios_new.c_cflag |= CLOCAL;
termios_new.c_cflag |= CREAD;

fctl = pportinfo->fctl;

switch(fctl)
{
   case '0':
    termios_new.c_cflag &= ~CRTSCTS;
   break;
   case '1':
    termios_new.c_cflag |= CRTSCTS;
   break;
   case '2':
    termios_new.c_iflag |= IXON | IXOFF | IXANY;
   break;
}

termios_new.c_cflag &= ~CSIZE;
databit = pportinfo->databit;
switch(databit)
{
   case '5':
    termios_new.c_cflag |= CS5;
    break;
   case '6':
    termios_new.c_cflag |= CS6;
    break;
   case '7':
    termios_new.c_cflag |= CS7;
    break;
   default:
    termios_new.c_cflag |= CS8;
    break;
}

parity = pportinfo->parity;
switch(parity)
{
   case '0':
    termios_new.c_cflag &= ~PARENB;
   break;
   case '1':
    termios_new.c_cflag |= PARENB;
    termios_new.c_cflag &= ~PARODD;
   break;
   case '2':
    termios_new.c_cflag |= PARENB;
    termios_new.c_cflag |= PARODD;
   break;
}

stopbit = pportinfo->stopbit;
if(stopbit == '2')
{
   termios_new.c_cflag |= CSTOPB;
}
else
{
   termios_new.c_cflag &= ~CSTOPB;
}

termios_new.c_oflag &= ~OPOST;
termios_new.c_cc[VMIN] = 1;
termios_new.c_cc[VTIME] = 1;

tcflush(fdcom, TCIFLUSH);
tmp = tcsetattr(fdcom, TCSANOW, &termios_new);
tcgetattr(fdcom, &termios_old);
return tmp;
}

int PortOpen(pportinfo_t pportinfo)
{
int fdcom;
char *ptty;

ptty = get_ptty(pportinfo);
//fdcom = open(ptty,O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY);
fdcom = open(ptty, O_RDWR | O_NOCTTY | O_NONBLOCK);
return fdcom;

}

void PortClose(int fdcom)
{
close(fdcom);
}

int PortSend(int fdcom, char *data, int datalen)
{
int len=0;
len = write(fdcom, data, datalen);
if(len == datalen)
{
   return len;
}
else
{
   tcflush(fdcom, TCOFLUSH);
   return -1;
}
}

int PortRecv(int fdcom, char *data, int datalen, int baudrate)
{
int readlen, fs_sel;
fd_set fs_read;
struct timeval tv_timeout;

FD_ZERO(&fs_read);
FD_SET(fdcom, &fs_read);
tv_timeout.tv_sec = TIMEOUT_SEC(datalen, baudrate);
tv_timeout.tv_usec = TIMEOUT_USEC;

fs_sel = select(fdcom+1, &fs_read, NULL, NULL, &tv_timeout);
if(fs_sel)
{
   readlen = read(fdcom, data, datalen);
   return readlen;
}
else
{
   return 1;
}
}

主函数:

int main(int argc, char *argv[])
{
int fdcom, i, SendLen, RecvLen;
struct termios termios_cur;
char RecvBuf[11];
RecvBuf[10]=0;
char *str = "1234567890";
portinfo_t portinfo =
{
'0',
115200,
'8',
'0',
'0',
'2',
'0',
'0',
'1',
0
};
if(argc != 2)
{
   printf("Usage:<type 0 -- send 1 -- receive>\n");
   printf("    eg:");
   printf("     MyPort0");
   exit(-1);
}
fdcom = PortOpen(&portinfo);
if(fdcom<0)
{
   printf("Error\n");
   exit(1);
}

PortSet(fdcom, &portinfo);

if(atoi(argv[1])==0)
{
   for(i=0;i<100;i++)
   {
    SendLen = PortSend(fdcom,str+i%10,1);
    if(SendLen>0)
    {
     printf("No %d send %d data %c.\n",i,SendLen,str[i%10]);
    }
    else
    {
     printf("ERROR:Send failed.\n");
    }
    sleep(1);
   }
   PortClose(fdcom);
}
else
{
   for(;;)
   {
    RecvLen = PortRecv(fdcom, RecvBuf, 10, portinfo.baudrate);
    if(RecvLen>0)
    {
     //for(i=0;i<RecvLen;i++)
     //{
     // printf("Receive data No %d is %x:%c.\n",i,RecvBuf[i],RecvBuf[i]);
     //}
    
     printf("%s\nTotal frame length is %d.\n",RecvBuf,RecvLen);
    }
    else
    {
     printf("Error:receive error.\n");
    }
    sleep(2);
   }
}

return 0;
}


阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭