欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Linux 串口编程

程序员文章站 2022-06-09 08:42:57
...

首先了解一下终端,Linux 下包括当前终端、前台控制台终端、串口和虚拟终端主设备,这些终端均被映射成一个文件(即设备文件),从而能用文件IO函数来操作这些文件来控制终端。

实际的物理串口: 即串口终端/dev/ttyS[n],ttyS系列指的是物理串行接口,即ttyS0为COM1,ttyS1为COM2。

若使用当前主机串口通过串口线连接到另一台主机的串口时,就能直接通信。

若使用的是VMware虚拟机方式,则可以用windows文件来代替串口,设置方法如下:

首先将虚拟机置为Power Off状态(很重要!否则不能设置),

点击虚拟机菜单“VM -- setting”,Linux 串口编程

没有seria port一项,点击Add--Serial Port,Linux 串口编程

选择next---然后选择OutPut to file 继续next,

Linux 串口编程

然后选择关联的windows文件,Finish,就设置完成了,Linux 串口编程

然后可以看到在Hardware里面有串口设备一项了。


重启虚拟机,如下图可以看到左数第六项图标变绿,说明设置成功。Linux 串口编程


下面测试是否能进行串口通信。

给出《linux高级程序设计》中的一段代码:

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

int speed_arr[] = {B38400, B19200, B9600, B4800, B2400, B1200, B300,
						B38400, B19200, B9600, B4800, B2400, B1200, B300,};
int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300,
						38400, 19200, 9600, 4800, 2400, 1200, 300,};
//终端属性结构体定义
#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];		//控制字符 
};

//fd is the open tty; speed is the rate 
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);	//设置属性,TCSANOW表示改变立即发生 
				if(status != 0)
				perror("tcsetattr fd1");
				return;
		}	
		tcflush(fd, TCIOFLUSH);
	}
	
}
//set data bit, stop bit and checksum bit
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 7:
			options.c_cflag |= CS7;
			break;
		case 8:
			options.c_cflag |= CS8;		//设置每帧数据位为 8 bit 
			break;
		default:
			fprintf(stderr,"Unsupported data size\n");
			return(FALSE);	
	}
	//INPCK 使能奇偶校验 PARENB 允许输出产生奇偶信息以及输入的奇偶校验 PARDD输入
	//和输出是奇校验方式  CSTOPB设置两位停止位而不是一位 
	switch (parity)
	{
		case 'n':
		case 'N':
			options.c_cflag &= ~PARENB;			//clear parity enable
			options.c_iflag &= ~INPCK;			//enable parity checking
			break;
		case 'o':
		case 'O':
			options.c_cflag |= (PARODD | PARENB);	//set as odd check
			options.c_iflag |= INPCK;				//disnable parity check
			break;
		case 'e':
		case 'E':
			options.c_cflag |= PARENB;				//enable parity
			options.c_cflag &= ~PARODD;
			options.c_iflag |= INPCK;				//disnable parity checking
			break;
		case 'S':
		case 's':
			options.c_cflag &= ~PARENB;
			options.c_cflag &= ~CSTOPB;
			break;
		default:
			fprintf(stderr,"Unsupported parity\n");
			return(FALSE);		
	}
	switch(stopbits)
	{
		case 1:
			options.c_cflag &= ~CSTOPB;
			break;
		case 2:
			options.c_cflag |= CSTOPB;
			break;
		default:
			fprintf(stderr,"Unsupported stop bits\n");
			return(FALSE);	
	}
	//set input parity option
	if(parity != 'n')
		options.c_iflag |= INPCK;
	options.c_cc[VTIME] = 150;		//15 seconds
	options.c_cc[VMIN] = 0;
	
	tcflush(fd, TCIFLUSH);			//update the options and do it now
	if( tcsetattr(fd, TCSANOW, &options) != 0)
	{
		perror("SetupSerial 3");
		return(FALSE);	
	}
	return (TRUE);
}
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.\n", argv[1]);
		exit(EXIT_FALURE);	
	}
	if((fd = open(dev, O_RDWR)) == -1)
	{
		perror("open");
		exit(EXIT_FAILURE);	
	}
	set_speed(fd, 19200); 
	
	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");
		exit(EXIT_FAILURE);		
	}
	printf("pls check the tty data\n");
	close(fd);
	exit(EXIT_SUCCESS);
}

在linux下运行:

Linux 串口编程

注意:若关联多个串口,则不一定为ttyS1,打开windows下关联的文件可以看到输出信息,即完成linux与windows串口通信。Linux 串口编程