7.1.1 实际的物理串口
如果使用虚拟机开发串口程序,可以使用win下文件来代替串口
7.1.2 控制台终端
tty1-tty6为控制台终端
7.1.3 虚拟终端
- /dev/ptmx虚拟设备
是一个字符文件,用于创建虚拟网络设备master/slave配对设备,要打开一个未使用的虚拟终端,通过调用posix_openpt(),来打开/dev/ptmx。 - /dev/pts虚拟设备
7.2 终端属性控制
终端属性包括:
输入属性、输出属性、控制属性、本地属性、行路规划属性和控制字符
7.2.1 读取/设置终端属性信息
终端属性结构体
#define NCCS 19
struct termios{
tcflag_t c_iflag //输入属性
tcflag_t c_oflag //输出属性
tcflag_t c_cflag //控制属性
tcflag_t c_lflag //本地属性
cc_t c_line //线路规划属性
cc_t c_cc[NCCS] //控制字符
}
获取某个打开的终端属性
extern int tcgetattr(int __fd, struct termios *__termios_p)
设置某个终端的属性
extern int tcsetattr(int __fd, int __optional_actions, __const struct termios *__termios_p)
__optional_actions指定什么时候改变会起作用
TCSANOW 改变立即发生
TCSADRAIN 应用于修改影像输出的选项时使用
TCSAFLUSH 应用于所有已接收但未读入的输入都在改变发生前丢弃
7.2.2 c_cflag终端控制选项
1.设置baud rate
波特率和比特率的区别
https://blog.csdn.net/qq_42035602/article/details/80194941
说白了就是波特率是信号经过调制后,单位时间内载波变化的次数,
比特率是单位时间内传输的位数,之所以不同,是因为一个载波内,可能传输多个二进制位,即;
比特率=波特率*单个调制状态对应的二进制位数
uart刚好对应一个载波传输一位,莫搞混。
获取输出波特率的属性
extern speed_t cfgetospeed(__const struct termios *__termios_p);
获取输入波特率的属性
extern speed_t cfgetispeed(__const struct termios *__termios_p);
设置输入、输出波特率
extern int cfsetospeed(struct termios *__termios_p, speed_t __speed);
extern int cfsetispeed(struct termios *__termios_p, speed_t __speed);
extern int cfsetspeed(struct termios *__termios_p, speed_t __speed);
2.设置帧数据位宽度
struct termios options;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
3.设置奇偶校验方式
options.c_cflag &= ~PARENB //无奇偶校验
options.c_cflag &= ~STOPB //1位停止位
4.设置硬件流控制
7.2.3 c_lflag
管理采用何种方式来输入字符,一般为标准模式或者原始模式
使用默认方式
所有字符缓存在buffer空间中,指导用户输入CR或者LF字符后才将其发送,输入内容的回显由本端完成
options.c_lflag |= (ICANON|ECHO|ECHOE);
使用原始方式
每输入一个字符都立即发送到服务器,服务器将把这个字符回显给客户的屏幕,这种情况将不需要用户自己支持回显。
options.c_lflag |= (ICANON|ECHO|ECHOE|ISIG);
7.2.4 c_iflag终端输入回显
输入 man cfsetispeed 查看输入选项常量描述
如果c_cflag允许了奇偶校验,则必须再允许输入校验
7.2.5 c_oflag终端输入选项
在上述打开文件内/c_oflag查看输出选项常量描述
7.2.6 c_cc终端控制字符
7.2.7 IOCTLS控制终端
7.3 串口编程
vicli@www.100ask.org:~/2_linux_program/_7_serial$ cat serial_exp.c
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "termios.h"
#include "errno.h"
#include "curses.h"
//设置数据位长度,奇偶校验、停止位等
int set_Parity(int fd, int databits, int stopbits, int parity)
{
struct termios options;
if(tcgetattr(fd, &options) != 0){
perror("Setupserial 1");
return (FALSE);
}
options.c_cflag &= ~CSIZE;
switch(databits){
case 8 : options.c_cflag |= CS8;
break;
default: fprintf(stderr, "unsupported data size\n");
return (FALSE);
}
switch(parity){
case 'N': options.c_cflag &= ~PARENB;
options.c_iflag &= ~INPCK;
break;
default : fprintf(stderr, "unsupported parity\n");
}
switch(stopbits){
case 1: options.c_cflag &= ~CSTOPB;
break;
default: fprintf(stderr, "unsupported stop bits\n");
return (FALSE);
}
if(parity != 'n')
options.c_iflag |= INPCK;
options.c_cc[VTIME] = 150;
options.c_cc[VMIN] = 0;
//刷清(扔掉)输入缓存(终端驱动法度已接管到,但用户法度尚未读)或输出缓存(用户法度已经写,但尚未发送).
tcflush(fd, TCIFLUSH);
if(tcsetattr(fd, TCSANOW, &options) != 0){
perror("setupserial 3");
return (FALSE);
}
return (TRUE);
}
int speed_arr[] = {B115200, B38400, B19200, B9600};
int name_arr[] = {115200, 38400, 19200, 9600};
void set_speed(int fd, int speed)
{
int i;
int status;
struct termios Opt;
tcgetattr(fd, &Opt);
for(i = 0; i < sizeof(speed_arr)/sizeof(int); i++){
if(speed == name_arr[i]){
tcflush(fd, TCIOFLUSH);
cfsetispeed(&Opt, speed_arr[i]);
cfsetospeed(&Opt, speed_arr[i]);
status = tcsetattr(fd, TCSANOW, &Opt);
if(status != 0){
perror("tcsetattr\n");
}
return;
}
}
}
int main(int argc, char *argv[])
{
int fd;
int nread;
char *ptr = argv[2];
char *dev = argv[1];
if(argc < 3){
printf("pls usage %s/dev/ttyS[n] your_message", argv[1]);
exit(EXIT_FAILURE);
}
if((fd = open(dev, O_RDWR)) == -1){
perror("open");
exit(EXIT_FAILURE);
}
set_speed(fd, 115200);
if((set_Parity(fd, 8, 1, 'N')) == FALSE){
printf("set parity error\n");
exit(EXIT_FAILURE);
}
if(write(fd, ptr, strlen(ptr)) < 0){
perror("write\n");
exit(EXIT_FAILURE);
}
printf("pls check the tty data\n");
close(fd);
exit(EXIT_SUCCESS);
}