Linux环境下2410开发板串口读写关键代码
今天偶然整理原来的项目开发文档,找到了曾经在2410开发板上做的串口读写程序的代码。
现在贴出来供大家参考。
#include <qtopia/qpeapplication.h>
/************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
/***********************************/
#include <pthread.h>
#include <qnamespace.h>
int argc;
char **argv;
int fd,rc,ii,ret;
char rbuf[8];
char wbuf[8]="12345";
/****************/
int file,size,len;
int tmp_id=0;
int id_count=0;//已经收到的ID,计数
/****************/
char *dev ="/dev/ttyS1"; //串口号 /dev/ttyS1 对应于串口1
int openport(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;
}
int setport(int fd, int baud,int databits,int stopbits,int parity)
{
int baudrate;
struct termios newtio;
switch(baud)
{
case 300:
baudrate=B300;
break;
case 600:
baudrate=B600;
break;
case 1200:
baudrate=B1200;
break;
case 2400:
baudrate=B2400;
break;
case 4800:
baudrate=B4800;
break;
case 9600:
baudrate=B9600;
break;
case 19200:
baudrate=B19200;
break;
case 38400:
baudrate=B38400;
break;
default :
baudrate=B9600;
break;
}
tcgetattr(fd,&newtio);
bzero(&newtio,sizeof(newtio));
//setting c_cflag
newtio.c_cflag &=~CSIZE;
switch (databits) /*设置数据位数*/
{
case 7:
newtio.c_cflag |= CS7; //7位数据位
break;
case 8:
newtio.c_cflag |= CS8; //8位数据位
break;
default:
newtio.c_cflag |= CS8;
break;
}
switch (parity) //设置校验
{
case 'n':
case 'N':
newtio.c_cflag &= ~PARENB; /* Clear parity enable */
newtio.c_iflag &= ~INPCK; /* Enable parity checking */
break;
case 'o':
case 'O':
newtio.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/
newtio.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'e':
case 'E':
newtio.c_cflag |= PARENB; /* Enable parity */
newtio.c_cflag &= ~PARODD; /* 转换为偶效验*/
newtio.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'S':
case 's': /*as no parity*/
newtio.c_cflag &= ~PARENB;
newtio.c_cflag &= ~CSTOPB;break;
default:
newtio.c_cflag &= ~PARENB; /* Clear parity enable */
newtio.c_iflag &= ~INPCK; /* Enable parity checking */
break;
}
switch (stopbits)//设置停止位
{
case 1:
newtio.c_cflag &= ~CSTOPB; //1
break;
case 2:
newtio.c_cflag |= CSTOPB; //2
break;
default:
newtio.c_cflag &= ~CSTOPB;
break;
}
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 0;
newtio.c_cflag |= (CLOCAL|CREAD);
newtio.c_oflag|=OPOST;
newtio.c_iflag &=~(IXON|IXOFF|IXANY);
cfsetispeed(&newtio,baudrate);
cfsetospeed(&newtio,baudrate);
tcflush(fd, TCIFLUSH);
if (tcsetattr(fd,TCSANOW,&newtio) != 0)
{
perror("SetupSerial 3");
return -1;
}
return 0;
}
int readport(int fd,char *buf,int len,int maxwaittime)//读数据,参数为串口,BUF,长度,超时时间
{
int no=0;int rc;int rcnum=len;
struct timeval tv;
fd_set readfd;
tv.tv_sec=maxwaittime/1000; //SECOND
tv.tv_usec=maxwaittime%1000*1000; //USECOND
FD_ZERO(&readfd);
FD_SET(fd,&readfd);
rc=select(fd+1,&readfd,NULL,NULL,&tv);
if(rc>0)
{
while(len)
{
rc=read(fd,&buf[no],1);
if(rc>0)
no=no+1;
len=len-1;
}
if(no!=rcnum)
return -1; //如果收到的长度与期望长度不一样,返回-1
return rcnum; //收到长度与期望长度一样,返回长度
}
else
{
return -1;
}
return -1;
}
void writeport(int fd,char *buf,int len) //发送数据
{
write(fd,buf,len);
}
void clearport(int fd) //如果出现数据与规约不符合,可以调用这个函数来刷新串口读写数据
{
tcflush(fd,TCIOFLUSH);
}
void *thread1(void *)
{
//线程 1
while(1)
{
rbuf[0]='\0';
/*超时太长,会丢失数据包,如果连续*/
rc=readport(fd,rbuf,5,50); //读取5个字节,超时时间为100,500毫秒
if(rc!=-1)
{
rbuf[5]='\0';
//writeport(fd,wbuf,rc);
writeport(fd,rbuf,rc); //把收到的数据 发回
printf("Rev id:%s\n",rbuf);
}
//else
//{
// printf("Lost recv:%d\t Lost Text:%s\n",rc,rbuf);
// writeport(fd,wbuf,rc);
//}
}
close(fd); //关闭串口
pthread_exit(0);
}
void *thread2(void *)
{
QPEApplication a( argc, argv );
HelloForm f(0,"yunfly",Qt::WStyle_Customize|Qt::WStyle_NoBorder);
a.showMainWidget( &f );
//int result=a.exec();
a.exec();
pthread_exit(0);
}
int main( int a_rgc, char *a_rgv[] )
{
argc=a_rgc;
argv=a_rgv;
/********************初始化串口*************************/
// for(ii=0;ii<256;ii++)wbuf[ii]=ii;
fd=openport(dev); //打开串口
if(fd>0){
ret=setport(fd,115200,8,1,'N'); //设置串口,波特率,数据位,停止位,校验
if(ret<0){
printf("Can't Set Serial Port!\n");
exit(0);
}
}
else
{
printf("Can't Open Serial Port!\n");
exit(0);
}
/*****************************************************/
pthread_t id1,id2;
int ret;
/*Create Thread 1: RS232 Serial */
ret=pthread_create(&id1,NULL,thread1,NULL);
if(ret!=0){
printf("Create pthread error!\n");
exit(1);
}
/*Create Thread 2:QT Window*/
ret=pthread_create(&id2,NULL,thread2,NULL);
if(ret!=0){
printf("Create pthread error!\n");
exit(1);
}
pthread_join(id1,NULL);
pthread_join(id2,NULL);
exit(0);
}
关键函数解释:
(1)串口打开函数
在Linux 下,设备都被看成是“文件”,因此打开一个串口,就是打开一个文件。
int fd= open(文件,文件读写方式)
例如:
开发板上的串口0是 /dev/ttyS0
开发板上的串口1是 /dev/ttyS1
同样,在PC机上的串口也是一样。
(2)串口设置函数
int setport(int fd, int baud,int databits,int stopbits,int parity)
该函数主要是设置串口波特率、校验码等
(3)查询法读取串口数据
maxwaittime为最大等待时间,也就是超时时间,buf为数据接收缓冲区
(4)串口数据写入函数
(5)线程函数
因为采用查询法获取串口数据,如果采用单线程的话,QT主界面将被阻塞了,无法操作。因此,这里设置了2个线程。一个线程启动QT界面,一个线程负责串口接收数据。
小结:
以上的办法不是最好的,只是实现起来相对简单。如果是做应用的话,建议采用串口中断读取数据。