折腾这个折腾了好几天的时间,功夫不负有心人,终于还是折腾出来了。关于串口的实现,涉及的比较多,不过也没有想象中的那么难。之所以折腾那么就,主要还是犯了一个很低级的出错,就是在读数据的时候老出错(写数据老早就可以了,幸庆自己还有那么一点完美主义)。一开是使用的是网上广泛流传的那个文件包叫“qextserialport-1.2win-alpha”,用到了里面的几个文件。 posix_qextserialport.h qextserialbase.h qetserialport.h 以及其对应的.cpp文件。 这些文件里面已经写好了对串口的初始化,打开,关闭,读写等等。可是我觉得内容太多,很多功能和我要实现的简单收发功能不相关。
在这里用到的关于串口的分别是:termios,tcgetattr,tcsetattr,tcsendbreak,tcdrain,tcflush,tcflow,cfmakeraw,
cfgetospeed,cfgetispeed,cfsetispeed,cfsetospeed。
分别对其进行分析:
其原型为:
int tcgetattr(int fd, struct termios *termios_p);
int tcsetattr(int fd, int optional_actions, struct termios *termios_p);
int tcsendbreak(int fd, int duration);
int tcdrain(int fd);
int tcflush(int fd, int queue_selector);
int tcflow(int fd, int action);
int cfmakeraw(struct termios *termios_p);
speed_t cfgetispeed(struct termios *termios_p);
speed_t cfgetospeed(struct termios *termios_p);
int cfsetispeed(struct termios *termios_p, speed_t speed);
int cfsetospeed(struct termios *termios_p, speed_t speed);
作用:
tcgetattr() 得到与 fd 指向的对象相关的参数,将它们保存于 termios_p 引用的 termios 结构中。函数可以从后台进程中调用;但是,终端属性可能被后来的前台进程所改变。
tcsetattr() 设置与终端相关的参数 (除非需要底层支持却无法满足)。
tcsendbreak() 传送连续的 0 值比特流,持续一段时间,如果终端使用异步串行数据传输的话。如果 duration 是 0,它至少传输 0.25 秒,不会超过 0.5 秒。如果 duration 非零,它发送的时间长度由实现定义。
如果终端并非使用异步串行数据传输,tcsendbreak() 什么都不做。
tcdrain() 等待直到所有写入 fd 引用的对象的输出都被传输。
tcflush() 丢弃要写入 引用的对象,但是尚未传输的数据,或者收到但是尚未读取的数据,取决于 queue_selector 的值:
刷新收到的数据但是不读 刷新写入的数据但是不传送 同时刷新收到的数据但是不读,并且刷新写入的数据但是不传送。
tcflow() 挂起 fd 引用的对象上的数据传输或接收,取决于 action 的值:
挂起输出 重新开始被挂起的输出 发送一个 STOP 字符,停止终端设备向系统传送数据 发送一个 START 字符,使终端设备向系统传输数据 。
cfmakeraw()设置终端属性,就是设置termios结构中的各个参数。
cfgetospeed() 返回 termios 结构中存储的输出波特率。
cfsetospeed() 设置 termios 结构中存储的输出波特率为 speed,必须是这样的格式“B115200”。
cfsetispeed() 设置 termios 结构中存储的输入波特率为 speed。如果输入波特率被设为0,实际输入波特率将等于输出波特率。
下面是我的程序:
fd_gps = ::open("/dev/ttySAC1", O_RDWR | O_NOCTTY | O_NONBLOCK); //打开串口1
if (fd_gps<0)
{
perror("open serial error!/n");
}
tcgetattr(fd_gps,&gps_opt); //初始化
bzero(&gps_opt, sizeof(gps_opt));
cfsetispeed(&gps_opt,B9600); //设置波特率 uartbiit[baud]
cfsetospeed(&gps_opt,B9600);
gps_opt.c_cflag |=(CLOCAL|CREAD);//忽略MODEM控制线,打开接受者
gps_opt.c_cflag &= ~CRTSCTS;
gps_opt.c_cflag &= ~CSIZE;
gps_opt.c_cflag |= CS8; //设置8数据位
gps_opt.c_cflag &= ~PARENB; //无奇偶校检
gps_opt.c_cflag &= ~CSTOPB;
//不是开发终端之类的,只是串口传输数据,而不需要串口来处理
gps_opt.c_oflag &= ~(OPOST); //选择原始数据输出
gps_opt.c_lflag &= ~(ICANON|ISIG|ECHO|ECHOE);//设置原始输入模式
gps_opt.c_iflag &= ~(INPCK|BRKINT|ICRNL|ISTRIP|IXON);
gps_opt.c_cc[VMIN] = 0; //指定了最少读取的字符数,如果设置为0,那么VTIME 就指定了读取每个字符的等待时间
gps_opt.c_cc[VTIME] = 0;
tcflush(fd_gps,TCIOFLUSH);//刷新
if (tcsetattr(fd_gps,TCSANOW,&gps_opt) != 0) //装载初始化参数
{
perror("Setup Serial Error!/n");
::close(fd_gps);
}
readgpstimer = new QTimer(this);
connect(readgpstimer,SIGNAL(timeout()),this,SLOT(readgpsCom()));
//关联定时器计满信号和相应的槽函数
readgpstimer->start(100);
//定时器开始计时,其中100表示100ms
}
void DriveInfo::open_gprscom()
{
fd_gprs = ::open("/dev/ttySAC2", O_RDWR | O_NOCTTY | O_NONBLOCK); //打开串口2
if (fd_gprs<0)
{
perror("open serial error!/n");
}
tcgetattr(fd_gprs,&gprs_opt); //初始化
bzero(&gprs_opt, sizeof(gprs_opt));//置字符串前sizeof个字为零
cfsetispeed(&gprs_opt,B115200); //设置波特率 uartbiit[baud]
cfsetospeed(&gprs_opt,B115200);
gprs_opt.c_cflag |=(CLOCAL|CREAD);//忽略MODEM控制线,打开接受者
gprs_opt.c_cflag &= ~CRTSCTS;
gprs_opt.c_cflag &= ~CSIZE;
gprs_opt.c_cflag |= CS8; //设置8数据位
gprs_opt.c_cflag &= ~PARENB; //无奇偶校检
gprs_opt.c_cflag &= ~CSTOPB;
//不是开发终端之类的,只是串口传输数据,而不需要串口来处理
gprs_opt.c_oflag &= ~(OPOST); //选择原始数据输出
gprs_opt.c_lflag &= ~(ICANON|ISIG|ECHO|ECHOE);//设置原始输入模式
gprs_opt.c_iflag &= ~(INPCK|BRKINT|ICRNL|ISTRIP|IXON);
gprs_opt.c_cc[VMIN] = 0; //指定了最少读取的字符数,如果设置为0,那么VTIME 就指定了读取每个字符的等待时间
gprs_opt.c_cc[VTIME] = 0;
tcflush(fd_gprs,TCIOFLUSH);//刷新
if (tcsetattr(fd_gprs,TCSANOW,&gprs_opt) != 0) //装载初始化参数
{
perror("Setup Serial Error! /n");
::close(fd_gprs);
}
readgprstimer = new QTimer(this);
connect(readgprstimer,SIGNAL(timeout()),this,SLOT(readgprsCom()));
//关联定时器计满信号和相应的槽函数
readgprstimer->start(100);
//定时器开始计时,其中100表示100ms
此程序在mini2440下正常收发数据。