赞
踩
串行接口 (Serial Interface) 是指数据一位一位地顺序传送,其特点是通信线路简单,只要一对传输线就可以实现双向通信,从而大大降低了成本,特别适用于远距离通信,但传送速度较慢。一条信息的各位数据被逐位按顺序传送的通讯方式称为串行通讯。
串行通讯的特点是:数据位的传送,按位顺序进行,最少只需一根传输线即可完成;成本低但传送速度慢。串行通讯的距离可以从几米到几千米;根据信息的传送方向,串行通讯可以进一步分为单工、半双工和全双工三种。
同步串行接口(SynchronousSerialInterface,SSI)是一种常用的工业用通信接口。。
异步串行是指UART(Universal Asynchronous Receiver/Transmitter),通用异步接收/发送。UART是一个并行输入成为串行输出的芯片,通常集成在主板上。UART包含TTL电平的串口和RS232电平的串口。
串口除了RS232,还有RS422,RS485,今天主要说的是RS232,其实USB(Universal Serial Bus)也是串口的一种,它的协议更加复杂,还有采用D+和D-差分信号,抗干扰能力更强,速率更快。
图片都是之前从网上找到
接下来开始讲代码了,主要分成两个部分,一就是串口配置,二是串口读写
- int open_uart(char* port)
- {
- int fd = open(port,O_RDWR|O_NOCTTY);
- if (fd < 0){
- printf("Open serial %s fail\n",port);
- return -1;
- }
- else{
- //printf("Open serial %s successful\n",port);
- }
- //set bolck mode
- if (fcntl(fd,F_SETFL,0)<0){
- printf("set %s block failed\n",port);
- }
- if(0 == isatty(STDIN_FILENO)){
- printf("standard input is not a terminal device\n");
- }
- //else{
- // printf("isatty success\n");
- //}
- return fd;
- }
配置串口
- int set_uart_config(int fd,uart_cfg_t* s_cfg)
- {
- int ret;
- unsigned int i;
- int speed_arr[] = { B115200, B9600};
- int name_arr[] = {115200, 9600};
- struct termios options;
-
- ret = tcgetattr( fd,&options);
- if( ret != 0){
- printf("ERROR: Get Serial Failed\n");
- return ret;
- }
-
- for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++){
- if(s_cfg->speed == name_arr[i]){
- cfsetispeed(&options, speed_arr[i]);
- cfsetospeed(&options, speed_arr[i]);
- }
- }
-
- options.c_cflag |= CLOCAL;
- options.c_cflag |= CREAD;
-
- switch(s_cfg->flow_ctrl)
- {
- case 0 :
- options.c_cflag &= ~CRTSCTS;
- break;
- case 1 :
- options.c_cflag |= CRTSCTS;
- break;
- case 2 :
- options.c_cflag |= IXON | IXOFF | IXANY;
- break;
- default:
- options.c_cflag |= IXON | IXOFF | IXANY;
- break;
- }
-
- options.c_cflag &= ~CSIZE;
- switch (s_cfg->data_bits){
- case 5 :
- options.c_cflag |= CS5;
- break;
- case 6 :
- options.c_cflag |= CS6;
- break;
- case 7 :
- options.c_cflag |= CS7;
- break;
- case 8:
- options.c_cflag |= CS8;
- break;
- default:
- options.c_cflag |= CS8;
- break;
- }
-
- switch (s_cfg->parity[0]){
- case 'n':
- case 'N':
- options.c_cflag &= ~PARENB;
- options.c_iflag &= ~INPCK;
- break;
- case 'o':
- case 'O':
- options.c_cflag |= (PARODD | PARENB);
- options.c_iflag |= INPCK;
- break;
- case 'e':
- case 'E':
- options.c_cflag |= PARENB;
- options.c_cflag &= ~PARODD;
- options.c_iflag |= INPCK;
- break;
- case 's':
- case 'S':
- options.c_cflag &= ~PARENB;
- options.c_cflag &= ~CSTOPB;
- break;
- default:
- options.c_cflag &= ~PARENB;
- options.c_cflag &= ~CSTOPB;
- break;
- }
-
- switch (s_cfg->stop_bits){
- case 1:
- options.c_cflag &= ~CSTOPB;
- break;
- case 2:
- options.c_cflag |= CSTOPB;
- break;
- default:
- options.c_cflag |= CSTOPB;
- break;
- }
-
- options.c_oflag &= ~OPOST;
- options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
- options.c_cc[VTIME] = 20;
- options.c_cc[VMIN] = 255;
- tcflush(fd,TCIFLUSH);
- ret=tcsetattr(fd,TCSANOW,&options);
- if (ret != 0){
- printf("ERROR: com set error!\n");
- return ret;
- }
- return ret;
- }
下面这些是我在写的时候,从网上查找并记录下来的一些笔记:
tcflag_t 是 unsigned short类型,cc_t 是 unsigned char类型
CRTCTS
使用硬件流控制。在高速(19200bps或更高)传输时,使用软件流控制会使效率降低,这个时候必须使用硬件流控制
~CRTCTS不控制
IXOFF
如果设置,为避免tty设备的输入缓冲区溢出,tty设备可以向终端发送停止符^S和开始符^Q,要求终端停止或重新开始
向计算机发送数据。通过停止符和开始符来控制数据流的方式叫软件流控制,软件流控制方式较少用,我们主要还是用
硬件流控制方式。硬件流控制在c_cflag标志中设置。
IXON
如果设置,接收到^S后会停止向这个tty设备输出,接收到^Q后会恢复输出。
IXANY
如果设置,则接到任何字符都会重新开始输出,而不仅仅是^Q字符。
options.c_cflag |= CS8; //使用8位数据位
options.c_cflag |= CS7; //使用7位数据位
options.c_cflag |= CS6; //使用6位数据位
options.c_cflag |= CS5; //使用5位数据位
CSIZE 先屏蔽其他标志位
options.c_cflag |= CSTOPB; //2位停止位
options.c_cflag &= ~CSTOPB; //1位停止位
PARODD 使用奇校验而不是偶校验
PARENB 校验使能位
INPCK 奇偶校验使能
1. N(None [没有])
2. O Odd 奇校验
3. E Even 偶校验
4. S Space 校验位固定为0
ISIG 当输入INTR、QUIT、SUSP或DSUSP时,产生相应的信号
ICANON 使用标准输入模式
XCASE 在ICANON和XCASE同时设置的情况下,终端只使用大写。
ECHO 显示输入字符
ECHOE 如果ICANON同时设置,ERASE将删除输入的字符
ECHOK 如果ICANON同时设置,KILL将删除当前行
OPOST 处理后输出
open未设置O_NONBLOCK或O_NDELAY的情况下
VTIME定义要求等待的时间量(取值不能大于cc_t)。
VMIN定义了要求等待的最小字节数。
options.c_cc[VTIME] = X; //设置从获取到1个字节后开始计时的超时时间
options.c_cc[VMIN] = Y; ? //设置要求等待的最小字节数
1、X=0,Y!=0。函数read()只有在读取了Y个字节的数据或者收到一个信号的时候才返回;
2、X!=0,Y=0。即使没有数据可以读取,read()函数等待X时间量后返回;
3、X!=0,Y!=0。第一个字节数据到时开始,最先满足收到Y个字节或达超时时间X任意一个条件,read()返回;
4、X=0,Y=0。即使读取不到任何数据,函数read也会立即返回
常用函数介绍。
1、读取当前参数函数:
int tcgetattr(int fd,struct termios *termios_p)
fd:open操作后返回的文件句柄
*termios_p:为前面介绍的结构体
初始化开始前调用这个函数.
2、获取当前波特率函数:
int speed_t cfgetispeed(const struct termios *termios_p)
int speed_t cfgetospeed(const struct termios *termios_p)
*termios_p:为前面介绍的结构体
成功返回0,失败返回-1
3、波特率设置函数:
int cfsetispeed(struct termios *termios_p,speed_t speed)
int cfsetospeed(struct termios *termios_p,speed_t speed)
*termios_p:为前面介绍的结构体
speed:波特率,常用B2400,B4800,B9600,B115200,B460800
成功返回0,失败返回-1
4、清空buffer数据函数:
int tcflush(int fd,int queue_selector)
queue_selector:有三个常用宏定义
TCIFLUSH:清空正读的数据,且不会读出
TCOFLUSH:清空正写入的数据,且不会发送到终端
TCIOFLUSH:清空所有正在发生的I/O数据.
成功返回0,失败返回-1
5、设置串口参数函数:
int tcsetattr(int fd,int optional_actions,cons struct termios *termios_p)
optional_actions:有三个常用宏定义
TCSANOW:不等数据传输完毕,立即改变属性
TCSADRAIN:等所有数据传输完毕,再改变属性
TCSAFLUSH:清空输入输出缓冲区才改变属性
成功返回0,失败返回-1
第二部分:串口读写,在这里我使用的是经tx和rx连接起来,自环
- int single_uart_test(uart_cfg_t *s_cfg)
- {
- int len = 0,res = 0,len_tmp = 0,flag = 0;
- char tmp[4096];
- bzero(tmp,sizeof(tmp));
- int fd = open_uart(uart_map(s_cfg->dev_id));
- init_uart(fd,s_cfg);
-
- if(signal(SIGTSTP,func_quit) == SIG_ERR){
- printf("signal error exit now!\n");
- return -1;
- }
- if(signal(SIGINT,func_quit) == SIG_ERR){
- printf("signal error exit now!\n");
- return -1;
- }
- printf("Welcome to com%d test mode:\n",s_cfg->dev_id);
-
- while(true){
- if (!flag) printf("Com%d says:",s_cfg->dev_id);
- flag++;
- fgets(big_buf,BUFFER_SIZE,stdin);
- len = strlen(big_buf);
- //printf("len:%d\n",len);
- write_uart(fd,big_buf,len,s_cfg->dev_id);
- read_uart(fd,s_cfg->dev_id,len,read_buf);
-
- if( (0 == strncmp(read_buf,"quit",4)) || (0 == strncmp(read_buf,"exit",4))){
- printf("quit console %d test mode \n",s_cfg->dev_id);
- exit(0);
- }
- if ( 0 != strncmp(read_buf,big_buf,sizeof(read_buf))){
- res++;
- }
- //string -'\0'
- if(len == (BUFFER_SIZE-1)){
- memcpy(tmp+len_tmp,read_buf,len);
- len_tmp += len;
- //printf("tmp:%s\n",tmp);
- }else{
- memcpy(tmp+len_tmp,read_buf,len);
- if(res == 0){
- printf("Com%d recv:%s\n",s_cfg->dev_id,tmp);
- printf("Com%d ------->pass \n",s_cfg->dev_id);
- len_tmp = 0;
- bzero(tmp,sizeof(tmp));
- }else{
- printf("Com%d ------->fail \n",s_cfg->dev_id);
- //flushes both data received but not read, and data written but not transmitted.
- tcflush(fd,TCIOFLUSH);
- }
- flag = 0;
- }
- bzero(read_buf,sizeof(read_buf));
- bzero(big_buf,sizeof(big_buf));
- }
- close_uart(fd,s_cfg->dev_id);
- return err_no;
- }
源码放在资源下载,源码是一个48ports串口服务器的串口测试代码,有删减。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。