关闭

使用多路复用实现3个串口的通信

5553人阅读 评论(0) 收藏 举报
分类:

如题,Linux环境下操作串口设备,实现多路复用。

串口配置函数:

/*
 * set_com_config.c
 *
 *  Created on: 2012-7-18
 *      Author: liwei.cai
 */
#include <termios.h>
int set_com_config(int fd, int baud_rate,
		int data_bits, char parity, int stop_bits)
{
	struct termios new_cfg, old_cfg;
	int speed;

	//保存并测试现在有串口参数设置,在这里如果串口号等出错,会有相关的出错信息
	if(tcgetattr(fd, &old_cfg) != 0)
	{
		perror("tcgetattr");
		return -1;
	}
	//设置字符大小
	new_cfg = old_cfg;
	cfmakeraw(&new_cfg);//配置为原始模式
	new_cfg.c_cflag &= ~CSIZE;

	//设置波特率
	switch(baud_rate)
	{
		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;
		default:
		case 115200:
		{
			speed = B115200;
		}
		break;
	}
	cfsetispeed(&new_cfg, speed);
	cfsetospeed(&new_cfg, speed);

	//设置数据位
	switch(data_bits)
	{
		case 7:
		{
			new_cfg.c_cflag |=CS7;
		}
		break;
		default:
		case 8:
		{
			new_cfg.c_cflag |=CS8;
		}
		break;
	}

	//设置奇偶校验位
	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 |= (PARODD | PARENB);
			new_cfg.c_iflag |= INPCK;
		}
		break;
		case 'e':
		case 'E':
		{
			new_cfg.c_cflag |= PARENB;
			new_cfg.c_iflag &= ~PARODD;
			new_cfg.c_cflag |= INPCK;
		}
		break;

		case 's':
		case 'S':
		{
			new_cfg.c_cflag &= ~PARENB;
			new_cfg.c_iflag &= ~CSTOPB;
		}
		break;
	}

	//设置停止位
	switch(stop_bits)
	{
	default:
	case 1:
	{
		new_cfg.c_iflag &= ~CSTOPB;
	}
	break;

	case 2:
		new_cfg.c_iflag |= CSTOPB;
		break;
	}
	//设置等待时间和最小接受字符
	new_cfg.c_cc[VTIME] = 0;
	new_cfg.c_cc[VMIN] = 1;

	//处理未接受字符
	tcflush(fd, TCIFLUSH);
	//激活新配置
	if ((tcsetattr(fd, TCSANOW, &new_cfg)) != 0)
	{
		perror("tcsetattr");
		return -1;
	}
	return 0;
}
读取串口函数:

/*
 * open_port.c
 *
 *  Created on: 2012-7-18
 *      Author: liwei.cai
 */
//#include <termio.h>
//打开串口函数
int open_port(int com_port)
{
	int fd;
#if (COM_TYPE == GNR_COM) //使用普通串口
	char *dev[] = {"/dev/ttyS0", "/dev/ttyS1", "/dev/ttyS2"};
#else //使用USB转串口
	char *dev[] = {"/dev/ttyUSB0", "/dev/ttyUSB1", "/dev/ttyUSB2"};
#endif
	if ((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 serial port");
		return -1;
	}
	//恢复串口为阻塞状态
	if(fcntl(fd, F_SETFL, 0) < 0)
	{
		perror("fcntl F_SETFL\n");
	}
	//测试是否为终端设备
	if(isatty(STDIN_FILENO) == 0)
	{
		perror("standard input is not a terminal device");
	}
	return fd;
}
相关头文件:

/*
 * uart_api.h
 *
 *  Created on: 2012-7-18
 *      Author: liwei.cai
 */

#ifndef UART_API_H_
#define UART_API_H_

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <termios.h>

#define BUFFER_SIZE 1024
#define HOST_COM_PORT 1
#define TARGET_COM_PORT 2
#define MAX_COM_NUM 3

#include "open_port.c"
#include "set_com_config.c"


#endif /* UART_API_H_ */

功能主函数:

/*
 * main.c
 *
 *  Created on: 2012-7-19
 *      Author: liwei.cai
 */
#include <poll.h>
#include "uart_api.h"
int main(void)
{
	struct pollfd fds[MAX_COM_NUM];
	char buf[BUFFER_SIZE];
	int i, res, real_read, maxfd;

	//首先按照一定的权限打开两个源文件

	if((fds[0].fd = open_port(COM_1)) < 0) //串口1 接受数据
	{
		printf("Open COM1 error!\n");
		return 1;
	}
	if (set_com_config(fds[0].fd,115200, 8, 'N', 1) < 0)//配置串口1
	{
		perror("set_com_config3");
		return 1;
	}

	if((fds[1].fd = open_port(COM_2)) < 0)
	{
		printf("Open COM2 error!\n");
		return 1;
	}
	if (set_com_config(fds[1].fd,115200, 8, 'N', 1) < 0)//配置串口2
	{
		perror("set_com_config3");
		return 1;
	}

	if((fds[2].fd = open_port(COM_3)) < 0)
	{
		printf("Open COM3 error!\n");
		return 1;
	}
	if (set_com_config(fds[2].fd,115200, 8, 'N', 1) < 0)//配置串口3
	{
		perror("set_com_config3");
		return 1;
	}

	//取出两个文件描述符中的较大者
	for(i = 0; i < MAX_COM_NUM; i++)
	{
		fds[i].events = POLLIN;
	}
	//循环测试该文件描述符是否准备就绪,并调用select函数对象相关文件描述符做对应操作
	while(fds[0].events || fds[1].events
			|| fds[2].events)
	{
		if(poll(fds, MAX_COM_NUM,0) < 0)
		{
			printf("Poll error!\n");
			return 1;
		}
		for (i = 0; i < MAX_COM_NUM; i++)
		{
			if (fds[i].revents)
			{
				memset(buf, 0, BUFFER_SIZE);
				real_read = read (fds[i].fd, buf, BUFFER_SIZE);
				if (real_read < 0)
				{
					if (errno != EAGAIN)
					{
						return 1;
					}
				}
				else if (!real_read)
				{
					close(fds[i].fd);
					fds[i].events = 0;
				}
				else
				{
					buf[real_read] = '\0';
					//printf("%s", buf);
					if (i == 0)
					{
						write(fds[1].fd, buf, strlen(buf));
						write(fds[2].fd, buf, strlen(buf));
					}
					else
					{
						write(fds[0].fd, buf, strlen(buf));
					}

					if ((buf[0] == 'q') || (buf[0] == 'Q'))
					{
						return 1;
					}
				}// end of if real_read
			} //end of if revents
		} //end of for
	} //end of while
	return 0;
}





0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:122032次
    • 积分:1537
    • 等级:
    • 排名:千里之外
    • 原创:27篇
    • 转载:6篇
    • 译文:0篇
    • 评论:25条
    最新评论