串口编程.Linux串口编程
http://leiweni1972.blog.163.com/blog/static/16897128220107270328884/ 在第一次调试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
,RecvBuf);
//}
printf("%s\nTotal frame length is %d.\n",RecvBuf,RecvLen);
}
else
{
printf("Error:receive error.\n");
}
sleep(2);
}
}
return 0;
}
文章评论(0条评论)
登录后参与讨论