Introduction: Smart IOT Cart for Internal Logistics (Intel IoT)

The project titled the "Smart IOT Cart for Internal Logistics". Nowdays shopping if not in its entirety,but in increasing majority is done online. It is the most convent form of shopping,as it can be done within the comfort of our home. But not everything can be bought online and there is always the issue of the time of delivery . Our entire project is based on the concept to save the consumers time. Our project is customized to be implemented in any level of shopping establishment.

The main technology used behind our implementation is concept of the Internet of things. How this works is that there is paired mobile app that you can download and that app will have the inventory of the entire shop. After the consumer selects the items,he can either choose to pay the bill via an online portal or can pay it at the shopping counter in person. The bill is transferred in real time to oour smart robo cart,which identifies each item and picks it out into the cart via the robotic arm.after all the items are gathered it proceeds to the check point. Explaining it in a real life scenario,a couple entering a mall can pick out the groceries on the app and by the time they finish their rest of the shopping,their items are ready at the counter either packed (if payment is already done) or waiting for payment.this is especially helpful for a physically disabled person or senior citizens in making their lives much easier. In this age of fast and time saving 21st century man,this implementation is a natural choice for an even faster future.

Step 1: Hardware Assembly Part 1

1. Robotic Arm

Why Need Robotic Arm ?
Idea is simple . In order to pick the items from the shop, we merge this robotic arm module to the Robot. Grocery Items are picked using the gripper that attached to the robotic Arm.

How to Assemble ?
You have to purchase a robotic arm or make it by your own. We here used is a purchased one and that is a 3D printed arm from ebay. Here is the Ebay Link if you want to purchase the same . http://www.ebay.in/itm/Robotic-Arm-/182061698367?...

Note : Here used 4 DOF Robotic Arm. i.e. 4 servo motors are needed.
Then Assemble that robotic arm according to the instructions in the link : https://www.instructables.com/id/EEZYbotARM/

Step 2: Hardware Assembly Part 2

2. Robotic Chasis

You can buy a DIY robot chasis kit from Amazon
Link for purchase : Amazon.in -Robotic Chassis DIY Kit

The chassis kit consist of 1 x Acrylic Robotic Base, 1 x Acrylic Platform, 2 x BO Motor, 2 x BO Motor Wheel, 2 x BO Motor Clamp, 1 x Castor Wheel, 4 x Sleeve (40mm), 6 x Sleeve (15mm), 7 x Screw + Nuts (M3 x 50mm), 8 x Screw + Nuts (M3 x 25mm), 2 x Pointed Screw (M2 x 10mm).

Assemble that chassis kit and that can be used as a movable trolley cum cart. Then place the robotic arm on the top of it. Refer the picture.

Then place a box infront of robotic arm, which is used as a cart. It is for carrying the items that are picked by robotic arm.

Step 3: Hardware Assembly Part 3

Get ready these components

1. Intel Edison Arduino breakout board
- Refer Intel Edison Docummentation and configure your board.
2. i2c Motor shield
- For controlling the dc motors in robotic chassis
3. RFID Reader and tag
- RFID Reader will be attached in the moving trolley and the RFID Card is attached to Products in the shop. This module is for the Identification of Items. Also we can use Intel real sense camera for better accuracy if needed. Here we use RFID-RC522 Module. You can also use 125khz Module
4. Seed base shield
- Refer seed studio kit documentation for more.
5. Ultrasonic sensor (If necessary)
- We can use this sensor for avoiding the obstacles in front of moving trolley and can make the movement easy.

Step 4: MQTT Configuration

MQTT is a machine-to-machine (M2M)/"Internet of Things" connectivity protocol. Its a lightweight messaging protocol for small sensors and mobile devices, optimized for high-latency or unreliable networks.
You need to configure the MQTT server in your Desktop or Laptop (for local connectivity), Using Mosquito (MQTT Broker).

Here is the arduino source code . When it is connected and everything is okay, the board will print the message ''Publication and Subscription are done".

if (!client.connected()) {
    Serial.println("client.connected Passed");

  if (!client.connect("Arduino"))   // Fails everytime right here
      Serial.println("client.connect FAILED");

    if (!client.publish("outTopic", "hello world"))
      Serial.println("client.publish FAILED");

if (!client.subscribe("inTopic"))
      Serial.println("client.subscribe FAILED");

  Serial.println("Publication and Subscription are done");
  }
  else
    Serial.println("Connection Failed");
}

Step 5: MQTT Subscription and Item Purchase Using Robotic Arm

Customers have the option to select the items using the Android App and after the selection, the app will publish an MQTT message and it will be subscribed in edison. When edison gets the product info , it will move to the products and using the RFID , it will identify the product and when it identifies, the robot will stop there and then the Robotic arm will pick the item and put it in the cart.

if (res == 'a') { // Getting the product id 'a' from the Android App using MQTT. i.e. Customer selected the Items to purchase through App

 rfidon();       //  Call the function for Tracking the product using RFID

  motor1.run(FORWARD);  // Trolley is moving to find the item
  }
 // Function rfidon()<br><br>void rfidon()</p><p>{ Serial.println("RFID is working Now");

  uchar i, tmp;
  uchar status;
  uchar str[MAX_LEN];
  uchar RC_size;
  uchar blockAddr;  //选择操作的块地址0~63
  String mynum = "";

 //runFunction();
  //寻卡,返回卡类型
  status = MFRC522_Request(PICC_REQIDL, str);
  Serial.println(status);
  Serial.println(MI_OK);
  while (status != MI_OK)
  {
    status = MFRC522_Request(PICC_REQIDL, str);
    Serial.println(status);
    Serial.println(MI_OK);
    if (status == MI_OK)
    {
      Serial.println("Card detected");

 status = MFRC522_Anticoll(str);
      memcpy(serNum, str, 5);
      if (status == MI_OK)
      {
do{
        Serial.println("The card's number is  : ");
        Serial.print(serNum[0]);
        Serial.print(" , ");
        Serial.print(serNum[1], BIN);
        Serial.print(" , ");
        Serial.print(serNum[2], BIN);
        Serial.print(" , ");
        Serial.print(serNum[3], BIN);
        Serial.print(" , ");
        Serial.print(serNum[4], BIN);
         status = MFRC522_Request(PICC_REQIDL, str);
           status = MFRC522_Anticoll(str);
      memcpy(serNum, str, 5);
        //Serial.println(" ");

   // Should really check all pairs, but for now we'll just use the first
}
        while (serNum[0] != 225);
     if (serNum[0] == 225) {
                Serial.println("RFID Detected");  // Product is Identified 
                Serial.print(serNum[0]);
                MotorSpeedSetAB(0,0);              // Stopping the Vehicle / Trolley
                 
  servo_4.attach(9);

for(servo4_pos =175; servo4_pos >= 30; servo4_pos--)
 { 
  servo_4.write(servo4_pos);
 delay(20);
 //Serial.println("inside servo 4 ");
 }
 servo_4.detach();
 delay(1000);
  servo_1.attach(3);
    for(servo1_pos =5; servo1_pos <= 100; servo1_pos++)
 { 
  servo_1.write(servo1_pos);
 delay(20);
 } 
servo_1.detach();
    delay(1000);</p><p> delay(1000);
  servo_1.attach(3);
    for(servo1_pos =100; servo1_pos >= 5; servo1_pos--)
 { 
  servo_1.write(servo1_pos);
 delay(20);
 } 
 delay(1000);</p><p> servo_4.attach(9);

for(servo4_pos =30; servo4_pos <= 175; servo4_pos++)
 { 
  servo_4.write(servo4_pos);
 delay(20);
 Serial.println("inside servo 4 ");
 }
 servo_4.detach();
                 //break;
   delay(1000);
   servo_1.attach(3);
    for(servo1_pos =5; servo1_pos <= 100; servo1_pos++)
 { 
  servo_1.write(servo1_pos);
 delay(20);
 } 
 for(servo1_pos =100; servo1_pos >= 5; servo1_pos--)
 { 
  servo_1.write(servo1_pos);
 delay(20);
 } 
servo_1.detach();
    delay(1000);
    
                
 }
        
      }
      //  Serial.print(str[0],BIN);
      //                        Serial.print(" , ");
      //    Serial.print(str[1],BIN);
      //                        Serial.println(" ");
    }   }
  //Serial.println(" ");
  MFRC522_Halt();   

Step 6: Access WiFi in Intel Edison [Connectivity]

We need to access the wifi in Intel edison . Here is the Source Code

#include<WiFi.h>

char ssid[] = "Intel_Hackathon";     //  your network SSID (name)
char pass[] = "Intelhack";  // your network password
int status = WL_IDLE_STATUS;     // the Wifi radio's status

byte server[] = {192, 168, 21, 96}; // Replace your MQTT Server IP 

WiFiClient wifiClient;

PubSubClient client(server, 1883, callback, wifiClient);

void printWifiData() {

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);
  Serial.println(ip); // print your MAC address:
  byte mac[6];
  WiFi.macAddress(mac);
  Serial.print("MAC address: ");
  Serial.print(mac[5], HEX);
  Serial.print(":");
  Serial.print(mac[4], HEX);
  Serial.print(":");
  Serial.print(mac[3], HEX);
  Serial.print(":");
  Serial.print(mac[2], HEX);
  Serial.print(":");
  Serial.print(mac[1], HEX);
  Serial.print(":");
  Serial.println(mac[0], HEX);</p><p>}</p><p>void printCurrentNet() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());</p><p>  // print the MAC address of the router you're attached to:
  byte bssid[6];
  WiFi.BSSID(bssid);
  Serial.print("BSSID: ");
  Serial.print(bssid[5], HEX);
  Serial.print(":");
  Serial.print(bssid[4], HEX);
  Serial.print(":");
  Serial.print(bssid[3], HEX);
  Serial.print(":");
  Serial.print(bssid[2], HEX);
  Serial.print(":");
  Serial.print(bssid[1], HEX);
  Serial.print(":");
  Serial.println(bssid[0], HEX);// print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.println(rssi);</p><p>  // print the encryption type:
  byte encryption = WiFi.encryptionType();
  Serial.print("Encryption Type:");
  Serial.println(encryption, HEX);
  Serial.println();
}</p>

Step 7: Movement of Trolley Robot

Source code For the movement of Trolley robot

void runFunction()
{ Wire.begin(); // join i2c bus (address optional for master) Serial.println("sent DC speed 100"); MotorDirectionSet(0b0101); //"0b1010" defines the output polarity, "10" means the M+ is "positive" while the M- is "negtive" // make sure M+ and M- is different polatity when driving DC motors. MotorSpeedSetAB(100,100);//defines the speed of motor 1 and motor 2;

//0b0101 Rotating in the opposite direction }

//Function to set the 2 DC motor speed //motorSpeedA : the DC motor A speed; should be 0~100; //motorSpeedB: the DC motor B speed; should be 0~100;

void MotorSpeedSetAB(unsigned char MotorSpeedA , unsigned char MotorSpeedB) { MotorSpeedA=map(MotorSpeedA,0,100,0,255); MotorSpeedB=map(MotorSpeedB,0,100,0,255); Wire.beginTransmission(I2CMotorDriverAdd); // transmit to device I2CMotorDriverAdd Wire.write(MotorSpeedSet); // set pwm header Wire.write(MotorSpeedA); // send pwma Wire.write(MotorSpeedB); // send pwmb Wire.endTransmission(); // stop transmitting } //set the prescale frequency of PWM, 0x03 default; void MotorPWMFrequenceSet(unsigned char Frequence) { Wire.beginTransmission(I2CMotorDriverAdd); // transmit to device I2CMotorDriverAdd Wire.write(PWMFrequenceSet); // set frequence header Wire.write(Frequence); // send frequence Wire.write(Nothing); // need to send this byte as the third byte(no meaning) Wire.endTransmission(); // stop transmitting } //set the direction of DC motor. void MotorDirectionSet(unsigned char Direction) { // Adjust the direction of the motors 0b0000 I4 I3 I2 I1 Wire.beginTransmission(I2CMotorDriverAdd); // transmit to device I2CMotorDriverAdd Wire.write(DirectionSet); // Direction control header Wire.write(Direction); // send direction control information Wire.write(Nothing); // need to send this byte as the third byte(no meaning) Wire.endTransmission(); // stop transmitting }

void MotorDriectionAndSpeedSet(unsigned char Direction,unsigned char MotorSpeedA,unsigned char MotorSpeedB) { //you can adjust the driection and speed together MotorDirectionSet(Direction); MotorSpeedSetAB(MotorSpeedA,MotorSpeedB); }

Step 8: Robotic Arm Movement

Arduino source code for the movement of Robotic Arm / Servo Motor

#include<Servo.h>

Servo servo_1; Servo servo_2; Servo servo_3; Servo servo_4; Servo servo_5; int servo1_pos = 0; int servo2_pos = 0; int servo3_pos = 0; int servo4_pos = 0;

servo_4.attach(9);

for(servo4_pos =175; servo4_pos >= 30; servo4_pos--) { servo_4.write(servo4_pos); delay(20); //Serial.println("inside servo 4 "); } servo_4.detach(); delay(1000); servo_1.attach(3); for(servo1_pos =5; servo1_pos <= 100; servo1_pos++) { servo_1.write(servo1_pos); delay(20); } servo_1.detach(); delay(1000);

delay(1000); servo_1.attach(3); for(servo1_pos =100; servo1_pos >= 5; servo1_pos--) { servo_1.write(servo1_pos); delay(20); } delay(1000);

servo_4.attach(9);

for(servo4_pos =30; servo4_pos <= 175; servo4_pos++) { servo_4.write(servo4_pos); delay(20); Serial.println("inside servo 4 "); } servo_4.detach(); //break; delay(1000); servo_1.attach(3); for(servo1_pos =5; servo1_pos <= 100; servo1_pos++) { servo_1.write(servo1_pos); delay(20); } for(servo1_pos =100; servo1_pos >= 5; servo1_pos--) { servo_1.write(servo1_pos); delay(20); } servo_1.detach(); delay(1000);

Step 9: Android Application

Android Application is for shops. In that App, all the groceries in the shop are listed and users can select it through the App. After confirmation of product selection, the shopping robot will move and find the products and after picking all the items, the cart will send the information to the customer (not included now) and send the billing info to the customer and billing desk (not included now). In the technical perspective, the app will publish the message via MQTT to the edison. Edison will subscribe the data and works according to the instruction.


Source Code :- MQTT Message Publish in Android

private void addPublishButtonListener()   {
        buy=(FancyButton)findViewById(R.id.buy);

      buy.setOnClickListener(new OnClickListener() {
            //InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);

        @Override
            public void onClick(View arg0) {
                // EditText t = (EditText) findViewById(R.id.EditTextTopic);
                // EditText m = (EditText) findViewById(R.id.editTextMessage);
                // TextView result = (TextView) findViewById(R.id.textResultStatus);
                // inputMethodManager.hideSoftInputFromWindow(result.getWindowToken(), 0);

             String topic = "inTopic";
                String message = "a";

               if (topic != null && topic.isEmpty() == false && message != null && message.isEmpty() == false) {
                    //result.setText("");
                    Bundle data = new Bundle();
                    data.putCharSequence(MQTTservice.TOPIC, topic);
                    data.putCharSequence(MQTTservice.MESSAGE, message);
                    Message msg = Message.obtain(null, MQTTservice.PUBLISH);
                    msg.setData(data);
                    msg.replyTo = serviceHandler;
                    try {
                        service.send(msg);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                        //    result.setText("Publish failed with exception:" + e.getMessage());
                    }
                } else {
                    // result.setText("Topic and message required.");
                }
            }
        });
    }</p>

Step 10: Final Intel Edison Arduino Code

This is the Final Arduino Source code. You can also use cloud connectivity instead of this local connectivity. To do cloud integration, you have to choose IBM Bluemix or any other source.
Hope you enjoyed. Don't forget to mention your valuable comment !!! and Follow me for future updates.


<br><p>#define  uchar unsigned char
#define uint  unsigned int
Servo servo_1;
Servo servo_2;
Servo servo_3;
Servo servo_4;
Servo servo_5;
int servo1_pos = 0;
int servo2_pos = 0;
int servo3_pos = 0;
int servo4_pos = 0;
//数组最大长度
#define MAX_LEN 16</p><p>/////////////////////////////////////////////////////////////////////
//set the pin
/////////////////////////////////////////////////////////////////////
const int chipSelectPin = 10;
const int NRSTPD = 5;</p><p>//MF522命令字
#define PCD_IDLE              0x00               //NO action;取消当前命令
#define PCD_AUTHENT           0x0E               //验证密钥
#define PCD_RECEIVE           0x08               //接收数据
#define PCD_TRANSMIT          0x04               //发送数据
#define PCD_TRANSCEIVE        0x0C               //发送并接收数据
#define PCD_RESETPHASE        0x0F               //复位
#define PCD_CALCCRC           0x03               //CRC计算</p><p>//Mifare_One卡片命令字
#define PICC_REQIDL           0x26               //寻天线区内未进入休眠状态
#define PICC_REQALL           0x52               //寻天线区内全部卡
#define PICC_ANTICOLL         0x93               //防冲撞
#define PICC_SElECTTAG        0x93               //选卡
#define PICC_AUTHENT1A        0x60               //验证A密钥
#define PICC_AUTHENT1B        0x61               //验证B密钥
#define PICC_READ             0x30               //读块
#define PICC_WRITE            0xA0               //写块
#define PICC_DECREMENT        0xC0               //扣款
#define PICC_INCREMENT        0xC1               //充值
#define PICC_RESTORE          0xC2               //调块数据到缓冲区
#define PICC_TRANSFER         0xB0               //保存缓冲区中数据
#define PICC_HALT             0x50               //休眠</p><p>//和MF522通讯时返回的错误代码
#define MI_OK                 0
#define MI_NOTAGERR           1
#define MI_ERR                2</p><p>//------------------MFRC522寄存器---------------
//Page 0:Command and Status
#define     Reserved00            0x00
#define     CommandReg            0x01
#define     CommIEnReg            0x02
#define     DivlEnReg             0x03
#define     CommIrqReg            0x04
#define     DivIrqReg             0x05
#define     ErrorReg              0x06
#define     Status1Reg            0x07
#define     Status2Reg            0x08
#define     FIFODataReg           0x09
#define     FIFOLevelReg          0x0A
#define     WaterLevelReg         0x0B
#define     ControlReg            0x0C
#define     BitFramingReg         0x0D
#define     CollReg               0x0E
#define     Reserved01            0x0F
//Page 1:Command
#define     Reserved10            0x10
#define     ModeReg               0x11
#define     TxModeReg             0x12
#define     RxModeReg             0x13
#define     TxControlReg          0x14
#define     TxAutoReg             0x15
#define     TxSelReg              0x16
#define     RxSelReg              0x17
#define     RxThresholdReg        0x18
#define     DemodReg              0x19
#define     Reserved11            0x1A
#define     Reserved12            0x1B
#define     MifareReg             0x1C
#define     Reserved13            0x1D
#define     Reserved14            0x1E
#define     SerialSpeedReg        0x1F
//Page 2:CFG
#define     Reserved20            0x20
#define     CRCResultRegM         0x21
#define     CRCResultRegL         0x22
#define     Reserved21            0x23
#define     ModWidthReg           0x24
#define     Reserved22            0x25
#define     RFCfgReg              0x26
#define     GsNReg                0x27
#define     CWGsPReg            0x28
#define     ModGsPReg             0x29
#define     TModeReg              0x2A
#define     TPrescalerReg         0x2B
#define     TReloadRegH           0x2C
#define     TReloadRegL           0x2D
#define     TCounterValueRegH     0x2E
#define     TCounterValueRegL     0x2F
//Page 3:TestRegister
#define     Reserved30            0x30
#define     TestSel1Reg           0x31
#define     TestSel2Reg           0x32
#define     TestPinEnReg          0x33
#define     TestPinValueReg       0x34
#define     TestBusReg            0x35
#define     AutoTestReg           0x36
#define     VersionReg            0x37
#define     AnalogTestReg         0x38
#define     TestDAC1Reg           0x39
#define     TestDAC2Reg           0x3A
#define     TestADCReg            0x3B
#define     Reserved31            0x3C
#define     Reserved32            0x3D
#define     Reserved33            0x3E
#define     Reserved34        0x3F
//-----------------------------------------------</p><p>//---------------Servo motor -------------------
#include </p><p>#define MotorSpeedSet             0x82
#define PWMFrequenceSet           0x84
#define DirectionSet              0xaa
#define MotorSetA                 0xa1
#define MotorSetB                 0xa5
#define Nothing                   0x01</p><p>#define I2CMotorDriverAdd         0x0f   // Set the address of the I2CMotorDriver</p><p>///////////////////////////////////////////////////////////////////////////////
// Enanble the i2c motor driver to drive a 4-wire stepper. the i2c motor driver will
//driver a 4-wire with 8 polarity  .
//Direction: stepper direction ; 1/0
//motor speed: defines the time interval the i2C motor driver change it output to drive the stepper
//the actul interval time is : motorspeed * 4ms. that is , when motor speed is 10, the interval time 
//would be 40 ms
//////////////////////////////////////////////////////////////////////////////////
void StepperMotorEnable(unsigned char Direction, unsigned char motorspeed)
{
  Wire.beginTransmission(I2CMotorDriverAdd); // transmit to device I2CMotorDriverAdd
       // set pwm header 
  Wire.write(Direction);              // send pwma 
  Wire.write(motorspeed);              // send pwmb    
  Wire.endTransmission();    // stop transmitting 
}</p><p>//////////////////////////////////////////////////////////////////////
//Function to set the 2 DC motor speed
//motorSpeedA : the DC motor A speed; should be 0~100;
//motorSpeedB: the DC motor B speed; should be 0~100;</p><p>void MotorSpeedSetAB(unsigned char MotorSpeedA , unsigned char MotorSpeedB)  {
  MotorSpeedA=map(MotorSpeedA,0,100,0,255);
  MotorSpeedB=map(MotorSpeedB,0,100,0,255);
  Wire.beginTransmission(I2CMotorDriverAdd); // transmit to device I2CMotorDriverAdd
  Wire.write(MotorSpeedSet);        // set pwm header 
  Wire.write(MotorSpeedA);              // send pwma 
  Wire.write(MotorSpeedB);              // send pwmb    
  Wire.endTransmission();    // stop transmitting
}
//set the prescale frequency of PWM, 0x03 default;
void MotorPWMFrequenceSet(unsigned char Frequence)  {    
  Wire.beginTransmission(I2CMotorDriverAdd); // transmit to device I2CMotorDriverAdd
  Wire.write(PWMFrequenceSet);        // set frequence header
  Wire.write(Frequence);              //  send frequence 
  Wire.write(Nothing);              //  need to send this byte as the third byte(no meaning)  
  Wire.endTransmission();    // stop transmitting
}
//set the direction of DC motor. 
void MotorDirectionSet(unsigned char Direction)  {     //  Adjust the direction of the motors 0b0000 I4 I3 I2 I1
  Wire.beginTransmission(I2CMotorDriverAdd); // transmit to device I2CMotorDriverAdd
  Wire.write(DirectionSet);        // Direction control header
  Wire.write(Direction);              // send direction control information
  Wire.write(Nothing);              // need to send this byte as the third byte(no meaning)  
  Wire.endTransmission();    // stop transmitting 
}</p><p>void MotorDriectionAndSpeedSet(unsigned char Direction,unsigned char MotorSpeedA,unsigned char MotorSpeedB)  {  //you can adjust the driection and speed together
  MotorDirectionSet(Direction);
  MotorSpeedSetAB(MotorSpeedA,MotorSpeedB);  
}</p><p>//---------------Servo motor-------------------</p><p>//4字节卡序列号,第5字节为校验字节
uchar serNum[5];</p><p>uchar  writeData[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}; //初始化 100元钱
uchar  moneyConsume = 18 ;  //消费18元
uchar  moneyAdd = 10 ;  //充值10元
//扇区A密码,16个扇区,每个扇区密码6Byte
uchar sectorKeyA[16][16] = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
  {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
  //{0x19, 0x84, 0x07, 0x15, 0x76, 0x14},
  {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
};
uchar sectorNewKeyA[16][16] = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
  {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xff, 0x07, 0x80, 0x69, 0x19, 0x84, 0x07, 0x15, 0x76, 0x14},
  //you can set another ket , such as  " 0x19, 0x84, 0x07, 0x15, 0x76, 0x14 "
  //{0x19, 0x84, 0x07, 0x15, 0x76, 0x14, 0xff,0x07,0x80,0x69, 0x19,0x84,0x07,0x15,0x76,0x14},
  // but when loop, please set the  sectorKeyA, the same key, so that RFID module can read the card
  {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xff, 0x07, 0x80, 0x69, 0x19, 0x33, 0x07, 0x15, 0x34, 0x14},
};</p><p>#include 
#include 
</p><p>// Update these with values suitable for your network.
char ssid[] = "Intel_Hackathon";     //  your network SSID (name)
char pass[] = "Intelhack";  // your network password
int status = WL_IDLE_STATUS;     // the Wifi radio's status</p><p>byte server[] = {192, 168, 21, 96};
char res;</p><p>void callback(char* topic, byte* payload, unsigned int length) {
  // handle message arrived</p><p>  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
    res = (char)payload[i];</p><p>  }</p><p>  if (res == 'a') {
    //  digitalWrite(3, HIGH);   // turn the LED on (HIGH is the voltage level)
    // delay(1000);</p><p>    rfidon();
    //  motor1.run(FORWARD);
  }</p><p>  
  if (res == 'b')
  {
    // wait for a second
    //  digitalWrite(3, LOW);
    Serial.print("OFF");// turn the LED off by making the voltage LOW
    //  delay(1000);               // wait for a second</p><p>    //motor1.setSpeed(0);
  }
  //</p><p>}</p><p>WiFiClient wifiClient;
PubSubClient client(server, 1883, callback, wifiClient);
void runFunction()
{
   Wire.begin(); // join i2c bus (address optional for master)
                    Serial.println("sent DC speed 100");
     MotorDirectionSet(0b0101);  //"0b1010" defines the output polarity, "10" means the M+ is "positive" while the M- is "negtive"
//                                  // make sure M+ and M- is different polatity when driving DC motors.
    MotorSpeedSetAB(100,100);//defines the speed of motor 1 and motor 2;
//    delay(10); //this delay needed
    //delay(5000);</p><p>    //MotorDirectionSet(0b0101);  
//0b0101  Rotating in the opposite direction
   
  }
void setup()
{</p><p>  Serial.begin(9600);                       // RFID reader SOUT pin connected to Serial RX pin at 2400bps
  // start the SPI library:
  SPI.begin();</p><p>  pinMode(chipSelectPin, OUTPUT);            // Set digital pin 10 as OUTPUT to connect it to the RFID /ENABLE pin
  digitalWrite(chipSelectPin, LOW);          // Activate the RFID reader
  pinMode(NRSTPD, OUTPUT);              // Set digital pin 10 , Not Reset and Power-down
  digitalWrite(NRSTPD, HIGH);</p><p>  MFRC522_Init();
  //Initialize serial and wait for port to open:
  //Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }</p><p>  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while (true);
  }</p><p>  String fv = WiFi.firmwareVersion();
  if ( fv != "1.1.0" )
    Serial.println("Please upgrade the firmware");</p><p>  // attempt to connect to Wifi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to WPA SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network:
    status = WiFi.begin(ssid, pass);</p><p>    // wait 10 seconds for connection:
    delay(10000);
  }</p><p>  // you're connected now, so print out the data:
  Serial.print("You're connected to the network");
  printCurrentNet();
  printWifiData();</p><p>  //delay(1000);</p><p>  if (!client.connected())
  {
    Serial.println("client.connected Passed");</p><p>    if (!client.connect("Arduino"))   // Fails everytime right here
      Serial.println("client.connect FAILED");</p><p>    if (!client.publish("outTopic", "hello world"))
      Serial.println("client.publish FAILED");</p><p>    if (!client.subscribe("inTopic"))
      Serial.println("client.subscribe FAILED");</p><p>    Serial.println("Publication and Subscription are done");
  }
  else
    Serial.println("Connection Failed");
}</p><p>void loop()
{</p><p>  client.loop();</p><p>}</p><p>void printWifiData() {
  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);
  Serial.println(ip);</p><p>  // print your MAC address:
  byte mac[6];
  WiFi.macAddress(mac);
  Serial.print("MAC address: ");
  Serial.print(mac[5], HEX);
  Serial.print(":");
  Serial.print(mac[4], HEX);
  Serial.print(":");
  Serial.print(mac[3], HEX);
  Serial.print(":");
  Serial.print(mac[2], HEX);
  Serial.print(":");
  Serial.print(mac[1], HEX);
  Serial.print(":");
  Serial.println(mac[0], HEX);</p><p>}</p><p>void printCurrentNet() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());</p><p>  // print the MAC address of the router you're attached to:
  byte bssid[6];
  WiFi.BSSID(bssid);
  Serial.print("BSSID: ");
  Serial.print(bssid[5], HEX);
  Serial.print(":");
  Serial.print(bssid[4], HEX);
  Serial.print(":");
  Serial.print(bssid[3], HEX);
  Serial.print(":");
  Serial.print(bssid[2], HEX);
  Serial.print(":");
  Serial.print(bssid[1], HEX);
  Serial.print(":");
  Serial.println(bssid[0], HEX);</p><p>  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.println(rssi);</p><p>  // print the encryption type:
  byte encryption = WiFi.encryptionType();
  Serial.print("Encryption Type:");
  Serial.println(encryption, HEX);
  Serial.println();
}</p><p>void rfidon()</p><p>{ Serial.println("RFID is working Now");</p><p>  uchar i, tmp;
  uchar status;
  uchar str[MAX_LEN];
  uchar RC_size;
  uchar blockAddr;  //选择操作的块地址0~63
  String mynum = "";</p><p> //runFunction();
  //寻卡,返回卡类型
  status = MFRC522_Request(PICC_REQIDL, str);
  Serial.println(status);
  Serial.println(MI_OK);
  while (status != MI_OK)
  {
    status = MFRC522_Request(PICC_REQIDL, str);
    Serial.println(status);
    Serial.println(MI_OK);
    if (status == MI_OK)
    {
      Serial.println("Card detected");</p><p>      status = MFRC522_Anticoll(str);
      memcpy(serNum, str, 5);
      if (status == MI_OK)
      {
do{
        Serial.println("The card's number is  : ");
        Serial.print(serNum[0]);
        Serial.print(" , ");
        Serial.print(serNum[1], BIN);
        Serial.print(" , ");
        Serial.print(serNum[2], BIN);
        Serial.print(" , ");
        Serial.print(serNum[3], BIN);
        Serial.print(" , ");
        Serial.print(serNum[4], BIN);
         status = MFRC522_Request(PICC_REQIDL, str);
           status = MFRC522_Anticoll(str);
      memcpy(serNum, str, 5);
        //Serial.println(" ");</p><p>        // Should really check all pairs, but for now we'll just use the first
}
        while (serNum[0] != 225);
     if (serNum[0] == 225) {
                Serial.println("RFID Detected");
                Serial.print(serNum[0]);
                MotorSpeedSetAB(0,0);
                 
  servo_4.attach(9);</p><p>for(servo4_pos =175; servo4_pos >= 30; servo4_pos--)
 { 
  servo_4.write(servo4_pos);
 delay(20);
 //Serial.println("inside servo 4 ");
 }
 servo_4.detach();
 delay(1000);
  servo_1.attach(3);
    for(servo1_pos =5; servo1_pos <= 100; servo1_pos++)
 { 
  servo_1.write(servo1_pos);
 delay(20);
 } 
servo_1.detach();
    delay(1000);</p><p> delay(1000);
  servo_1.attach(3);
    for(servo1_pos =100; servo1_pos >= 5; servo1_pos--)
 { 
  servo_1.write(servo1_pos);
 delay(20);
 } 
 delay(1000);</p><p> servo_4.attach(9);</p><p>for(servo4_pos =30; servo4_pos <= 175; servo4_pos++)
 { 
  servo_4.write(servo4_pos);
 delay(20);
 Serial.println("inside servo 4 ");
 }
 servo_4.detach();
                 //break;
   delay(1000);
   servo_1.attach(3);
    for(servo1_pos =5; servo1_pos <= 100; servo1_pos++)
 { 
  servo_1.write(servo1_pos);
 delay(20);
 } 
 for(servo1_pos =100; servo1_pos >= 5; servo1_pos--)
 { 
  servo_1.write(servo1_pos);
 delay(20);
 } 
servo_1.detach();
    delay(1000);
    
                
 }
        
      }
      //  Serial.print(str[0],BIN);
      //                        Serial.print(" , ");
      //    Serial.print(str[1],BIN);
      //                        Serial.println(" ");
    }</p><p>    //防冲撞,返回卡的序列号 4字节</p><p>  }
  //Serial.println(" ");
  MFRC522_Halt();     //命令卡片进入休眠状态</p><p>}</p><p>void Write_MFRC522(uchar addr, uchar val)
{
  digitalWrite(chipSelectPin, LOW);</p><p>  //地址格式:0XXXXXX0
  SPI.transfer((addr << 1) & 0x7E);
  SPI.transfer(val);</p><p>  digitalWrite(chipSelectPin, HIGH);
}</p><p>/*
 * 函 数 名:Read_MFRC522
 * 功能描述:从MFRC522的某一寄存器读一个字节数据
 * 输入参数:addr--寄存器地址
 * 返 回 值:返回读取到的一个字节数据
 */
uchar Read_MFRC522(uchar addr)
{
  uchar val;</p><p>  digitalWrite(chipSelectPin, LOW);</p><p>  //地址格式:1XXXXXX0
  SPI.transfer(((addr << 1) & 0x7E) | 0x80);
  val = SPI.transfer(0x00);</p><p>  digitalWrite(chipSelectPin, HIGH);</p><p>  return val;
}</p><p>/*
 * 函 数 名:SetBitMask
 * 功能描述:置RC522寄存器位
 * 输入参数:reg--寄存器地址;mask--置位值
 * 返 回 值:无
 */
void SetBitMask(uchar reg, uchar mask)
{
  uchar tmp;
  tmp = Read_MFRC522(reg);
  Write_MFRC522(reg, tmp | mask);  // set bit mask
}</p><p>/*
 * 函 数 名:ClearBitMask
 * 功能描述:清RC522寄存器位
 * 输入参数:reg--寄存器地址;mask--清位值
 * 返 回 值:无
 */
void ClearBitMask(uchar reg, uchar mask)
{
  uchar tmp;
  tmp = Read_MFRC522(reg);
  Write_MFRC522(reg, tmp & (~mask));  // clear bit mask
}</p><p>/*
 * 函 数 名:AntennaOn
 * 功能描述:开启天线,每次启动或关闭天险发射之间应至少有1ms的间隔
 * 输入参数:无
 * 返 回 值:无
 */
void AntennaOn(void)
{
  uchar temp;</p><p>  temp = Read_MFRC522(TxControlReg);
  if (!(temp & 0x03))
  {
    SetBitMask(TxControlReg, 0x03);
  }
}</p><p>/*
 * 函 数 名:AntennaOff
 * 功能描述:关闭天线,每次启动或关闭天险发射之间应至少有1ms的间隔
 * 输入参数:无
 * 返 回 值:无
 */
void AntennaOff(void)
{
  ClearBitMask(TxControlReg, 0x03);
}</p><p>/*
 * 函 数 名:ResetMFRC522
 * 功能描述:复位RC522
 * 输入参数:无
 * 返 回 值:无
 */
void MFRC522_Reset(void)
{
  Write_MFRC522(CommandReg, PCD_RESETPHASE);
}</p><p>/*
 * 函 数 名:InitMFRC522
 * 功能描述:初始化RC522
 * 输入参数:无
 * 返 回 值:无
 */
void MFRC522_Init(void)
{
  digitalWrite(NRSTPD, HIGH);</p><p>  MFRC522_Reset();</p><p>  //Timer: TPrescaler*TreloadVal/6.78MHz = 24ms
  Write_MFRC522(TModeReg, 0x8D);    //Tauto=1; f(Timer) = 6.78MHz/TPreScaler
  Write_MFRC522(TPrescalerReg, 0x3E); //TModeReg[3..0] + TPrescalerReg
  Write_MFRC522(TReloadRegL, 30);
  Write_MFRC522(TReloadRegH, 0);</p><p>  Write_MFRC522(TxAutoReg, 0x40);   //100%ASK
  Write_MFRC522(ModeReg, 0x3D);   //CRC初始值0x6363  ???</p><p>  //ClearBitMask(Status2Reg, 0x08);   //MFCrypto1On=0
  //Write_MFRC522(RxSelReg, 0x86);    //RxWait = RxSelReg[5..0]
  //Write_MFRC522(RFCfgReg, 0x7F);      //RxGain = 48dB</p><p>  AntennaOn();    //打开天线
}</p><p>/*
 * 函 数 名:MFRC522_Request
 * 功能描述:寻卡,读取卡类型号
 * 输入参数:reqMode--寻卡方式,
 *       TagType--返回卡片类型
 *        0x4400 = Mifare_UltraLight
 *        0x0400 = Mifare_One(S50)
 *        0x0200 = Mifare_One(S70)
 *        0x0800 = Mifare_Pro(X)
 *        0x4403 = Mifare_DESFire
 * 返 回 值:成功返回MI_OK
 */
uchar MFRC522_Request(uchar reqMode, uchar *TagType)
{
  uchar status;
  uint backBits;      //接收到的数据位数</p><p>  Write_MFRC522(BitFramingReg, 0x07);   //TxLastBists = BitFramingReg[2..0] ???</p><p>  TagType[0] = reqMode;
  status = MFRC522_ToCard(PCD_TRANSCEIVE, TagType, 1, TagType, &backBits);</p><p>  if ((status != MI_OK) || (backBits != 0x10))
  {
    status = MI_ERR;
  }</p><p>  return status;
}</p><p>/*
 * 函 数 名:MFRC522_ToCard
 * 功能描述:RC522和ISO14443卡通讯
 * 输入参数:command--MF522命令字,
 *       sendData--通过RC522发送到卡片的数据,
 *       sendLen--发送的数据长度
 *       backData--接收到的卡片返回数据,
 *       backLen--返回数据的位长度
 * 返 回 值:成功返回MI_OK
 */
uchar MFRC522_ToCard(uchar command, uchar *sendData, uchar sendLen, uchar *backData, uint *backLen)
{
  uchar status = MI_ERR;
  uchar irqEn = 0x00;
  uchar waitIRq = 0x00;
  uchar lastBits;
  uchar n;
  uint i;</p><p>  switch (command)
  {
    case PCD_AUTHENT:   //认证卡密
      {
        irqEn = 0x12;
        waitIRq = 0x10;
        break;
      }
    case PCD_TRANSCEIVE:  //发送FIFO中数据
      {
        irqEn = 0x77;
        waitIRq = 0x30;
        break;
      }
    default:
      break;
  }</p><p>  Write_MFRC522(CommIEnReg, irqEn | 0x80); //允许中断请求
  ClearBitMask(CommIrqReg, 0x80);     //清除所有中断请求位
  SetBitMask(FIFOLevelReg, 0x80);     //FlushBuffer=1, FIFO初始化</p><p>  Write_MFRC522(CommandReg, PCD_IDLE);  //NO action;取消当前命令  ???</p><p>  //向FIFO中写入数据
  for (i = 0; i < sendLen; i++)
  {
    Write_MFRC522(FIFODataReg, sendData[i]);
  }</p><p>  //执行命令
  Write_MFRC522(CommandReg, command);
  if (command == PCD_TRANSCEIVE)
  {
    SetBitMask(BitFramingReg, 0x80);    //StartSend=1,transmission of data starts
  }</p><p>  //等待接收数据完成
  i = 2000; //i根据时钟频率调整,操作M1卡最大等待时间25ms ???
  do
  {
    //CommIrqReg[7..0]
    //Set1 TxIRq RxIRq IdleIRq HiAlerIRq LoAlertIRq ErrIRq TimerIRq
    n = Read_MFRC522(CommIrqReg);
    i--;
  }
  while ((i != 0) && !(n & 0x01) && !(n & waitIRq));</p><p>  ClearBitMask(BitFramingReg, 0x80);      //StartSend=0</p><p>  if (i != 0)
  {
    if (!(Read_MFRC522(ErrorReg) & 0x1B)) //BufferOvfl Collerr CRCErr ProtecolErr
    {
      status = MI_OK;
      if (n & irqEn & 0x01)
      {
        status = MI_NOTAGERR;     //??
      }</p><p>      if (command == PCD_TRANSCEIVE)
      {
        n = Read_MFRC522(FIFOLevelReg);
        lastBits = Read_MFRC522(ControlReg) & 0x07;
        if (lastBits)
        {
          *backLen = (n - 1) * 8 + lastBits;
        }
        else
        {
          *backLen = n * 8;
        }</p><p>        if (n == 0)
        {
          n = 1;
        }
        if (n > MAX_LEN)
        {
          n = MAX_LEN;
        }</p><p>        //读取FIFO中接收到的数据
        for (i = 0; i < n; i++)
        {
          backData[i] = Read_MFRC522(FIFODataReg);
        }
      }
    }
    else
    {
      status = MI_ERR;
    }</p><p>  }</p><p>  //SetBitMask(ControlReg,0x80);           //timer stops
  //Write_MFRC522(CommandReg, PCD_IDLE);</p><p>  return status;
}</p><p>/*
 * 函 数 名:MFRC522_Anticoll
 * 功能描述:防冲突检测,读取选中卡片的卡序列号
 * 输入参数:serNum--返回4字节卡序列号,第5字节为校验字节
 * 返 回 值:成功返回MI_OK
 */
uchar MFRC522_Anticoll(uchar *serNum)
{
  uchar status;
  uchar i;
  uchar serNumCheck = 0;
  uint unLen;</p><p>  //ClearBitMask(Status2Reg, 0x08);   //TempSensclear
  //ClearBitMask(CollReg,0x80);     //ValuesAfterColl
  Write_MFRC522(BitFramingReg, 0x00);   //TxLastBists = BitFramingReg[2..0]</p><p>  serNum[0] = PICC_ANTICOLL;
  serNum[1] = 0x20;
  status = MFRC522_ToCard(PCD_TRANSCEIVE, serNum, 2, serNum, &unLen);</p><p>  if (status == MI_OK)
  {
    //校验卡序列号
    for (i = 0; i < 4; i++)
    {
      serNumCheck ^= serNum[i];
    }
    if (serNumCheck != serNum[i])
    {
      status = MI_ERR;
    }
  }</p><p>  //SetBitMask(CollReg, 0x80);    //ValuesAfterColl=1</p><p>  return status;
}</p><p>/*
 * 函 数 名:CalulateCRC
 * 功能描述:用MF522计算CRC
 * 输入参数:pIndata--要读数CRC的数据,len--数据长度,pOutData--计算的CRC结果
 * 返 回 值:无
 */
void CalulateCRC(uchar *pIndata, uchar len, uchar *pOutData)
{
  uchar i, n;</p><p>  ClearBitMask(DivIrqReg, 0x04);      //CRCIrq = 0
  SetBitMask(FIFOLevelReg, 0x80);     //清FIFO指针
  //Write_MFRC522(CommandReg, PCD_IDLE);</p><p>  //向FIFO中写入数据
  for (i = 0; i < len; i++)
  {
    Write_MFRC522(FIFODataReg, *(pIndata + i));
  }
  Write_MFRC522(CommandReg, PCD_CALCCRC);</p><p>  //等待CRC计算完成
  i = 0xFF;
  do
  {
    n = Read_MFRC522(DivIrqReg);
    i--;
  }
  while ((i != 0) && !(n & 0x04));  //CRCIrq = 1</p><p>  //读取CRC计算结果
  pOutData[0] = Read_MFRC522(CRCResultRegL);
  pOutData[1] = Read_MFRC522(CRCResultRegM);
}</p><p>/*
 * 函 数 名:MFRC522_SelectTag
 * 功能描述:选卡,读取卡存储器容量
 * 输入参数:serNum--传入卡序列号
 * 返 回 值:成功返回卡容量
 */
uchar MFRC522_SelectTag(uchar *serNum)
{
  uchar i;
  uchar status;
  uchar size;
  uint recvBits;
  uchar buffer[9];</p><p>  //ClearBitMask(Status2Reg, 0x08);     //MFCrypto1On=0</p><p>  buffer[0] = PICC_SElECTTAG;
  buffer[1] = 0x70;
  for (i = 0; i < 5; i++)
  {
    buffer[i + 2] = *(serNum + i);
  }
  CalulateCRC(buffer, 7, &buffer[7]);   //??
  status = MFRC522_ToCard(PCD_TRANSCEIVE, buffer, 9, buffer, &recvBits);</p><p>  if ((status == MI_OK) && (recvBits == 0x18))
  {
    size = buffer[0];
  }
  else
  {
    size = 0;
  }</p><p>  return size;
}</p><p>/*
 * 函 数 名:MFRC522_Auth
 * 功能描述:验证卡片密码
 * 输入参数:authMode--密码验证模式
                 0x60 = 验证A密钥
                 0x61 = 验证B密钥
             BlockAddr--块地址
             Sectorkey--扇区密码
             serNum--卡片序列号,4字节
 * 返 回 值:成功返回MI_OK
 */
uchar MFRC522_Auth(uchar authMode, uchar BlockAddr, uchar *Sectorkey, uchar *serNum)
{
  uchar status;
  uint recvBits;
  uchar i;
  uchar buff[12];</p><p>  //验证指令+块地址+扇区密码+卡序列号
  buff[0] = authMode;
  buff[1] = BlockAddr;
  for (i = 0; i < 6; i++)
  {
    buff[i + 2] = *(Sectorkey + i);
  }
  for (i = 0; i < 4; i++)
  {
    buff[i + 8] = *(serNum + i);
  }
  status = MFRC522_ToCard(PCD_AUTHENT, buff, 12, buff, &recvBits);</p><p>  if ((status != MI_OK) || (!(Read_MFRC522(Status2Reg) & 0x08)))
  {
    status = MI_ERR;
  }</p><p>  return status;
}</p><p>/*
 * 函 数 名:MFRC522_Read
 * 功能描述:读块数据
 * 输入参数:blockAddr--块地址;recvData--读出的块数据
 * 返 回 值:成功返回MI_OK
 */
uchar MFRC522_Read(uchar blockAddr, uchar *recvData)
{
  uchar status;
  uint unLen;</p><p>  recvData[0] = PICC_READ;
  recvData[1] = blockAddr;
  CalulateCRC(recvData, 2, &recvData[2]);
  status = MFRC522_ToCard(PCD_TRANSCEIVE, recvData, 4, recvData, &unLen);</p><p>  if ((status != MI_OK) || (unLen != 0x90))
  {
    status = MI_ERR;
  }</p><p>  return status;
}</p><p>/*
 * 函 数 名:MFRC522_Write
 * 功能描述:写块数据
 * 输入参数:blockAddr--块地址;writeData--向块写16字节数据
 * 返 回 值:成功返回MI_OK
 */
uchar MFRC522_Write(uchar blockAddr, uchar *writeData)
{
  uchar status;
  uint recvBits;
  uchar i;
  uchar buff[18];</p><p>  buff[0] = PICC_WRITE;
  buff[1] = blockAddr;
  CalulateCRC(buff, 2, &buff[2]);
  status = MFRC522_ToCard(PCD_TRANSCEIVE, buff, 4, buff, &recvBits);</p><p>  if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A))
  {
    status = MI_ERR;
  }</p><p>  if (status == MI_OK)
  {
    for (i = 0; i < 16; i++) //向FIFO写16Byte数据
    {
      buff[i] = *(writeData + i);
    }
    CalulateCRC(buff, 16, &buff[16]);
    status = MFRC522_ToCard(PCD_TRANSCEIVE, buff, 18, buff, &recvBits);</p><p>    if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A))
    {
      status = MI_ERR;
    }
  }</p><p>  return status;
}</p><p>/*
 * 函 数 名:MFRC522_Halt
 * 功能描述:命令卡片进入休眠状态
 * 输入参数:无
 * 返 回 值:无
 */
void MFRC522_Halt(void)
{
  uchar status;
  uint unLen;
  uchar buff[4];</p><p>  buff[0] = PICC_HALT;
  buff[1] = 0;
  CalulateCRC(buff, 2, &buff[2]);</p><p>  status = MFRC522_ToCard(PCD_TRANSCEIVE, buff, 4, buff, &unLen);
}</p>