Linux下读取RFID卡号(C串口编程)
由于项目需要用到RFID、GPRS、摄像头等模块所以便看了一下,整理了一下学习思路,本篇先是整理一下串口读取RFID卡号的程序思路,后面还会更其他的
RFID模块:
本次采用的是125K的RFID读卡器和标签,很容易理解的,其实就是一张卡片里面存了一串数字(这个问题有点像你问一个艺术家洛必达法则是啥咦洛必达是啥),然后有个读卡器,当你把卡片放到读卡器上时,读卡器会将卡里面存的卡号读取出来,然后放到串口发送缓冲区,等待我们去读取,那么问题就是怎么读取。
串口读写:
大家都知道。linux下面一切皆文件,设备也不例外,上面提到的串口就是个设备文件,linux设备文件一般存放在“/dev/”下,当你ls的时候会发现一大堆什么ttyS0、sda、video....现在笔记本串口设备文件一般都是ttyUSBx(x=0,1,2...)。既然是文件,那就能打开喽,不过它不是被“右键->打开”,而是被“系统调用open()”。当然不只是把它打开就完了,操作串口有一系列的系统调用。说到系统调用,其实就是系统底层给在上层编写程序的你提供的一些系统级函数。
一些需要的头文件:
- #include <unistd.h> /*linux系统调用*/
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <fcntl.h> /*文件控制*/
- #include <sys/stat.h> /*文件状态*/
- #include <sys/types.h> /*定义系统类型,像size_t等*/
- #include <errno.h> /*出错码*/
- #include <termios.h> /*终端参数*/
1.打开串口
这里把open()这个系统调用封装成一个com_open()函数,可以方便判断是否打开成功并打印错误信息。
参数*DEV是文件路径(上面提到的/dev/ttyUSBx),第二个参数告诉它是以什么方式打开,常见的有:
O_RDONLY 只读
O_WRONLY 只写
O_RDWR 读写
注:上面的三个不能同时出现,即不能这样写O_RDONLY | O_RDWR,像下面这些是可选的:
O_NOCTTY 如果路径名指向终端设备,不要把这个设备用作控制终端。
O_NONBLOCK 阻塞模式(详见配置串口处)
open()返回值是int型fd文件描述符,const char *DEV)
- {
- int fd = -1;
- open(DEV, O_RDWR);
- if(fd == -1)
- {
- perror("open error");
- exit(0);
- }
- return fd;
- }
2.配置串口
设置串口属性(类似于约定好双方通信协议),即上面提到的配置串口,其实主要就是设置termios.h中的termios结构体参数:
- typedef struct com_attr /*我自己定义的串口属性结构*/
- {
- unsigned int baudrate; /*波特率*/
- unsigned char databits; /*数据位*/
- unsigned char stopbits; /*停止位*/
- unsigned char parity; /*校验位*/
- }com_attr;
- struct termios /*termios结构,其实终极目的就是把我们自己定义的结构属性设置到这里面去*/
- {
- tcflag_t c_iflag; //输入模式标志
- tcflag_t c_oflag; //输出模式标志
- tcflag_t c_cflag; //控制模式标志
- tcflag_t c_lflag; //本地模式标志
- cc_t c_line; //line discipline
- cc_t c_cc[NCC]; //control characters
- }
可以看到两个参数,第一个文件描述符,告诉它你想在个文件操作,第二个是我定义的串口属性结构体:
注:由于项目需要,可能有些不必要的参数我就没有去设置和解释,详细可以google一下配置串口属性结构体详细介绍!
- int set_com_attr(int fd, com_attr *attr)
- {
- struct termios opt;
- memset(&opt, 0, sizeof(struct termios));
- tcgetattr(fd, &opt);
- cfmakeraw(&opt);
- /*******************波特率********************/
- printf("set baudrate %d\n", attr->baudrate);
- switch (attr->baudrate)
- {
- case 50:
- cfsetispeed(&opt, B50);
- cfsetospeed(&opt, B50);
- break;
- case 75:
- cfsetispeed(&opt, B75);
- cfsetospeed(&opt, B75);
- break;
- case 110:
- cfsetispeed(&opt, B110);
- cfsetospeed(&opt, B110);
- break;
- case 134:
- cfsetispeed(&opt, B134);
- cfsetospeed(&opt, B134);
- break;
- case 150:
- cfsetispeed(&opt, B150);
- cfsetospeed(&opt, B150);
- break;
- case 200:
- cfsetispeed(&opt, B200);
- cfsetospeed(&opt, B200);
- break;
- case 300:
- cfsetispeed(&opt, B300);
- cfsetospeed(&opt, B300);
- break;
- case 600:
- cfsetispeed(&opt, B600);
- cfsetospeed(&opt, B600);
- break;
- case 1200:
- cfsetispeed(&opt, B1200);
- cfsetospeed(&opt, B1200);
- break;
- case 1800:
- cfsetispeed(&opt, B1800);
- cfsetospeed(&opt, B1800);
- break;
- case 2400:
- cfsetispeed(&opt, B2400);
- cfsetospeed(&opt, B2400);
- break;
- case 4800:
- cfsetispeed(&opt, B4800);
- cfsetospeed(&opt, B4800);
- break;
- case 9600:
- cfsetispeed(&opt, B9600);
- cfsetospeed(&opt, B9600);
- break;
- case 19200:
- cfsetispeed(&opt, B19200);
- cfsetospeed(&opt, B19200);
- break;
- case 38400:
- cfsetispeed(&opt, B38400);
- cfsetospeed(&opt, B38400);
- break;
- case 57600:
- cfsetispeed(&opt, B57600);
- cfsetospeed(&opt, B57600);
- break;
- case 115200:
- cfsetispeed(&opt, B115200);
- cfsetospeed(&opt, B115200);
- break;
- case 230400:
- cfsetispeed(&opt, B230400);
- cfsetospeed(&opt, B230400);
- break;
- case 460800:
- cfsetispeed(&opt, B460800);
- cfsetospeed(&opt, B460800);
- break;
- case 500000:
- cfsetispeed(&opt, B500000);
- cfsetospeed(&opt, B500000);
- break;
- case 576000:
- cfsetispeed(&opt, B576000);
- cfsetospeed(&opt, B576000);
- break;
- case 921600:
- cfsetispeed(&opt, B921600);
- cfsetospeed(&opt, B921600);
- break;
- case 1000000:
- cfsetispeed(&opt, B1000000);
- cfsetospeed(&opt, B1000000);
- break;
- case 1152000:
- cfsetispeed(&opt, B1152000);
- cfsetospeed(&opt, B1152000);
- break;
- case 1500000:
- cfsetispeed(&opt, B1500000);
- cfsetospeed(&opt, B1500000);
- break;
- case 2000000:
- cfsetispeed(&opt, B2000000);
- cfsetospeed(&opt, B2000000);
- break;
- case 2500000:
- cfsetispeed(&opt, B2500000);
- cfsetospeed(&opt, B2500000);
- break;
- case 3000000:
- cfsetispeed(&opt, B3000000);
- cfsetospeed(&opt, B3000000);
- break;
- case 3500000:
- cfsetispeed(&opt, B3500000);
- cfsetospeed(&opt, B3500000);
- break;
- case 4000000:
- cfsetispeed(&opt, B4000000);
- cfsetospeed(&opt, B4000000);
- break;
- default:
- printf("unsupported baudrate %d\n", attr->baudrate);
- return FALSE;
- break;
- }
- /************************校验位************************/
- switch (attr->parity)
- {
- case COMM_NOPARITY:
- opt.c_cflag &= ~PARENB;
- opt.c_iflag &= ~INPCK;
- break;
- case COMM_ODDPARITY:
- opt.c_cflag |= PARENB;
- opt.c_cflag |= PARODD;
- opt.c_iflag |= INPCK;
- break;
- case COMM_EVENPARITY:
- opt.c_cflag |= PARENB;
- opt.c_cflag &= ~PARODD;
- opt.c_iflag |= INPCK;
- default:
- printf("unsupported parity %d\n", attr->parity);
- return FALSE;
- break;
- }
- opt.c_cflag &= ~CSIZE; /*无论设置多少校验位都需要的*/
- /*******************数据位*****************/
- switch (attr->databits)
- {
- case 5:
- opt.c_cflag |= CS5;
- break;
- case 6:
- opt.c_cflag |= CS6;
- break;
- case 7:
- opt.c_cflag |= CS7;
- break;
- case 8:
- opt.c_cflag |= CS8;
- break;
- default:
- printf("unsupported data bits %d\n", attr->databits);
- return FALSE;
- break;
- }
- opt.c_cflag &= ~CSTOPB;
- /*******************停止位***************/
- switch (attr->stopbits)
- {
- case COMM_ONESTOPBIT:
- opt.c_cflag &= ~CSTOPB;
- break;
- case COMM_TWOSTOPBITS:
- opt.c_cflag |= CSTOPB;
- break;
- default:
- printf("unsupported stop bits %d\n", attr->stopbits);
- return FALSE;
- break;
- }
- /*等待时间,阻塞模式下设置的*/
- //opt.c_cc[VTIME] = 0; /*设置超时时间*/
- //opt.c_cc[VMIN] = 1;
- opt.c_iflag &= ~(ICRNL | INLCR);
- opt.c_iflag &= ~(IXON | IXOFF | IXANY);/*关闭软件流控(一般都是关闭软硬流控,我也不知道为啥)*/
- tcflush(fd, TCIOFLUSH); //刷清缓冲区
- if (tcsetattr(fd, TCSANOW, &opt) < 0)
- {
- printf("tcsetattr faild\n");
- return FALSE;
- }
- return TRUE;
- }
当以阻塞模式打开时也可以通过修改结构体termios来改变位非阻塞模式或者通过函数fcntl()函数:
阻塞:fcntl(fd, F_SETFL, 0)
对于read,阻塞指当串口输入缓冲区没有数据的时候,read函数将会阻塞在这里,直到串口输入缓冲区中有数据可读取时read读到了需要的字节数之后,返回值为读到的字节数;对于write,指当串口输出缓冲区满或剩下的空间小于将要写入的字节数,write函数将阻塞在这里,一直到串口输出缓冲区中剩下的空间大于等于将要写入的字节数,执行写入操作,返回写入的字节数。
注:控制符VTIME定义要等待的时间t(百毫秒),VMIN定义了要等待的最小字节数n,以下几种情况:
VTIME=0,VMIN=n,read必须在读取了VMIN个字节的数据或者收到一个信号才会返回。
VTIME=t,VMIN=0,不管能否读取到数据,read也要等待VTIME的时间量。
VTIME=t,VMIN=n,那么将从read读取第一个字节的数据时开始计时,并会在读取到VMIN个字节或者VTIME时间后返回。
VTIME=0,VMIN=0,不管能否读取到数据,read都会立即返回。
非阻塞的定义:fcntl(fd, F_SETFL,FNDELAY)
当串口输入缓冲区没有数据的时候,read函数立即返回,返回值为0。
- void get_com_attr(int fd)
- {
- struct termios opt;
- if(fd < 0)
- {
- printf("get_com_attr error");
- exit(0);
- }
- memset(&opt, 0, sizeof(struct termios));
- tcgetattr(fd, &opt);
- cfmakeraw(&opt);
- }
有必要说一下int tcsetattr(int fd, int optional_actions, const struct termios *termios_p)
int tcgetattr(int fd, struct termios *termios_p)
tcgetattr函数用于获取与终端相关的参数。参数fd为终端的文件描述符,结果保存在termios结构体中。
tcsetattr函数用于设置终端的相关参数。参数optional_actions用于控制修改起作用的时间,而结构体termios_p中保存了要修改的参数;
optional_actions可以取如下的值:
TCSANOW:不等数据传输完毕就立即改变属性。
TCSADRAIN:等待所有数据传输结束才改变属性。
TCSAFLUSH:清空输入输出缓冲区才改变属性。
3.读取串口
这里也是将read()系统调用封装成com_read(),当我们设置好通讯协议了(串口属性),就可以对串口进行读写了。
参数一fd就不用说了,第二个参数read_buff从名字看出就是要把数据读到这个缓冲区中,第三个参数是你想要读多少字节,注意是”你想要“,而返回值则是读到的真正字节数,当你读到末尾(假如缓冲区有10个字节,而你想要读20个)或者出现异常中断了读操作,就会出现返回值ret(return)
!= nbytes。
- int com_read(int fd, unsigned char *read_buff, unsigned int nbytes)
- {
- int ret;
- if(fd < 0)
- {
- printf("com_read error");
- exit(0);
- }
- ret = read(fd, read_buff, nbytes);
- return ret;
- }
4.写入串口
道理和写差不多
- int com_write(int fd, BYTE *write_buff, DWORD nbytes)
- {
- int ret;
- if(fd < 0)
- {
- printf("com_write error");
- exit(0);
- }
- ret = write(fd, write_buff, nbytes);
- return ret;
- }
5.关闭串口
记得每次操作完串口要关闭串口(当然了,当你操作多个文件时可别操作错了文件描述符,那就gg了)
- void com_close(int fd)
- {
- if(fd < 0)
- {
- printf("com_close error");
- exit(0);
- }
- close(fd);
- }
好了,万事具备,下面就可以插上设备刷卡读卡号啦(注意看清你的设备ttyUSBx中的x是多少啊),具体读卡号函数就看大家的具体需求啦。
由于博主的项目需求是要将卡号变成一个字符串然后再填充到另一个字符串,然后再巴拉巴拉,可是这个卡号读出来是一串16进制数据,所以想了半天决定用类型转换(不过听说可以用fprintf)。
Linux下读取RFID卡号(C串口编程)的更多相关文章
- linux下保存下位机输出的串口信息为文件
linux下保存下位机输出的串口信息为文件 1.stty -F /dev/ttyUSB0 raw (转换成raw模式) 2.stty -F /dev/ttyUSB0 speed 115200 (设置波 ...
- Arduino + RFID 读取 IC 卡 Arduino uno中获得RFID的UID 并通过串口转发RFID卡号
RFID简介:射频识别即RFID(Radio Frequency IDentification)技术,又称无线射频识别,是一种通信技术,可通过无线电讯号识别特定目标并读写相关数据,而无需识别系统与特定 ...
- LINUX下的tty,console与串口分析
1.LINUX下TTY.CONSOLE.串口之间是怎样的层次关系?具体的函数接口是怎样的?串口是如何被调用的? 2.printk函数是把信息发送到控制台上吧?如何让PRINTK把信息通过串口送出?或者 ...
- linux下对2个连通的串口读写遇到的问题
想要分析下zmodem协议,搜索发现linux下的工具lrzsz是一个包含x,y,z modem传输的工具,下载其源码,下载.它可以借助各种串行的接口进行数据传输,比如串口,socket也可以,这点描 ...
- 在windows 、linux下读取目录下所有文件名
Windows要引入的头文件是<Windows.h> 主要是两个函数FindFirstFile.FindNextFile MSDN里是这么说的: FindFirstFile functio ...
- linux下进程、端口号相互查看方法
linux下通过进程名查看其占用端口: 1.先查看进程pid ps -ef | grep 进程名 2.通过pid查看占用端口 netstat -nap | grep 进程pid 例:通过nginx进程 ...
- Linux下反斜杠号"\"引发的思考
今天在检查home目录时发现有一个名为“\”的文件,觉得很奇怪,从来没见过,就准备用Vim打开看看,很自然地输入命令查看一下,结果居然打不开. ubuntu@ubuntu:~$ vi \> ub ...
- Linux下读取默认MAC地址
导读MAC(Media Access Control,介质访问控制)计算机通过它来定义并识别网络设备的位置.在嵌入式linux学习中不可避免也会遇到MAC,本文主要描述了如何通过操作OTP来读取嵌入式 ...
- windows和linux下读取文件乱码的终极解决办法!
乱码是个很恶心的问题. windows和linux读取txt文件,一旦读取了,编码发生改变,就无法再还原了,只有重启项目. 网上有很多方法都是读取文件头,方法很好,但是亲测都不能用(右移8位判断0xf ...
随机推荐
- lr总结
最近一直在用Loardrunner做性能测试,记录下自己在工作中遇到的问题. LR的基本设置 首先是录制,在录制前选择TOOLS-recording options 在General中选择record ...
- bzoj 1132 几何
思路:我刚开始算三角形的方法是原点叉积三条边,然后计算每条边向量积的贡献,但是对于同一条线上的点 有时候没有办法抵消掉..... 看网上的思路是对于一个三角形的面积通过两条边的叉积获得,然后枚举一个点 ...
- 【2-SAT】The Ministers’ Major Mess UVALive – 4452
题目链接:https://cn.vjudge.net/contest/209474#problem/C 题目大意: 一共有m个提案,n个政客,每个政客都会对一些提案(最多四个)提出自己的意见——通过或 ...
- Centos 7 mysql 安装使用记
某次把美团云1G 1核 centos 7 装到死机,明白了源码编译安装mysql是个大坑,遂绕路到其他大道. 安装命令 wget http://dev.mysql.com/get/mysql-comm ...
- 介绍在JSP中如何使用JavaBeans?
在JSP中使用JavaBean常用的动作有: 1)<jsp:useBean />:用来创建和查找bean对象: 2)<jsp:setProperty />:用来设置bean的属 ...
- PlayMaker GUI的Normalized
PlayMaker GUI的Normalized 在PlayMaker的GUI设置中,开发者可以通过Left.Top设置控件元素的起始点位置,通过Width.Height设置控件的大小.考虑到用户 ...
- django 编码错误
估计这个问题是2.7的问题3.0好像就统一utf编码了 报错代码: python :ascii codec can't decode byte 0xe8 in posi 当django中报这个错误的时 ...
- [BZOJ4784][ZJOI2017]仙人掌(树形DP)
4784: [Zjoi2017]仙人掌 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 312 Solved: 181[Submit][Status] ...
- bozj 1449/2895: 球队预算 -- 费用流
2895: 球队预算 Time Limit: 10 Sec Memory Limit: 256 MB Description 在一个篮球联赛里,有n支球队,球队的支出是和他们的胜负场次有关系的,具体 ...
- web前端 -- onkeydown、onkeypress、onkeyup、onblur、onchange、oninput、onpropertychange的区别
FROM:http://www.cnblogs.com/svage/archive/2011/11/15/2249954.html onkeydown:按下任何键(字母.数字.系统.tab等)都能触发 ...