日期:2014-05-16 浏览次数:20754 次
用过开发板的朋友们都知道,UART在一个芯片中是很珍贵的资源,它可以被配置为485功能,也可以配置232功能,而在工业通讯中,485,232都是常用的通讯方式。
这里多说一句题外话:一直没有找到linux比较好的编辑工具,vim虽然功能强大,但是没有鼠标,总感觉不爽,gedit虽然有鼠标,但是缩进功能实在是不行,这里推荐一款本人一直用的,感觉用的不错,就是大家熟悉的eclipse for c++,这个有Linux版本,用起来虽然没有windows下那么爽,但是比大多数(至少笔者用过的)都好用。
首先说,Linux的串口通讯和我们逻辑编程的编程方法是不同的:
裸机下需要配置寄存器,然后如果中断方式,设置中断函数,如果查询方式,就查询状态位,判断是否有数据过来,如果要发送数据则就是往发送寄存器发送数据,然后就自动发出去了。
Linux下可不同,那些所谓的驱动都已经写好了,我们需要调用的是Linux统一封装的数据结构和函数来操作串口,对于不同的芯片,只要是Linux操作系统,都可以用这一类型的东西操作串口。
在Linux中所有串口配置数据都可以用struct termios来描述,里面有许多的成员函数,像我们配置波特率,数据位长度和奇偶校验,具体配置方法可以参考这篇程:http://wenku.baidu.com/view/114854b069dc5022aaea00b7.html
下面是笔者写的程序,大家可以拿来当做模板来使用,主要实现对UART0的操作:
#include <unistd.h> #include <stdio.h> #include <termios.h> #include <fcntl.h> #include <string.h> #include <time.h> //为了保证用户输入的波特率是个正确的值,所以需要这两个数组验证,对于设置波特率时候,前面要加个B int speed_arr[] = { B115200, B57600, B38400, B19200, B9600, B4800, B2400, B1200, B300, B115200, B57600, B38400, B19200, B9600, B4800, B2400, B1200, B300, }; int name_arr[] = {115200, 57600, 38400, 19200, 9600, 4800, 2400, 1200, 300, 115200, 57600, 38400, 19200, 9600, 4800, 2400, 1200, 300, }; /*----------------------------------------- 函数名: set_speed 参数: int fd ,int speed 返回值: void 描述: 设置fd表述符的串口波特率 *-----------------------------------------*/ void set_speed(int fd ,int speed) { struct termios opt; int i; int status; tcgetattr(fd,&opt); for(i = 0;i < sizeof(speed_arr)/sizeof(int);i++) { if(speed == name_arr[i]) //找到标准的波特率与用户一致 { tcflush(fd,TCIOFLUSH); //清除IO输入和输出缓存 cfsetispeed(&opt,speed_arr[i]); //设置串口输入波特率 cfsetospeed(&opt,speed_arr[i]); //设置串口输出波特率 status = tcsetattr(fd,TCSANOW,&opt); //将属性设置到opt的数据结构中,并且立即生效 if(status != 0) perror("tcsetattr fd:"); //设置失败 return ; } tcflush(fd,TCIOFLUSH); //每次清除IO缓存 } } /*----------------------------------------- 函数名: set_parity 参数: int fd 返回值: int 描述: 设置fd表述符的奇偶校验 *-----------------------------------------*/ int set_parity(int fd) { struct termios opt; if(tcgetattr(fd,&opt) != 0) //或许原先的配置信息 { perror("Get opt in parity error:"); return -1; } /*通过设置opt数据结构,来配置相关功能,以下为八个数据位,不使能奇偶校验*/ opt.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); opt.c_oflag &= ~OPOST; opt.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); opt.c_cflag &= ~(CSIZE | PARENB); opt.c_cflag |= CS8; tcflush(fd,TCIFLUSH); //清空输入缓存 if(tcsetattr(fd,TCSANOW,&opt) != 0) { perror("set attr parity error:"); return -1; } return 0; } /*----------------------------------------- 函数名: serial_init 参数: char *dev_path,int speed,int is_block 返回值: 初始化成功返回打开的文件描述符 描述: 串口初始化,根据串口文件路径名,串口的速度,和串口是否阻塞,block为1表示阻塞 *-----------------------------------------*/ int serial_init(char *dev_path,int speed,int is_block) { int fd; int flag; flag = 0; flag |= O_RDWR; //设置为可读写的串口属性文件 if(is_block == 0) flag |=O_NONBLOCK; //若为0则表示以非阻塞方式打开 fd = open(dev_path,flag); //打开设备文件 if(fd < 0) { perror("Open device file err:"); close(fd); return -1; } /*打开设备文件后,下面开始设置波特率*/ set_speed(fd,speed); /