zoukankan      html  css  js  c++  java
  • linux串口通信编程

    在linux下, 串口也被当做一个文件来使用, 所以串口传输数据实际上也就是对文件进行read/write操作.

    UART串口基本知识:

    一般, 串口至少有三根线:

    地线GND, 接收线RX和发送线TX. 有的开发板还可能把控制线CTS/RTS也引出来.


    串口查看方式:

    在PC端, 如果用USB口连接, 一般显示为/dev/ttyUSBx, 其中x为0, 1, 2...

    在开发板上,一般显示为/dev/ttySx, 其中x为0, 1, 2...


    在电脑上可以使用下面的方法查看或者设置串口属性:

    查看串口所有属性: sudo stty -F /dev/ttyUSB1 -a
    设置串口波特率: sudo stty -F /dev/ttyUSB1 ispeed 1152000 ospeed 1152000

    串口常用参数:

    波特率: 每秒钟传送的bit数. --> 通信速度.
    数据位: 每字节中实际所占的bit数, 取决于通信协议的选取. 比如,标准的ASCII码是0~127(7位)。扩展的ASCII码是0~255(8位)。
    停止位: 单个数据包的最后一位. 典型值为1, 1.5和2位..
    奇偶校验位: 有四种检错方式, 偶、奇、高和低。可以没有校验位.
    比特率: 数字信号的传输速率,单位时间内传输的二进制代码的有效位(bit)数,其单位为bit/s(bps)、Kbps或Mbps (此处K和M分别为1000和1000000)。

    串口编程流程:

    打开串口 --> 设置串口参数 --> 读写数据 --> 关闭串口
    其中设置串口属性是比较重要的环节.
    下面代码的功能: 给串口发送一个启动命令, 然后进入循环---从串口接收数据(数据头和数据分开传输), 并发送命令消息, 直到遇到终端信号或程序出错.
    第一个是C语言实现,第二个是python实现。

    #include <unistd.h>
    #include <signal.h>
    #include <time.h>
    #include <fcntl.h>
    #include <string.h>
    #include <getopt.h>
    #include <errno.h>
    #include <termios.h>
    #include <stdio.h>
    #include <stdlib.h>
     
    #define UART_NAME "/dev/ttyS0"
     
    static int g_quit;
    static int g_speed;
     
    static void handle_signal(int sig)
    {
    	if (SIGINT == sig || SIGTERM == sig)
    		g_quit = 1;
    }
     
    static struct sigaction sigact = {
    	.sa_handler = handle_signal,
    };
     
    static struct option longopts[] = {
    	{"help", no_argument, NULL, 'h'},
    	{"baudrate", required_argument, NULL, 'r'},
    	{0, 0, 0, 0},
    };
     
     
    static void print_usage(void)
    {
    	fprintf(stdout, "usage:
    ");
    	fprintf(stdout, "	-r | --baudrate  the serial baud rate
    ");
    	fprintf(stdout, "	-h | --help      show this help and exit
    ");
    }
     
     
    static int parse_arg(int argc, char **argv)
    {
    	int ret = 0;
    	char c = '0';
     
    	while (
    		(c = getopt_long(argc, argv, "-:r:h", longopts, NULL))
    		!= -1) {
    		switch (c) {
    		case 'r':
    			g_speed = atoi(optarg);
    			break;
    		case 'h':
    			ret = -1;
    			break;
    		case ':':
    			fprintf(stdout, "%c require argument
    ", optopt);
    			ret = -1;
    			break;
    		case '?':
    			fprintf(stdout, "%c invalid argument
    ", optopt);
    			ret = -1;
    			break;
    		default:
    			break;
    		}
    	}
     
    	return ret;
    }
     
    static int uart_open(char *filename)
    {
    	int fd;
     
    	//fd = open(filename, O_RDWR);
    	fd = open(filename, O_RDWR|O_NOCTTY|O_NDELAY);
    	if (fd < 0) {
    		printf("%s %d: failed to open output file
    ",
    				__FILE__, __LINE__);
    		return -1;
    	}
     
    	//nonblock
    	if (fcntl(fd, F_SETFL, 0) < 0) {
    		printf("fcntl failed
    ");
    		close(fd);
    		return -1;
    	}
    	return fd;
    }
     
    static int uart_set(int fd, int speed, int flow_ctrl,
    		int databits, int parity, int stopbits)
    {
    	struct termios options;
    	int ret = 0;
     
    	if (tcgetattr(fd, &options) != 0) {
    		printf("Setup serial fialed!
    ");
    		return -1;
    	}
     
    	int i;
    	int speed_arr[] = {B1500000, B1152000, B1000000, B921600,
    		B576000, B500000, B460800, B230400, B115200, B57600,
    		B38400, B19200, B9600, B4800, B2400, B1800, B1200,
    		B600, B300, B200, B150, B134, B110, B75, B50, B0};
    	int name_arr[] = {1500000, 1152000, 1000000, 921600,
    		576000, 500000, 460800, 230400, 115200, 57600,
    		38400, 19200, 9600, 4800, 2400, 1800, 1200,
    		600, 300, 200, 150, 134, 110, 75, 50, 0};
     
    	if (tcgetattr(fd, &options) != 0) {
    		printf("Setup serial fialed!
    ");
    		return -1;
    	}
     
    	printf("speed = %d
    ", speed);
    	for (i = 0; i < sizeof(speed_arr) / sizeof(int); i++) {
    		if (speed == name_arr[i]) {
    			ret = cfsetispeed(&options, speed_arr[i]);
    			if (ret) {
    				perror("cfsetispeed");
    				printf("set in speed failed
    ");
    			}
     
    			ret = cfsetospeed(&options, speed_arr[i]);
    			if (ret) {
    				perror("cfsetispeed");
    				printf("set out speed failed
    ");
    			}
    			break;
    		}
    	}
     
    	options.c_cflag |= CLOCAL;
    	options.c_cflag |= CREAD;
     
    	switch (flow_ctrl) {
    	case 0: // no flow control
    		options.c_cflag &= ~CRTSCTS;
    		break;
    	case 1: // hardware flow control
    		options.c_cflag |= CRTSCTS;
    		break;
    	case 2: //software flow control
    		options.c_cflag |= IXON|IXOFF|IXANY;
    		break;
    	default:
    		printf("Unsupported flow control
    ");
    		return -1;
    	}
     
    	options.c_cflag &= ~CSIZE;
    	switch (databits) {
    	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:
    		printf("Unsupported databits!
    ");
    		return -1;
    	}
     
    	switch (parity) {
    	case 'n': //no parity
    	case 'N':
    		options.c_cflag &= ~PARENB;
    		options.c_iflag &= ~INPCK;
    		break;
    	case 'o': //odd parity
    	case 'O':
    		options.c_cflag |= (PARODD | PARENB);
    		options.c_iflag &= INPCK;
    		break;
    	case 'e': //even parity
    	case 'E':
    		options.c_cflag |= PARENB;
    		options.c_cflag &= ~PARODD;
    		options.c_iflag |= INPCK;
    		break;
    	case 's': //blank
    	case 'S':
    		options.c_cflag &= ~PARENB;
    		options.c_iflag &= ~CSTOPB;
    		break;
    	default:
    		printf("Unsupported parity
    ");
    		return -1;
    	}
     
    	switch (stopbits) {
    	case 1:
    		options.c_cflag &= ~CSTOPB;
    		break;
    	case 2:
    		options.c_cflag |= CSTOPB;
    		break;
    	default:
    		printf("Unsupported stop bits
    ");
    		return -1;
    	}
     
    	//mode
    	options.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input*/
    	options.c_oflag  &= ~OPOST;   /*Output*/
     
    	//wait_time: 0.1s; min char to read:1
    	options.c_cc[VTIME] = 1;
    	options.c_cc[VMIN] = 1;
     
    	//if data overflow, receive data, but not read
    	tcflush(fd, TCIFLUSH);
     
    	//save configuration
    	if (tcsetattr(fd, TCSANOW, &options) != 0) {
    		printf("set serial error!
    ");
    		return -1;
    	}
    	return 0;
    }
     
    static int recv_data(int fd, int fdtest)
    {
    	int inflg = 0;
    	int ret, size;
    	int *data = NULL;
     
    	do {
    		if (g_quit)
    			break;
     
    		inflg = 0;
    		ret = 0;
    		size = 0;
    		int hsize = read(fd, &size, 4);
     
    		if (hsize < 0) {
    			printf("read header size error
    ");
    			ret = -1;
    			break;
    		}
     
    		if (size <= 0)
    			continue;
     
    		printf("size = %d
    ", size);
    		if (data) {
    			free(data);
    			data = NULL;
    		}
    		data = calloc(1, size);
    		if (!data) {
    			printf("calloc failed
    ");
    			ret = -1;
    			break;
    		}
     
    		int len = 0;
    		int left_size = size - len;
     
    		do {
    			len = read(fd, data, left_size);
    			if (len < 0) {
    				printf("read fd error
    ");
    				ret = -1;
    				break;
    			}
    			//printf("real read size = %d
    ", len);
    			int n = write(fdtest, data, len);
     
    			if (n < 0) {
    				printf("write error!
    ");
    				ret = -1;
    				break;
    			}
    			left_size = left_size - len;
    		} while (left_size > 0);
     
    		inflg = 1;
    	} while (!inflg);
     
    	if (data) {
    		free(data);
    		data = NULL;
    	}
    	return ret;
    }
     
    int main(int argc, char **argv)
    {
    	int ret = 0;
    	int fd, fdtest;
    	char send[1] = {'a'};
     
    	ret = sigaction(SIGINT, &sigact, NULL);
    	ret |= sigaction(SIGTERM, &sigact, NULL);
    	if (ret) {
    		printf("%s line%d: %s
    ",
    			__FILE__, __LINE__, strerror(errno));
    		return -1;
    	}
     
    	g_speed = 9600;
     
    	ret = parse_arg(argc, argv);
    	if (ret) {
    		print_usage();
    		return -1;
    	}
     
    	fd = uart_open("/dev/ttyS0");
    	if (fd < 0)
    		return -1;
     
    	int speed = g_speed;
    	int flow_ctrl = 0;
    	int databits = 8;
    	int stopbits = 1;
    	int parity = 'O';
     
    	ret = uart_set(fd, speed, flow_ctrl, databits, parity, stopbits);
    	if (ret) {
    		printf("uart_set failed
    ");
    		goto out;
    	}
     
    	fdtest = open("/mnt/recv.h264", O_RDWR|O_SYNC);
    	if (fdtest < 0) {
    		printf("open fdtest failed
    ");
    		goto out;
    	}
     
    	int n = write(fd, send, 1);
     
    	if (n <= 0) {
    		printf("send a failed
    ");
    		close(fdtest);
    		goto out;
    	}
     
    	do {
    		if (g_quit)
    			break;
     
    		ret = recv_data(fd, fdtest);
     
    		usleep(1000*10);
    		send[0] = 'b';
     
    		int res = write(fd, send, 1);
     
    		if (res < 0)
    			break;
    		/* printf("%s: %s: %d
    ", __FILE__, __func__, __LINE__); */
    	} while (!ret);
    	close(fdtest);
    out:
    	close(fd);
    	return ret;
    }
    

    python

    #!/usr/bin/python
    import serial
    import time
    import struct
     
    def w():
    	baud = 115200
    	fd = open("/home/sarah/2newh264/test15.h264", "w+")
    	ser = serial.Serial('/dev/ttyUSB1', baud, timeout=8)
    	print "baud: ", baud
    	cmd0 = 'a'
    	cmd1 = 'b'
    	ser.write(cmd0)
    	print "send ""+cmd0+"" to remotes"
    	while (1):
    		print "send ""+cmd1+"" to remotes"
    		h = ser.read(4)
    		if not h:
    			continue
    		size = struct.unpack("i", h)
    		print "size: ", size[0]
    		input = ser.read(size[0])
    		fd.write(input)
    		print "
    "
    		ser.write(cmd1)
    	ser.close()
    	close(fd)
     
    w()
    

    参考文档:

    linux串口通信编程_不积跬步无以至千里-CSDN博客_linux串口通信编程
    串口通信程序比较完整的一个! http://blog.csdn.net/w282529350/article/details/7378388
    LInux下串口设置详解 http://www.linuxidc.com/Linux/2011-04/33976.htm
    cfsetispeed 中文man页面 http://os.51cto.com/art/201108/286606.htm

    python serial 介绍 http://blog.csdn.net/u011577439/article/details/51762041

    Linux串口编程_WuYujun's blog-CSDN博客_linux 串口编程

      

  • 相关阅读:
    mysql登录等
    软工实践寒假作业(1/2)
    结对作业二——顶会热词统计的实现
    基于okhttp的安卓端网络编程
    Le vent se lève, il faut tenter de vivre
    软件评测
    一道算法题
    结对作业一
    软工实践寒假作业(2/2)
    实验六:Mininet脚本实现控制交换机行为
  • 原文地址:https://www.cnblogs.com/Malphite/p/15074299.html
Copyright © 2011-2022 走看看