【第一周】:现在是2019年12月,现大三。希望借这个平台和正在阅读文章的你一起学习和提升。本着分享和记录的目的,我将不定期更新文章,如果文章中有不足之处,还请各位多多指教,如果需要源代码,欢迎在评论区留言邮箱。
本文为《搭建物联网基础通信框架系列教程》的分支部分,读写Linux的串口数据。
Ubuntu16.04
struct termios
{
tcflag_t c_iflag; /* input mode flags */
tcflag_t c_oflag; /* output mode flags */
tcflag_t c_cflag; /* control mode flags */
tcflag_t c_lflag; /* local mode flags */
cc_t c_line; /* line discipline */
cc_t c_cc[NCCS]; /* control characters */
speed_t c_ispeed; /* input speed */
speed_t c_ospeed; /* output speed */
};
变量的含义前辈们已经注释得很清楚了,在这我就不做解释了。
tcgetattr 函数用于获取串口的配置信息。
/* Put the state of FD into *TERMIOS_P. */
extern int tcgetattr (int __fd, struct termios *__termios_p) __THROW;
参数1:串口设备文件的文件描述符fd。
参数2:上述结构体指针
返回值:
成功返回0.
失败返回-1,并设置错误码。
tcsetattr 函数用于设置串口的属性。
/* Set the state of FD to *TERMIOS_P.
Values for OPTIONAL_ACTIONS (TCSA*) are in . */
extern int tcsetattr (int __fd, int __optional_actions,
const struct termios *__termios_p) __THROW;
参数1:串口设备文件的文件描述符fd。
参数2:用于控制函数的执行属性,可取如下值
/* tcsetattr uses these */
#define TCSANOW 0
#define TCSADRAIN 1
#define TCSAFLUSH 2
TCSANOW:不等数据传输完毕就立即改变属性。
TCSADRAIN:等待所有数据传输结束才改变属性。
TCSAFLUSH:清空输入输出缓冲区才改变属性。
返回值:
成功返回0.
失败返回-1,并设置错误码。
tcflush 用于清空串口缓冲区数据
/* Flush pending data on FD.
Values for QUEUE_SELECTOR (TC{I,O,IO}FLUSH) are in . */
extern int tcflush (int __fd, int __queue_selector) __THROW;
参数1:串口设备文件的文件描述符fd。
参数1:用于控制函数的执行属性,可取如下值
/* tcflush() and TCFLSH use these */
#define TCIFLUSH 0
#define TCOFLUSH 1
#define TCIOFLUSH 2
TCIFLUSH:清除正收到的数据,且不会读取出来。
TCOFLUSH :清除正写入的数据,且不会发送至终端。
TCIOFLUSH:清除所有正在发生的I/O数据。
返回值:
成功返回0.
失败返回-1,并设置错误码。
因为波特率可取的值很多,如果逐个判断代码冗余太大,这里我采用两个数组存放可取的值。
//波特率和宏定义对应表
static const speed_t baudRateTable_Def[] = { B0,B50,B75,B110,B134,B150,B200,B600,B1200,B1800,B2400,B4800,B9600,B19200,B38400,B57600,B115200 };
static const int baudRateTable[] = { 0,50,75,110,134,150,200,600,1200,1800,2400,4800,9600,19200,38400,57600,115200 };
系统宏定义
/* c_cflag bit meaning */
#ifdef __USE_MISC
# define CBAUD 0010017
#endif
#define B0 0000000 /* hang up */
#define B50 0000001
#define B75 0000002
#define B110 0000003
#define B134 0000004
#define B150 0000005
#define B200 0000006
#define B300 0000007
#define B600 0000010
#define B1200 0000011
#define B1800 0000012
#define B2400 0000013
#define B4800 0000014
#define B9600 0000015
#define B19200 0000016
#define B38400 0000017
bool CSerial::setBaudeRate(int baudeRate)
{
int i = 0;
m_iBaudRate = baudeRate;
for (i = 0; i < 17; i++){
if (baudeRate == baudRateTable[i]){
cfsetispeed(&m_Termios, baudRateTable_Def[i]); //接收数据波特率
cfsetospeed(&m_Termios, baudRateTable_Def[i]); //发送数据波特率
m_uiError &= ~ERROR_CFG_BaudeRate;
return true;
}
}
cout << "Invalid BaudeRate!" << endl;
m_uiError |= ERROR_CFG_BaudeRate; //波特率配置出错置位
return false; //设置的波特率不是常用的标准值
}
系统宏定义
#ifdef __USE_MISC
# define CIBAUD 002003600000 /* input baud rate (not used) */
# define CMSPAR 010000000000 /* mark or space (stick) parity */
# define CRTSCTS 020000000000 /* flow control */
#endif
bool CSerial::setFlowCtrl_hw(bool bFlowCtrl_hw)
{
m_bFlowCtrl_hw = bFlowCtrl_hw;
if (bFlowCtrl_hw){
m_Termios.c_cflag |= CRTSCTS; //硬件流控
}
else{
m_Termios.c_cflag &= ~CRTSCTS;
}
return true;
}
系统宏定义
#define CSIZE 0000060
#define CS5 0000000
#define CS6 0000020
#define CS7 0000040
#define CS8 0000060
#define CSTOPB 0000100
#define CREAD 0000200
#define PARENB 0000400
#define PARODD 0001000
#define HUPCL 0002000
#define CLOCAL 0004000
bool CSerial::setDataBits(int dataBits)
{
m_iDataBits = dataBits;
m_Termios.c_cflag &= ~CSIZE; //在设置数据位时,必须先使用CSIZE做位屏蔽
switch (dataBits)
{
case 5:
m_Termios.c_cflag |= CS5;
break;
case 6:
m_Termios.c_cflag |= CS6;
break;
case 7:
m_Termios.c_cflag |= CS7;
break;
case 8:
m_Termios.c_cflag |= CS8;
break;
default:
cout << "Invalid DataBits!" << endl;
m_uiError |= ERROR_CFG_DataBits; //数据位配置出错置位
return false;
break;
}
m_uiError &= ~ERROR_CFG_DataBits;
return true;
}
系统宏定义
#define CSIZE 0000060
#define CS5 0000000
#define CS6 0000020
#define CS7 0000040
#define CS8 0000060
#define CSTOPB 0000100
#define CREAD 0000200
#define PARENB 0000400
#define PARODD 0001000
#define HUPCL 0002000
#define CLOCAL 0004000
bool CSerial::setStopBits(int stopBits)
{
m_iStopBits = stopBits;
switch (stopBits)
{
case 1:
m_Termios.c_cflag &= ~CSTOPB;
break;
case 2:
m_Termios.c_cflag |= CSTOPB;
break;
default:
cout << "Invalid StopBits!" << endl;
m_uiError |= ERROR_CFG_StopBits; //停止位配置出错置位
return false;
break;
}
m_uiError &= ~ERROR_CFG_StopBits;
return true;
}
bool CSerial::setFlowCtrl_hw(bool bFlowCtrl_hw)
{
m_bFlowCtrl_hw = bFlowCtrl_hw;
if (bFlowCtrl_hw){
m_Termios.c_cflag |= CRTSCTS; //硬件流控
}
else{
m_Termios.c_cflag &= ~CRTSCTS;
}
return true;
}
bool CSerial::setFlowCtrl_sw(bool bFlowCtrl_sw)
{
if (bFlowCtrl_sw) {
m_Termios.c_iflag |= IXON | IXOFF; //使用软件流控制
}
else {
m_Termios.c_iflag &= ~(IXON | IXOFF);
}
return true;
}
系统宏定义
#define VINTR 0
#define VQUIT 1
#define VERASE 2
#define VKILL 3
#define VEOF 4
#define VTIME 5
#define VMIN 6
#define VSWTC 7
#define VSTART 8
#define VSTOP 9
#define VSUSP 10
#define VEOL 11
#define VREPRINT 12
#define VDISCARD 13
#define VWERASE 14
#define VLNEXT 15
#define VEOL2 16
bool CSerial::setVMIN(int vmin)
{
m_iVMIN = vmin;
m_Termios.c_cc[VMIN] = (cc_t)vmin;
return true;
}
bool CSerial::setVTIME(int vtime)
{
m_iVTIME = vtime;
m_Termios.c_cc[VTIME] = (cc_t)vtime;
return true;
}
VMIN 位置用于设置读取字符的最小数量,例如:如果设置为1,串口中只要收到数据read函数就会返回
VTIME 位置用于设置等待时间,单位为n分之1秒
bool CSerial::enableConfig()
{
if (m_uiError){ //配置中存在错误
cout << "Configuration had errors!" << endl;
return false;
}
m_Termios.c_cflag |= CLOCAL | CREAD; //使能本地发送和接收
tcflush(m_fd_Dev, TCIFLUSH); //清空串口中的缓存数据
if (tcsetattr(m_fd_Dev, TCSANOW, &m_Termios) != 0) //进行设置生效
{
perror("tcsetattr error:");
return false;
}
return true;
}