linux串口编程实现---有图有真相

来源:互联网 发布:http user agent php 编辑:程序博客网 时间:2024/06/04 19:05

多日来在学习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了。

0 0
原创粉丝点击