Linux C编程连载(3)-串口编程

【更新说明】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

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值