Linux下的串口编程及非阻塞模式
本篇介绍了如何在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下的串口编程及非阻塞模式的更多相关文章
- Linux下的串口编程实例
//串口相关的头文件 #include<stdio.h> /*标准输入输出定义*/ #include<stdlib.h> /*标准函数库定义*/ #in ...
- Linux下的串口编程(转)
https://blog.csdn.net/tigerjibo/article/details/6179291 #include<stdio.h> /*标准输入输出定义*/ #includ ...
- Linux下的C编程实战
Linux下的C编程实战(一) ――开发平台搭建 1.引言 Linux操作系统在服务器领域的应用和普及已经有较长的历史,这源于它的开源特点以及其超越Windows的安全性和稳定性.而近年来, Linu ...
- 详解linux下的串口通讯开发
串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用.常用的串口是RS-232-C接口(又称EIA RS-232-C)它是在1970年由美国电子工业协会(EIA)联合贝尔系统.调制解调 ...
- 【转载】详解linux下的串口通讯开发
来源:https://www.cnblogs.com/sunyubo/archive/2010/09/26/2282116.html 串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使 ...
- socket异步通信-如何设置成非阻塞模式、非阻塞模式下判断connect成功(失败)、判断recv/recvfrom成功(失败)、判断send/sendto
socket异步通信-如何设置成非阻塞模式.非阻塞模式下判断connect成功(失败).判断recv/recvfrom成功(失败).判断send/sendto 博客分类: Linux Socket s ...
- 使用命名管道的OVERLAPPED方式实现非阻塞模式编程 .
命令管道是进程间通讯的一种常用方式,对于命令管道的介绍可以参考别的资料和书籍,这里推荐一个<VC++下命名管道编程的原理及实现>这篇博文,写得比较清楚.但是都是介绍了阻塞模式的编程,我这里 ...
- 服务器编程心得(四)—— 如何将socket设置为非阻塞模式
1. windows平台上无论利用socket()函数还是WSASocket()函数创建的socket都是阻塞模式的: SOCKET WSAAPI socket( _In_ int af, _In_ ...
- Linux下TCP网络编程与基于Windows下C#socket编程间通信
一.linux下TCP网络编程基础,需要了解相关函数 Socket():用于套接字初始化. Bind():将 socket 与本机上的一个端口绑定,就可以在该端口监听服务请求. Listen():使s ...
随机推荐
- web api添加拦截器
实现思路 1.标识控制器有拦截特性: 2.控制器拦截处理: 代码实现 1.标识控制器有拦截特性,代码: [MyFilter] public string PostFindUser([FromBody] ...
- MyCat源码分析系列之——BufferPool与缓存机制
更多MyCat源码分析,请戳MyCat源码分析系列 BufferPool MyCat的缓冲区采用的是java.nio.ByteBuffer,由BufferPool类统一管理,相关的设置在SystemC ...
- Netty简介
Netty简介 Netty是由JBOSS提供的一个Java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客户端程序.和传统BIO不同,NI ...
- DotNet 资源大全
awesome-dotnet 是由 quozd 发起和维护.内容包括:编译器.压缩.应用框架.应用模板.加密.数据库.反编译.IDE.日志.风格指南等. https://github.com/jobb ...
- C#开发微信门户及应用(17)-微信企业号的通讯录管理开发之部门管理
前面一篇随笔企业号的一些基础信息,以及介绍如何配置企业号的回调方式实现和企业号服务器进行沟通的桥梁.本篇主要还是继续介绍企业号的开发工作的开展,介绍微信企业号通讯录管理开发功能,介绍其中组织机构里面如 ...
- C#开发微信门户及应用(7)-微信多客服功能及开发集成
最近一直在弄微信的集成功能开发,发现微信给认证账户开通了一个多客服的功能,对于客户的咨询,可以切换至客服处理的方式,而且可以添加多个客服进行处理,这个在客户咨询比较多的时候,是一个不错的营销功能.微信 ...
- 解析ListView联动的实现--仿饿了么点餐界面
一.博客的由来 大神王丰蛋哥 之前一篇博客仿饿了点餐界面2个ListView联动(http://www.cnblogs.com/wangfengdange/p/5886064.html) 主要实现了2 ...
- 【工匠大道】 svn命令自己总结
本文地址 分享提纲: 1. svn 不常见单有用的命令 2. svn查看切换用户 1. svn自己总结的一些不常见,但有用的命令 1)[导出svn不带版本代码]导出不带svn版本控制的代码到本地 ...
- 《连载 | 物联网框架ServerSuperIO教程》- 11.实现设备(驱动)与设备(驱动)交互和级联控制。注:设备驱动模拟金三与普京的对话
1.C#跨平台物联网通讯框架ServerSuperIO(SSIO)介绍 <连载 | 物联网框架ServerSuperIO教程>1.4种通讯模式机制. <连载 | 物联网框架Serve ...
- 模拟Bootstrap响应式网格系统
Bootstrap响应式(适应于不同的终端设备).Bootstrap栅格系统是利用百分比把视口等分为12个,然后利用媒体查询,设置float属性使之并列显示 一.媒体查询 媒体查询包含一个可选的媒体类 ...