在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:\n");
fprintf(stdout, "\t-r | --baudrate the serial baud rate\n");
fprintf(stdout, "\t-h | --help show this help and exit\n");
}


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\n", optopt);
ret = -1;
break;
case '?':
fprintf(stdout, "%c invalid argument\n", 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\n",
__FILE__, __LINE__);
return -1;
}

//nonblock
if (fcntl(fd, F_SETFL, 0) < 0) {
printf("fcntl failed\n");
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!\n");
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!\n");
return -1;
}

printf("speed = %d\n", 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\n");
}

ret = cfsetospeed(&options, speed_arr[i]);
if (ret) {
perror("cfsetispeed");
printf("set out speed failed\n");
}
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\n");
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!\n");
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\n");
return -1;
}

switch (stopbits) {
case 1:
options.c_cflag &= ~CSTOPB;
break;
case 2:
options.c_cflag |= CSTOPB;
break;
default:
printf("Unsupported stop bits\n");
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!\n");
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\n");
ret = -1;
break;
}

if (size <= 0)
continue;

printf("size = %d\n", size);
if (data) {
free(data);
data = NULL;
}
data = calloc(1, size);
if (!data) {
printf("calloc failed\n");
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\n");
ret = -1;
break;
}
//printf("real read size = %d\n", len);
int n = write(fdtest, data, len);

if (n < 0) {
printf("write error!\n");
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\n",
__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\n");
goto out;
}

fdtest = open("/mnt/recv.h264", O_RDWR|O_SYNC);
if (fdtest < 0) {
printf("open fdtest failed\n");
goto out;
}

int n = write(fd, send, 1);

if (n <= 0) {
printf("send a failed\n");
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\n", __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 "\n"
ser.write(cmd1)
ser.close()
close(fd)

w()