您的位置:首页 > 运维架构 > Linux

Linux 串口编程中遇到的问题

2010-09-17 11:35 525 查看
今年年初,工作闲暇之时在江西网上发布了做一些小程序的帖子,后面有一个公司老板跟我说有个项目:XXX需要用到串口编程,我那时一个是确实也有点忙,自己就只是抽了点空闲时间写了下linux的一个小串口程序,其实网上的大多程序都还是能用,我的就是稍微的改进了点,网上多数都只是能够设置串口的属性,然后读取这个串口上的消息并显示,我就改进了下,还可以自己手动输入...

现在就贴下代码了:

.h文件

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <signal.h>
#include <sys/select.h>

#define STA_IN 0

int openSerial(int port);
int setSerialAtr(int fd,long bitRate,int dataBit,int stopBit,char Parity);
int writeSerial(int fd,char *write_buf);

int writeSerial2(int fd,unsigned char *write_buf);
int readSerial(int fd,char *read_buf,int bufLen);
int closeSerial(int fd);

。cpp文件

#include "serial.h"

int openSerial(int port)
{
int fd;
char fileName[64] = {0};
sprintf(fileName,"/dev/ttyS%d",port);
#ifdef DEBUG
printf("%s %d fileName:%s/n",__FILE__,__LINE__,fileName);
#endif
if((fd = open(fileName,O_RDWR)) < 0)
{
perror("fopen error!");
return -1;
}
return fd;
}

int setSerialAtr(int fd,long bitRate,int dataBit,int stopBit,char Parity)
{
struct termios opt;

if(tcgetattr(fd,&opt) != 0)
{
perror("tcgetattr error!");
return -1;
}
//设置比特率
opt.c_oflag &= ~ONOCR;
opt.c_lflag &= ICANON;

switch(bitRate)
{
case 0:
cfsetispeed(&opt,B0);
cfsetospeed(&opt,B0);
break;
case 50:
cfsetispeed(&opt,B50);
cfsetospeed(&opt,B50);
break;
case 75:
cfsetispeed(&opt,B75);
cfsetospeed(&opt,B75);
break;
case 110:
cfsetispeed(&opt,B110);
cfsetospeed(&opt,B110);
break;
case 134:
cfsetispeed(&opt,B134);
cfsetospeed(&opt,B134);
break;
case 150:
cfsetispeed(&opt,B150);
cfsetospeed(&opt,B150);
break;
case 200:
cfsetispeed(&opt,B200);
cfsetospeed(&opt,B200);
break;
case 300:
cfsetispeed(&opt,B300);
cfsetospeed(&opt,B300);
break;
case 600:
cfsetispeed(&opt,B600);
cfsetospeed(&opt,B600);
break;
case 1200:
cfsetispeed(&opt,B1200);
cfsetospeed(&opt,B1200);
break;
case 1800:
cfsetispeed(&opt,B1800);
cfsetospeed(&opt,B1800);
break;
case 2400:
cfsetispeed(&opt,B2400);
cfsetospeed(&opt,B2400);
break;
case 4800:
cfsetispeed(&opt,B4800);
cfsetospeed(&opt,B4800);
break;
case 9600:
cfsetispeed(&opt,B9600);
cfsetospeed(&opt,B9600);
break;
case 19200:
cfsetispeed(&opt,B19200);
cfsetospeed(&opt,B19200);
break;
case 38400:
cfsetispeed(&opt,B38400);
//printf("38400/n");
cfsetospeed(&opt,B38400);
break;
case 57600:
cfsetispeed(&opt,B57600);
cfsetospeed(&opt,B57600);
break;
default:
printf("wafeaef");
break;
}
if(tcsetattr(fd,TCSANOW,&opt) != 0)
{
perror("tcsetattr error!");
return -1;
}
tcflush(fd, TCIOFLUSH);
//设置比特率结束

//设置数据位开始
opt.c_cflag &=~CSIZE;
switch(dataBit)
{
case 5:
opt.c_cflag |= CS5;
break;
case 6:
opt.c_cflag |= CS6;
break;
case 7:
opt.c_cflag |= CS7;
break;
case 8:
opt.c_cflag |= CS8;
break;
default:
perror("no support dataBit!");
return -1;
}
//设置数据位结束
tcflush(fd, TCIOFLUSH);
//设置停止位开始
switch (stopBit)
{
case 1:
opt.c_cflag &= ~CSTOPB;
break;
case 2:
opt.c_cflag |= CSTOPB;
break;
default:
fprintf(stderr,"Unsupported stop bits/n");
return -1;
}
//设置停止位结束
tcflush(fd, TCIOFLUSH);
//设置校验位
switch(Parity)
{
case 'n':
case 'N':
opt.c_cflag &= ~PARENB; /* Clear parity enable */
opt.c_iflag &= ~INPCK; /* Enable parity checking */
opt.c_iflag &= IGNCR; //忽略回车
opt.c_iflag &= INLCR;
// printf("set parity N ok!/n");
break;
case 'o':
case 'O':
opt.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/
opt.c_iflag |= INPCK; /* Disnable parity checking */
printf("set parity O ok!/n");
break;
case 'e':
case 'E':
opt.c_cflag |= PARENB; /* Enable parity */
opt.c_cflag &= ~PARODD; /* 转换为偶效验*/
opt.c_iflag |= INPCK; /* Disnable parity checking */
printf("set parity E ok!/n");
break;
case 's':
case 'S':
opt.c_cflag &= ~PARENB;
opt.c_cflag &= ~CSTOPB;
printf("set parity s ok!/n");
break;
default:
fprintf(stderr,"Unsupported parity/n");
return -1;
}
if (Parity != 'n')
opt.c_iflag |= INPCK;
tcflush(fd,TCIFLUSH);
opt.c_cc[VTIME] = 150; /* 设置超时15 seconds*/
opt.c_cc[VMIN] = 0; /* Update the options and do it NOW */
if (tcsetattr(fd,TCSANOW,&opt) != 0)
{
perror("SetupSerial 3");
return -1;
}
//设置结束
return 0;
}

int writeSerial(int fd,unsigned char *write_buf)
{
//int totalLen = strlen(write_buf);
int writeLen = 0;
if((writeLen = write(fd,write_buf,1)) < 0)
{
perror("write error!");
return -1;
}
//printf("%s %d %d %d/n",__FILE__,__LINE__,*write_buf,writeLen);
return 0;
}

int writeSerial2(int fd,unsigned char *write_buf)
{
int totalLen = strlen(write_buf);
int writeLen = 0;
if((writeLen = write(fd,write_buf,totalLen)) < 0)
{
perror("write error!");
return -1;
}
//printf("%s %d %d %d/n",__FILE__,__LINE__,*write_buf,writeLen);
return 0;
}

int readSerial(int fd,char *read_buf,int bufLen)
{
int readLen = 0;
if((readLen = read(fd,read_buf,bufLen-1)) <= 0)
{
perror("read error!");
return -1;
}
read_buf[readLen] = '/0';
return readLen;
}

int closeSerial(int fd)
{
close(fd);
}

unsigned char analyzeArgs(char *args)
{
unsigned char sub = 0;

if(2 != strlen(args))
{
return -1;
}
if((args[0] >= '0' && args[0] <= '9'))
{
sub += (args[0]-'0')*16;
}
else if(args[0] >= 'a' && args[0] <= 'f')
{
sub += (args[0] - 'a'+10)*16;
}
else if(args[0] >= 'A' && args[0] <= 'F')
{
sub += (args[0]-'A'+10)*16;
}
else
{
return -1;
}

if((args[1] >= '0' && args[1] <= '9'))
{
sub += args[1]-'0';
}
else if(args[1] >= 'a' && args[1] <= 'f')
{
sub += args[1] - 'a'+10;
}
else if(args[1] >= 'A' && args[1] <= 'F')
{
sub += args[1]-'A'+10;
}
else
{
return -1;
}
return sub;
}

int main(int argc,char* argv[])
{
int serialNum,databit,stopbit;
long int bitrate;
unsigned char parity;
int fd;
char read_buf[1024] = {0};
char write_buf[2] = {0};
char c = '/0';
unsigned char arg = 0;
int i = 2;

fd_set fds;
int retSelect;
struct timeval timeout;
if(argc < 2)
{
printf("useage:exec bitrate(比特率) args(需要写进串口的数据,类似00 1F bF等)/n");
return -1;
}
serialNum = 0;//打开/dev/stty0
bitrate = atol(argv[1]);//波特率
databit = 8;//数据位
stopbit = 1;//停止位
parity = 'n';//校验位

timeout.tv_sec = 2;
timeout.tv_usec = 0;

fd = openSerial(serialNum);
// printf("args:%d %d %d %d %c/n",fd,bitrate,databit,stopbit,parity);
if(setSerialAtr(fd,bitrate,databit,stopbit,parity) != 0)
{
printf("setSerialAtr error!/n");
return -1;
}

printf("wrtie data: ");
for(i = 2;i < argc;i++)
{
arg = analyzeArgs(argv[i]);
if(-1 != arg)
{
// sprintf(write_buf,"%02x",arg);
printf("%02x ",arg);
writeSerial(fd,&arg);
}
}
printf("/n");

while(1)
{
FD_ZERO(&fds);
FD_SET(STA_IN,&fds);
FD_SET(fd,&fds);
retSelect = select(fd+1,&fds,NULL,NULL,&timeout);
switch(retSelect)
{
case -1:
perror("select error!");
return -1;
case 0:
//printf("no data/n");
break;

default:
//printf("-----------/n");
if(FD_ISSET(STA_IN,&fds))
{
if(read(STA_IN,write_buf,256) > 0)
{
writeSerial2(fd,write_buf);
memset(write_buf,0,256);
//while((c=getchar())!='/n'&&c!=EOF);
//setbuf(STA_IN,NULL);
//fflush(STA_IN);
}
}
else if(FD_ISSET(fd,&fds))
{
if(readSerial(fd,read_buf,1024)> 0)
{
printf("%s",read_buf);
memset(read_buf,0,1024);
}
}
else
{
printf("error!!!!/n");
}
break;
}
}

closeSerial(fd);
}

makefile:

CC=gcc
export CFLAGS += -DDEBUG
all:serial

serial:serial.c serial.h
$(CC) $(CFLAGS) -o serial serial.c

clean:
rm -f serial.c.bak
rm -f serial.h.bak
rm -f Makefile.bak
rm -f core*
rm -f serial

程序就到此为止,这个我觉得写程序你可以写出来,问题是你要调试,你要保证你的程序是准确无误的,在虚拟机下有一个方法:通过添加一个串口,使用PC上的COM口,这样你就可以通过串口调试工具配合调试,用串口调试工具写(这个方法不行,串口不能被两个程序同时打开读写:虚拟机,串口调试工具;方法只有通过一个嵌入式设备接对应的COM口),你的虚拟机执行这个执行档接收写的数据,看看能不能正常接收,如果可以说明你的程序是正确的,这样你才可以放心使用。

今天我们的板子想不到就需要这样的一个小程序,对云台的485口进行测试,呵呵,正好用到,可是我拿来那个程序都忘了怎么用,想到了原来的调试方法但是始终没有输出,后面郁闷了半天终于想到虚拟机的串口没有连接上...好郁闷...
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: