电子标签的读取: D-Think_M50模块

D-Think_M50模块支持ISO15693标准,可以进行电子标签的读取(比如图书馆书籍的电子标签)。在淘宝上搜索D-Think_M50即可买到。

实际上这个模块是一个串口设备,Arduino 控制它只需要通过一个串口,而且你完全可以用一个USB转串口模块对它进行调试。
一般的串口设备是极易使用,不需要多说的。但是这个模块拥有一个复杂的串口消息协议,仔细阅读模块DataSheet才能发送合法的串口命令。
我把一些功能写成了函数(比如读取卡号,读取标签的前4个字节),方便Arduino 对它进行控制。

DThink

D-Think_M50使用测试:

1、程序思路:
按商家提供的DataSheet对串口命令的描述,把功能封装成函数。本例提供了“读取标签号”和“读取标签的前4个字节”的函数。测试效果是不断尝试读取标签,当模块读到标签时在串口显示前4字节,否则显示”no card”

2、材料:
Arduino Mega2560(或其它拥有多个串口的Arduino)、D-Think_M50模块、电子标签(可以使用图书馆的书)
3、接线:

D-Think_M50 Arduino Mega2560
RX TX1(18)
TX RX1(19)
VCC 5V
GND GND
其它引脚不接

4、代码:

/*
 * ISO15693 RFID 读卡器,测试程序
 * 
 * 材料:
 * Arduino(Mega2560)、D-Think_M50 V1.2 RFID读写器
 * 
 * 原理:
 * 通过串口,按照一定的通信协议与RFID读写器通信,详见D-Think_M50 V1.2 RFID读写器技术资料
 * 
 * 接线:
 * VCC-5V  GND-GND  TX-RX  RX-TX
 * 
 * 本例:
 * RFID不断读取,并在串口打印卡里的前四个字节
 */
 
// Rfid 类,用于控制一个D-Think_M50模块
class Rfid{
private:
  // D-Think_M50模块接的串口
  HardwareSerial *ser;
   
  // 按ISO15693协议对即将发送的数据封装数据包
  // msg是需要封装的字节数组,msg_len是msg字节数组的长度
  // id是D-Think_M50模块的识别号
  // 封装后的字节数组放在buf指针的位置
  // 返回值是封装后字节数组的长度
  static uint8_t rfid_encode(uint16_t id, uint8_t *buf, uint8_t *msg, uint8_t msg_len){
    uint8_t *p, *tmp, check=0;
    p = buf;
    *p++ = 0xAA;
    *p++ = 0xBB;
    *p = msg_len + 3;
    if(*p==0xAA){
      *++p = 0;
    }
    p++;
    *p++ = 0;
    *p = id>>8;
    check ^= *p;
    if(*p==0xAA){
      *++p = 0;
    }
    p++;
    *p = id & 0x00ff;
    check ^= *p;
    if(*p==0xAA){
      *++p = 0;
    }
    p++;
    for(tmp=msg;tmp-msg<msg_len;tmp++,p++){
      *p = *tmp;
      check ^= *p;
      if(*p==0xAA){
        *p = 0;
      }
    }
    *p++ = check;
    return p-buf;
  }
 
  // 读取发来的字节数组,并按ISO15693协议解析出其有效载荷
  int rfid_recv(uint8_t *msg){
    int recv,cnt;
    for(cnt=0;cnt<9;cnt++){       recv = ser->read();
      if(recv==-1){
        ser->flush();
        return -1;
      }
      if(recv==0xAA&&cnt!=0) ser->read();
    }
    for(cnt=0;(recv=ser->read())!=-1;cnt++){
      msg[cnt] = recv;
      if(recv==0xAA) ser->read();
    }
    ser->flush();
    return cnt-1;
  }
 
  // 初始化Rfid模块,设置其工作状态为ISO15693协议
  void rfid_init(){
    int len;
    uint8_t buf[0x50], msg[] = {0x08,0x01,'1'};
    ser->begin(19200);
    len = rfid_encode(0,buf,msg,sizeof(msg));
    ser->write(buf,len);
    delay(200);
    rfid_recv(buf);
  }
public:
 
  // 构造函数
  Rfid(HardwareSerial &ser_in){
    ser = &ser_in;
    rfid_init();
  }
  // 读取电子标签的标签号,若标签不存在或失败返回-1,成功返回0,读到的9个字节放在data指针处
  int readID(uint8_t *data){
    int len;
    uint8_t msg[0x20] = {0x01,0x10}, buf[0x30];
     
    len = rfid_encode(0,buf,msg,2);
    ser->write(buf,len);
   
    delay(35);
    len = rfid_recv(data);
 
    if(len!=9){
      return -1;
    }else{
      return 0;
    }
  }
 
  // 读取电子标签的前4个字节,若标签不存在或失败返回-1,成功返回0,读到的4个字节放在data指针处
  int read4bytes(uint8_t *data){
    int len;
    uint8_t msg[0x20] = {0x01,0x10}, buf[0x30];
     
    len = rfid_encode(0,buf,msg,2);
    ser->write(buf,len);
   
    delay(35);
    len = rfid_recv(msg+2);
    if(len!=9){
      return -1;
    }else{    
      msg[0] = 0x05; msg[11] = 0x10; msg[11] = 0; msg[12] = 1;
      len = rfid_encode(0,buf,msg,13);
      ser->write(buf,len);
      delay(45);
      len = rfid_recv(msg);
      if(len!=4){
        return -1;
      }else{
        memcpy(data,msg,4);
        return 0;
      }
    }
  }
 
};
 
Rfid *r;
 
void setup() {
  Serial.begin(9600);
  r = new Rfid(Serial1);
}
 
void loop() {
  uint8_t data[4];
  if(r->read4bytes(data)==-1){
    Serial.println("no card");
  }else{
    for(int i=0;i<4;i++){
      Serial.print(data[i]);
      Serial.print(' ');
    }
    Serial.println();
  }
}

 

5、测试结果
不断尝试读取标签,当模块读到标签时在串口显示前4字节,否则显示”no card”