LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1261|回复: 4

linux下串口编程遇到的困难。

[复制链接]
发表于 2007-3-26 20:33:22 | 显示全部楼层 |阅读模式
最近要做个LINUX下串口控制的程序,对LINUX不熟悉,参看了Serial Programming HOWTO以后,在自己机子上实验了上面的程序,发现读不到数据,从网上DOWN了别人的代码还是读不到。一到读数据的时候就会阻塞。我是在WINXP下用的虚拟机虚拟REDHAT 9.0,因为只有一个串口,所以我是把2 3脚对接来做实验的。另外我有台56K的外猫,在WIN下可以被识别,但是到LINUX下我用minicom 设置了波特率,数据位长以后minicom 并没有显示OK,也没有MODEM的初始数据。LINUX下,串口是不是要被设置才能用?或者是因为别的什么错误,请指点一下。很急。
下面是Serial Programming HOWTO中的例子,里面的write是我加上去的,我机子上读不到数据。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>

#define BAUDRATE B38400      

// 定义您所需要的串口号
#define MODEMDEVICE "/dev/ttyS1"
#define _POSIX_SOURCE 1 /*POSIX compliant source POSIX系统兼容*/
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
main() {
int fd,c, res;
struct termios oldtio,newtio;
char buf[255];
int n;

开启设备用于读写,但是不要以控制 tty 的模式,因为我们并不希望在发送 Ctrl-C
后结束此进程
*/
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
if (fd <0) {perror(MODEMDEVICE); exit(-1); }
tcgetattr(fd,&oldtio);
           // 储存当前的串口设置
bzero(&newtio, sizeof(newtio));
                                      // 清空新的串口设置结构体
/*BAUDRATE: 设置串口的传输速率bps, 也可以使用 cfsetispeed 和 cfsetospeed 来设置
   CRTSCTS : 输出硬件流控(只能在具完整线路的缆线下工作,参考 Serial-HOWTO 第七节)
   CS8     : 8n1 (每一帧8比特数据,无奇偶校验位,1 比特停止位)
   CLOCAL  : 本地连接,无调制解调器控制
   CREAD   : 允许接收数据
*/
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
    /* IGNPAR  : 忽略奇偶校验出错的字节
       ICRNL   : 把 CR 映像成 NL (否则从其它机器传来的 CR 无法终止输入)或者就把设备设
        为 raw 状态(没有额外的输入处理)*/
newtio.c_iflag = IGNPAR | ICRNL;

/*
  Raw 模式输出
*/
newtio.c_oflag = 0;

/*
ICANON : 启动 标准输出, 关闭所有回显echo 功能,不向程序发送信号
*/
newtio.c_lflag = ICANON;

/*
初始化所有的控制字符, 默认值可以在 /usr/include/termios.h 找到,
并且做了注解,不过这里我们并不需要考虑这些
*/
newtio.c_cc[VINTR]    = 0;     /* Ctrl-c */
newtio.c_cc[VQUIT]    = 0;     /* Ctrl-\ */
newtio.c_cc[VERASE]   = 0;     /* del */
newtio.c_cc[VKILL]    = 0;     /* @ */
newtio.c_cc[VEOF]     = 4;     /* Ctrl-d */
newtio.c_cc[VTIME]    = 0;     /* inter-character timer unused */
                                /* 不使用字符间的计时器 */
newtio.c_cc[VMIN]     = 1;     /* blocking read until 1 character arrives */
                                   /* 阻塞,直到读取到一个字符 */
newtio.c_cc[VSWTC]    = 0;     /* ''''\0'''' */
newtio.c_cc[VSTART]   = 0;     /* Ctrl-q */
newtio.c_cc[VSTOP]    = 0;     /* Ctrl-s */
newtio.c_cc[VSUSP]    = 0;     /* Ctrl-z */
newtio.c_cc[VEOL]     = 0;     /* ''''\0'''' */
newtio.c_cc[VREPRINT] = 0;     /* Ctrl-r */
newtio.c_cc[VDISCARD] = 0;     /* Ctrl-u */
newtio.c_cc[VWERASE]  = 0;     /* Ctrl-w */
newtio.c_cc[VLNEXT]   = 0;     /* Ctrl-v */
newtio.c_cc[VEOL2]    = 0;     /* ''''\0'''' */

/*
清空数据线,启动新的串口设置
*/
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);

/*
终端设置完成,现在就可以处理数据了
在本程序中,在一行的开始输入一个 ''''z'''' 会终止该程序
*/
n = write(fd, "ABCD\r", 5);
if( n < 0 )
{
    printf("write failed");
    exit(-1);
}

while (STOP==FALSE) {     /*
         // 循环直到满足终止条件
     即使输入超过 255 个字节,读取的程序段还是会一直等到行结束符出现才会停止。
    如果读到的字符少于应刚获得的字符数,则剩下的字符串会在下一次读取时读到。
res 用来获得每次真正读到的字节数
*/
res = read(fd,buf,255);
buf[res]=0;                 // 设置字符串结束符,从而可以顺利使用 printf
printf(":%s:%d\n", buf, res);
if (buf[0]==''''z'''') STOP=TRUE;
}
/* restore the old port settings 恢复旧的串口设置 */
tcsetattr(fd,TCSANOW,&oldtio);
}
发表于 2007-3-27 10:11:18 | 显示全部楼层
我也遇到过这个问题
open(COM1, O_RDWR | O_NOCTTY |O_NONBLOCK )  //O_NONBLOCK非阻塞

newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
这一句好想不行,你把 BAUDRATE | 去掉,加
cfsetispeed(&newtio_new, B9600);
cfsetospeed(&newtio_new, B9600);
//B9600你看着改吧。。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-3-27 12:53:19 | 显示全部楼层
不行的,我试了,非阻塞顶多是不阻塞了,但数据一样是读不到。我看有人贴了贴子情况跟我好象差不多,说板子加载了终端控制程序把数据拿走了,OPEN里的NOCTTY作用不就是取消这个?还是我理解错了?
回复 支持 反对

使用道具 举报

发表于 2007-3-27 15:02:02 | 显示全部楼层
那你的板子上面有没有第2个串口呢,一般都留了针脚的,你查查板子的使用手册,把串口2引出来。。一串口又要当MINICOM,又要收发数据,我想还是容易冲突的。。具体的还等高手来回答。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-3-27 16:33:18 | 显示全部楼层
OK!问题终于解决了,就是虚拟机的原因,虚拟机中使用串口要自己添加硬件的,看了别人的贴子才知道的。我现在用的一个串口23脚对接,读得到数据了已经。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表