TTY和串口编程

TTY和串口编程

典型的字符设备
控制终端 tty

   tty是控制终端设备文件的统称,代表正控制着系统的终端

伪终端 pty(pseudo tty)

   pty masterpty slave构成;图形终端和远程控制终端都是pty

控制台终端 console

   主机的显示器称为控制台终端console,当在控制台终端登录时,tty1是虚拟终端,使用ALT+F1-6)来切换虚拟终端tty[1~6]tty0是代表当前所使用的虚拟终端的别名

串口终端 ttyS[n]
终端间的关系

1、串口终端、控制台终端、伪终端都可以称为控制终端

2、串口终端:标准输入输出都是指向串口,而非控制台屏幕

3、伪终端:用secure CRTputty等软件的telnet/ssh按照协议发送指令内容,由linux telnetdsshd服务调用mingetty完成标准输入输出设备的对接,并完成login

串口

用户常见的数据通信的基本方式有两种:

并行通信;
一条信息的各位数据被同时传送的通讯方式
串行通信;
一条信息的各位数据被逐位按顺序传送的通讯方式

串行通信是计算机常用的接口,如:RS-232-C接口。该标准规定采用一个DB25芯引脚连接器或DB9芯引脚连接器

异步串行通信

异步通信以单字符为发送单位,字符与字符发送可能存在间隔,因此在异步通信协议中做了如下规定:
起始位

   发送一个逻辑”0”,表示字符资料传送开始

数据位

  可允许4,5,6,7的数据位

停止位

  一个字符资料结束的标志位,支持1/1.5/2位的停止位

奇偶校验位

  根据传送数据内’1’的个数是偶数还是奇数来校验数据是否传送准确

空闲位

    在没有资料发送时,线路处于逻辑“1”状态

串口配置流程

设置波特率

n 保存原先串口配置使用 tcgetattr(fd,&oldtio) 函数

           struct termios newtio,oldtio;

           tcgetattr( fd,&oldtio);

n 激活选项有 CLOCAL CREAD, 用于本地连接和接收使能。

           newtio.c_cflag | =  CLOCAL | CREAD;

n 设置波特率,使用函数 cfsetispeed cfsetospeed

           cfsetispeed(&newtio, B115200);

           cfsetospeed(&newtio, B115200);

n 设置数据位,需使用掩码设置。

  newtio.c_cflag &= ~CSIZE;

  newtio.c_cflag |= CS8;

n 设置奇偶校验位,使用 c_cflag c_iflag
n 设置奇校验:

  newtio.c_cflag |= PARENB;

  newtio.c_cflag |= PARODD;

  newtio.c_iflag |= (INPCK | ISTRIP);

n 设置偶校验:

  newtio.c_iflag |= (INPCK | ISTRIP);

  newtio.c_cflag |= PARENB;

  newtio.c_cflag &= ~PARODD;

n 设置停止位,通过激活 c_cflag 中的 CSTOPB 实现。若停止位为 1 ,则清除 CSTOPB ,若停止位为 2 ,则激活 CSTOPB

  newtio.c_cflag &= ~CSTOPB;

n 设置最少字符和等待时间,对于接收字符和等待时间没有特别要求时,可设为 0

  newtio.c_cc[VTIME]  = 0;

  newtio.c_cc[VMIN] = 0;

设置流控制

不采用流控制

newtio.c_cflag &= ~CRTSCTS

硬件流控制

   newtio.c_cflag |= CRTSCTS

软件流控制

newtio.c_cflag | = IXON|IXOFF|IXANY

 

设置串口堵塞模式

fcntl 函数:

  fcntlfd, F_SETFL, 0;

  fcntl   (fd, F_SETFL, FNDELAY);

//*****************************************设置串口参数*******************************************
//2013.10.15.
//函数名:void set_opt(int fd, int nBit, int nECC)
//参数:int fd[文件描述符];int nBit[数据位长度7或8];int nECC[奇偶校验1奇校验、2偶校验、0没有]
//参数:int nSpeed[波特率];int nStop[停止位1或2]
//*****************************************设置串口参数*************************************

#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
int set_opt(int fd, int nBit, int nECC, int nSpeed, int nStop, bool Block)
{
 struct termios newstr;
 struct termios oldstr;

 memset(&newstr, 0, sizeof(newstr));
 memset(&oldstr, 0, sizeof(oldstr));
 //把原来的参数保存到oldterm
 tcgetattr(fd, &oldstr);

 //设置字符控制
 newstr.c_cflag |=  (CLOCAL | CREAD);  //CLOCAL:忽略调制解调器线路状态。CREAD:使用接收器
 newstr.c_cflag &= ~CSIZE;
 switch(nBit)
 {
 case 7:
  newstr.c_cflag |= CS7;     //设置字符长度为7
  break;
 case 8:
  newstr.c_cflag |= CS8;     //设置字符长度为8
  break;
 }
 //设置校验位
 switch(nECC)
 {
 case 0:          //无校验
  newstr.c_cflag &= ~PARENB;  
  break;
 case 1:          //设置奇校验
  newstr.c_cflag |= PARENB;
  newstr.c_cflag |= PARODD;
  newstr.c_iflag |= (INPCK | ISTRIP);
  break;
 case 2:          //设置偶校验
  newstr.c_iflag |= (INPCK | ISTRIP);
  newstr.c_cflag |= PARENB;
  newstr.c_cflag &= ~PARODD;
  break;
 }
 //设置波特率
 switch(nSpeed)  
 {  
 case 2400:  
  cfsetispeed(&newstr,B2400);  
  cfsetospeed(&newstr,B2400);  
  break;  
 case 4800:  
  cfsetispeed(&newstr,B4800);  
  cfsetospeed(&newstr,B4800);  
  break;  
 case 9600:  
  cfsetispeed(&newstr,B9600);  
  cfsetospeed(&newstr,B9600);  
  break;
 case 57600:  
  cfsetispeed(&newstr,B57600);  
  cfsetospeed(&newstr,B57600);  
  break;  
 case 115200:  
  cfsetispeed(&newstr,B115200);  
  cfsetospeed(&newstr,B115200);  
  break;  
 case 460800:  
  cfsetispeed(&newstr,B460800);  
  cfsetospeed(&newstr,B460800);  
  break;            
 default:  
  cfsetispeed(&newstr,B9600);  
  cfsetospeed(&newstr,B9600);  
  break;  
 }
 //设置停止位
 switch(nStop)
 {
 case 1:
  newstr.c_cflag &= ~CSTOPB;     //设置停止位为1
  break;
 case 2:
  newstr.c_cflag |= CSTOPB;     //设置停止位为2
  break;
 }
 //设置阻塞时间(阻塞条件下有效)
 newstr.c_cc[VTIME] = 150;      //(阻塞时间15s)
 newstr.c_cc[VMIN]  = 0;
 if (Block)
 {
  fcntl(fd, F_SETFL, 0);      //设置堵塞
 }
 tcflush(fd, TCIFLUSH);       //清空
 int i = tcsetattr(fd, TCSAFLUSH, &newstr);
 if (i != 0)
 {
  perror("Com Set Error");
  return 1;
 }
 printf("Com Set Success!");

 return 0;
}

int main()
{
 int fd = open("/dev/ttyS1", O_RDWR | O_NOCTTY | O_NDELAY);
 set_opt(fd, 8, 0, 9600, 1, true);
 char acBuf[1024] = {0};
 while (1)
 {
  printf("Please input:\n");
  memset(acBuf, 0, 1024);
  scanf("%s", acBuf);
  write(fd, acBuf, strlen(acBuf));
  read(fd, acBuf, sizeof(acBuf));
  printf("read data:  %s\n", acBuf);
 } 
 close(fd);

 return 0;
}

利用串口,实现两台机器间的聊天程序serialchat
通过读取配置文件serial.cfg,获取初始化串口的数据
通过控制终端,实现聊天内容的输入和输出,完成自由聊天,如:
you say:hello!
he say:hello!
支持汉字聊天

#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  

#define BUF_LEN 1024

static int set_opt(int fd, int nSpeed, int nBits, char nEvent, int nStop)  
{  
 struct termios newtio;  
 struct termios oldtio;  

 if(tcgetattr(fd,&oldtio) != 0)  
 {  
  perror("SetupSerial 1");  
  return -1;  
 }  

 bzero(&newtio,sizeof(newtio));  
 newtio.c_cflag |= CLOCAL |CREAD;  
 newtio.c_cflag &= ~CSIZE;  

 /***********数据位选择****************/   
 switch(nBits)  
 {  
 case 7:  
  newtio.c_cflag |= CS7;  
  break;  
 case 8:  
  newtio.c_cflag |= CS8;  
  break;      
 }  
 /***********校验位选择****************/ 
 /***********校验位选择****************/ 
 switch(nEvent)  
 {  
 case 'O':
 case 'o':
  newtio.c_cflag |= PARENB;  
  newtio.c_cflag |= PARODD;  
  newtio.c_iflag |= (INPCK | ISTRIP);  
  break;  
 case 'E':
 case 'e':
  newtio.c_iflag |= (INPCK |ISTRIP);  
  newtio.c_cflag |= PARENB;  
  newtio.c_cflag &= ~PARODD;  
  break;  
 case 'N':
 case 'n':
  newtio.c_cflag &= ~PARENB;  
  break;
 case 'S':
 case 's': /*as no parity*/
  newtio.c_cflag &= ~PARENB;
  newtio.c_cflag &= ~CSTOPB;
  newtio.c_iflag |= INPCK;
  break;
 default:
  return -1;
 }
 /***********波特率选择****************/  
 switch(nSpeed)  
 {  
 case 2400:  
  cfsetispeed(&newtio,B2400);  
  cfsetospeed(&newtio,B2400);  
  break;  
 case 4800:  
  cfsetispeed(&newtio,B4800);  
  cfsetospeed(&newtio,B4800);  
  break;  
 case 9600:  
  cfsetispeed(&newtio,B9600);  
  cfsetospeed(&newtio,B9600);  
  break;
 case 57600:  
  cfsetispeed(&newtio,B57600);  
  cfsetospeed(&newtio,B57600);  
  break;  
 case 115200:  
  cfsetispeed(&newtio,B115200);  
  cfsetospeed(&newtio,B115200);  
  break;  
 case 460800:  
  cfsetispeed(&newtio,B460800);  
  cfsetospeed(&newtio,B460800);  
  break;            
 default:  
  cfsetispeed(&newtio,B9600);  
  cfsetospeed(&newtio,B9600);  
  break;  
 }  
 /***********停止位选择****************/ 
 if(nStop == 1){  
  newtio.c_cflag &= ~CSTOPB;  
 }  
 else if(nStop ==2){  
  newtio.c_cflag |= CSTOPB;  
 }  
 newtio.c_cc[VTIME] = 150;   //阻塞条件下有效
 newtio.c_cc[VMIN]  = 0;  

 tcflush(fd,TCIFLUSH);  
 if((tcsetattr(fd,TCSANOW,&newtio)) != 0)  
 {  
  perror("com set error");  
  return -1;  
 }  
 printf("set done!\n");  
 return 0;  
}

int main(int argc, char *argv[])
{
 int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY );
 if (fd < 0)
 {
  printf("Open Com error : %d, message : %s\n",errno, strerror(errno));
  return -1;
 }

  set_opt(fd, 9600, 8, 'n',8);


 if( fcntl(fd, F_SETFL, FNDELAY) < 0)
 {
  printf("set block error : %d\n",errno);
 }

 char buf[BUF_LEN] = {0};
 int read_size = 0;
 while(1)
 {
  printf("wait...\n");
  read_size=read(fd, buf, BUF_LEN);
  buf[read_size] = '\0';
  printf("read size : %d, read data : \n%s", read_size,buf);
  
 }

 close(fd);
 return 0;
}

 

你可能感兴趣的:(TTY和串口编程)