linux串口编程

串口可以说是嵌入式 Linux 系统必备的外设,系统终端通常都是串口。除了终端功能之外,实际应用中,Linux 系统也经常通过串口完成与其它设备的通信和数据传递。
Linux 的串口表现为设备文件。 Linux 的串口设备文件命名一般为/dev/ttySn( n=0、 1、2…..),若串口是 USB 扩展的,则串口设备文件命名多为/dev/ttyUSBn( n=0、1、2….)。当然这种命名规则不是绝对的,不同的硬件平台对串口设备文件的命名可能有所区别。在编写 Linux 串口的C程序代码时,需要包含termios.h头文件。该文件包含了 POSIX 终端属性描述结构 struct termios,该结构如下所示:

struct termios {
tcflag_t c_cflag // 控制标志 可设置串口的波特率、数据位、奇偶校验、停止位以及流控
tcflag_t c_iflag; //输入标志 
tcflag_t c_oflag; // 输出标志 
tcflag_t c_lflag;  本地标志 
tcflag_t c_cc[NCCS]; 控制字符 
};
//typedef unsigned int tcflag_t;

获取和设置终端属性:
使用函数 tcgetattr()可以获取串口设备的 termios 结构。该函数原型如下:

int tcgetattr(int fd, struct termios *termptr);

函数执行成功返回 0, 串口设备的 termios 结构由 temptr 参数返回; 若出错则返回-1。
获得 termios 结构后,可以把串口的属性设置到 termios 结构中。串口属性设置完成后,
可通过 tcsetattr()函数把新的属性设置应用到串口中。 tcsetattr()函数原型如下:

int tcsetattr(int fd, int opt, const struct termios *termptr);

在串口驱动程序里有输入缓冲区和输出缓冲区。 在改变串口属性时,缓冲区可能有数据
存在,如何处理缓冲区中的数据,可通过 opt 参数实现:
TCSANOW: 更改立即发生;
TCSADRAIN: 发送了所有输出后更改才发生,若更改输出参数则应用此选项;
TCSAFLUSH: 发送了所有输出后更改才发生,在更改发生时未读的所有输入数据被删除( Flush)。
设置波特率
串口的波特率分输入波特率和输出波特率,可分别通过 cfsetispeed()和 cfsetospeed()函数设置。这两个函数原型为:

int cfsetispeed(struct termios *termptr, speed_t speed);
int cfsetospeed(struct termios *termptr, speed_t speed);

这两个函数若执行成功返回 0,若出错则返回-1。 speed 参数为需要设置的波特率,可
选择的常量如表 16.5 所列。
这里写图片描述
设置数据位
设置串口数据位是在 termios 结构的 c_cflag 成员上设置,可用的选项标志如表 16.6 所
列。
这里写图片描述
设置串口的数据位为 8 位的代码如下:

opt. c_cflag &= ~CSIZE;
opt. c_cflag |= CS8;

设置奇偶校验
设置串口的奇偶校验是在 termios 结构的 c_cflag 成员上设置,可用的选项标志如表 16.7
所列。
这里写图片描述
Linux 的串口驱动支持无校验(‘ N’)、偶校验(‘ E’)和奇校验(‘ O‘)。
设置无校验的方法为:

opt->c_cflag &= ~PARENB;

设置偶校验的方法为:

opt->c_cflag |= PARENB;
opt->c_cflag &= ~PARODD;

设置奇校验的方法为:

opt->c_cflag |= PARENB;
opt->c_cflag |= ~PARODD;

设置停止位
设置串口停止位是在 termios 对象的 c_cflag 成员上设置,需要用到的选项标志为
CSTOPB( 2 位停止位,否则为 1 位)。
例如,设置 1 位停止位的方法为:

opt->c_cflag &= ~CSTOPB;

其它设置
调用 read()函数读取串口数据时,返回读取数据的数量需要考虑两个变量: MIN 和 TIME。
MIN 和 TIME 在 termios 结构的 c_cc 成员的数组下标名为 VMIN 和 VTIME。
MIN 是指一次 read 调用期望返回的最小字节数。VTIME 说明等待数据到达的分秒数(秒
的 1/10 为分秒)。 TIME 与 MIN 组合使用的具体含义分为以下四种情形:
当 MIN > 0, TIME > 0 时
计时器在收到第一个字节后启动,在计时器超时之前( TIME 的时间到),若已收到 MIN
个字节,则 read 返回 MIN 个字节,否则,在计时器超时后返回实际接收到的字节。
当 MIN > 0, TIME = 0 时
MIN 个字节完整接收后, read 才返回,这可能会造成 read 无限期地阻塞。
当 MIN = 0, TIME > 0 时
TIME 为允许等待的最大时间,计时器在调用 read 时立即启动,在串口接到 1 字节数据或者计时器超时后即返回,如果是计时器超时,则返回 0。
当 MIN = 0, TIME = 0 时
如果有数据可用,则 read 最多返回所要求的字节数,如果无数据可用,则 read 立即返回 0。
设置 TIME 为 150、 MIN 为 255 的方法如下:

opt.c_cc[VTIME] = 150;
opt.c_cc[VMIN] = 255;

串口编程实例

1、设置串口

//串口设置函数,波特率,数据位,校验位,停止位
//返回值:成功 = 0 ,失败 < 0
int set_opt(int fd)
{
    struct termios newtio;
    if  ( tcgetattr( fd,&newtio)  !=  0)
    {
        perror("SetupSerial 1");
        return -1;
    }
    bzero( &newtio, sizeof( newtio ) );
    newtio.c_cflag  |=  CLOCAL | CREAD;//本地连接,接收使能
    newtio.c_cflag &= ~CSIZE;
    newtio.c_cflag |= CS8;         //8位数据位
    newtio.c_cflag &= ~PARENB;    //无校验
    cfsetispeed(&newtio, B115200);//输入波特率
    cfsetospeed(&newtio, B115200);//输出波特率
    newtio.c_cflag &=  ~CSTOPB;   //1位停止位
    newtio.c_cc[VTIME]  = 0;
    newtio.c_cc[VMIN] = 0;
    tcflush(fd,TCIFLUSH);        //清空终端未完成的输入/输出请求及数据。
    if((tcsetattr(fd,TCSANOW,&newtio))!=0)
    {
        perror("com set error");
        return -1;
    }
    return 0;
}

2、打开串口

int serial_fd=0;
//打开串口
serial_fd = open( "/dev/ttyUSB0", O_RDWR|O_NONBLOCK);
if (serial_fd < 0)
{
    printf("### ERROR:open serial failed\n");
    return -1;
}
else printf("open serial success\n");
//设置串口
serial_set_code=set_opt(serial_fd);
if(serial_set_code < 0)
 {
     printf("### ERROR:set serial failed\n");
     return -1;
 }
 else printf("set serial success\n");

3、发送数据

int len;
char buf[] = "hello ZLG!";
len = write(fd, buf, sizeof(buf));
if (len < 0) {
printf("write data to serial failed! \n");
}

4、读取数据

int len;
unsigned char buf[11];
len = read(fd, buf, 11);
if (len < 0){
printf("reading data failed \n");
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值