本篇介绍了如何在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. JavaScript:正则表达式 前瞻

    正向前瞻:用来捕获出现在特定字符之前的字符,只有当字符后面跟着某个特定字符才去捕获它.(?=) 负向前瞻:它用匹配只有当字符后面不跟着某个特定字符时才去匹配它.(?!) 在执行前瞻和负向前瞻之类的运算 ...

  2. UWP开发之Mvvmlight实践五:SuspensionManager中断挂起以及复原处理

    最近比较忙有一段时间没有更新了,再接再厉继续分享. 案例下载:https://github.com/NewBLife/UWP/tree/master/SuspendSample 先我们看看App在生命 ...

  3. RMAN异机恢复快速参考

    应用场景:服务器A为正常运行的生产环境,需要在服务器B上部署一套相同环境做测试. 数据库环境:RHEL6.4 + Oracle 11.2.0.4.7 一. 服务器A备份数据库 1.1 在线备份(数据库 ...

  4. AR创意分享:儿童涂鸦遇上程序绘图

    第一节 临摹 小明经常临摹同桌小美的画作. 美术课上,老师表扬了小美的新作. 图1.1 小美的作品<蒙娜·毛虫的微笑> 临,是照着原作画:摹,是用薄纸张蒙在原作上面画. 第二节 借画 小明 ...

  5. Visual Studio问题集锦:coloader80.dll未正确安装

    问题 今天在修改之前的一个项目的时候报了一个错,大概内容如下: 有一个 Visual Studio 的 DLL 文件(coloader80.dll)未正确安装.请通过"控制面板"中 ...

  6. LINQ to SQL语句(19)之ADO.NET与LINQ to SQL

    它基于由 ADO.NET 提供程序模型提供的服务.因此,我们可以将 LINQ to SQL 代码与现有的 ADO.Net 应用程序混合在一起,将当前 ADO.NET 解决方案迁移到 LINQ to S ...

  7. 设计模式(十)组合模式(Composite Pattern)

    一.引言 在软件开发过程中,我们经常会遇到处理简单对象和复合对象的情况,例如对操作系统中目录的处理就是这样的一个例子,因为目录可以包括单独的文件,也可以包括文件夹,文件夹又是由文件组成的,由于简单对象 ...

  8. is not in the sudoers file的解决方法

    遇到这个问题 修改sudoers 文件   /etc/sudoers 添加

  9. python学习笔记(python简史)

    一.python介绍 python的创始人为吉多·范罗苏姆(Guido van Rossum) 目前python主要应用领域: ·云计算 ·WEB开发 ·科学运算.人工智能 ·系统运维 ·金融:量化交 ...

  10. volatile

    Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值.而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存.这样在任何时刻,两个不同的线程总是看到某个成员变量的 ...