Linux C编程连载【3】-串口编程

1.. 设计目的

设计一个串口程序,该程序执行时,具有通信参数选择及串口收发数据功能,界面友好。

2 设计流程图及说明

如图1.1所示,程序运行后,首先进入功能选择,共4中功能可供选择,分别为接收数据,发送数据,接收文件,发送文件。根据提示,键入不同的数字,可以进入不同的功能。设置完毕,进入参数设置,可以保持默认参数,也可以设置用户参数,若设置有误,还可以对参数重新设置。参数设置确认后,打开串口。若串口打开无误,则根据用户的选择进入不同的功能。

Linux C编程连载【3】-串口编程

图1.1 总体设计流程图

3 设计测试

3.1 测试环境及步骤

测试环境:VMware WorkStation 6.0.2+Fedora 10+minicom+广嵌开发板

测试步骤:

(1) 配置minicom

[[email protected] ~]$sudo minicom –s

Linux C编程连载【3】-串口编程

图3.1 配置minicom

(2) 建立nfs服务

[[email protected] ~]$sudo ifconfig eth0 192.168.2.1 netmask 255.255.255.0

[[email protected] ~]$sudo vi /etc/exports

添加

/mnt/share 192.168.2.*(rw,no_root_squash)

[[email protected] ~]$ sudo service nfs restart

将交叉编译的程序拷贝至/mnt/share目录下。

(3) 开发板连接串口,用网线和宿主机相连,运行minicom进入开发板(目标机)

[[email protected] ~]$sudo minicom

[[email protected](none) /]#mount –t nfs –o nolock 192.168.2.1:/mnt/share /mnt

(4) 打开另一个终端,进入宿主机程序目录

[[email protected] ~]$cd work/c/device/serial/

[[email protected] ~]$sudo ./serial

(5) 目标机

[[email protected](none) mnt]# ./serial

3.2 测试结果

(1)用2号功能(发送数据)控制目标机执行相应的命令

宿主机运行./serial,在功能选择时键入2,参数选择默认,进入数据发送。在宿主机输入相应的命令就可以控制目标机执行相应的命令。如图3.2所示,宿主机(图3.2左)分别发送ls、cd mnt、q(退出发送数据程序),目标机(图3.2右)执行了相应的命令。

Linux C编程连载【3】-串口编程

图3.2 宿主机控制目标机

(2)目标机与宿主机数据收发

宿主机运行./serial,键入2,选择数据发送。目标机运行./serial,键入1,选择数据接收。通信参数保持默认。宿主机发送hello,测试结果如图3.3(a)、(b)所示。

Linux C编程连载【3】-串口编程

图3.3(a) 宿主机发送数据

Linux C编程连载【3】-串口编程

图3.3(b) 目标机接收数据

(3)目标机接收宿主机启动信息

如图3.4所示,关闭minicom,宿主机运行./serial,选择1号功能,接收数据,参数保持默认。开发板上电,宿主机即可接收开发板启动信息。

Linux C编程连载【3】-串口编程

图3.4 宿主机接收目标机启动信息

(4)目标机接收文件

如图3.5所示,关闭minicom,宿主机运行./serial,选择3号功能,接收文件,参数保持默认。输入接收文件名为1.txt(可以指定保存路径,如/home/tande/1.txt)。打开宿主机开发板。接收完成后,文件夹中多了一个1.txt的文件。该文件的权限是root,要更改权限后才能查看。

Linux C编程连载【3】-串口编程

图3.5宿主机接收文件

(5)目标机发送文件

1)编辑发送文件(以root身份)

[[email protected] serial]$ sudo vi 1.txt?

ls

cd home

q

2)打开minicom,进入目标机。

3)新建一个终端,执行./serial,选择4号功能,参数保持默认。键入发送的文件名为1.txt。实验结果如图3.6(a)、(b)所示。

Linux C编程连载【3】-串口编程

图3.6(a)宿主机发送文件

Linux C编程连载【3】-串口编程

图3.6(b)目标机接收文件数据

(6) 通信参数设置

功能选择完成后,进入通信参数设置。程序提示“Use the default parameter ? y/n”。键入y,保持默认参数不变。键入n,进入用户参数设置。设置完成后,程序会提示参数信息,并询问“The parameter is OK? y/n”键入y,参数设置完成,键入n,返回重新设置,测试结果如图3.7(a-d)所示。若串口类型为USB转串口,则需要将uart.h中宏定义

#define COM_TYPE GNR_COM 改为 #define COM_TYPE USB_COM

重新编译即可。

Linux C编程连载【3】-串口编程

图3.7(a)参数设置

Linux C编程连载【3】-串口编程

图3.7(b)参数设置

Linux C编程连载【3】-串口编程

图3.7(c)参数设置

Linux C编程连载【3】-串口编程

图3.7(d)参数设置

【代码清单】

uart.h

#ifndef __UART_H__ #define __UART_H__ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <termios.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <errno.h> #define GNR_COM 0 #define USB_COM 1 #define COM_TYPE GNR_COM #define MAX_COM_NUM 6 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 |= CLOCAL|CREAD; new_cfg.c_cflag &= ~CSIZE; switch(baud_rate){ case 2400: { speed=B2400; } break; case 4800: { speed=B4800; } break; case 9600: { speed=B9600; } break; case 115200: { speed=B115200; } break; default : { speed=B115200; } break; }//end of switch cfsetispeed(&new_cfg,speed); cfsetospeed(&new_cfg,speed); switch(data_bits){ case 7: { new_cfg.c_cflag|=CS7; } break; case 8: { new_cfg.c_cflag|=CS8; } break; default: { new_cfg.c_cflag|=CS8; } break; }//end of switch 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_cflag &= ~PARODD; new_cfg.c_iflag |= INPCK; } break; case 's': case 'S': { new_cfg.c_cflag &= ~PARENB; new_cfg.c_cflag &= ~CSTOPB; } break; }//end of switch switch(stop_bits){ default: case 1: { new_cfg.c_cflag &= ~CSTOPB; } break; case 2: { new_cfg.c_cflag |= CSTOPB; } break; }//end of switch new_cfg.c_cc[VTIME] = 0; new_cfg.c_cc[VMIN] = 1; tcflush(fd,TCIFLUSH);//flush cache data if((tcsetattr(fd,TCSANOW,&new_cfg))!=0){ perror("tcsetattr"); return -1; } return 0; } int open_port(int com_port){ int fd; #if (COM_TYPE==GNR_COM) char *dev[] = {"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2"}; #else 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("fcntl F_SETFL"); } if(isatty(STDIN_FILENO)==0){ perror("standard input is not a terminal device"); } return fd; } #endif


serial.c

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #include <sys/types.h> #include <time.h> #include <sys/stat.h> #include <errno.h> #include "uart.h" #define BUFF_SIZE 1024 void rev_data(void); void send_data(void); void rev_file(void); void send_file(void); char init_set(void); static int fd; int main(int argc,char *argv[]) { int func=0; time_t sys_time; printf("Welcome to use serial tools!\n"); printf("Author:Tan De\n"); //printf("Today is %s\n",gettimeofday()); sys_time = time(NULL); printf("%s", ctime(&sys_time)); printf("Please choice function:\n"); printf("1-Receive data\n"); printf("2-Send data\n"); printf("3-Receive file\n"); //printf("If you want to use this function ,you must mkdir like serial /home/tande/serial(or ~/serial) in your home dir!\n"); printf("4-Send file\n"); printf("Your choice:"); scanf("%d",&func); getchar();//fflush(stdin); while(init_set()=='n') { init_set(); } switch(func) { case 1: printf("Receive data is ready!\n"); rev_data(); break; case 2: printf("Send data is ready!\n"); send_data(); break; case 3: printf("Receive file is ready!\n"); rev_file(); break; case 4: printf("Send file is ready\n"); send_file(); break; default: printf("Choose error!\nPleaserun again !\n"); } close(fd); return 0; } char init_set(void) { int com_port=1; int baud_rate=115200; int data_bits=8; char parity='N'; int stop_bits=1; static char set_flag='y'; static char corr_flag='y'; static char def_flag='y'; if(def_flag=='y') { printf("Default parameter : COM%d,%d,%d,%c,%d\n",com_port,baud_rate,data_bits,parity,stop_bits); printf("Use the default parameter? (y/n)\n"); scanf("%c",&set_flag); getchar(); if(set_flag=='n') { set_flag='y';//Enable user set mode def_flag='n';//Disable default paramter set mode } else if(set_flag=='y') { set_flag='n';//Disable user set mode } } if(set_flag=='y'){ printf("Please set serial port num!\n"); printf("1-COM1\n2-COM2\n3-COM3\n4-COM4\n5-COM5\n6-COM6\n"); printf("Serial port:"); scanf("%d",&com_port); getchar(); printf("Please set baud_rate!\n"); printf("2400 4800 9600 19200 38400 115200\n"); printf("Baud rate:"); scanf("%d",&baud_rate); getchar(); printf("Please set data_bits!\n7 8\n"); printf("Data_bits:"); scanf("%d",&data_bits); getchar(); printf("Please set parity\n"); printf("N-NONE O-ODD E-EVEN\n"); printf("Parity:"); scanf("%c",&parity); getchar(); printf("Please set stop_bits\n"); printf("1 2\n"); printf("Stop bits:"); scanf("%d",&stop_bits); getchar(); printf("Your choice is COM%d,%d,%d,%c,%d\n",com_port,baud_rate,data_bits,parity,stop_bits); printf("The Parameter is OK! (y/n)"); scanf("%c",&corr_flag); getchar(); if(corr_flag=='y') set_flag='n'; }//end of set parameter if(corr_flag=='y') { if((fd=open_port(com_port))>0) { printf("fd is %d\n",fd); if(set_com_config(fd,baud_rate,data_bits,parity,stop_bits)<0){ perror("Set_com_config"); } printf("Open Serial %d is OK!\n",com_port); } else { perror("open_port"); exit(1); } } return corr_flag; } void rev_data(void) { char buff[BUFF_SIZE]; do { memset(buff,0,BUFF_SIZE); if(read(fd,buff,BUFF_SIZE)>0) { printf("The receive data is :%s",buff); } else { } }while(strncmp(buff,"quit",4)&&strncmp(buff,"q",1)&&strncmp(buff,"Q",1)); close(fd); } void send_data(void) { char buff[BUFF_SIZE]; do{ printf("Input string (enter 'quit' or 'q' to exit):"); memset(buff,0,BUFF_SIZE); if(fgets(buff,BUFF_SIZE,stdin)==NULL) { perror("fgets"); break; } write(fd,buff,strlen(buff)); }while(strncmp(buff,"quit",4)&&strncmp(buff,"q",1)&&strncmp(buff,"Q",1)); close(fd); } void rev_file(void) { int len; int count; int page=5; int file_fd; char *content_path=""; char file_path[100]; char buff[BUFF_SIZE]; mode_t mode; // printf("You must make sure dir serial in ~/serial!\n"); // getchar(); // if((mkdir(content_path,mode &0777))==0) // printf("mkdir /home/tande/serial successful!\n"); //memset(file_path,0,100); printf("Please input the file_path to save the file data:\n"); fgets(file_path,sizeof(file_path),stdin); do { memset(buff,0,BUFF_SIZE); if((len=read(fd,buff,BUFF_SIZE))>0) { printf("File saving in %s\n",file_path); if((file_fd=open(file_path,O_RDWR|O_CREAT|O_APPEND,644))>0) if(count=write(file_fd,buff,strlen(buff))>0) { len=len-count; } else{ perror("Write data to file"); } else perror("Save data!\n"); } else { } }while(strncmp(buff,"quit",4)&&strncmp(buff,"q",1)&&strncmp(buff,"Q",1)&&((len!=0)||(page--))); printf("File saved in %s\n",file_path); close(file_fd); close(fd); } void send_file(void) { int file_fd; int len=1024; int count=0; int page=4; char *content_path=""; char file_path[100]; char buff[BUFF_SIZE*page]; printf("Please input the file_path to send the file:\n"); fgets(file_path,sizeof(file_path),stdin); printf("File Path :%s\n",file_path); if((file_fd=open(file_path,O_RDWR))>0) { memset(buff,0,BUFF_SIZE*page); if((len=read(file_fd,buff,sizeof(buff)))>0) { } else{ perror("Read file!\n"); } } else { perror("Open file!\n"); } do { if((count=write(fd,buff,len))>0) { len=len-count; printf("Sending file in %s\n",file_path); printf("Buff:%s\n",buff); } else { } memset(buff,0,BUFF_SIZE*page); }while((len!=0)); printf("Send file finish!\n"); close(file_fd); close(fd); }