#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include<time.h>
#include <termios.h>
#include <sys/select.h>
#include <sys/types.h>
//#include "COMM.h"
#define ACK_SUCCESS 0x00 // 操作成功
#define ACK_FAIL 0x01 // 操作失败
#define ACK_FULL 0x04 // Full
#define ACK_NOUSER 0x05 // 无此用户
#define ACK_USER_EXIST 0x07 // 用户已存在
#define ACK_TIMEOUT 0x08 // 采集超时
#define ACK_COUNT 0x3 //发生错误时候,重试次数
extern unsigned char TXBUF[9900];
extern unsigned char RXBUF[9900];
extern unsigned char rev_ok;
extern unsigned int TX_len;
extern unsigned int RX_len;
extern unsigned char one_onecontrast(unsigned char user_number_h,unsigned char user_number_l);
extern unsigned char one_morecontrast(void);
extern unsigned char Get_UserNumber_Right(void);
extern unsigned char set_addmode(unsigned char yn_repeat);
extern unsigned char add_Fingerprint(unsigned char time_number,unsigned char user_number_h,
unsigned char user_number_l,unsigned char user_right);
extern unsigned char del_alluser(void);
extern unsigned char del_oneuser(unsigned char user_number_h,unsigned char user_number_l);
extern unsigned char read_usernumber(void);
int fd;
unsigned char USER_NUMBER_H; // 用户号高8位
unsigned char USER_NUMBER_L; // 用户号低8位
unsigned char USER_RIGHT; // 用户权限
unsigned char FEATURE_BUFFER[512]; // 要下传的指纹特征值数据
unsigned char FEATURE_LEN; // 要下传的指纹特征值的长度
unsigned char CharToHex(unsigned char ch);
unsigned char select_one_onecontrast(void);
void select_Get_Usernumber_right(void);
/*********************************************************************************************
* name: SERIAL_TX
* func: 发生数据到指纹模块串口
* para: none
* ret: none
* modify:
* comment:
*********************************************************************************************/
int SERIAL_TX(void)
{
int ret;
ret = write(fd, TXBUF, TX_len); // 试图从串口发送数 据
if(ret == -1) // 确实接收到了数据,并打印出来
{
// *(rcv_buf+ret)='\0';
printf(" Write device error!\n");
return -1;
// ret = 0;
}
return 0;
}
/*********************************************************************************************
* name: SERIAL_RX
* func: 从指纹模块串口接收数据
* para: none
* ret: none
* modify:
* comment:
*********************************************************************************************/
void SERIAL_RX(void)
{
// read(fd, RXBUF , RX_len);
#if 1
int ret,n,pos,retval;
fd_set rfds;
struct timeval tv ;
pos = 0;//指向接收缓冲
tv.tv_sec = 2;
tv.tv_usec = 0;
for(n = 0; n < RX_len; n++)
{
RXBUF[n] = 0xFF;
}
//while(FD_ISSET(fd,&uart_r)||FD_ISSET(fd,&uart_w)); // 检测串口是否有读写动作
while(1) // 检测串口是否有读写动作
{
FD_ZERO(&rfds);// 清空串口接收端口集
FD_SET(fd,&rfds);// 设置串口接收端口集
retval = select(fd+1,&rfds,NULL,NULL,&tv);
if(retval == -1)
{
perror("select()");
break;
}
else if(retval)
{ //判断是否还有数据
//sleep(2);
ret = read(fd, RXBUF, RX_len);
pos += ret;
//printf("ret = %d \n",ret);
if((RXBUF[pos-2] == '\r') & (RXBUF[pos-1] == '\n')) // 确实接收到了数据,并打印出来
{
FD_ZERO(&rfds);
FD_SET(fd,&rfds);
retval = select(fd+1,&rfds,NULL,NULL,&tv);
if(!retval)//no datas
{
break;
}
}
}
else
{
break;
}
}
}
void init_ttyS(int fd)
{
struct termios newtio;
bzero(&newtio, sizeof(newtio));
tcgetattr(fd, &newtio); // 得到当前串口的参数
cfsetispeed(&newtio, B19200); // 将输入波特率设为19200
cfsetospeed(&newtio, B19200); // 将输出波特率设为19200
newtio.c_cflag |= (CLOCAL | CREAD); // 使能接收并使能本地状态
newtio.c_cflag &= ~PARENB; // 无校验 8位数据位1位停止位
newtio.c_cflag &= ~CSTOPB;
newtio.c_cflag &= ~CSIZE;
newtio.c_cflag |= CS8;
newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 原始数据输入
newtio.c_oflag &= ~(OPOST);
newtio.c_cc[VTIME] = 0; // 设置等待时间和最小接收字符数
newtio.c_cc[VMIN] = 0;
tcflush(fd, TCIFLUSH); // 处理未接收的字符
tcsetattr(fd,TCSANOW,&newtio); // 激活新配置
}
unsigned char set_addmode(unsigned char yn_repeat)
{
unsigned char check, i;
TXBUF[0] = 0xF5;
TXBUF[1] = 0x2D;
TXBUF[2] = 0x00;
TXBUF[3] = yn_repeat;
TXBUF[4] = 0x00;
TXBUF[5] = 0x00;
check = TXBUF[1];
for (i = 2; i < 6; i++)
{
check ^= TXBUF[i];
}
TXBUF[6] = check;
TXBUF[7] = 0xF5;
rev_ok = 1;
TX_len = 8;
RX_len = 8;
SERIAL_TX();
sleep(delaytime);
SERIAL_RX();
rev_ok = RXBUF[4];
return (rev_ok);
}
int main(int argc, char ** argv)
{
int t,ret;
char mode;
char *device = "/dev/tts/0"; // 设备路径,初始使用UART0
for(t=1;t<argc;t++) // 获取程序入口时输入的参数
{
if(!strcmp(argv[t],"-d") && (argc > (t+1)))
{
device = argv[t+1];
}
}
if(!strcmp(device,"/dev/tts/1")) // 不允许使用UART1,因为它已和PC相连。
{
printf("can not use /dev/tts/1\n");
return -1;
}
fd = open(device, O_RDWR); // 打开设备
if (fd < 0) // 设备打开失败
{
printf("open device error\n");
return -1;
}
init_ttyS(fd); // 初始化设备
while(1)
{
set_addmode(1); // 设置指纹添加模式,禁止重复
}
close(fd); // 关闭打开的设备
return 0; // 正常返回
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------2-----------------------------------------------------------------------------------------------------------------------------------
据通信的基本方式可分为并行通信与串行通信两种。
· 并行通信是指利用多条数据传输线将一个资料的各位同时传送。它的特点是传输速度
快,适用于短距离通信,但要求传输速度较高的应用场合。
· 串行通信是指利用一条传输线将资料一位位地顺序传送。特点是通信线路简单,利用
简单的线缆就可实现通信,降低成本,适用于远距离通信,但传输速度慢的应用场合。
串口设置详解
本节主要讲解设置串口的主要方法。
如前所述,设置串口中最基本的包括波特率设置,校验位和停止位设置。串口的设置主
要是设置struct termios结构体的各成员值,如下所示:
#include
struct termio
{
unsigned short c_iflag; /* 输入模式标志 */
unsigned short c_oflag; /* 输出模式标志 */
unsigned short c_cflag; /* 控制模式标志*/
unsigned short c_lflag; /*本地模式标志 */
unsigned char c_line; /* line discipline */
unsigned char c_cc[NCC]; /* control characters */
};
在这个结构中最为重要的是c_cflag,通过对它的赋值,用户可以设置波特率、字符大小、
数据位、停止位、奇偶校验位和硬件流控等。另外c_iflag 和c_cc 也是比较常用的标志。在
此主要对这3 个成员进行详细说明。
c_cflag支持的常量名称
CBAUD 波特率的位掩码
B0 0波特率(放弃DTR)
B1800 1800波特率
B2400 2400波特率
B4800 4800波特率
B9600 9600波特率
B19200 19200波特率
B38400 38400波特率
B57600 57600波特率
B115200 115200波特率
EXTA 外部时钟率
EXTB 外部时钟率
CSIZE 数据位的位掩码
CS5 5个数据位
CS6 6个数据位
CS7 7个数据位
CS8 8个数据位
CSTOPB 2个停止位(不设则是1个停止位)
CREAD 接收使能
PARENB 校验位使能
PARODD 使用奇校验而不使用偶校验
HUPCL 最后关闭时挂线(放弃DTR)
CLOCAL 本地连接(不改变端口所有者)
LOBLK 块作业控制输出
CNET_CTSRTS 硬件流控制使能
c_iflag支持的常量名称
INPCK 奇偶校验使能
IGNPAR 忽略奇偶校验错误
PARMRK 奇偶校验错误掩码
ISTRIP 除去奇偶校验位
IXON 启动出口硬件流控
IXOFF 启动入口软件流控
IXANY 允许字符重新启动流控
IGNBRK 忽略中断情况
BRKINT 当发生中断时发送SIGINT信号
INLCR 将NL映射到CR
IGNCR 忽略CR
ICRNL 将CR映射到NL
IUCLC 将高位情况映射到低位情况
IMAXBEL 当输入太长时回复ECHO
c_cc 支持的常量名称
VINTR 中断控制,对应键为CTRL+C
VQUIT 退出操作,对应键为CRTL+Z
VERASE 删除操作,对应键为Backspace(BS)
VKILL 删除行,对应键为CTRL+U
VEOF 位于文件结尾,对应键为CTRL+D
VEOL 位于行尾,对应键为Carriage return(CR)
VEOL2 位于第二行尾,对应键为Line feed(LF)
VMIN 指定了最少读取的字符数
VTIME 指定了读取每个字符的等待时间
串口控制函数
Tcgetattr 取属性(termios结构)
Tcsetattr 设置属性(termios结构)
cfgetispeed 得到输入速度
Cfgetospeed 得到输出速度
Cfsetispeed 设置输入速度
Cfsetospeed 设置输出速度
Tcdrain 等待所有输出都被传输
tcflow 挂起传输或接收
tcflush 刷清未决输入和/或输出
Tcsendbreak 送BREAK字符
tcgetpgrp 得到前台进程组ID
tcsetpgrp 设置前台进程组ID
[color=#ff0000]完整的串口配置模板,实用!把常用的选项在函数里面列出,可大大方便用户的调试使用[/color]
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
struct termios newtio,oldtio;
/*保存测试现有串口参数设置,在这里如果串口号等出错,会有相关的出错信息*/
if ( tcgetattr( fd,&oldtio) != 0)
{
perror("SetupSerial 1");
return -1;
}
bzero( &newtio, sizeof( newtio ) );
/*步骤一,设置字符大小*/
newtio.c_cflag |= CLOCAL | CREAD;
newtio.c_cflag &= ~CSIZE;
/*设置停止位*/
switch( nBits )
{
case 7:
newtio.c_cflag |= CS7;
break;
case 8:
newtio.c_cflag |= CS8;
break;
}
/*设置奇偶校验位*/
switch( nEvent )
{
case 'O': //奇数
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);
break;
case 'E': //偶数
newtio.c_iflag |= (INPCK | ISTRIP);
newtio.c_cflag |= PARENB;
newtio.c_cflag &= ~PARODD;
break;
case 'N': //无奇偶校验位
newtio.c_cflag &= ~PARENB;
break;
}
/*设置波特率*/
switch( nSpeed )
{
case 2400:
cfsetispeed(&newtio, B2400);
cfsetospeed(&newtio, B2400);
break;
case 4800:
cfsetispeed(&newtio, B4800);
cfsetospeed(&newtio, B4800);
break;
case 9600:
cfsetispeed(&newtio, B9600);
cfsetospeed(&newtio, B9600);
break;
case 115200:
cfsetispeed(&newtio, B115200);
cfsetospeed(&newtio, B115200);
break;
case 460800:
cfsetispeed(&newtio, B460800);
cfsetospeed(&newtio, B460800);
break;
default:
cfsetispeed(&newtio, B9600);
cfsetospeed(&newtio, B9600);
break;
}
/*设置停止位*/
if( nStop == 1 )
newtio.c_cflag &= ~CSTOPB;
else if ( nStop == 2 )
newtio.c_cflag |= CSTOPB;
/*设置等待时间和最小接收字符*/
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 0;
/*处理未接收字符*/
tcflush(fd,TCIFLUSH);
/*激活新配置*/
if((tcsetattr(fd,TCSANOW,&newtio))!=0)
{
perror("com set error");
return -1;
}
printf("set done!\n");
return 0;
}
[b]串口使用详解[/b]
在配置完串口的相关属性后,就可对串口进行打开,读写操作了。其使用方式与文件操作一样,区别在于串口是一个终端设备。
[b]打开串口[/b]
fd = open( "/dev/ttyS0", O_RDWR|O_NOCTTY|O_NDELAY);
Open函数中除普通参数外,另有两个参数O_NOCTTY和O_NDELAY。
O_NOCTTY: 通知linix系统,这个程序不会成为这个端口的控制终端。
O_NDELAY: 通知linux系统不关心DCD信号线所处的状态(端口的另一端是否激活或者停止)。
然后,恢复串口的状态为阻塞状态,用于等待串口数据的读入。用fcntl函数:
fcntl(fd, F_SETFL, 0);
接着,测试打开的文件描述府是否引用一个终端设备,以进一步确认串口是否正确打开。
isatty(STDIN_FILENO);
串口的读写与普通文件一样,使用read,write函数。
read(fd,buff,8);
write(fd,buff,8);
实例
#i nclude stdio.h>
#i nclude string.h>
#i nclude sys/types.h>
#i nclude errno.h>
#i nclude sys/stat.h>
#i nclude fcntl.h>
#i nclude unistd.h>
#i nclude termios.h>
#i nclude stdlib.h>
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
struct termios newtio,oldtio;
if ( tcgetattr( fd,&oldtio) != 0) {
perror("SetupSerial 1");
return -1;
}
bzero( &newtio, sizeof( newtio ) );
newtio.c_cflag |= CLOCAL | CREAD;
newtio.c_cflag &= ~CSIZE;
switch( nBits )
{
case 7:
newtio.c_cflag |= CS7;
break;
case 8:
newtio.c_cflag |= CS8;
break;
}
switch( nEvent )
{
case 'O':
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);
break;
case 'E':
newtio.c_iflag |= (INPCK | ISTRIP);
newtio.c_cflag |= PARENB;
newtio.c_cflag &= ~PARODD;
break;
case 'N':
newtio.c_cflag &= ~PARENB;
break;
}
switch( nSpeed )
{
case 2400:
cfsetispeed(&newtio, B2400);
cfsetospeed(&newtio, B2400);
break;
case 4800:
cfsetispeed(&newtio, B4800);
cfsetospeed(&newtio, B4800);
break;
case 9600:
cfsetispeed(&newtio, B9600);
cfsetospeed(&newtio, B9600);
break;
case 115200:
cfsetispeed(&newtio, B115200);
cfsetospeed(&newtio, B115200);
break;
default:
cfsetispeed(&newtio, B9600);
cfsetospeed(&newtio, B9600);
break;
}
if( nStop == 1 )
newtio.c_cflag &= ~CSTOPB;
else if ( nStop == 2 )
newtio.c_cflag |= CSTOPB;
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 0;
tcflush(fd,TCIFLUSH);
if((tcsetattr(fd,TCSANOW,&newtio))!=0)
{
perror("com set error");
return -1;
}
printf("set done!\n");
return 0;
}
int open_port(int fd,int comport)
{
char *dev[]={"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2"};
long vdisable;
if (comport==1)
{ fd = open( "/dev/ttyS0", O_RDWR|O_NOCTTY|O_NDELAY);
if (-1 == fd){
perror("Can't Open Serial Port");
return(-1);
}
else
printf("open ttyS0 .....\n");
}
else if(comport==2)
{ fd = open( "/dev/ttyS1", O_RDWR|O_NOCTTY|O_NDELAY);
if (-1 == fd){
perror("Can't Open Serial Port");
return(-1);
}
else
printf("open ttyS1 .....\n");
}
else if (comport==3)
{
fd = open( "/dev/ttyS2", O_RDWR|O_NOCTTY|O_NDELAY);
if (-1 == fd){
perror("Can't Open Serial Port");
return(-1);
}
else
printf("open ttyS2 .....\n");
}
if(fcntl(fd, F_SETFL, 0)0)
printf("fcntl failed!\n");
else
printf("fcntl=%d\n",fcntl(fd, F_SETFL,0));
if(isatty(STDIN_FILENO)==0)
printf("standard input is not a terminal device\n");
else
printf("isatty success!\n");
printf("fd-open=%d\n",fd);
return fd;
}
int main(void)
{
int fd;
int nread,i;
char buff[]="Hello\n";
if((fd=open_port(fd,1))0){
perror("open_port error");
return;
}
if((i=set_opt(fd,115200,8,'N',1))0){
perror("set_opt error");
return;
}
printf("fd=%d\n",fd);
// fd=3;
nread=read(fd,buff,8);
printf("nread=%d,%s\n",nread,buff);
close(fd);
return;
}