本篇介绍了如何在linux系统下向串口发送数据。包括read的阻塞和非阻塞。以及select方法。

打开串口

在Linux系统下,打开串口是通过使用标准的文件打开函数操作的。

#include <fcntl.h>

/* 以读写的方式打开 */

int fd = open( "/dev/ttyUSB0",O_RDWR);  

设置串口

所有对串口的操作都是通过结构体 struct termios 和 几个函数实现的。

tcgetattr          //获取属性
tcsetattr   //设置属性
cfgetispeed    //得到输入速度
cfsetispeed    //设置输入速度
cfgetospeed    //得到输出速度
cfsetospedd    //设置输出速度
tcdrain //等待所有输出都被传输
tcflow //挂起传输或接收
tcflush //刷清未决输入和输出
tcsendbreak    //送break字符
tcgetpgrp   //得到前台进程组ID
tcsetpgrp   //设置前台进程组ID
tcgetattr( 0,&oldstdio);  //获取默认的配置选项 存储到oldstdio结构体中
tcgetattr( fd,&oldstdio);  //获取当前配置选项 存储到oldstdio结构体中
tcsetattr( fd,TCSANOW,&oldstdio);  //TCSANOW 修改立即生效
cfgetispeed( &oldstdio);      //得到波特率
cfsetispeed(&oldstdio, B115200 )    //设置波特率为115200
即可使用read或open来操作串口的发送与接收。  

测试代码:
#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <string.h> int serial_send( int fd, char *Data ); int main()
{
int fd;
int num;
struct termios oldstdio; fd = open("/dev/ttyUSB0", O_RDWR );
if( -==fd )
{
printf("cannot open /dev/ttyUSB0\r\n");
return -;
}
tcgetattr( fd, &oldstdio);
cfsetispeed(&oldstdio, B115200);
tcsetattr( fd, TCSANOW, &oldstdio);
tcflush( fd, TCIFLUSH ); num = serial_send( fd,"Serial BAUND is default \r\n" ); close(fd);
return ;
} int serial_send( int fd, char *Data )
{
int string_num;
string_num = strlen(Data);
return write( fd,Data, string_num );
}

在没有数据读取的时候,执行read函数会发生阻塞,执行下面的程序,在串口接收端没有数据时,返回0,并不会发生阻塞。

#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h> const char *Serial_Dev = "/dev/ttyUSB0"; typedef struct {
char R_flag;
char W_flag;
int len;
char Data[];
}Serial; typedef struct {
int Forward;
int left;
int rotate;
unsigned char Check;
char Enter[];
}Vehicle; Vehicle Serial_Tx = {,,,,{"\r\n"}};
Serial Serial_D = {,,,{}};
int S_fd; int wait_flag = ; int serial_send( int fd, char *Data );
int set_opt(int fd,int nSpeed,int nBits,char nEvent,int nStop); void * Pthread_Serial( void *arg )
{
int n=;
int ret;
struct termios oldstdio;
char Rx_Data[];
char Tx_Data[]={}; S_fd = open( Serial_Dev, O_RDWR|O_NOCTTY );
if( -==S_fd )
pthread_exit(NULL); ret = set_opt(S_fd,,,'N',);
if(ret == -)
{
pthread_exit(NULL);
} while()
{
ret = read( S_fd, Rx_Data, );
if( ret > )
{
Serial_D.len = ret;
memset( Serial_D.Data, , Serial_D.len+ );
memcpy( Serial_D.Data, Rx_Data, Serial_D.len );
printf("%s",Serial_D.Data);
}
else
{
usleep();
sprintf( Tx_Data,"send %d\r\n", n++ );
serial_send( S_fd, Tx_Data );
//printf("send ok%d\r\n",n++);
}
}
pthread_exit(NULL);
} int main()
{
pthread_t pthread_id; //Create a thread
pthread_create( &pthread_id, NULL, &Pthread_Serial, NULL );
usleep(); if( -==S_fd )
{
printf("error: cannot open serial dev\r\n");
return -;
} while()
{
usleep(); } return ;
} int serial_send( int fd, char *Data )
{
int string_num;
string_num = strlen(Data);
return write( S_fd,Data, string_num );
} int set_opt(int fd,int nSpeed,int nBits,char nEvent,int nStop)
{
struct termios newtio,oldtio;
if(tcgetattr(fd,&oldtio)!=)
{
perror("error:SetupSerial 3\n");
return -;
}
bzero(&newtio,sizeof(newtio));
//使能串口接收
newtio.c_cflag |= CLOCAL | CREAD;
newtio.c_cflag &= ~CSIZE; newtio.c_lflag &=~ICANON;//原始模式 //newtio.c_lflag |=ICANON; //标准模式 //设置串口数据位
switch(nBits)
{
case :
newtio.c_cflag |= CS7;
break;
case :
newtio.c_cflag |=CS8;
break;
}
//设置奇偶校验位
switch(nEvent) {
case 'O':
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);
break;
case 'E':
newtio.c_iflag |= (INPCK | ISTRIP);
newtio.c_cflag |= PARENB;
newtio.c_cflag &= ~PARODD;
break;
case 'N':
newtio.c_cflag &=~PARENB;
break;
}
//设置串口波特率
switch(nSpeed)
{
case :
cfsetispeed(&newtio,B2400);
cfsetospeed(&newtio,B2400);
break;
case :
cfsetispeed(&newtio,B4800);
cfsetospeed(&newtio,B4800);
break;
case :
cfsetispeed(&newtio,B9600);
cfsetospeed(&newtio,B9600);
break;
case :
cfsetispeed(&newtio,B115200);
cfsetospeed(&newtio,B115200);
break;
case :
cfsetispeed(&newtio,B460800);
cfsetospeed(&newtio,B460800);
break;
default:
cfsetispeed(&newtio,B9600);
cfsetospeed(&newtio,B9600);
break;
}
//设置停止位
if(nStop == )
newtio.c_cflag &= ~CSTOPB;
else if(nStop == )
newtio.c_cflag |= CSTOPB;
newtio.c_cc[VTIME] = ;
newtio.c_cc[VMIN] = ;
tcflush(fd,TCIFLUSH); if(tcsetattr(fd,TCSANOW,&newtio)!=)
{
perror("com set error\n");
return -;
}
return ;
}

可以使用select函数来判断有没有接收到数据。

int read_datas_tty(int fd,char *rcv_buf,int sec,int usec)
{
int retval;
unsigned char tempchar2;
fd_set rfds;
struct timeval tv;
int ret,pos; tv.tv_sec = sec;//set the rcv wait time
tv.tv_usec = usec;//100000us = 0.1s while()
{
FD_ZERO(&rfds);
FD_SET(fd,&rfds);
retval = select(fd+,&rfds,NULL,NULL,&tv);
if(retval ==-)
{
printf("select error\r\n");
break;
}
else if(retval)
{
ret= read(fd,rcv_buf,);
tempchar2 = rcv_buf;
printf("rcv_buf is %s\n",rcv_buf); }
else
{
break;
}
}
return ;
}

将上面的函数放到read前面调用即可。

下面是我用在小车上的代码:

#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include "serial.h" const char *Serial_Dev = "/dev/ttyUSB0"; typedef struct {
int Forward;
int left;
int rotate;
unsigned char status;
unsigned char Check;
char Enter[];
}Vehicle; typedef struct {
int fd;
int sec;
int usec;
Vehicle* Veh;
}Uart; Vehicle Motor = {,,,,,{'\r','\n','\0'}};
Uart serial_usb={ -,,,NULL};; void * Pthread_Serial_Rx( void *arg )
{
int fd;
int retval;
struct timeval tv;
fd_set rfds;
Uart *ser = (Uart *)arg;
char Rx_data[];
int len;
int Num=; fd = ser->fd;
tv.tv_sec = ser->sec;
tv.tv_usec = ser->usec; while()
{
FD_ZERO(&rfds);
FD_SET( fd,&rfds );
retval = select(fd+,&rfds,NULL,NULL,&tv);
if( retval == - )
{
printf("error\r\n");
break;
}
else if( retval)
{
len = read(fd,Rx_data,);
// printf("read %d\r\n",len);
if( (len == )&&( Rx_data[] == 'S' ) )
{
if( Rx_data[] == '' )
ser->Veh->status = ;
else
ser->Veh->status = ;
Num=;
}
}
else
{
usleep();
Num++;
} if( Num>)
{
ser->Veh->status = ;
Num=;
}
}
pthread_exit(NULL); } void * Pthread_Serial( void *arg )
{
int n=;
int fd;
pthread_t pthread_id; fd = open( Serial_Dev, O_RDWR|O_NOCTTY );
if( -==fd )
pthread_exit(NULL); if( set_opt(fd,,,'N',)== -)
{
pthread_exit(NULL);
}
serial_usb.fd = fd;
serial_usb.sec = ;
serial_usb.usec = ;
serial_usb.Veh = &Motor; pthread_create( &pthread_id, NULL, &Pthread_Serial_Rx, ( void *)&serial_usb ); while( ==pthread_kill(pthread_id,) )
{
if(Motor.status)
{
Motor.Forward = ;
Motor.left = ;
Motor.rotate = ;
Motor.Check = (unsigned char)(Motor.Forward + Motor.left + Motor.rotate);
write( fd, &Motor, );
//serial_send( fd, "this is ok\r\n" );
} usleep();
} printf("receive thread is quited\r\n");
pthread_exit(NULL);
} int main()
{
pthread_t pthread_id; //Create a thread
pthread_create( &pthread_id, NULL, &Pthread_Serial, NULL );
usleep(); if( != pthread_kill(pthread_id,))
{
printf("error: cannot open serial dev\r\n");
return -;
}
printf("%d\r\n",sizeof(Vehicle));
//serial_send( serial_usb.fd, "this is ok\r\n" ); while( ==pthread_kill(pthread_id,) )
{
usleep();
if( Motor.status )
printf("The device is online %d\r\n",Motor.status);
else
printf("The device is offline\r\n");
}
printf("serial thread is quited\r\n");
return ;
}

sd

Linux下的串口编程及非阻塞模式的更多相关文章

  1. Linux下的串口编程实例

    //串口相关的头文件  #include<stdio.h>      /*标准输入输出定义*/  #include<stdlib.h>     /*标准函数库定义*/  #in ...

  2. Linux下的串口编程(转)

    https://blog.csdn.net/tigerjibo/article/details/6179291 #include<stdio.h> /*标准输入输出定义*/ #includ ...

  3. Linux下的C编程实战

    Linux下的C编程实战(一) ――开发平台搭建 1.引言 Linux操作系统在服务器领域的应用和普及已经有较长的历史,这源于它的开源特点以及其超越Windows的安全性和稳定性.而近年来, Linu ...

  4. 详解linux下的串口通讯开发

    串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用.常用的串口是RS-232-C接口(又称EIA RS-232-C)它是在1970年由美国电子工业协会(EIA)联合贝尔系统.调制解调 ...

  5. 【转载】详解linux下的串口通讯开发

    来源:https://www.cnblogs.com/sunyubo/archive/2010/09/26/2282116.html 串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使 ...

  6. socket异步通信-如何设置成非阻塞模式、非阻塞模式下判断connect成功(失败)、判断recv/recvfrom成功(失败)、判断send/sendto

    socket异步通信-如何设置成非阻塞模式.非阻塞模式下判断connect成功(失败).判断recv/recvfrom成功(失败).判断send/sendto 博客分类: Linux Socket s ...

  7. 使用命名管道的OVERLAPPED方式实现非阻塞模式编程 .

    命令管道是进程间通讯的一种常用方式,对于命令管道的介绍可以参考别的资料和书籍,这里推荐一个<VC++下命名管道编程的原理及实现>这篇博文,写得比较清楚.但是都是介绍了阻塞模式的编程,我这里 ...

  8. 服务器编程心得(四)—— 如何将socket设置为非阻塞模式

    1. windows平台上无论利用socket()函数还是WSASocket()函数创建的socket都是阻塞模式的: SOCKET WSAAPI socket( _In_ int af, _In_ ...

  9. Linux下TCP网络编程与基于Windows下C#socket编程间通信

    一.linux下TCP网络编程基础,需要了解相关函数 Socket():用于套接字初始化. Bind():将 socket 与本机上的一个端口绑定,就可以在该端口监听服务请求. Listen():使s ...

随机推荐

  1. SQL Server-简单查询示例(十一)

    前言 本节我们讲讲一些简单查询语句示例以及需要注意的地方,简短的内容,深入的理解,Always to review the basics. EOMONTH 在SQL Server 2012的教程示例中 ...

  2. Hawk 4.3 转换器

    转换器是最为常用的一种类型,当然它的使用也是最复杂的. 转换器有三种子类型: A:单文档->单文档:例如仅将某一列的字符提取出来 B:单文档->多文档:典型的如从爬虫转换,每一行url都可 ...

  3. ERROR 1010 (HY000): Error dropping database (can't rmdir './test/', errno: 17)

    在删除数据库的时候报标题所示错误 mysql> drop database test; ERROR (HY000): Error dropping database (can't rmdir ' ...

  4. JQuery中的工具函数总结

    前提引入 前提当然也是要引入Jquery啦... <script src="http://libs.baidu.com/jquery/1.9.0/jquery.js" typ ...

  5. JQuery中ajax的相关方法总结

    前提条件 话说是jquery中的ajax方法,那么前提条件当然是引入jquery啦. <script src="http://libs.baidu.com/jquery/1.9.0/j ...

  6. 【转】基于linux下的dm9000网卡移植全分析

    转自:http://blog.sina.com.cn/s/blog_6abf2c04010189ui.html DM9000可以直接与ISA总线相连,也可以与大多数CPU直接相连.Mini2440采用 ...

  7. 如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源

    1.前言 关于微信内部正在使用的网络层封装库Mars开源的消息,1个多月前就已满天飞(参见<微信Mars:微信内部正在使用的网络层封装库,即将开源>),不过微信团队没有失约,微信Mars ...

  8. IL初步了解

    一.概述: 近来也是在看AOP方面的东西,了解到Emit可以实现.之前对Emit的了解也就是停留在Reflector针对方法反编译出来的部分指令.就用这次机会学习下Emit也用这篇随笔记录下学习的过程 ...

  9. WinForm构造函数的作用

    最近练习C#项目:何问起收藏夹(HoverTreeSCJ),实现编辑网址时,遇到这个问题:比如打开窗口后,要自动显示数据.解决方法:那么可以通过窗体的构造函数传递参数. 比如窗体类: public p ...

  10. ASP.NET从MVC5升级到MVC6 RC2 总目录 - 发布在RC2Release之后

    序言 随着MVC6RC2的推出,MVC6的脚步越来越近了.但是在我们的手里,有大批量的MVC5的项目.如何将MVC5升级到MVC6,将是一个很大的课题.微软官方暂时没有一个升级指导,或者一个迁移工具, ...