CTDP linux 程序员手册 C和C++编程(12)一个 Linux 串口测试例子

下面的这个 Linux 串口测试程序在启动的时候需要相关的命令行参数。程序启动后,通过指定的串口,它将把键盘输入值发送出去。这个程序可以通过连接: com.c下载。我建议你通过连接下载它,而不是通过浏览器阅读,否则可能由于回车换行符引起不兼容的问题。

#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <sys/types.h>

#define BAUDRATE B38400
#define MODEMDEVICE "/dev/ttyS1"
#define _POSIX_SOURCE 1 //POSIX 兼容源码
#define FALSE 0
#define TRUE 1

volatile int STOP=FALSE;

void signal_handler_IO (int status); //信号处理
int wait_flag=TRUE; //TRUE 当没有信号到达
char devicename[80];
long Baud_Rate = 38400; // 缺省波特率 (110 到 38400)
long BAUD; // 从命令行得到 波特率
long DATABITS;
long STOPBITS;
long PARITYON;
long PARITY;
int Data_Bits = 8; // 数据位数 bits
int Stop_Bits = 1; // 停止位数 bits
int Parity = 0; // 校验位:
 // 00 = NONE, 01 = Odd, 02 = Even, 03 = Mark, 04 = Space
int Format = 4;
FILE *input;
FILE *output;
int status;

main(int Parm_Count, char *Parms[])
{
 char version[80] = " POSIX compliant Communications test program version 1.00 4-25-1999\r\n";
 char version1[80] = " Copyright(C) Mark Zehner/Peter Baumann 1999\r\n";
 char version2[80] = " This code is based on a DOS based test program by Mark Zehner and a Serial\r\n";
 char version3[80] = " Programming POSIX howto by Peter Baumann, integrated by Mark Zehner\r\n"; 
char version4[80] = " This program allows you to send characters out the specified port by typing\r\n";
 char version5[80] = " on the keyboard. Characters typed will be echoed to the console, and \r\n";
 char version6[80] = " characters received will be echoed to the console.\r\n";
 char version7[80] = " The setup parameters for the device name, receive data format, baud rate\r\n";
 char version8[80] = " and other serial port parameters must be entered on the command line \r\n";
 char version9[80] = " To see how to do this, just type the name of this program. \r\n";
 char version10[80] = " This program is free software; you can redistribute it and/or modify it\r\n";
 char version11[80] = " under the terms of the GNU General Public License as published by the \r\n";
 char version12[80] = " Free Software Foundation, version 2.\r\n";
 char version13[80] = " This program comes with ABSOLUTELY NO WARRANTY.\r\n";
 char instr[100] ="\r\nOn the command you must include six items in the following order, they are:\r\n";
 char instr1[80] =" 1. The device name Ex: ttyS0 for com1, ttyS1 for com2, etc\r\n";
 char instr2[80] =" 2. Baud Rate Ex: 38400 \r\n";
 char instr3[80] =" 3. Number of Data Bits Ex: 8 \r\n";
 char instr4[80] =" 4. Number of Stop Bits Ex: 0 or 1\r\n";
 char instr5[80] =" 5. Parity Ex: 0=none, 1=odd, 2=even\r\n";
 char instr6[80] =" 6. Format of data received: 1=hex, 2=dec, 3=hex/asc, 4=dec/asc, 5=asc\r\n";
 char instr7[80] =" Example command line: com ttyS0 38400 8 0 0 4 \r\n";
 char Param_strings[7][80];
 char message[90];

 int fd, tty, c, res, i, error;
 char In1, Key;
 struct termios oldtio, newtio; //为端口保存新的和老的端口设置
 struct termios oldkey, newkey; //为键盘保存新的和老的端口设置
 struct sigaction saio; //定义信号动作
 char buf[255]; //缓存
 
input = fopen("/dev/tty", "r"); //打开终端键盘open the terminal keyboard
 output = fopen("/dev/tty", "w"); //打开终端屏幕

 if (!input || !output)
 {
 fprintf(stderr, "Unable to open /dev/tty\n");
 exit(1);
 }

 error=0;
 fputs(version,output); //显示程序介绍
 fputs(version1,output);
 fputs(version2,output);
 fputs(version3,output);
 fputs(version4,output);
 fputs(version5,output);
 fputs(version6,output);
 fputs(version7,output);
 fputs(version8,output);
 fputs(version9,output);
 fputs(version10,output);
 fputs(version11,output); 
fputs(version12,output);
 fputs(version13,output);
 //从命令行读取参数
 if (Parm_Count==7) //如果命令行参数个数正确
 {
 for (i=1; i&#60Parm_Count; i++) // 找到全部参数
 {
 strcpy(Param_strings[i-1],Parms[i]);
 }
 i=sscanf(Param_strings[0],"%s",devicename);
 if (i != 1) error=1;
 i=sscanf(Param_strings[1],"%li",&Baud_Rate);
 if (i != 1) error=1;
 i=sscanf(Param_strings[2],"%i",&Data_Bits);
 if (i != 1) error=1;
 i=sscanf(Param_strings[3],"%i",&Stop_Bits);
 if (i != 1) error=1;
 i=sscanf(Param_strings[4],"%i",&Parity);
 if (i != 1) error=1;
 i=sscanf(Param_strings[5],"%i",&Format);
 if (i != 1) error=1;
 sprintf(message,"Device=%s, Baud=%li\r\n",devicename, Baud_Rate); //output the received setup parameters
 fputs(message,output);
 sprintf(message,"Data Bits=%i Stop Bits=%i Parity=%i Format=%i\r\n",Data_Bits, Stop_Bits, Parity, Format);
 fputs(message,output);
 } //end of if param_count==7
 if ((Parm_Count==7) && (error==0)) //如果命令行输入正确
 { //run the program
 tty = open("/dev/tty", O_RDWR | O_NOCTTY | O_NONBLOCK); //set the user console port up
 tcgetattr(tty,&oldkey); // 保存当前设置,这样命令可以被正确中断
 // 为非规范输入处理设置端口属性//必须是 NOCTTY
 newkey.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
 newkey.c_iflag = IGNPAR;
 newkey.c_oflag = 0;
 newkey.c_lflag = 0; //ICANON;
 newkey.c_cc[VMIN]=1;
 newkey.c_cc[VTIME]=0;
 tcflush(tty, TCIFLUSH);
 tcsetattr(tty,TCSANOW,&newkey);

 switch (Baud_Rate)
 {
 case 38400:
 default:
 BAUD = B38400;
 break;
 case 19200:
 BAUD = B19200;
 break;
 case 9600:
 BAUD = B9600;
 break;
 case 4800:
 BAUD = B4800;
 break;
 case 2400:
 BAUD = B2400;
 break;
 case 1800:
 BAUD = B1800;
 break;
 case 1200:
 BAUD = B1200;
 break;
 case 600:
 BAUD = B600;
 break;
 case 300:
 BAUD = B300;
 break;
 case 200:
 BAUD = B200;
 break;
 case 150:
 BAUD = B150;
 break;
 case 134:
 BAUD = B134;
 break;
 case 110:
 BAUD = B110;
 break;
 case 75:
 BAUD = B75;
 break;
 case 50:
 BAUD = B50;
 break;
 } //end of switch baud_rate
 switch (Data_Bits)
 {
 case 8:
 default:
 DATABITS = CS8;
 break;
 case 7:
 DATABITS = CS7;
 break;
 case 6:
 DATABITS = CS6;
 break;
 case 5:
 DATABITS = CS5;
 break;
 } //end of switch data_bits
 switch (Stop_Bits)
 {
 case 1:
 default:
 STOPBITS = 0;
 break;
 case 2:
 STOPBITS = CSTOPB;
 break;
 } //end of switch stop bits
 switch (Parity)
 {
 case 0:
 default: //none
 PARITYON = 0;
 PARITY = 0;
 break;
 case 1: //奇
 PARITYON = PARENB;
 PARITY = PARODD;
 break;
 case 2: //偶
 PARITYON = PARENB;
 PARITY = 0;
 break;
 } //end of switch parity
 
//打开设备(com 口)为非阻塞模式(读将立即返回)
 fd = open(devicename, O_RDWR | O_NOCTTY | O_NONBLOCK);
 if (fd < 0)
 {
 perror(devicename);
 exit(-1);
 }

 //在异步设备之前,安装串口过程
 saio.sa_handler = signal_handler_IO;
 sigemptyset(&saio.sa_mask); //saio.sa_mask = 0;
 saio.sa_flags = 0;
 saio.sa_restorer = NULL;
 sigaction(SIGIO,&saio,NULL);

 // 允许接受 SIGIO信号
 fcntl(fd, F_SETOWN, getpid());
 // 设置文件描述符异步 (手册说只有 O_APPEND 和 O_NONBLOCK, 可以用于 F_SETFL...)
 fcntl(fd, F_SETFL, FASYNC);
 tcgetattr(fd,&oldtio); // 保存当前串口设置 
// 为规范输入过程,设置新的属性 
newtio.c_cflag = BAUD | CRTSCTS | DATABITS | STOPBITS | PARITYON | PARITY | CLOCAL | CREAD;
 newtio.c_iflag = IGNPAR;
 newtio.c_oflag = 0;
 newtio.c_lflag = 0; //ICANON;
 newtio.c_cc[VMIN]=1;
 newtio.c_cc[VTIME]=0;
 tcflush(fd, TCIFLUSH);
 tcsetattr(fd,TCSANOW,&newtio);

 // 循环等待输入.通常我们在此做一些有用得事情
 while (STOP==FALSE)
 {
 status = fread(&Key,1,1,input);
 if (status==1) //如果一个键被敲击
 {
 switch (Key)
 { /* 键处理分支过程*/
 case 0x1b: /* Esc */
 STOP=TRUE;
 break;
 default:
 fputc((int) Key,output);
// sprintf(message,"%x ",Key); //debug
// fputs(message,output);
 write(fd,&Key,1); //写一个 byte 到串口
 break;
 } //end of switch key
 } //end if a key was hit
 // 接受到 SIGIO信号, wait_flag = FALSE, 输入是可选得并且可以读
 if (wait_flag==FALSE) /如果输入是可选的
 {
 res = read(fd,buf,255);
 if (resɬ)
 {
 for (i=0; i<res; i++) //遍历字符串中的全部字符
 {
 In1 = buf[i];
 switch (Format)
 {
 case 1: //hex
 sprintf(message,"%x ",In1);
 fputs(message,output);
 break;
 case 2: //decimal
 sprintf(message,"%d ",In1);
 fputs(message,output);
 break;
 case 3: //hex and asc
 if ((In1ថ) || (In1))
 {
 sprintf(message,"%x",In1);
 fputs(message,output);
 }
 else fputc ((int) In1, output);
 break;
 case 4: //decimal and asc
 default:
 if ((In1ថ) || (In1))
 {
 sprintf(message,"%d",In1);
 fputs(message,output);
 }
 else fputc ((int) In1, output);
 break;
 case 5: //asc
 fputc ((int) In1, output);
 break;
 } //end of switch format
 } //end of for all chars in string
 } //end if resɘ
// buf[res]=0;
// printf(":%s:%d\n", buf, res);
// if (res==1) STOP=TRUE; /* 如果只有一个CR输入,停止循环 */
 wait_flag = TRUE; /* 等待新的输入 */
 } //end if wait flag == FALSE

 } //while stop==FALSE
 // 恢复老串口设置
 tcsetattr(fd,TCSANOW,&oldtio);
 tcsetattr(tty,TCSANOW,&oldkey);
 close(tty);
 close(fd); //关闭串口
 } //end if command line entrys were correct
 else //给出如何使用命令行
 {
 fputs(instr,output);
 fputs(instr1,output);
 fputs(instr2,output);
 fputs(instr3,output);
 fputs(instr4,output);
 fputs(instr5,output);
 fputs(instr6,output);
 fputs(instr7,output);
 }
 fclose(input);
 fclose(output);
} //end of main

/***************************************************************************
*信号处理过程. 设置wait_flag = FALSE, 标明上面的循环当中收到了字符*
***************************************************************************/

void signal_handler_IO (int status)
{
// printf("received SIGIO signal.\n");
 wait_flag = FALSE;
}

<!-- google_ad_client = "pub-0057014352875780"; google_ad_width = 120; google_ad_height = 600; google_ad_format = "120x600_as"; google_ad_channel ="2584929872"; google_color_border = ["336699","000000","B4D0DC","A8DDA0"]; google_color_bg = ["FFFFFF","F0F0F0","ECF8FF","EBFFED"]; google_color_link = ["0000FF","0000FF","0000CC","0000CC"]; google_color_url = "008000"; google_color_text = ["000000","000000","6F6F6F","6F6F6F"]; //-->

使用这个程序的例子

这个程序允许一个用户通过两根串口线与另一个用户交流信息。它是一个测试的扩展,对于串口联接可以任意设置。编译好的程序名为 com 。可以如下使用它:

com /dev/ttyS0 38400 8 1 0 4

它将工作在 com1 口,波特率 38400 , 8 bits. 我把它做成一个文件,叫做 "fcom1" 并且放在系统目录内,可以作为一个脚本启动它。
google_ad_client = "pub-2416224910262877"; google_ad_width = 728; google_ad_height = 90; google_ad_format = "728x90_as"; google_ad_channel = ""; google_color_border = "E1771E"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_text = "000000"; google_color_url = "008000";

你可能感兴趣的:(编程,C++,c,linux,C#)