文件编程(5)串口应用编程

来源:互联网 发布:mac安装windows 编辑:程序博客网 时间:2024/06/07 03:58

一.终端

1.首先我们来了解一下终端的概念,终端指的是用户和计算机进行对话的接口,比如键盘,显示器,串口等物理设备,以及Xwindow上的虚拟终端等。类Unix系统都有文本式虚拟终端,使用ctrl + Alt + F1~F6可以进入文本虚拟终端。在Xwindow上可以打开几十个甚至更多的图形式虚拟终端,这些虚拟终端包括xterm还有rxvt等,而windows上则有crt以及putty等虚拟终端。


2.终端的工作模式

通过在termios结构的c_lflag中设置ICANNOW标志来定义终端是以什么模式工作。

(1)规范模式

所有的输入是基于行进行处理的。在用户输入一个行结束符(回车或者EOF)之前,用户调用read函数是读不到任何字符的。除了EOF之外的行结束符,包括回车都会被当做普通字符读到缓冲区。在这种模式下,行编辑是可行的,而且一次调用read函数最多只能读取一行数据,如果可读数据过多,会留到下一次再读取。


(2)非规范模式

所有输入都是即时有效,不需要用户输入行结束符,而且不可进行行编辑。对参数MIN(c_cc[VMIN])和TIME(c_cc[VTIME])的设置决定read函数的调用方式。分别如下

---》MIN = 0,TIME=0:

read函数立即返回。若有数据可读,则读取数据并返回读取到的字节数,否则读取失败并返回0

---》MIN >0,TIME=0:

至少有MIN个有效数据才会返回,否则一直阻塞

---》MIN = 0,TIME>0:

只要有数据可读或者是经过TIME个十分之一秒的时间就返回。要么返回读取到的字节数,要么返回0

---》MIN > 0,TIME>0:

当有MIN个字节数据可读的时候或者是两个输入字符之间的时间间隔超过TIME个十分之一秒的时候就返回。但是要在输入第一个字符以后才会启动定时器,所以至少读回一个字符。


(3)原始模式

   其实是一种特殊的非规范模式。所有输入数据以字节为单位被处理。终端不可回显,而且所有特定的终端输入输出控制处理不可用。通过调用cfmakeraw函数可以将终端设置为原始模式。


二.主要数据结构

1.struct  termios

{

unsigned short c_iflag;//输入模式标志

unsigned short  c_oflag; //输模式标志

unsigned short  c_cflag; //控制模式标志

unsigned short  c_lflag; //本地模式标志


unsigned char c_line;//线路规程

unsigned char c_cc[NCC];//控制特性

speed_t   c_ispeed; //输入波特率 

speed_t   c_ospeed;//输出波特率 

}

涉及到的头文件#include<termios.h>


2.c_cflag:他的成员都不能直接赋值对其进行初始化,而是要用按位与和按位或的方式操作。

(1)B115200:波特率,B+表示波特率的数值。

(2)EXTA:外部时钟率

(3)EXTB:外部时钟率

(4)CSIZE:数据位的位掩码

(5)CS5~CS8:(5~8)个数据位

(6)CSTOPB:2个停止位(不设则是一个停止位)

(7)CREAD:接收使能

(8)PARENB:校验位使能

(9)PARODD:使用奇校验而不是用偶校验

(10)HUPCL:最后关闭时挂线(放弃DTR)

(11)CLOCAL:本地连接,不改变端口所有者

(12)CRTSCTS:硬件流控


3.c_iflag:输入模式标志用于控制端口接收端的字符输入处理。他支持的常量名称如下

(1) IGNPAR:忽略奇偶校验

(2)PARMRK:奇偶校验错误掩码

(3)ISTRIP:裁剪掉第八位比特

(4)IXON:启动输出软件流控

(5)IXOFF:启动输入软件流控

(6)IXANY:允许输入任意字符可以重新启动输出(默认为输入起始字符才重启输出)

(7)IGNBRK:忽略输入终止条件

(8)BRKINT:当检测到输入终止条件的时候发送SIGINT信号

(9)INLCR:将换行(NL)转换为回车(CR)

(10)IGNCR:忽略回车

(11)ICRNL:将回车转换为换行

(12)IUCLC:将大写转为小写

(13)IMAXBEL:当输入队列满了的时候响铃


4.c_oflag:用于控制终端端口发送出去的字符处理,c_oflag支持的常量名称如下所示。(延时掩码几乎已经废弃了)

(1)OPOST:启用输出管理功能,如果不设置该标志,则其它标志都会被忽略

(2)OLCUC:将输出的大写转换为小写

(3)。。。。。。各种延时掩码


5.c_lflag:

(1)ISIG:若收到信号字符(如INTR,QUIT等)则会产生相应的信号

(2)ICANON:启用规范模式

(3)ECHO:启用本地回显功能

(4)ECHOE:若设置ICANON,则允许退格操作

(5)ECHOK:若设置ICANON,则KILL字符会删除当前行

(6)ECHONL:若设置ICANON,则允许回显换行符

(7)ECHOCTL,ECHOPRT,ECHOKE

(8)NOFLSH:在通常情况下,如果接受到INTR,QUIT和SUSP控制字符的时候,会清空输入和输出队列。如果设置该标志,则所有的队列不会被清空。

(9)TOSTOP:如果一个后台进程试图向他的控制终端进行写操作,则系统会向该后台进程所在的进程组发送SIGTTOU信号。该信号通常终止进程的执行。

(10)IEXTEN:启用输入处理功能。


6.c_cc:定义特殊控制特性。

(1)VINTR:中断控制字符。对应键为ctrl + c

(2)VQUIT:退出操作符,对应键为ctrl + z

(3)VERASE:删除操作符

(4)VKILL:删除行符,ctrl + u

(5)VEOF:文件结尾符,ctrl + d

(6)VEOL:附加行结尾符

(7)VEOL2:第二行结尾符

(8)VMIN:指定最少读取的字符数

(9)VTIME:指定读取的每个字符之间的超时时间


/**************************************filename:serialconfig.c*author:ZhenjunLiu*desc:config the serial with some args*************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <errno.h>#include <termios.h>#include <fcntl.h>#include <sys/time.h>#include <unistd.h>int set_com_config(int fd,int baudrate,int data_bit,char parity,int stop_bit){struct termios new_cfg,old_cfg;int speed;/*1.保存原先串口配置*/if(tcgetattr(fd,&old_cfg) != 0){perror("tcgetattr");return -1;}new_cfg = old_cfg;/*2.激活选项,设置为原始模式*/new_cfg.c_cflag |= CLOCAL | CREAD;cfmakeraw(&new_cfg);/*3.设置位掩码,除去位掩码*/new_cfg.c_cflag &= ~CSIZE;/*4.设置波特率*/switch(baudrate){case 2400:{speed = B2400;}break;case 4800:{speed = B4800;}break;case 9600:{speed = B9600;}break;case 19200:{speed = B19200;}break;case 38400:{speed = B38400;}break;case 230400:{speed = B230400;}break;case 115200:default:{speed = B115200;}break;}/*实际波特率的设置*/cfsetispeed(&new_cfg,speed);cfsetospeed(&new_cfg,speed);/*5.数据位设置*/switch(data_bit){case 7:{new_cfg.c_cflag |= CS7;}break;default:case 8:{new_cfg.c_cflag |= CS8;}break;}/*6.奇偶校验位*/switch(parity){default:case 'n':case 'N':{new_cfg.c_cflag &= ~PARENB;new_cfg.c_iflag &= ~INPCK;}break;case 'o':case 'O':{new_cfg.c_cflag |= (PARENB | PARODD);new_cfg.c_iflag |= INPCK;}break;case 'e':case 'E':{new_cfg.c_cflag |= PARENB;new_cfg.c_cflag &= ~PARODD;new_cfg.c_iflag |= INPCK;}break;case 's':case 'S':{new_cfg.c_cflag &= ~PARENB;new_cfg.c_cflag &= ~CSTOPB;}break;}/*7.设置停止位*/switch(stop_bit){case 1:default:{new_cfg.c_cflag &= ~CSTOPB; }break;case 2:{new_cfg.c_cflag |= CSTOPB;}break;}/*8.设置最少字符和等待时间*/new_cfg.c_cc[VTIME] = 0;new_cfg.c_cc[VMIN] = 6;/*9.清除串口缓冲TCIFLUSH:对接收到而未被读取的数据进行清空处理TCOFLUSH:对尚未传送成功的输出数据进行清空处理TCIOFLUSH:包括前两种功能,即对尚未处理的数据进行处理*/tcflush(fd,TCIFLUSH);/*10.激活配置TCSANOW:配置的修改立即生效TCSADRAIN:配置的修改在所有写入fd的输出都传输完毕之后生效TCSAFLUSH:所有已接收但未读入的输入都将在修改生效之前被丢弃*/if((tcsetattr(fd,TCSANOW,&new_cfg)) != 0){perror("tcsetattr");return -1;}return 0;}//#define COMGERAL1#define MAX_COM_NUM 4int open_serial(int com_port){int fd;#ifdef COMGERAL char *dev[] = {"/dev/ttySAC0","/dev/ttySAC1","/dev/ttySAC2","/dev/ttySAC3"};#elsechar *dev[] = {"/dev/ttyUSB0","/dev/ttyUSB1","/dev/ttyUSB2","/dev/ttyUSB3"};#endifif((com_port < 0) || (com_port > MAX_COM_NUM)){return -1;}fd = open(dev[com_port -1],O_RDWR | O_NOCTTY | O_NDELAY);if(fd < 0){perror("open");return -1;}if(fcntl(fd,F_SETFL,0) < 0){perror("fcntl");return -1; }if(isatty(fd) == 0){perror("This is not a tty");return -1;}return fd;}#define BUF_SIZE 1024int main(void){int fd,res;char buf[BUF_SIZE];char buff[BUF_SIZE];fd_set inset,tempset;struct timeval tv;FD_ZERO(&inset);if((fd = open_serial(1)) < 0){perror("open port");return -1;}if(set_com_config(fd,115200,8,'N',1) < 0){perror("set com_config");return -1;}FD_SET(fd,&inset);tv.tv_sec = 5;tv.tv_usec = 0;do{tempset = inset;printf("Please input some data(quit to exit)\n");memset(buf,0,BUF_SIZE);if(fgets(buf,BUF_SIZE,stdin) == NULL){perror("input error");break;}write(fd,buf,strlen(buf));memset(buff,0,BUF_SIZE);sleep(1);tv.tv_sec = 5;tv.tv_usec = 0;res = select(fd + 1,&tempset,NULL,NULL,&tv); if(res == 0)printf("time out \n");else if (res < 0)printf("select error\n");else{read(fd,buff,BUF_SIZE);printf("from zigbee:%s",buff);}}while(strncmp(buf,"quit",4) && (FD_ISSET(fd,&inset)));close(fd);return 0;}


0 0
原创粉丝点击