结构体成员
设置串口中最基本的包括波特率设置,校验位和停止位设置。在linux环境下,串口的设置主要是设置
struct termios
结构体的各成员值,如下所示:
struct termio
{
unsigned short c_iflag; /* 输入模式标志 */
unsigned short c_oflag; /* 输出模式标志 */
unsigned short c_cflag; /* 控制模式标志*/
unsigned short c_lflag; /*本地模式标志 */
unsigned char c_line; /* line discipline */
unsigned char c_cc[NCC]; /* control characters */
};
在这个结构中最为重要的是c_cflag
,通过对它的赋值,用户可以设置波特率、字符大小、 数据位、停止位、奇偶校验位和硬件流控等。另外c_iflag
和c_cc
也是比较常用的标志。在 此主要对这3 个成员进行详细说明。
c_cflag
宏名 | 含义 |
---|---|
CBAUD | 波特率的位掩码 |
B0 | 0波特率(放弃DTR) |
B1800 | 2400波特率 |
B4800 | 4800波特率 |
B9600 | 9600波特率 |
B19200 | 19200波特率 |
B38400 | 38400波特率 |
B57600 | 57600波特率 |
B115200 | 115200波特率 |
EXTA | 外部时钟率 |
EXTB | 外部时钟率 |
CSIZE | 数据位的位掩码 |
CS5 | 5个数据位 |
CS6 | 6个数据位 |
CS7 | 7个数据位 |
CS8 | 8个数据位 |
CSTOPB | 2个停止位(不设则是1个停止位) |
CREAD | 接收使能 |
PARENB | 校验位使能 |
PARODD | 使用奇校验而不使用偶校验 |
HUPCL | 最后关闭时挂线(放弃DTR) |
CLOCAL | 本地连接(不改变端口所有者) |
LOBLK | 块作业控制输出 |
CNET_CTSRTS | 硬件流控制使能 |
c_iflag
宏名 | c_iflag支持的常量名称 |
---|---|
INPCK | 奇偶校验使能 |
IGNPAR | 忽略奇偶校验错误 |
PARMRK | 奇偶校验错误掩码 |
ISTRIP | 除去奇偶校验位 |
IXON | 启动出口硬件流控 |
IXOFF | 启动入口软件流控 |
IXANY | 允许字符重新启动流控 |
IGNBRK | 忽略中断情况 |
BRKINT | 当发生中断时发送SIGINT信号 |
INLCR | 将NL映射到CR |
IGNCR | 忽略CR |
ICRNL | 将CR映射到NL |
IUCLC | 将高位情况映射到低位情况 |
IMAXBEL | 当输入太长时回复ECHO |
c_cc支持的常量名称
宏名 | 支持的常量名称 |
---|---|
VINTR | 中断控制,对应键为CTRL+C |
VQUIT | 退出操作,对应键为CRTL+Z |
VERASE | 删除操作,对应键为Backspace(BS) |
VKILL | 删除行,对应键为CTRL+U |
VEOF | 位于文件结尾,对应键为CTRL+D |
VEOL | 位于行尾,对应键为Carriage |
VEOL2 | 位于第二行尾,对应键为Line |
VMIN | 指定了最少读取的字符数 |
VTIME | 指定了读取每个字符的等待时间 |
串口控制函数
函数名 | 功能 |
---|---|
Tcgetattr | 取属性(termios结构) |
Tcsetattr | 设置属性(termios结构) |
cfgetispeed | 得到输入速度 |
cfgetospeed | 得到输出速度 |
cfsetispeed | 设置输入速度 |
cfsetospeed | 设置输出速度 |
Tcdrain | 等待所有输出都被传输 |
tcflow | 挂起传输或接收 |
tcflush | 刷清未决输入和/或输出 |
Tcsendbreak | 送BREAK字符 |
tcgetpgrp | 得到前台进程组ID |
tcsetpgrp | 设置前台进程组ID |
常用串口属性的设置方法
设置流控制
termios_new.c_cflag &= ~CRTSCTS; //不使用流控制
termios_new.c_cflag |= CRTSCTS; //使用硬件流控制
termios_new.c_iflag |= IXON|IXOFF|IXANY; //使用软件流控制
屏蔽字符大小位
termios_new.c_cflag &= ~CSIZE;
设置数据位大小
termios_new.c_cflag |= CS8; //使用8位数据位
termios_new.c_cflag |= CS7; //使用7位数据位
termios_new.c_cflag |= CS6; //使用6位数据位
termios_new.c_cflag |= CS5; //使用5位数据位
设置奇偶校验方式
termios_new.c_cflag &= ~PARENB; //无奇偶校验
termios_new.c_cflag |= PARENB; //奇校验
termios_new.c_cflag &= ~PARODD;
termios_new.c_cflag |= PARENB; //偶校验
termios_new.c_cflag &= ~PARODD;
停止位
termios_new.c_cflag |= CSTOPB; //2位停止位
termios_new.c_cflag &= ~CSTOPB; //1位停止位
输出模式
termios_new.c_cflag &= ~OPOST; //原始数据(RAW)输出
控制字符
termios_new.c_cc[VMIN] = 1; //读取字符的最小数量
termios_new.c_cc[VTIME] = 1; //读取第一个字符的等待时间
实例
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
struct env_info {
uint8_t head[3]; //标识位st
uint8_t type; //数据类型
uint8_t snum; //房间编号
uint8_t temp[2]; //温度
uint8_t hum[2]; //湿度
uint8_t x; //三轴信息
uint8_t y;
uint8_t z;
uint32_t ill; //光照
uint32_t bet; //电池电量
uint32_t adc; //电位器信息
};
int init_usb()
{
struct termios options;
//打开串口设备
int fd_uart = open("/dev/ttyUSB0", O_RDWR);
printf("fd_uart = %d\n",fd_uart);
if(fd_uart < 0){
perror("open err");
return -1;
}
//设置串口属性
tcgetattr(fd_uart, &options); //取属性(termios结构)
//控制模式标志
options.c_cflag |= ( CLOCAL | CREAD ); //(本地连接(不改变端口所有者)|接收使能)
options.c_cflag &= ~CSIZE; //屏蔽字符大小位
options.c_cflag &= ~CRTSCTS; //不使用流控制
options.c_cflag |= CS8; //8个数据位
options.c_cflag &= ~CSTOPB; //~1位停止位
options.c_iflag |= IGNPAR; //忽略奇偶校验错误
options.c_iflag &= ~(ICRNL | IXON); //~(将CR映射到NL|启动出口硬件流控)
options.c_oflag = 0; //输出模式标志
options.c_lflag = 0; //本地模式标志
cfsetispeed(&options, B115200); //设置输入速度,115200波特率
cfsetospeed(&options, B115200); //设置输出速度,115200波特率
tcsetattr(fd_uart, TCSANOW, &options); //设置属性(termios结构)
return fd_uart;
}
int main(int argc, char *argv[])
{
int fd_uart;
while(1)
{
fd_uart = init_usb();
if(fd_uart > 0){
break;
}
}
struct env_info options;
struct env_info *pmsg = &options;
char action = 0x83;
while(1)
{
read(fd_uart,pmsg,sizeof(struct env_info));
printf("温度:%d\n",pmsg->temp[0]);
printf("湿度:%d\n",pmsg->hum[0]);
printf("x:%d\n",pmsg->x);
printf("y:%d\n",pmsg->y);
printf("z:%d\n",pmsg->z);
printf("光照强度:%u\n",pmsg->ill);
printf("电池电量:%u\n",pmsg->bet);
printf("电位器:%u\n",pmsg->adc);
write(fd_uart,&action,sizeof(action));
sleep(1);
}
return 0;
}