概念:。典型的串口通信只需要3根线分别是地线GND发送线TX上图中串口设备节点有以下3种类型。1dev/ttyXX 是一个数字编号譬如 0、1、2、3 等设备节点tty是teletype 的 简称在Linux中/dev/ttyX 代表虚拟控制台终端Linux 内核在初始化时生/dev/tty1~/dev/tty63 共63个虚拟控制台终端。2串口设备节点在iTOP-3568开发板上引出UART2、UART4、UART7、UART9四 个串口其中UART2为串口调试终端对应的设备节点为/dev/ttyFIQ0其他三个串口UART4、 UART7、UART9对应的设备节点分别为/dev/ttyS4、/dev/ttyS7、/dev/ttyS9。3基于USB的虚拟串口ttyGS0以及ttyUSBXX 是一个数字编号譬如 0、1、2、 3 等都是USB的虚拟串口其中ttyGS0为usbgadget虚拟串口在系统启动之后可以在 windows 终端通过adbshell 命令进入开发板控制台。ttyUSBX在这里为4G模块的虚拟串口打印串口子系统:2字符设备层负责将用户空间的串口读写请求传递给内核空间的 tty_core 层。字符设备层将串口设备看作一个特殊的字符设备通过字符设备接口来进行操作。3tty_core 层是串口设备的通用处理层。在Linux内核中用于管 理串口设备如数据传输控制缓冲管理等。4uart_core 层位于tty_core层的下方提供了串口设备的底层驱动接口如负责控制串 口数据的发送和接收、中断处理、时钟管理等底层操作。首先要使能串口的驱动程序目的是让串口控制器工作起来不需要写串口外设直接操作设备节点发数据就可以了设备树首先对于串口的设备树只有下面东西可以改动:针对rk3568针对imx6ull的话只需添加引脚复用即可uart3 { pinctrl-names default; pinctrl-0 pinctrl_uart3; status okay; };串口应用编程:串口应用编程首先要配置串口的一些参数比如数据位停止位校验位structtermios结构体是Linux内核中用于终端I/O控制的结构体用于配置终端设备的输 入输出模式等属性。定义于头文件//这个结构体就是设置串口的模式等 struct termios { tcflag_t c_iflag; // 输入模式标志 tcflag_t c_oflag; // 输出模式标志 tcflag_t c_cflag; // 控制模式标志 tcflag_t c_lflag; // 本地模式标志 cc_t c_cc[NCCS]; // 控制字符数组 };常用串口控制函数介绍1tcgetattr()函数读取终端设备的当前属性如波特率、输入输出模式等并保存到structtermios结构体 中/* 功能读取终端/串口设备的当前属性保存到 struct termios 结构体中 参数 fd 文件描述符已打开的串口设备 termios_p保存当前终端属性的 struct termios 结构体指针 返回值 成功 - 返回 0 失败 - 返回 -1 */ int tcgetattr(int fd, struct termios *termios_p);2: tcsetattr()函数tcsetattr()函数在 Linux 系统中用于设置终端设备属性的函数常用于配置串口设备的 参数/* 功能设置终端/串口的配置参数 fd : 文件描述符打开的串口设备 optional_actions: 配置生效时机 TCSANOW - 立即生效 TCSADRAIN - 等待输出发送完再生效 TCSAFLUSH - 清空缓冲区再生效 termios_p : 指向 struct termios 结构体指针存放新配置 返回值 成功 - 返回 0 失败 - 返回 -1 */ int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);3: cfsetispeed()函数和 cfsetospeed()函数这俩个函数分别用于设置输入波特率和输出波特率/* 功能设置终端设备的输入波特率 参数 termios_p 指向 struct termios 结构体的指针保存终端设备属性信息 speed 要设置的输入波特率值 返回值 成功 - 返回 0 失败 - 返回 -1 */ int cfsetispeed(struct termios *termios_p, speed_t speed); int cfsetospeed(struct termios *termios_p, speed_t speed);4cfgetispeed()函数和 cfgetospeed()函数这俩个函数用于获取终端设备的输入和输出波特率/* 函数名称cfsetispeed 功能设置终端/串口的输入波特率 参数 termios_p指向 struct termios 结构体指针 speed 要设置的输入波特率B9600、B115200 等 返回值 成功 - 返回 0 失败 - 返回 -1 */ int cfsetispeed(struct termios *termios_p, speed_t speed); int cfsetospeed(struct termios *termios_p, speed_t speed);5tcflush()函数tcflush()函数用于清空终端的输入缓冲区、输出缓冲区或两者避免残留数据干扰后续操作/* 功能刷新终端/串口的数据缓冲区丢弃缓冲区中的残留数据 参数 fd 已打开的终端设备文件描述符 queue_selector 刷新缓冲区的方式 TCIFLUSH - 刷新输入缓冲区丢弃未读取的数据 TCOFLUSH - 刷新输出缓冲区丢弃未发送的数据 TCIOFLUSH - 同时刷新输入输出缓冲区 返回值 成功 - 返回 0 失败 - 返回 -1 */ int tcflush(int fd, int queue_selector);6tcflow()函数用于暂停或恢复终端的输入/输出数据流常用于流控场景如XON/XOFF协 议/* 功能暂停或恢复终端的输入/输出数据流用于流控场景 参数 fd 已打开的终端设备文件描述符 action 数据流控制动作 TCOOFF - 暂停数据的传输停止发送数据 TCOON - 恢复数据的传输继续发送数据 TCIOFF - 暂停数据的接收停止接收数据 TCION - 恢复数据的接收继续接收数据 返回值 成功 - 返回 0 失败 - 返回 -1 */ int tcflow(int fd, int action);7设置数据位大小/* 功能说明 将 termios 结构体中 c_cflag 标志位里的**数据位相关比特位清零** CSIZE 是数据位的位掩码代表数据位长度的所有比特位 */ new_cfg.c_cflag ~CSIZE; /* 功能说明 设置数据位为 8 位 CS8 代表 8 位数据位 */ new_cfg.c_cflag | CS8;8: 设置奇偶校验位/* 奇校验代码示例 功能启用奇校验、7位数据位、1个停止位 */ // 启用奇偶校验 options.c_cflag | PARENB; // 设置为奇校验PARODD1 options.c_cflag | PARODD; // 1 个停止位 options.c_cflag ~CSTOPB; // 清除数据位掩码 options.c_cflag ~CSIZE; // 设置8位数据位 options.c_cflag | CS8; // 立即生效配置 tcsetattr(fd, TCSANOW, options); /* 偶校验代码示例 功能启用偶校验、7位数据位、1个停止位 */ // 启用奇偶校验 options.c_cflag | PARENB; // 清除PARODD设置偶校验 options.c_cflag ~PARODD; // 清除数据位掩码 options.c_cflag ~CSIZE; // 设置8位数据位 options.c_cflag | CS8; // 立即生效配置 tcsetattr(fd, TCSANOW, options); /* 无校验代码示例 功能禁用奇偶校验最常用 */ struct termios options; // 获取当前串口配置 tcgetattr(fd, options); // 清除PARENB禁用奇偶校验 options.c_cflag ~PARENB;8设置停止位new_cfg.c_cflag ~CSTOPB; // 设置停止位为 1 位完整代码如下#includestdio.h #includetermios.h #includestring.h #includefcntl.h #includeunistd.h /* 设置串口参数的函数 参数 fd : 文件描述符 speed : 波特率 bits : 数据位 check : 校验位 stop : 停止位 返回值成功0失败-1/-2 */ int set_uart(int fd,int speed,int bits,char check,int stop) { struct termios newtio,oldtio; //步骤一保存原来的串口配置 if(tcgetattr(fd,oldtio)!0){ printf(tcgetattr oldtio error\n); return -1; } bzero(newtio,sizeof(newtio)); //步骤二设置控制模式标志 //开启串口接收 设置为本地工作模式 //清空原来的数据位掩码 newtio.c_cflag | CLOCAL | CREAD; newtio.c_cflag ~CSIZE; //步骤三设置数据位 switch(bits){ case 7: newtio.c_cflag | CS7; break; case 8: newtio.c_cflag | CS8; break; } //步骤四设置奇偶校验位 switch(check){ case O://奇校验 newtio.c_cflag | PARENB; newtio.c_cflag | PARODD; newtio.c_iflag | (INPCK | ISTRIP); break; case E://偶校验 newtio.c_cflag | PARENB; newtio.c_cflag ~PARODD; //开启奇偶校验检查功能并且自动剥离掉校验位只保留有效数据。 newtio.c_iflag | (INPCK | ISTRIP); break; case N://无校验 newtio.c_cflag ~PARENB; break; } //步骤五设置波特率 switch(speed){ case 9600: cfsetispeed(newtio,B9600); cfsetospeed(newtio,B9600); break; case 115200: cfsetispeed(newtio,B115200); cfsetospeed(newtio,B115200); break; } //步骤六设置停止位 switch(stop){ case 1: newtio.c_cflag ~CSTOPB;//1位停止位 break; case 2: newtio.c_cflag | CSTOPB;//2位停止位 break; } //步骤七刷新输入队列 tcflush(fd,TCIFLUSH); //步骤八设置配置立刻生效 if(tcsetattr(fd,TCSANOW,newtio)!0){ printf(tcsetattr newtio error\n); return -2; } return 0; } int main(int argc,char *argv[]) { int fd; char buf[128]; int count; //步骤九打开串口设备 fd open(/dev/ttyS9,O_RDWR | O_NOCTTY | O_NDELAY); //设置串口参数 set_uart(fd,115200,8,N,1); //写入数据 write(fd,argv[1],strlen(argv[1])); sleep(1); //读取数据 count read(fd,buf,sizeof(buf)); buf[count] \0; //输出读取的数据 printf(read message is %s\n,buf); //关闭串口设备 close(fd); return 0; }然后把串口的TX和RX短接就可以了运行测试自发自收