Linux C 配置串口

Linux C 配置串口,第1张

配置串口需要包含头文件

其中最核心的配置结构体为:

如何获取该结构呢?我们 *** 作串口跟 *** 作文件一样,也是调用 open() 函数来打开串口,

这样我们就能够得到一个文件描述符 fd ,然后就可以调用 tcgetattr() 函数来获取上述配置结构体了。

Linux 串口默认的配置为:波特率 9600,数据位 8 位,无奇偶校验,停止位 1 位,无 CTS/RTS 。

以下介绍一些常用的配置项:波特率、奇偶校验、数据位、停止位、硬件控制流。

相关接口:

Linux 将串口的波特率分为了输入波特率和输出波特率,不过最常用的场景是将两者设置成一样。

cfgetispeed() 函数获取输入波特率, cfgetospeed() 函数获取输出波特率。 cfsetispeed() 函数设置输入波特率, cfsetospeed() 函数用于设置输出波特率,当然 cfsetspeed() 函数扩展为同时设置输入和输出波特率。

上述接口中的 speed_t 是一系列波特率的标志位,例如常用的 115200 波特率就为 B115200,参考下述选项:

设置奇偶校验位可以通过修改 termios 结构体中的 c_cflag 成员来实现,若无校验,则将 PARENB 位设为 0;若有校验,则 PARENB 为 1。之后再根据 PARODD 来区分奇偶校验, PARODD 为 1 表示奇校验, PARODD 为 0 表示偶校验。例如设置无奇偶校验位:

设置数据位可以通过修改 termios 结构体中的 c_cflag 成员来实现,CS5、CS6、CS7 和 CS8 分别代表数据位 5、6、7 和 8。不过在设置数据位之前,需要先用 CSIZE 来做屏蔽字段,清楚这几个标志位,例如设置数据位为 8 位:

设置停止位可以通过修改 termios 结构体中的 c_cflag 成员来实现, CSTOPB 位为 1 表示 2 位停止位, CSTOPB 位为 0 标志 1 位停止位。例如设置停止位为 1 位:

设置硬件控制流可以通过修改 termios 结构体中的 c_cflag 成员来实现, CRTSCTS 为 1 表示使用硬件控制流,为 0 表示不使用硬件控制流。例如使能硬件控制流:

当然,最后还需要用 tcflush() 抛弃存储在 fd 里的未接收的数据。

再利用接口 tcsetattr() 函数将配置信息写入文件描述符 fd :

这样整个串口最常用的用法就配置完成了。

具体的配置使用可以参考我的项目 HCI-Middleware 里的 hci_transport_uart_linux.c 文件。

参考:

这是通信串口名称。在Linux环境下,串口名从ttyS0开始依次是ttyS1、ttyS2等。在本程序中,使用ttyS0作为通信串口。在打开ttyS0的时候,选项 O_NOCTTY 表示不能把本串口当成控制终端,否则用户的键盘输入信息将影响程序的执行; O_NDELAY表示打开串口的时候,程序并不关心另一端 的串口是否在使用中。在Linux中,打开串口设备和打开普通文件一样,使用的是open()系统调用。比如我么打开串口设备1也就是COM1,只需要:fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY )打开的串口设备有很多设置选项。本文中使用int setup_com(int fd)设置。在系统头文件中 定义了终端控制结构struct termios,tcgetattr()和tcsetattr()两个系统函数获得和设置这些属性。结构 struct termios中的域描述的主要属性包括:c_cflag : 控制选项c_lflag : 线选项c_iflag : 输入选项c_oflag :输出选项c_cc :控制字符c_ispeed :输入数据波特率c_ospeed :输出数据波特率如果要设置某个选项,那么就使用"|=“运算,如果关闭某个选项就使用”&=“和”~"运算。本文使用的各个选项的意义定义如下:c_cflag:CLOCAL 本地模式,不改变端口的所有者CREAD 表示使能数据接收器PARENB 表示偶校验PARODD 表示奇校验CSTOPB 使用两个停止位CSIZE 对数据的bit使用掩码CS8 数据宽度是8bitc_lflag:ICANON 使能规范输入,否则使用原始数据(本文使用)ECHO 回送(echo)输入数据ECHOE 回送擦除字符ISIG 使能SIGINTR,SIGSUSP, SIGDSUSP和 SIGQUIT 信号c_iflag:IXON 使能输出软件控制IXOFF 使能输入软件控制IXANY 允许任何字符再次开启数据流INLCR 把字符NL(0A)映射到CR(0D)IGNCR 忽略字符CR(0D)ICRNL 把CR(0D)映射成字符NR(0A)c_oflag: OPOST 输出后处理,如果不设置表示原始数据(本文使用原始数据)c_cc[VMIN]: 最少可读数据c_cc[VTIME]: 等待数据时间(10秒的倍数)

以前写的,但是没写完,偏偏你要的那部分没写。呵呵~~

先声明,没调试过。。仅供参考,有错误的地方请指正,谢谢!

////////////////////////

/******setport.h*******/

////////////////////////

#ifndef SETPORT_H

#define SETPORT_H

/*********************

int dwBaudRate //波特率

char bTTY //串口号

char bDataBit //数据位5,6,7,8

char bParity //奇偶校验 无校验:'N' 偶校验'E' 奇校验'O'

char bStopBit //停止位1,2

char bFctl //流控制无控制:'N' 硬件控制:'H'软件控制:'S'

**********************/

//-------------------打开串口-------------------//bTTY==0,1,2,3, 对应串口Com1到Com4,成功返回文件描述符,失败==(-1)

extern int PortOpen(char bTTY)

//-------------------设置串口-------------------//成功==(0) 失败==(-1)

extern int PortSet(int dwFdcom,int dwBaudRate,char bTTY,char bDataBit,char bParity,char bStopBit,char bFctl)

//-------------------关闭串口-------------------//

extern void PortClose(int dwFdcom)

//-------------------写串口-------------------//成功返回datalen 失败==(<0)

extern int PortWrite(int dwFdcom,char *cpSendBuf,unsigned int DataLen)

//-------------------读串口-------------------//成功返回datalen 失败==(-1)

extern int PortRead(int dwFdcom,char *cpRecvBuf,unsigned int DataLen,unsigned int dwBaudRate)

//-------------------超时设置-------------------//成功==0失败==(<0)

extern int PortTimeOut(int dwFdcom, char timeout, int len)

#endif

/////////////////////////////

/***********setport.c*******/

////////////////////////////

#include <stdio.h>

#include <fcntl.h>

#include <stdlib.h>

#include <unistd.h>

#include <string.h>

#include <termios.h>

#include <sys/times.h>

#include <sys/types.h>

#include <sys/ioctl.h>

#include "setport.h"

//-------------------打开串口-------------------//

extern int PortOpen(char bTTY)

{

int dwFdcom

unsigned char Ptty[10]="/dev/ttyS"

unsigned char *cpGtty

cpGtty=strcat(Ptty,&bTTY)

if(!cpGtty) return -1

else {

dwFdcom=open(cpGtty,O_RDWR|O_NOCTTY)

}

return (dwFdcom)

}

//-------------------关闭串口-------------------//

extern void PortClose(int dwFdcom)

{

close(dwFdcom)

}

//-------------------设置串口-------------------//

extern int PortSet(int dwFdcom,int dwBaudRate,char bTTY,char bDataBit,char bParity,char bStopBit,char bFctl)

{

static int speed_arr[] = {B38400, B19200, B9600, B4800, B2400, B1200, B300, B38400, B19200, B9600, B4800, B2400, B1200, B300}

static int name_arr[] = {38400, 19200, 9600, 4800, 2400,1200, 300, 38400, 19200, 9600, 4800, 2400, 1200, 300}

struct termios oldtm_t,newtm_t

int i=0char *pDatabit

bzero(&oldtm_t,sizeof(oldtm_t))

bzero(&newtm_t,sizeof(newtm_t))

cfmakeraw(&newtm_t)

tcgetattr(dwFdcom,&oldtm_t)

/*------------设置端口属性------------*/

for( i<sizeof(speed_arr)/sizeof(int) i++)

{

if(dwBaudRate==name_arr[i])

{

cfsetispeed(&newtm_t,speed_arr[i])

cfsetospeed(&newtm_t,speed_arr[i])

}

else return -1

}

newtm_t.c_cflag|=CLOCAL

newtm_t.c_cflag|=CREAD

newtm_t.c_cflag &= ~CSIZE

switch(bDataBit) //数据位

{

case '5':

newtm_t.c_cflag|=CS5

break

case '6':

newtm_t.c_cflag|=CS6

break

case '7':

newtm_t.c_cflag|=CS7

break

case '8':

newtm_t.c_cflag|=CS8

break

default:

return -2

}

switch(bParity)

{

case 'N':{ //无校验

newtm_t.c_cflag&=~PARENB

newtm_t.c_iflag&= ~INPCK

}break

case 'O':{ //奇校验

newtm_t.c_cflag |= (PARODD | PARENB)

newtm_t.c_iflag |= INPCK

}break

case 'E':{ //偶校验

newtm_t.c_cflag |= PARENB

newtm_t.c_cflag &= ~PARODD

newtm_t.c_iflag |= INPCK

}break

default:

return -3

}

//停止位

if(bStopBit=='2') newtm_t.c_cflag|=CSTOPB //2

else newtm_t.c_cflag&=~CSTOPB //1

switch(bFctl) //流控制

{

case 'N':{ //无控制

newtm_t.c_cflag &= ~CRTSCTS

newtm_t.c_iflag &= ~(IXON | IXOFF | IXANY )

}break

case 'H':{ //硬件控制

newtm_t.c_cflag |= CRTSCTS

newtm_t.c_iflag &= ~(IXON | IXOFF | IXANY )

}break

case 'S':{ //软件控制

newtm_t.c_cflag &= ~CRTSCTS

newtm_t.c_iflag |= (IXON | IXOFF | IXANY )

}break

default:

return -4

}

tcflush(dwFdcom,TCIFLUSH)//端口复位

tcsetattr(dwFdcom,TCSANOW,&newtm_t) //使端口属性设置生效

return 0

}

//-------------------超时设置-------------------//

extern int PortTimeOut(int dwFdcom, char timeout, int len)

{

struct termios newtm_t

if(tcgetattr(dwFdcom, &newtm_t) != 0)

{

return (-1)

}

newtm_t.c_lflag &= ~ICANON

newtm_t.c_cc[VTIME] = timeout

newtm_t.c_cc[VMIN] = len

if(tcsetattr(dwFdcom, TCSANOW, &newtm_t) != 0)

{

return (-2)

}

return 0

}

////读写串口用文件读写方式,read和write两个方法,

////read是接收数据,write是发送数据


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/yw/8291849.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-15
下一篇2023-04-15

发表评论

登录后才能评论

评论列表(0条)

    保存