【更新说明】2012-5-10,添加内容
【设计目的】
设计一个串口程序,该程序执行时,具有通信参数选择及串口收发数据功能,界面友好。
【设计流程图】
如图1.1所示,程序运行后,首先进入功能选择,共4中功能可供选择,分别为接收数据,发送数据,接收文件,发送文件。根据提示,键入不同的数字,可以进入不同的功能。设置完毕,进入参数设置,可以保持默认参数,也可以设置用户参数,若设置有误,还可以对参数重新设置。参数设置确认后,打开串口。若串口打开无误,则根据用户的选择进入不同的功能。
图1.1 总体设计流程图
【设计测试】
1 测试环境及步骤
测试环境:VMware WorkStation 6.0.2+Fedora 10+minicom+广嵌开发板
测试步骤:
(1) 配置minicom
[tande@localhost ~]$sudo minicom –s
图3.1 配置minicom
(2) 建立nfs服务
[tande@localhost ~]$sudo ifconfig eth0 192.168.2.1 netmask 255.255.255.0
[tande@localhost ~]$sudo vi /etc/exports
添加
/mnt/share 192.168.2.*(rw,no_root_squash)
[tande@localhost ~]$ sudo service nfs restart
将交叉编译的程序拷贝至/mnt/share目录下。
(3) 开发板连接串口,用网线和宿主机相连,运行minicom进入开发板(目标机)
[tande@localhost ~]$sudo minicom
[root@(none) /]#mount –t nfs –o nolock 192.168.2.1:/mnt/share /mnt
(4) 打开另一个终端,进入宿主机程序目录
[tande@localhost ~]$cd work/c/device/serial/
[tande@localhost ~]$sudo ./serial
(5) 目标机
[root@(none) mnt]# ./serial
2 测试结果
(1)用2号功能(发送数据)控制目标机执行相应的命令
宿主机运行./serial,在功能选择时键入2,参数选择默认,进入数据发送。在宿主机输入相应的命令就可以控制目标机执行相应的命令。如图3.2所示,宿主机(图3.2左)分别发送ls、cd mnt、q(退出发送数据程序),目标机(图3.2右)执行了相应的命令。
图3.2 宿主机控制目标机
(2)目标机与宿主机数据收发
宿主机运行./serial,键入2,选择数据发送。目标机运行./serial,键入1,选择数据接收。通信参数保持默认。宿主机发送hello,测试结果如图3.3(a)、(b)所示。
图3.3(a) 宿主机发送数据
图3.3(b) 目标机接收数据
(3)目标机接收宿主机启动信息
如图3.4所示,关闭minicom,宿主机运行./serial,选择1号功能,接收数据,参数保持默认。开发板上电,宿主机即可接收开发板启动信息。
图3.4 宿主机接收目标机启动信息
(4)目标机接收文件
如图3.5所示,关闭minicom,宿主机运行./serial,选择3号功能,接收文件,参数保持默认。输入接收文件名为1.txt(可以指定保存路径,如/home/tande/1.txt)。打开宿主机开发板。接收完成后,文件夹中多了一个1.txt的文件。该文件的权限是root,要更改权限后才能查看。
图3.5宿主机接收文件
(5)目标机发送文件
1)编辑发送文件(以root身份)
[tande@localhost serial]$ sudo vi 1.txt?
ls
cd home
q
2)打开minicom,进入目标机。
3)新建一个终端,执行./serial,选择4号功能,参数保持默认。键入发送的文件名为1.txt。实验结果如图3.6(a)、(b)所示。
图3.6(a)宿主机发送文件
图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
重新编译即可。
图3.7(a)参数设置
图3.7(b)参数设置
图3.7(c)参数设置
图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);
}
【更新2012-5-10】
如何使所有用户都有权限操作串口?
最近,在用cgi做一个串口实验,Linux默认只有root才有权限操作串口。因此利用cgi发现无法打开串口。怎样才能使所有的用户操作串口呢?在网上查了很多方法,有的说修改/etc/group文件,有的说修改/etc/passwd,这些方法发现都不好使。尝试执行:
sudo chmod 666 /dev/ttyS0
执行正常,可发现系统重启后,权限又还原为0660,其他组的用户无权限对其进行操作。
最后找到一种好方法:
在 /etc/security/console.perms 文件里增加如下两行
<COMn>=/dev/ttyS*
<console> 0666 <COMn> 0666 root.uucp
若需设置单个设备则可将ttyS* 改为 ttyS0等。完成后重启系统,然后查看设备权限,你会发现已经按你的要求设置初始化权限了。
转载请标明出处,仅供学习交流,勿用于商业目的
Copyright @ http://blog.csdn.net/tandesir