linux串口编程实现---有图有真相
2015-07-22 16:50
597 查看
多日来在学习C++,之后又看了关于linux下串口编程的资料,实验多次,失败多次,最后终于成功,以此记录下,希望网友们可以借鉴,少走弯路。
我的linux是Ubuntu10.10,采用的是VMware的方式,至于minicom等的设置可以参考我的其他博文,有详细介绍和操作步骤,有的还有一些原理的介绍,首先说说为什么要写一个串口编程的程序(其实也是参考网友的资料自己修改的,O(∩_∩)O~),因为我想写一个类似于串口助手的工具,本意是希望在linux下可以使用,即使不能在linux下使用,也可以学习一下串口的基础操作。下面言归正传。
代码经过我的实践和修改,终于有一个较为理想的结果,至少基本的串口读写可以实现了,当然还存在一些小问题,串口波特率修改过后,显示改过之后的波特率并没有改变,不过经实践确实改变了,可能是函数的问题,关系到局部变量,我并没有采用全局变量,个人觉得可能写函数的时候采用引用的方法可能会解决,不过采用引用的方法,修改了之后函数之后编译不通过,最后放弃,有时间慢慢修改再,先记录下之前的成果。
首先新建一个文件#vim serialv1.6.c输入以下代码
#include
#include
#include
#include
#include
/***下面这个set_speed的子程序是在网上别的文章中摘抄过来的,就直接调用了,省了自己编写的麻烦***/
/*波特率设置,在termios结构体中设置波特率的时候要加B,如设置9600波特率,就要写B9600*/
int speed_arr[] = {B115200,B38400, B19200, B9600, B4800, B2400, B1200, B300 };
/* 设置波特率的速率 */
int name_arr[] = {115200,38400, 19200, 9600, 4800, 2400, 1200, 300 };
/*linux下操作串口相关的结构体为struct termios */
/*fd为文件描述符(句柄),fd由打开文件的时候获取
speed为波特率速率,参数为9600,115200*/
void set_speed(int fd, int speed)
{
int i;
int status;
struct termios Opt; //串口相关的结构体
tcgetattr(fd, &Opt); //保存原有的串口配置,保存在Opt中
for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++)
{
/* 输入参数为115200,转换为B115200,termios结构体中使用B115200*/
if (speed == name_arr[i])
{
tcflush(fd, TCIOFLUSH); //刷清输入、输出队列
cfsetispeed(&Opt, speed_arr[i]);//设置输入波特率
cfsetospeed(&Opt, speed_arr[i]);//设置输出波特率
status = tcsetattr(fd, TCSANOW, &Opt);//更改设置立即生效
if (status != 0)
{
perror("tcsetattr fd1 error");
return;
}
else
{
printf("set fd1 ok \n");
}
tcflush(fd,TCIOFLUSH); //刷清输入、输出队列
}
}
}
int main()
{
//fd用来保存文件描述符,
int fd,flag,wr_num=0,rd_num=0;
struct termios term;//定义一结构体
speed_t baud_rate_i,baud_rate_o,baud_rate_a,baud_rate_b; //定义波特率
char send_buf[]="hello,serial!",recv_buf[20];//读写使用的数组,发送,接收两种数组
//fd=open("/dev/ttyUSB0",O_RDWR|O_NONBLOCK|O_NOCTTY | O_NDELAY); //打开设备文件,使用USB转串口,设备文件为/dev/ttyUSB0 O_NOCTTY | O_NDELAY
fd=open("/dev/ttyUSB0",O_RDWR|O_NONBLOCK);
if(fd==-1) //error
printf("can not open the ttyUSB0!\n");
else //ok
printf("open USB-Serial ttyUSB0 ok!\n");
flag=tcgetattr(fd,&term);/*取得终端设备fd的属性,存放在termios类型的结构体term中*/
baud_rate_i=cfgetispeed(&term);/*从term中读取输入波特率*/
baud_rate_o=cfgetospeed(&term);/*从term中读取输出波特率*/
printf("baudrate of in is:%d,baudrate of out is%d,fd=%d\n",baud_rate_i,baud_rate_o,fd);/*打印设置之前的波特率,目的是方便和设置之后的波特率对比*/
set_speed(fd,115200);/*重新设置波特率*/
/* tcgetattr 与 tcgetattr成功时返回0 */
flag=tcgetattr(fd,&term);/*以下三行读取设置之后的波特率,用cfgetispeed和cfgetospeed得到的波特率是一个序号,可以通过查表(表见程序后面)得到真正的波特率,比如返回13,对应的实际波特率是9600。我这里没有做转换,直接把13输出了。*/
baud_rate_a=cfgetispeed(&term);/*设置输入波特率*/
baud_rate_b=cfgetospeed(&term);/*设置输出波特率*/
printf("baudrate of in is:%d,baudrate of out is%d,fd=%d,flag=%d\n,",baud_rate_a,baud_rate_b,fd,flag);/*打印设置之后的波特率,目的是方便和设置之后的波特率对比*/
while(1)
{
wr_num=write(fd,send_buf,sizeof(send_buf));/*先写入*//*返回值是真正写入了多少个字符*/
if(wr_num>0)
printf("write ttyUSB0 success!\n");
else
printf("write ttyUSB0 fail!\n");
sleep(1);
rd_num=read(fd,recv_buf,sizeof(recv_buf));/*再读出*//*返回值是真正读出了多少个字符*/
if(rd_num>0)
printf("we can read \"%s\" from the ttyUSB0.total:%d characters\n",recv_buf,rd_num);
else
printf("read ttyUSB0 fail!\n");
sleep(1);
}
}
输入完成之后保存
编译#gcc serialv1.6.c -o serialv1.6
生成的可执行文件为serialv1.6
下面说明串口的设置,我的代码中使用的是ttyUSB0,并没有使用ttyS0,由于我PC的配置有特殊原因,不过使用USB转串口,大家都可以实现,也算是通用,整体思路是使用将COM2 和USB转串口连接起来,打开COM2的串口助手就可以给USB转串口发送数据,实现串口读写,其实也可以将USB转串口的23引脚短接起来,应该也可以实现,连接好之后运行代码
#./serialv1.6
实验效果如图:
之前的波特率是4098之后仍然是,就是函数写的问题了,不过我设置的是115200,在COM2端口也是设置115200可以实现通信,说明设置是对了,不过显示仍存在问题,可以看到实现串口读写了,缓冲区大小的设置是20,因此读出了那么多的a,程序有待改进,最后,希望网友可以就串口编程前来交流。
刚才看到网页上#include显示不出来,可能是由于我们的网页的原因,下面是#include的内容
stdio.h
sys/types.h
sys/stat.h
fcntl.h
termios.h
每个都用尖括号括起来就OK了。
我的linux是Ubuntu10.10,采用的是VMware的方式,至于minicom等的设置可以参考我的其他博文,有详细介绍和操作步骤,有的还有一些原理的介绍,首先说说为什么要写一个串口编程的程序(其实也是参考网友的资料自己修改的,O(∩_∩)O~),因为我想写一个类似于串口助手的工具,本意是希望在linux下可以使用,即使不能在linux下使用,也可以学习一下串口的基础操作。下面言归正传。
代码经过我的实践和修改,终于有一个较为理想的结果,至少基本的串口读写可以实现了,当然还存在一些小问题,串口波特率修改过后,显示改过之后的波特率并没有改变,不过经实践确实改变了,可能是函数的问题,关系到局部变量,我并没有采用全局变量,个人觉得可能写函数的时候采用引用的方法可能会解决,不过采用引用的方法,修改了之后函数之后编译不通过,最后放弃,有时间慢慢修改再,先记录下之前的成果。
首先新建一个文件#vim serialv1.6.c输入以下代码
#include
#include
#include
#include
#include
/***下面这个set_speed的子程序是在网上别的文章中摘抄过来的,就直接调用了,省了自己编写的麻烦***/
/*波特率设置,在termios结构体中设置波特率的时候要加B,如设置9600波特率,就要写B9600*/
int speed_arr[] = {B115200,B38400, B19200, B9600, B4800, B2400, B1200, B300 };
/* 设置波特率的速率 */
int name_arr[] = {115200,38400, 19200, 9600, 4800, 2400, 1200, 300 };
/*linux下操作串口相关的结构体为struct termios */
/*fd为文件描述符(句柄),fd由打开文件的时候获取
speed为波特率速率,参数为9600,115200*/
void set_speed(int fd, int speed)
{
int i;
int status;
struct termios Opt; //串口相关的结构体
tcgetattr(fd, &Opt); //保存原有的串口配置,保存在Opt中
for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++)
{
/* 输入参数为115200,转换为B115200,termios结构体中使用B115200*/
if (speed == name_arr[i])
{
tcflush(fd, TCIOFLUSH); //刷清输入、输出队列
cfsetispeed(&Opt, speed_arr[i]);//设置输入波特率
cfsetospeed(&Opt, speed_arr[i]);//设置输出波特率
status = tcsetattr(fd, TCSANOW, &Opt);//更改设置立即生效
if (status != 0)
{
perror("tcsetattr fd1 error");
return;
}
else
{
printf("set fd1 ok \n");
}
tcflush(fd,TCIOFLUSH); //刷清输入、输出队列
}
}
}
int main()
{
//fd用来保存文件描述符,
int fd,flag,wr_num=0,rd_num=0;
struct termios term;//定义一结构体
speed_t baud_rate_i,baud_rate_o,baud_rate_a,baud_rate_b; //定义波特率
char send_buf[]="hello,serial!",recv_buf[20];//读写使用的数组,发送,接收两种数组
//fd=open("/dev/ttyUSB0",O_RDWR|O_NONBLOCK|O_NOCTTY | O_NDELAY); //打开设备文件,使用USB转串口,设备文件为/dev/ttyUSB0 O_NOCTTY | O_NDELAY
fd=open("/dev/ttyUSB0",O_RDWR|O_NONBLOCK);
if(fd==-1) //error
printf("can not open the ttyUSB0!\n");
else //ok
printf("open USB-Serial ttyUSB0 ok!\n");
flag=tcgetattr(fd,&term);/*取得终端设备fd的属性,存放在termios类型的结构体term中*/
baud_rate_i=cfgetispeed(&term);/*从term中读取输入波特率*/
baud_rate_o=cfgetospeed(&term);/*从term中读取输出波特率*/
printf("baudrate of in is:%d,baudrate of out is%d,fd=%d\n",baud_rate_i,baud_rate_o,fd);/*打印设置之前的波特率,目的是方便和设置之后的波特率对比*/
set_speed(fd,115200);/*重新设置波特率*/
/* tcgetattr 与 tcgetattr成功时返回0 */
flag=tcgetattr(fd,&term);/*以下三行读取设置之后的波特率,用cfgetispeed和cfgetospeed得到的波特率是一个序号,可以通过查表(表见程序后面)得到真正的波特率,比如返回13,对应的实际波特率是9600。我这里没有做转换,直接把13输出了。*/
baud_rate_a=cfgetispeed(&term);/*设置输入波特率*/
baud_rate_b=cfgetospeed(&term);/*设置输出波特率*/
printf("baudrate of in is:%d,baudrate of out is%d,fd=%d,flag=%d\n,",baud_rate_a,baud_rate_b,fd,flag);/*打印设置之后的波特率,目的是方便和设置之后的波特率对比*/
while(1)
{
wr_num=write(fd,send_buf,sizeof(send_buf));/*先写入*//*返回值是真正写入了多少个字符*/
if(wr_num>0)
printf("write ttyUSB0 success!\n");
else
printf("write ttyUSB0 fail!\n");
sleep(1);
rd_num=read(fd,recv_buf,sizeof(recv_buf));/*再读出*//*返回值是真正读出了多少个字符*/
if(rd_num>0)
printf("we can read \"%s\" from the ttyUSB0.total:%d characters\n",recv_buf,rd_num);
else
printf("read ttyUSB0 fail!\n");
sleep(1);
}
}
输入完成之后保存
编译#gcc serialv1.6.c -o serialv1.6
生成的可执行文件为serialv1.6
下面说明串口的设置,我的代码中使用的是ttyUSB0,并没有使用ttyS0,由于我PC的配置有特殊原因,不过使用USB转串口,大家都可以实现,也算是通用,整体思路是使用将COM2 和USB转串口连接起来,打开COM2的串口助手就可以给USB转串口发送数据,实现串口读写,其实也可以将USB转串口的23引脚短接起来,应该也可以实现,连接好之后运行代码
#./serialv1.6
实验效果如图:
之前的波特率是4098之后仍然是,就是函数写的问题了,不过我设置的是115200,在COM2端口也是设置115200可以实现通信,说明设置是对了,不过显示仍存在问题,可以看到实现串口读写了,缓冲区大小的设置是20,因此读出了那么多的a,程序有待改进,最后,希望网友可以就串口编程前来交流。
刚才看到网页上#include显示不出来,可能是由于我们的网页的原因,下面是#include的内容
stdio.h
sys/types.h
sys/stat.h
fcntl.h
termios.h
每个都用尖括号括起来就OK了。
相关文章推荐
- Linux下修改profile后用户无法登陆的问题
- Linux配置防火墙,开启80端口、3306端口 可能会遇到的小问题
- centos 7安装mysql
- Linux支持exFAT和NTFS
- linux下线程同步
- CentOS iptables 默认配置
- [150722]Linux vi 移动光标 命令
- linux下运行js文件
- Linux C语言程序设计(七)——栈与队列
- webbench,linux下并发测试工具
- 转_如何解决linux动态库版本控制
- linux 相关系统参数调优
- 【Linux探索之旅】第一部分第三课:测试并安装Ubuntu
- 【Linux探索之旅】第一部分第三课:测试并安装Ubuntu
- CentOS6.5 搭建基础PHP环境(yum安装)
- nmon监控Linux服务器性能
- VMware虚拟机的CentOS无法上网的解决方法
- linux cooked capture
- linux日志服务器搭建
- linux日志服务器搭建