本篇介绍了如何在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. HBase框架学习之路

    1 背景知识 1.1 解决问题 解决HDFS不支持单条记录的快速查找和更新的问题. 1.2 适用情况 存在亿万条记录的数据库,只有千万或者百万条记录使用RDBMS更加合适 确保你的应用不需要使用RDB ...

  2. MySQL用户管理

    主要总结MySQL进行用户管理的基本实现,包含MySQL登录,添加用户,删除用户,为用户分配权限,移除某用户的权限,修改密码,查看权限等基本操作,所有命令均亲测实现.本博文是本人的劳动成果所得,在博客 ...

  3. 从273二手车的M站点初探js模块化编程

    前言 这几天在看273M站点时被他们的页面交互方式所吸引,他们的首页是采用三次加载+分页的方式.也就说分为大分页和小分页两种交互.大分页就是通过分页按钮来操作,小分页是通过下拉(向下滑动)时异步加载数 ...

  4. C#基础回顾(一)—C#访问修饰符

    一.写在前面的话 好久没有停下来总结自己,转眼间15年过去好些天,回首过去的日子,亦或失去,亦或所得!生活的节奏,常常让我们带着急急忙忙的节奏去追赶,也许这并不是每个人所期望的生活方式!于他人,于自己 ...

  5. go语言注释

    Go语言注释实例代码教程 - Go支持C语言风格的/* */块注释,也支持C++风格的//行注释. 当然,行注释更通用,块注释主要用于针对包的详细说明或者屏蔽大块的代码. 每个包都应有一个包注解,即 ...

  6. ASP.NET Core 静态文件及JS包管理器(npm, Bower)的使用

    在 ASP.NET Core 中添加静态文件 虽然ASP.NET主要大都做着后端的事情,但前端的一些静态文件也是很重要的.在ASP.NET Core中要启用静态文件,需要Microsoft.AspNe ...

  7. .Net语言 APP开发平台——Smobiler学习日志:快速实现应用中的图片、声音等文件上传功能

    最前面的话:Smobiler是一个在VS环境中使用.Net语言来开发APP的开发平台,也许比Xamarin更方便 样式一 一.目标样式 我们要实现上图中的效果,需要如下的操作: 1.从工具栏上的&qu ...

  8. [Q&A] C1DataGrid 奇葩的 BeginNewRow() 方法

    一.前言 用户千千万,自然需求就千奇百怪都有,某天有人提了这样一个需求: 某个 C1DataGrid 在 ScrollViewer 的底部(使纵向滚动条显示出来),然后当该 C1DataGrid 增加 ...

  9. 【Java每日一题】20161227

    package Dec2016; public class Ques1227 { public static void main(String[] args){ } { c = 1; } int c ...

  10. Java全角、半角字符的关系以及转换

    如果搞明白了Java中全角字符和半角字符之间的关系,那他们之间的转换就不是个麻烦事儿.你只需要对这个关系有那么一个印象就足够了. 全角字符与半角字符的关系 通过下面的代码能看到Java中所有字符以及对 ...