射頻卡多線程讀寫原理及其實現

摘  要  介紹了射頻卡的工做原理及結構,並給出了使用多線程技術實現射頻卡監聽和讀寫的方法及其在C#下的具體實現。指出利用多線程實現射頻卡的監聽和讀寫可以提升射頻卡讀寫程序的併發性、可靠性和運行效率,從而提升整個應用系統的性能。
     關鍵詞  多線程  C#  射頻卡  性能
 

1  引言

     射頻卡又稱非接觸式IC卡, 是世界上最近幾年發展起來的一項新技術, 它成功的將射頻識別技術和IC卡技術結合起來。與傳統的接觸式IC卡相比, 射頻卡具備操做便捷、安全性高、抗干擾性強等優勢,而且因爲它不須要與讀卡機有直接物理性接觸,因此增長了讀卡機的讀寫壽命。目前,射頻卡已經在不少領域逐步獲得應用,特別是在安全性、保密性、便利性要求比較高的應用場所,表明了刷卡領域的發展方向。射頻卡的特色要求實現卡中數據讀寫的自動化,即當有射頻卡進入讀寫器的感應區內,讀寫器可以當即自動讀寫卡中數據,並實時傳入計算機進行顯示和處理,這就要求計算機對讀寫器進行循環監聽檢測。本文將利用多線程技術在後臺生成一個單獨的線程,用來監聽射頻卡的讀寫而不影響用戶在前臺的其它操做,從而提升應用系統的併發性、可靠性和執行效率。

2  射頻卡工做原理及結構

      筆者選用的射頻卡爲PHILIPS公司的Mifare S50(M1)卡,卡的電氣部分由一個天線和ASIC組成,卡片的天線是幾組繞線的線圈,適於封裝到IS0卡片中,ASIC由一個高速106KB波特率的RF接口,一個控制單元和一個8K位EEPROM組成。在工做時,讀寫器向M1卡發送一組固定頻率的電磁波,卡片內有一個LC串聯諧振電路,其頻率與讀寫器發射的頻率相同,在電磁波的激勵下,LC諧振電路產生共振,使電容內產生電荷,電容的另外一端接有一個單向導通的電子泵,將電容內的電荷送到另外一個電容內儲存,當所積累的電荷達到2V時,該電容可做爲電源爲其它電路提供工做電壓,將卡  內數據發射出去或者獲取讀寫器的數據。在此過程當中使用的M1射頻卡結構如圖1所示。
      射頻接口模塊用來得到讀寫器的電源電壓、復位信號、時鐘信號,同時卡內芯片中的有關電路對此信號進行調製、解碼、解密, 而後對命令請求、密碼、權限等進行判斷,以實現存儲區的合法讀寫。防碰撞模塊處理多張卡進入讀寫器有效範圍的狀況,這時防碰撞機制會從其中選擇一張進行操做,未選中的卡則處於空閒模式等待下一次選卡,該過程會返回被選中卡的序列號。讀寫驗證模塊驗證用戶的讀寫密碼與存儲區密碼是否相符,M1卡提供了兩套密碼KeyA 和KeyB,並結合控制位的使用能夠實現對每個扇區的讀或寫的控制,只有在密碼合法的狀況下,才能對指定區進行操做。控制及ALU單元實現值的特殊形式存儲,並能實現基本的加值和減值操做。
圖1  M1卡組成結構圖
      EEPROM是射頻卡的數據存儲區,分爲16個扇區,每一個扇區由4塊(塊0、塊一、塊二、塊3)組成,每塊大小爲16個字節,16個扇區的64個塊也可按絕對地址編號爲0~63。第0扇區的塊0用於存放廠商代碼,已經固化,不可更改。其它每一個扇區的塊0、塊一、塊2爲數據塊,可用於存貯數據。 數據塊可用做通常的數據保存,進行讀、寫操做,也能夠用做數據值,能夠進行初始化值、加值、減值、讀值等操做。每一個扇區的塊3爲控制塊,包括了密碼A、存取控制、密碼B三個部分,每一個扇區的密碼和存取控制都是獨立的,能夠根據實際須要設定各自的密碼及存取控制,具體結構如圖2所示。
每一個扇區的密碼和存取控制都是獨立的,能夠根據實際須要設定各自的密碼及存取控制。扇區中每一個塊的存取條件是由密碼和存取控制共同決定。
                                        6字節               4字節               6字節
圖2 扇區的控制塊結構

3  利用多線程技術實現卡讀寫

       目前的Windows系統都是多任務系統, 多任務指系統可同時運行多個進程, 進程就是應用程序的運行實例,而每一個進程也可同時執行多個線程。每一個進程都有本身私有的虛擬地址空間, 都有一個主線程, 在此基礎上還能夠創建另外的線程。進程中的線程是併發執行的, 每一個線程佔用CPU 的時間由系統來劃分。
圖3  射頻卡主要操做流程圖
      在應用程序中使用多線程,能夠將冗長的或很是耗時的任務放在後臺處理。即便在只有單處理器的計算機上,使用多線程也能夠很是顯著地提升應用程序的響應能力和可用性。爲了實現射頻卡讀寫器主動尋卡功能而且將返回的數據通知應用程序,能夠採用多線程技術。多線程具備異步操做的特色,使得讀寫器能夠只佔有不多的CPU資源,提升程序的運行效率。如下將利用C#語言具體實現射頻卡的多線程監聽讀寫,當啓動多線程讀寫功能後,主線程將創建一個單獨的後臺線程監聽讀寫器,當有射頻卡進入讀寫器有效範圍內就能夠實現該卡的自動識別和讀寫功能,而且無論卡在讀寫器有效範圍內的時間有多長,只實行一次操做,只有當該卡從新進入感應區才進行下一次讀寫。在讀寫以前還要實如今有效範圍內檢查卡、選擇卡、防碰撞、密碼驗證等預操做。操做射頻卡的主要流程如圖3所示。
      C#提供了進行多線程編程的類和接口,線程的建立能夠經過Thread、ThreadPool、Timer三種方法。Thread方法適用於需對線程進行復雜控制的場合; ThreadPool是一種相對較簡單的方法,適應於一些須要多個線程而又較短任務,缺點是對建立的線程不能加以控制,也不能設置其優先級;Timer則適用於需週期性調用的方法,它不在建立計時器的線程中運行,而是在由系統自動分配的單獨線程中運行。本次採用了Thread方法,相比之下Thread方法實現相對複雜,但控制更爲靈活。
      爲了方便實現射頻卡的讀寫編程功能,本程序利用了讀寫器附帶的動態鏈接庫,.NET框架提供了調用動態連接庫的服務,容許受管轄的代碼調用動態連接庫中實現的非受管轄函數,包括操做系統提供的Windows API函數,可以定位和調用輸出函數,根據須要組織其各個參數跨越互操做邊界。但動態連接庫中不少函數將指針做爲參數,而在C#中沒有指針的概念,用戶在受管理的代碼中不容許如直接存取內存等不安全的操做,爲了保持函數引用聲明中參數類型的一致性,在C#中經過引用封送指向這些數據類型的指針。程序實現的核心代碼以下:
[DllImport("RC500_232.dll")]
                   private static extern byte RC500_232_init(int mport,int mbaud);
                    [DllImport("RC500_232.dll")]
                   private static extern byte  RC500_232_request(byte mmode,ref UInt16 mtagtype);
                   [DllImport("RC500_232.dll")]
                   private static extern byte  RC500_232_anticoll(byte mbcnt,ref UInt32 msnr);
                   [DllImport("RC500_232.dll")]
                   private static extern byte  RC500_232_select(UInt32 msnr,ref byte msize);
                   [DllImport("RC500_232.dll")]
private static extern byte  RC500_232_authkey(byte mmode,byte msecnr, byte[] mkey);
                   [DllImport("RC500_232.dll")]
                   private static extern byte  RC500_232_read(byte maddr,byte[] mdata);
                   [DllImport("RC500_232.dll")]
                   private static extern byte  RC500_232_write(byte maddr,byte[] mdata);
                   …
private void Rf_read_Form_Load(object sender, System.EventArgs e)
                   {
                            flag=0;
                            if (RC500_232_init(1,19200)!=0)
                                     MessageBox.Show("端口打開失敗!");
                            else
                                     if (RC500_232_config()!=0)
                                     MessageBox.Show("初始化失敗!");
                            else
                                     MessageBox.Show("端口打開成功,讀卡器初始化成功!");
                   }
        …
                   private  void  Rf_232_Read()
                   {       …
                            while(true)
                            {
                              if (RC500_232_request(0, ref tagtype)!=0) //檢查有效範圍是否有卡
                                     {
                                               continue;
                                     }
                                     if (RC500_232_anticoll(0, ref snr)!=0) //防碰撞控制,snr返回卡的序列號
                                     {
                                               MessageBox.Show("防碰撞錯誤!");
                                               continue;
                                     }
                                     if (RC500_232_select(snr,ref size)!=0) //選擇某一序號的卡,
//size返回卡的容量大小
                                     {
                                               MessageBox.Show("選擇錯誤!");
                                               continue;
                                     }
                                     if (RC500_232_authkey(0,0,key)!=0) //密碼驗證,密碼存放在 key數組中
                                     {
                                               MessageBox.Show("密碼驗證錯誤!");
                                               continue;
                                     }
                                     if (RC500_232_read(0,data)!=0)// 將0扇區數據讀入byte類型數組data中,
//data爲16字節長
                                     {
                                       MessageBox.Show("數據讀取失敗");
                                               continue;
                                     }
                                     textBox1.Text="";
                                     for(i=0;i<16;i++)
                                     textBox1.Text=textBox1.Text+"  "+Convert.ToString(data[i],16);
                …
                                     RC500_232_halt();//讀寫一次後卡掛起,直到卡從新進入有效範圍
                                     RC500_232_alarm(1,25,25,1); //讀寫器發出蜂鳴,指示操做成功
                            }
                   }
                   private void threadstart_Click(object sender, System.EventArgs e)
                   {   …
                            Thread mythread = new Thread(new ThreadStart(Rf_232_Read));
                            mythread.Start();//線程啓動,執行Rf_232_Read函數
                            …
                   }
                  
以上實現的多線程讀卡程序,寫卡程序和讀卡程序相相似,這裏再也不贅述。

4  結束語

      採用多線程處理數據能夠有效地加快程序的反應速度、提升執行的效率,既能夠保證數據處理的實時性,又能及時響應用戶的其它操做。經過實踐證實,利用多線程實現射頻卡的監聽和讀寫是行之有效的技術,可以大大提升射頻卡讀寫程序的併發性、運行效率和可靠性,從而提升整個應用系統的性能。
相關文章
相關標籤/搜索