0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

讀寫卡模塊的外設(shè)驅(qū)動代碼編寫技巧

AGk5_ZLG_zhiyua ? 來源:互聯(lián)網(wǎng) ? 作者:佚名 ? 2017-11-12 06:39 ? 次閱讀
6.4 讀寫卡模塊

>>> 6.4.1 基本功能

ZLG600A 是ZLG 提供的符合14443 標(biāo)準(zhǔn)的13.56MHz 讀寫卡模塊,支持Plus CPU、Mifare DesfireCPU 卡、Mifare 1 S50/S70、Mifare 0 ultralight、Mifare Pro 卡,還支持ISO7816 協(xié)議讀寫接觸式IC 卡??梢源钶d兩個天線滿足不同位置的多卡讀寫要求,連接從機數(shù)多達127 個,支持I2C、UARTRS-232C、RS-485 多種接口。具備主動檢測卡進入功能,當(dāng)檢測到卡時,則產(chǎn)生中斷且通過串口、I2C 輸出數(shù)據(jù)。

ZLG600A 系列讀寫卡模塊選型指南詳見表6.18,電源電壓為5V,平均電流為77mA,TypeA、TypeB 和PLUS CPU卡讀卡距離分別為7.5cm、4cm 和5cm。

表6.18 選型指南表

由于RS-232C 和RS-485 與UART通信方式完全相同,僅在硬件上增加了一些轉(zhuǎn)換電路,因此后面不再特別說明。在這里僅介紹I2C 和UART 兩種通信方式,其引腳含義詳見表6.19。

表6.19 通信接口定義

注:方形焊盤為第1 管腳,3.3V 模塊J1-5 接3.3V 電源,5V 模塊J1-5 接5V 電源。

當(dāng)使用UART 通信時,只需要連接J1 中的電源引腳和TXD、RXD 引腳,其它引腳懸空,將LPC824 的USART0、USART1 或USART2 與ZLG600A 相連。當(dāng)使用I2C 通信時,需要連接J1 中的電源引腳和SCL、SDA 引腳。由于I2C 從機不能主動向I2C 主機發(fā)送數(shù)據(jù),因此需要使用INT 引腳,用于從機通知主機處理事務(wù)。其它未使用的引腳通過10K 的上拉電阻與高電平相連,將LPC824 的I2C0、I2C1、I2C2 或I2C3 與ZLG600A 相連。注:SCL 和SDA 模塊內(nèi)部都有上拉電阻,使用I2C 通信時無需再外接上拉電阻。

>>> 6.4.2 初始化

AMetal 已經(jīng)提供了ZLG600A 的驅(qū)動函數(shù),在使用其它各功能函數(shù)前必須先完成初始化,其初始化函數(shù)詳見表6.20。

表6.20 ZLG600A 初始化接口函數(shù)

初始化ZLG600A 意在獲取ZLG600A 的實例句柄(handle),雖然初始化函數(shù)不同,但返回值均為ZLG600A 的實例句柄,該實例句柄將作為其它功能接口函數(shù)handle 的實參。因此,無論選擇I2C 或UART 通信方式,只要基于實例句柄編程,則應(yīng)用程序與具體的通信方式無關(guān)。即便底層通信方式改變了,僅需在獲取實例句柄時換一個初始化函數(shù),而應(yīng)用程序“一行代碼”都不用修改。

1. UART 初始化

使用UART 時,其初始化函數(shù)原型為:

  • p_dev 為指向am_zlg600_uart_dev_t 類型實例的指針;

  • p_devinfo 為指向am_zlg600_uart_devinfo_t 類型實例信息的指針。

(1)實例

定義am_zlg600_uart_dev_t 類型(am_zlg600.h)實例如下:

其中,g_zlg600_uart_dev 為用戶自定義的實例,其地址作為p_dev 的實參傳遞。

(2)實例信息

實例信息主要描述了ZLG600A 使用UART 通信時的相關(guān)信息,包括UART 緩沖區(qū)信息、波特率等信息。其類型am_zlg600_uart_devinfo_t 定義(am_zlg600.h)如下:

實例信息主要包含幀格式、ZLG600A 模式、波特率和緩沖區(qū)信息。

  • 幀格式

frame_fmt 表示初始化時ZLG600A 使用的幀格式,為了兼容早期產(chǎn)品,ZLG600A 支持新幀格式和舊幀格式,其對應(yīng)的宏詳見表6.21。在初始化完成后,可以通過相應(yīng)的接口函數(shù)修改ZLG600A 使用的幀格式。但在初始化時,要知道ZLG600A 當(dāng)前使用的幀格式,出廠默認使用的幀格式為舊幀格式,frame_fmt 的值設(shè)置為:AM_ZLG600_FRAME_FMT_OLD。

表6.21 幀格式對應(yīng)的宏(am_zlg600.h)

注:若本次初始化完成后,通過后續(xù)相關(guān)功能接口函數(shù)更換使用的幀格式(如將舊幀格式更換為新幀格式),那么在系統(tǒng)下次啟動調(diào)用ZLG600A 初始化函數(shù)時,需要確保frame_fmt成員的值為更新后的幀格式(如新幀格式)。

  • ZLG600A 模式

now_mode 為初始化時使用的模式,ZLG600A 支持3 種模式:自動偵測模式、I2C 模式、UART 模式。其對應(yīng)的宏詳見表6.22,出廠默認為自動偵測模式。

表6.22 模式對應(yīng)的宏(am_zlg600.h)

注:由于在自動偵測模式下,為了使用UART 通信,需要Host 連續(xù)發(fā)送兩次0x20(兩次的時間間隔需要30us 以上),便于ZLG600A 檢測有效波特率,將會使得每次初始化ZLG600A 的耗費時間較長。因此在本次初始化完成后,通過后續(xù)接口函數(shù)將模式固定為UART 模式。更新模式后,系統(tǒng)在下次啟動調(diào)用ZLG600A 初始化函數(shù)時,需確保now_mode 成員的值為更新后的模式(如UART 模式)。

在自動偵測模式下,UART、I2C 接口均處于接收狀態(tài)。若ZLG600A 從UART 通信線上檢測到有效的波特率(需要Host 連續(xù)發(fā)送兩次0x20,且兩次的時間間隔在30us 以上,便于ZLG600 檢測到有效波特率),則模塊使用UART 通信方式;若模塊從I2C 總線上接收到匹配的從機地址,則模塊使用I2C 通信方式。只要其中一個接口先收到有效數(shù)據(jù),模塊將以此方式與主機通信,且關(guān)閉另外一種接口。

在UART 通信模式下,通信接口固定為UART,關(guān)閉I2C 接口,無需Host再連續(xù)發(fā)送兩次0x20 檢測ZLG600A 波特率。在I2C 通信模式下,關(guān)閉UART接口。在完成初始化后,可以通過相應(yīng)的接口函數(shù)修改ZLG600A 使用的模式。但在初始化時,要知道ZLG600A 當(dāng)前使用的模式,出廠默認使用的模式為自動偵測模式,now_mode 的值設(shè)置為:

AM_ZLG600_MODE_AUTO_CHECK。

  • 波特率

baudrate 為UART 波特率,支持波特率的宏定義詳見表6.23。在自動偵測模式下,可以選擇表中任一有效的波特率,ZLG600A 會自動檢測使用的波特率。若處于UART 模式,波特率將為固定的值,該值為配置ZLG600A 是UART 模式時使用的波特率。

表6.23 支持的UART 波特率對應(yīng)的宏(am_zlg600.h)

由于出廠默認模式為自動偵測模式,因此該值為任一有效的波特率,如定義波特率為115200,則該值為:AM_ZLG600_BAUDRATE_115200。

  • 緩沖區(qū)信息

當(dāng)選擇UART 方式通信時,發(fā)送和接收都需要一個保存數(shù)據(jù)的緩沖區(qū),以提高數(shù)據(jù)處理的效率和確保接收數(shù)據(jù)不會因為正在處理事務(wù)而丟失。緩沖區(qū)的大小由用戶根據(jù)實際情況指定,建議在64 字節(jié)以上,一般設(shè)置為128 字節(jié)。p_uart_rxbuf 和rxbuf_size 描述了接收緩沖區(qū)的首地址和大小,p_uart_txbuf 和txbuf_size 描述了發(fā)送緩沖區(qū)的首地址和大小。如果設(shè)置128 字節(jié)的緩沖區(qū)供發(fā)送和接收使用,其定義如下:

其中,g_zlg600_uart_txbuf[128]為用戶自定義的數(shù)組空間供發(fā)送使用,充當(dāng)發(fā)送緩沖區(qū),其地址(數(shù)組名g_zlg600_uart_txbuf 或首元素地址& g_zlg600_uart_txbuf[0])作為實例信息中p_uart_txbuf 成員的值,數(shù)組大?。ㄟ@里為128)作為實例信息中txbuf_size 成員的值。同理,g_zlg600_uart_rxbuf[128]充當(dāng)接收緩沖區(qū),其地址作為實例信息中p_uart_rxbuf 成員的值,數(shù)組大小作為實例信息中rxbuf_size 成員的值?;诖?,實例信息定義如下:

(3)UART 句柄uart_handle

若選擇LPC824 的USART1 與ZLG600A 通信,則可以通過LPC82x 的USART1 實例初始化函數(shù)am_lpc82x_usart1_inst_init()獲得UART 句柄。即:

獲得的UART 句柄即可直接作為uart_handle 的實參傳遞。

(4)實例句柄

ZLG600A 初始化函數(shù)am_zlg600_uart_init()的返回值即為ZLG600A 實例的句柄,該句柄將作為其它功能接口的第一個參數(shù)(handle)的實參。

其類型am_zlg600_handle_t(am_zlg600.h)定義如下:

若返回值為NULL,說明初始化失??;若返回值不為NULL,說明返回一個有效的handle。

基于模塊化編程思想,將初始化相關(guān)的實例、實例信息等的定義存放到對應(yīng)的配置文件中,通過頭文件引出實例初始化函數(shù)接口,源文件和頭文件的程序范例分別詳見程序清單6.98 和程序清單6.99。

程序清單6.98 ZLG600A(串口通信)實例初始化函數(shù)實現(xiàn)(am_hwconf_zlg600.c)

程序清單6.99 ZLG600A(串口通信)實例初始化函數(shù)聲明(am_hwconf_zlg600.h)

后續(xù)只需要使用無參數(shù)的實例初始化函數(shù),即可獲取ZLG600A 的實例句柄。即:

2. I2C 初始化

使用I2C 通信方式時,其初始化函數(shù)原型為:

  • p_dev 為指向am_zlg600_i2c_dev_t 類型實例的指針;

  • p_devinfo 為指向am_zlg600_i2c_devinfo_t 類型實例信息的指針。

(1)實例

定義am_zlg600_i2c_dev_t 類型(am_zlg600.h)實例如下:

其中,g_zlg600_i2c_dev 為用戶自定義的實例,其地址作為p_dev 的實參傳遞。

(2)實例信息

實例信息主要描述了ZLG600A 使用I2C 通信時的相關(guān)信息,包括I2C 緩沖區(qū)信息、波特率等信息。其類型am_zlg600_i2c_devinfo_t 的定義(am_zlg600.h)如下:

實例信息主要包含幀格式、ZLG600A 模式、7 位I2C 從機地址和中斷引腳信息。

frame_fmt 的含義與使用UART 通信方式時一致,對于出廠設(shè)置的模塊,frame_fmt 的值應(yīng)設(shè)置為:AM_ZLG600_FRAME_FMT_OLD。

now_mode 的含義與使用UART 通信方式時一致,對于出廠設(shè)置的模塊,now_mode 的值應(yīng)設(shè)置為:AM_ZLG600_MODE_AUTO_CHECK。在本次初始化完成后,若通過后續(xù)接口函數(shù)將模式固定為I2C 模式。則系統(tǒng)在下次啟動調(diào)用ZLG600A 初始化函數(shù)時,必須確保now_mode 成員的值為更新后的I2C 模式。

slv_addr 為ZLG600A 的7 位I2C 從機地址,出廠默認值為0x59,數(shù)據(jù)手冊中描述為0xB2,該值為8 位地址,右移一位,即移除表示讀寫方向的位后,值即為0x59。在本次初始化完成后,若通過后續(xù)接口函數(shù)修改I2C 地址。則系統(tǒng)在下次啟動調(diào)用ZLG600A 初始化函數(shù)時,必須確保slv_addr 成員的值為更新后的I2C 地址。

int_pin 為ZLG600A 的INT 引腳與實際微控制器(如LPC824)連接的引腳號。比如,選擇LPC824 的PIO0_13 與ZLG600A 的 INT 引腳相連,則該值應(yīng)設(shè)置為PIO0_13。

基于此,實例信息定義如下:

(3)I2C 句柄i2c_handle

若選擇LPC824 的I2C1 與ZLG600A 通信,則通過LPC82x 的I2C1 實例初始化函數(shù)am_lpc82x_i2c1_inst_init()獲得I2C 句柄。即:

獲得的I2C 句柄即可直接作為i2c_handle 的實參傳遞。

(4)實例句柄

am_zlg600_i2c_init()與am_zlg600_uart_init()的返回值相同,該返回值為ZLG600A 實例的句柄,該句柄將作為其它功能接口的第一個參數(shù)(handle)的實參。若返回值為NULL,說明初始化失?。蝗舴祷刂挡粸镹ULL,說明返回一個有效的handle。

基于模塊化編程思想,將初始化相關(guān)的實例、實例信息等的定義存放到對應(yīng)的配置文件中,通過頭文件引出實例初始化函數(shù)接口,源文件和頭文件的程序范例分別詳見程序清單6.100 和程序清單6.101。

程序清單6.100 新增ZLG600A 的I2C 通信方式的實例初始化函數(shù)(am_hwconf_zlg600.c)

程序清單6.101 am_hwconf_zlg600.h 文件內(nèi)容更新

后續(xù)只需要使用無參數(shù)的實例初始化函數(shù),即可獲取到ZLG600A 的實例句柄。即:

>>> 6.4.3 設(shè)備控制類接口函數(shù)

ZLG600A 支持多種IC 卡,比如,Mifare S50/S70、ISO7816-3、ISO14443(PICC)、PLUSCPU 卡等,每種卡都有對應(yīng)的命令。命令與接口函數(shù)基本上是一一對應(yīng)的關(guān)系,ZLG600A的命令較多,分為以下5 類:設(shè)備控制類命令、Mifare S50/S70 卡類命令、ISO7816-3 類命令、ISO14443(PICC)卡類命令和PLUS CPU 卡類命令。

設(shè)備控制類接口函數(shù)與具體卡片沒有直接關(guān)系,主要用于直接操作ZLG600A,比如,獲取ZLG600A 的設(shè)備信息和存儲IC 卡密鑰等,詳見表6.24。

表6.24 ZLG600A 設(shè)備控制類接口函數(shù)(am_zlg600.h)

1. 讀取設(shè)備信息

該函數(shù)意在獲取ZLG600A 的基本信息,包括產(chǎn)品信息和版本信息等,獲取的信息為字符串,比如,“ZLG600A V1.00”。其函數(shù)原型為:

其中,p_info 為獲取信息的指針,由于字符串長度為20 字節(jié),因此需要提供一個長度為20 字節(jié)的內(nèi)存空間,以便存放獲取到的信息。若返回值為AM_OK,說明獲取信息成功,反之失敗,范例程序詳見程序清單6.102。

程序清單6.102 讀取ZLG600A 設(shè)備信息范例程序

假定選擇UART 通信方式,即可使用am_zlg600_uart_inst_init()實例初始化函數(shù)獲取ZLG600A 的實例句柄。同時包含標(biāo)準(zhǔn)C 頭文件string.h,便于使用strcmp()函數(shù)判斷字符串是否為“ZLG600A V1.00”?

由于這次使用的是ZLG600A V1.00 模塊,因此獲取的信息一定為“ZLG600A V1.00”。如果你使用的是其它型號或版本的模塊,則要注意將比較信息的字符串修改,否則就算成功讀取信息,比較結(jié)果也是不相等的。

2. 裝載IC 卡密鑰

卡片內(nèi)存儲的數(shù)據(jù)均是加密的,必須驗證成功后才能讀寫數(shù)據(jù)。驗證就是將用戶提供的密鑰與卡片內(nèi)部存儲的密鑰對比,只有相同才認為驗證成功。ZLG600A 提供了用于存儲卡片驗證的密鑰的E2PROM,裝載IC 卡密鑰的作用就是將密鑰存放到指定的E2PROM 存儲區(qū),其函數(shù)原型為:

其中,key_type 為密鑰類型,密鑰一般分為2 類,其分別為TypeA 和TypeB。其對應(yīng)的宏詳見表6.25。ZLG600A 能保存A 類型密鑰16組,B 類型密鑰16 組。

表6.25 密鑰類型(am_zlg600.h)

注:之所以存在兩類密鑰,是由于實際卡片中往往存在兩類密鑰,兩類密鑰可以更加方便地進行權(quán)限管理,比如,TypeA 驗證成功后只能讀,而TypeB 只有驗證成功后才能寫入,但權(quán)限可以自定義設(shè)置。

key_sec 為保存的區(qū)號,由于ZLG600A 能保存A 類密鑰16 組和B 類密鑰16 組,因此每種類型保存的區(qū)域有16 個,其對應(yīng)區(qū)號為0 ~ 15。

p_key 指向了實際待保存密鑰的緩沖區(qū),key_length 為密鑰的長度,密鑰最大長度為16 字節(jié)。保存一組6 字節(jié)長度的A 類型密鑰至區(qū)號0 的范例程序詳見程序清單6.103。

程序清單6.103 裝載密鑰范例程序

當(dāng)后續(xù)需要驗證卡片時,只需要指定密鑰存放的E2PROM 區(qū)號0,無需再將密鑰發(fā)送給ZLG600A。

>>> 6.4.4 操作接口函數(shù)

Mifare 卡是一種符合ISO14443 標(biāo)準(zhǔn)的A 型卡,其接口函數(shù)詳見表6.26。

表6.26 Mifare S50/S70 接口函數(shù)(am_zlg600.h)

經(jīng)常使用的公交卡、房卡、水卡和飯卡等均是Mifare 卡。比如,S50 和S70,它們的區(qū)別在于容量的不同。S50 為1Kbyte,共16 個扇區(qū),每個扇區(qū)4 塊,每塊16 字節(jié)。S70 為4Kbyte,共40 個扇區(qū),前32 個扇區(qū)每個扇區(qū)4 塊,每塊16 字節(jié),后8 個扇區(qū)每個扇區(qū)16 塊,每塊16 字節(jié)。

1. 自動檢測

  • 設(shè)置自動檢測回調(diào)函數(shù)

當(dāng)有卡片靠近ZLG600A 時,將會自動調(diào)用用戶設(shè)定的回調(diào)函數(shù),讀取卡片的相關(guān)信息,因此需要先設(shè)置一個回調(diào)函數(shù)。其函數(shù)原型為:

其中,pfn_callback 為指向回調(diào)函數(shù)的指針,p_arg 為回調(diào)函數(shù)的參數(shù)。若返回AM_OK,表示設(shè)置成功,反之失敗,范例程序詳見程序清單6.104。

程序清單6.104 設(shè)置自動檢測回調(diào)函數(shù)范例程序

程序中定義了一個detect_flag 變量,表示是否檢測到卡片。如果初始值為0,說明未檢測到卡片。在設(shè)置自動檢測回調(diào)函數(shù)時,將其地址作為回調(diào)函數(shù)的p_arg 參數(shù)。因此在回調(diào)函數(shù)中,p_arg 實質(zhì)上是指向detect_flag 的指針,通過該指針將detect_flag 設(shè)置為1,表明當(dāng)前檢測到卡片。

  • 啟動自動檢測

當(dāng)設(shè)置好回調(diào)函數(shù)后,即可啟動自動檢測。其函數(shù)原型為:

其中,p_info 為指向自動檢測相關(guān)信息的指針,其類型am_zlg600_auto_detect_info_t 定義如下:

該信息結(jié)構(gòu)體包含檢測模式、天線模式、請求模式和密鑰驗證相關(guān)的信息。

  • 檢測模式

ad_mode 表示檢測模式,用于配置檢測相關(guān)動作。當(dāng)檢測到卡片時,是否掛起該卡片,若選擇掛起,設(shè)置ad_mode 的值為AM_ZLG600_MIFARE_CARD_AD_HALT(am_zlg600.h),則在檢測到一次該卡片后,就將該卡片掛起,后續(xù)檢測將忽略該卡片。若需再次檢測該卡片,必須將卡片遠離ZLG600A 后重新靠近才有效。若設(shè)置ad_mode 的值為0,則不會掛起卡片,每次自動檢測均可以檢測到靠近的卡片。

舉個簡單的例子可能更容易理解,在平常刷公交卡時,當(dāng)卡片靠近刷卡器時,會扣費一次,刷卡成功。若公交卡不離開刷卡器,則不會再次扣費,此時卡片已經(jīng)被刷卡器掛起了,不會再被識別到。若將公交卡離開刷卡器后再次靠近,將可能再次扣費。

當(dāng)ad_mode 的值均設(shè)置為AM_ZLG600_MIFARE_CARD_AD_HALT 時,則可以避免重復(fù)檢測到同一張卡片。

  • 天線模式

tx_mode 設(shè)置天線的工作模式,ZLG600A 有2 個天線TX1 和TX2,4 種工作模式:僅使用TX1、僅使用TX2、TX1 和TX2 交替使用、TX1 和TX2 同時使用,各種模式對應(yīng)的tx_mode 的值宏定義詳見表6.27。

表6.27 天線工作模式(am_zlg600.h)

  • 請求模式

req_mode 表示請求模式,即檢測所有的卡還是只檢測空閑卡,對應(yīng)的值宏定義詳見表6.28,一般來講只檢測空閑卡。

表6.28 請求模式(am_zlg600.h)

  • 密鑰驗證

由于絕大部分卡片在檢測到卡片時,都要先讀取一塊數(shù)據(jù),因此可以將讀取數(shù)據(jù)作為自動檢測的一個附加功能。即在檢測到卡片時,自動讀取1 塊(16 字節(jié))數(shù)據(jù)。由于讀取數(shù)據(jù)前均需要驗證,這就需要在啟動自動檢測時,指定密鑰驗證相關(guān)的信息。

所謂密鑰驗證就是將用戶提供的密鑰與卡片內(nèi)部存儲的密鑰對比,只有相等方能驗證成功。auth_mode 指定了3 種驗證模式,其對應(yīng)的宏表6.29。

表6.29 驗證模式(am_zlg600.h)

如果在自動檢測到卡片時,不需要讀取數(shù)據(jù),則應(yīng)該將auth_mode 的值設(shè)置為AM_ZLG600_MIFARE_CARD_AUTH_NO。由于不會用到信息結(jié)構(gòu)體中key_type、key[16]、key_len、nblock 四個成員的值,因此無需設(shè)置。

如果需要讀取數(shù)據(jù),則必須將auth_mode 置為AM_ZLG600_MIFARE_CARD_AUTH_E2或AM_ZLG600_MIFARE_CARD_AUTH_DIRECT,其主要區(qū)別是驗證密鑰存放位置不同。

如果使用“直接驗證”(AM_ZLG600_MIFARE_CARD_AUTH_DIRECT)的方式,則信息結(jié)構(gòu)體的key[16]包含了實際的密鑰,key_len 表示了密鑰的長度。

如果使用“E2 驗證”(AM_ZLG600_MIFARE_CARD_AUTH_E2)方式,則驗證密鑰存放在ZLG600A 的E2PROM 中。此時,信息結(jié)構(gòu)體的key[16] 僅使用了首元素key[0],其值為密鑰在E2PROM 中的區(qū)號(0 ~ 15)。自動檢測時,將使用ZLG600A 中E2PROM 對應(yīng)區(qū)號中的密鑰進行驗證。key_len 表示密鑰的長度。顯然,若使用“E2 驗證”,則需要確保已經(jīng)使用am_zlg600_ic_key_load()將密鑰存放到了ZLG600A 中E2PROM 相應(yīng)的區(qū)域。

信息結(jié)構(gòu)體中的nblock 指定了要驗證的塊,即讀取數(shù)據(jù)的塊,只有該塊被驗證成功后,才能讀取數(shù)據(jù)。Mifare S50 和Mifare S70 卡片包含的塊數(shù)目詳見表6.30。

表6.30 常見卡片的塊數(shù)目(am_zlg600.h)

假定無需讀取數(shù)據(jù),可以定義自動檢測信息如下:

定義好相關(guān)信息后,可以使用啟動函數(shù)啟動自動檢測,即:

  • 讀取卡片信息

當(dāng)啟動自動檢測后,若前面注冊的回調(diào)函數(shù)被調(diào)用,表明檢測到卡片,此時可以使用該接口讀取卡片的信息。其函數(shù)原型為:

其中,p_card_info 為指向卡片信息的指針,用于獲取卡片信息??ㄆ畔⒌念愋蚢m_zlg600_mifare_card_info_t(am_zlg600.h)定義如下:

該信息結(jié)構(gòu)體包含了天線驅(qū)動模式、卡片唯一序列號和讀取的數(shù)據(jù)等相關(guān)的信息。

  • 天線驅(qū)動模式

tx_mode 表示天線的驅(qū)動模式,在啟動自動檢測時,天線的模式有4 種:僅使用TX1、僅使用TX2、TX1 和TX2 交替使用、TX1 和TX2 同時使用。若啟動自動檢測時使用的模式為TX1 和TX2 交替使用,那么該值將會被設(shè)置為實際檢測到卡片的天線。tx_mode 可能被設(shè)置的值詳見表6.31。

表6.31 讀取到的天線驅(qū)動模式(am_zlg600.h)

當(dāng)TX1 和TX2 同時使用時,將無法區(qū)分具體檢測到卡片的天線。

  • 片唯一序列號

每張卡片都具有一個唯一序列號,即UID。所有卡片的UID 都是不相同的??ǖ男蛄刑栭L度有三種:4 字節(jié)、7 字節(jié)和10 字節(jié)。uid_len 表明了讀取到的UID 的長度,uid[10]中存放了讀取到的UID(字節(jié)數(shù))。

  • 讀取的數(shù)據(jù)

在啟動自動檢測時,指定了讀取卡片數(shù)據(jù)相關(guān)的驗證信息,若auth_mode 不為AM_ZLG600_MIFARE_CARD_AUTH_NO,且對應(yīng)的密鑰正確,驗證成功,將讀取啟動自動檢測時信息結(jié)構(gòu)體的nblock 成員指定的塊(由信息結(jié)構(gòu)體的nblock 指定)的數(shù)據(jù)。讀取的數(shù)據(jù)存放在card_data[16]數(shù)組中,讀取卡片信息的范例程序詳見程序清單6.105。

程序清單6.105 讀取卡片信息范例程序

讀取卡片信息成功后,將通過調(diào)試串口打印出讀取到的UID 信息。并翻轉(zhuǎn)LED1 燈的狀態(tài),指示讀取一次卡片信息成功。

2. 卡片驗證

由于卡片內(nèi)存儲的數(shù)據(jù)是加密的,因此必須驗證成功后才能讀寫數(shù)據(jù)。驗證方式有“E2驗證”和“直接驗證”,它們的區(qū)別是用于驗證的密鑰存放的位置不同。

  • E2 驗證

用于驗證的密鑰是存放在ZLG600A 的E2PROM 中,其函數(shù)原型為:

其中,key_type 的類型是密鑰類型,它的值為AM_ZLG600_IC_KEY_TYPE_A 或AM_ZLG600_IC_KEY_TYPE_B,分別代表A 類型密鑰和B 類型密鑰。

p_uid 為指向UID 高4 字節(jié)緩沖區(qū)的指針,若UID 為4 字節(jié),其值為獲取的UID 的首元素地址,即&card_info.uid[0];若UID 為7 字節(jié),其值為獲取的UID 的第3 號元素的地址,即&card_info.uid[3];若UID 為10 字節(jié),其值為獲取的UID 的第6 號元素的地址,即&card_info.uid[6]。key_sec 為密鑰存放在ZLG600A 的E2PROM 中的區(qū)號,該值應(yīng)該與使用am_zlg600_ic_key_load()函數(shù)存儲對應(yīng)密鑰時使用的區(qū)號一致。

nblock 指定本次驗證的塊號,返回值為AM_OK 時表明驗證成功,反之失敗,使用區(qū)號0 中的A 類密鑰驗證塊1 的范例程序詳見程序清單6.106。

程序清單6.106 E2 驗證范例程序

自動檢測獲取卡片信息card_info 詳見程序清單6.101,調(diào)用am_zlg600_ic_key_load()將密鑰存放在在0 區(qū)的E2PROM 中的程序詳見程序清單6.103。

實際上絕大部分卡都是4 字節(jié)的,而7 或10 字節(jié)的UID 卡極少。如果確定使用的卡片UID 為4 字節(jié),則p_uid 的值為&card_info.uid[0]。

  • 直接驗證

用于驗證的密鑰是由接口函數(shù)提供,其函數(shù)原型為:

其中,key_type、p_uid、nblock 的含義與“E2 驗證”相同,由于需要直接提供密鑰,因此使用p_key 指向密鑰存放的緩沖區(qū),key_len 表示密鑰的長度。返回值為AM_OK,表明驗證成功,反之失敗,直接使用6 字節(jié)密鑰進行驗證的范例程序詳見程序清單6.107。

程序清單6.107 直接驗證范例程序

程序使用6 字節(jié)全0xFF 作為密鑰驗證塊1,之所以這樣,是因為Mifare S50/S70 卡片的密鑰出廠默認為全0xFF,且密鑰長度為6 字節(jié)。對于出廠默認設(shè)置,使用A 類密鑰和B類密鑰驗證均可。對于一些有權(quán)限控制的卡片,如驗證A 類密鑰后僅只讀,驗證B 類密鑰后可寫,則需要根據(jù)實際情況進行驗證,密鑰和權(quán)限控制的修改后面會進一步介紹。

3. 讀寫數(shù)據(jù)

若驗證成功,則開始讀寫已驗證的塊。讀寫數(shù)據(jù)都是以塊為單位的,其大小為16 字節(jié)。

  • 讀取數(shù)據(jù)

讀取數(shù)據(jù)就是讀取某一塊的數(shù)據(jù),其函數(shù)原型為:

其中,nblock 指定讀取的塊號,p_buf 為指向存放數(shù)據(jù)的緩沖區(qū),緩沖區(qū)大小為16 字節(jié)。返回值為AM_OK 時,表明讀取數(shù)據(jù)成功,反之失敗。如程序清單6.108 所示為讀取塊1 數(shù)據(jù)的范例程序。

程序清單6.108 讀取數(shù)據(jù)范例程序

  • 寫入一塊數(shù)據(jù)

寫入數(shù)據(jù)就是將數(shù)據(jù)寫入到某一塊,其函數(shù)原型為:

其中,nblock 指定寫入的塊號,p_buf 為指向?qū)懭霐?shù)據(jù)的緩沖區(qū),緩沖區(qū)大小為16 字節(jié)。返回值為AM_OK 時,說明寫入數(shù)據(jù)成功,反之失敗。如程序清單6.109 所示為寫入16 字節(jié)數(shù)據(jù)至塊1 的范例程序。

程序清單6.109 寫入數(shù)據(jù)范例程序

如程序清單6.110 所示是展示卡片自動檢測、驗證和讀寫數(shù)據(jù)的綜合測試范例程序。

程序清單6.110 ZLG600 綜合測試范例程序

程序每檢測到一次卡片(detect_flag 的值為1),將讀取一次信息,然后使用調(diào)試串口打印UID 的值,接著進行讀寫檢測。若讀寫檢測失敗,表明驗證失敗,很可能密鑰不是初始密鑰,已經(jīng)被修改過了。

由于讀取UID 并不需要驗證,因此,當(dāng)測試程序運行時,將常見的公交卡、門禁卡、飯卡等卡靠近ZLG600A,均可以讀取卡片的UID。由于這些卡片的密鑰并不知曉,因此讀寫數(shù)據(jù)測試很可能會失敗。

>>> 6.4.5 密鑰和權(quán)限控制

Mifare S50/S70 卡的初始密鑰全為0xFF,顯然,對于實際產(chǎn)品來講,希望能夠更改其密鑰為其它值。由于存在密鑰A和密鑰B,可以對每個密鑰設(shè)定不一樣的權(quán)限,如驗證密鑰A后僅只讀,驗證密鑰B 后可寫。下面以Mifare S50 為例,介紹密鑰和權(quán)限控制的修改方法。

密鑰和權(quán)限控制是針對扇區(qū)而言的,即一個扇區(qū)的密鑰是相同的,不同扇區(qū)的密鑰可以不同。S50 共計16 個扇區(qū),每個扇區(qū)4 塊,每塊16 字節(jié),前3塊為普通的數(shù)據(jù)塊,最后一塊(尾塊)為密鑰和權(quán)限控制塊。對最后一塊存儲的數(shù)據(jù)進行修改,即可完成密鑰和權(quán)限控制的修改。操作最后一塊的存儲數(shù)據(jù)時要格外小心,數(shù)據(jù)稍有錯誤,就可能導(dǎo)致扇區(qū)被鎖死。尾塊的前6 字節(jié)為A 密鑰,后6字節(jié)為B 密鑰,中間4 字節(jié)用于權(quán)限控制,詳見圖6.11。

圖6.11 尾塊格式

如需修改密鑰和控制權(quán)限,重點在理解字節(jié)6、7 和8(字節(jié)9 是一個普通的數(shù)據(jù))的含義。3 個字節(jié)共計24 位,每6 位(分別為C1、C2、C3、

由于存在此關(guān)系,因此實際控制位的含義僅通過C1、C2、C3 三個位即可確定。控制尾塊和數(shù)據(jù)塊的控制位含義是不同的。對于尾塊,其控制了密鑰A、密鑰B 以及控制區(qū)域的訪問權(quán)限??刂莆坏暮x詳見表6.32。

表6.32 尾塊控制位含義

表中,“×”表示任何情況下都無權(quán)限,“KeyA”表示通過密鑰A 驗證后可以取得權(quán)限,KeyB 表示通過密鑰B 驗證后可以取得權(quán)限,“KeyA | B”表示通過密鑰A 或者密鑰B 驗證后均可取得權(quán)限。由此可見,密鑰A 的安全性很高,任何情況下都無法讀出。特殊情況下,當(dāng)C1C2C3 的值為000、010 或001 時,驗證密鑰A 后即可讀取密鑰B 區(qū)域的數(shù)據(jù)。

無論什么情況,驗證密鑰A 后,均可獲得控制區(qū)域的讀權(quán)限。通過讀取控制區(qū)域,可以知道當(dāng)前C1、C2、C3 的值,以判斷需要驗證哪個密鑰后可以獲得密鑰區(qū)域或控制區(qū)域的寫權(quán)限,進而修改密鑰和控制區(qū)域的值。比如,當(dāng)前的C1、C2、C3 的值為0、1、1,為了修改密鑰A,則需要先驗證密鑰B,驗證密鑰B 后,即可對尾塊進行寫入,寫入時其它數(shù)據(jù)保持不變,僅修改前6 字節(jié)(KeyA 區(qū)域)的值即可完全對密鑰A 的修改。

對于數(shù)據(jù)塊,C1、C2、C3 控制了對塊中存儲數(shù)據(jù)的操作權(quán)限,詳見表6.33。

表6.33 數(shù)據(jù)塊控制位含義

同樣,表中“×”表示任何情況下都無權(quán)限,“KeyA”表示通過密鑰A 驗證后可以取得權(quán)限,KeyB 表示通過密鑰B 驗證后可以取得權(quán)限,“KeyA | B”表示通過密鑰A 或者密鑰B 驗證后均可取得權(quán)限。

加值操作(相當(dāng)于充值)和減值操作(相當(dāng)于消費)是對塊中存放的值進行增加和減少操作,加值和減值均有對應(yīng)的命令可以直接使用。例如,當(dāng)前塊1 的C1、C2、C3 控制位的值為0、0、0(默認值),只要密鑰A 或密鑰B 驗證通過后,均可取得數(shù)據(jù)塊的讀、寫、加值、減值的權(quán)限??梢愿鶕?jù)實際需要,修改尾塊中相應(yīng)控制位的值(修改時,需確保具有寫入控制區(qū)域的權(quán)限),以對數(shù)據(jù)進行保護。

需要注意的是,凡是表中標(biāo)識驗證密鑰B 后可以取得權(quán)限的,在特殊情況下驗證密鑰B后可能并不能取得權(quán)限。在介紹尾塊控制位含義時,當(dāng)C1、C2、C3 的值為000、010 或001時,KeyB 區(qū)域?qū)⒖赡鼙蛔x取,詳見表6.32。這些情況下,由于密鑰B 可能被讀取,為了確保安全,此時密鑰B 驗證將無效,即使密鑰B 驗證通過,同樣無法取得相應(yīng)的權(quán)限。


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴

原文標(biāo)題:周立功:重用外設(shè)驅(qū)動代碼——讀寫卡模塊

文章出處:【微信號:ZLG_zhiyuan,微信公眾號:ZLG致遠電子】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    基于DWC2的USB驅(qū)動開發(fā)-0x0D PHY寄存器讀寫代碼編寫與測試

    我們前面重點介紹了ULPI接口和PHY的寄存器,這一篇來進行PHY寄存器讀寫代碼編寫與測試。從這一篇開始就正真進入了驅(qū)動編寫的過程了。
    的頭像 發(fā)表于 06-06 13:03 ?2029次閱讀
    基于DWC2的USB<b class='flag-5'>驅(qū)動</b>開發(fā)-0x0D PHY寄存器<b class='flag-5'>讀寫</b><b class='flag-5'>代碼</b><b class='flag-5'>編寫</b>與測試

    Linux模塊相關(guān)命令 Linux驅(qū)動模塊編寫與掛載

    Linux模塊相關(guān)命令 Linux驅(qū)動模塊編寫與掛載
    發(fā)表于 10-01 12:20 ?402次閱讀
    Linux<b class='flag-5'>模塊</b>相關(guān)命令 Linux<b class='flag-5'>驅(qū)動</b><b class='flag-5'>模塊</b>的<b class='flag-5'>編寫</b>與掛載

    C6678 SYS/BIOS讀寫外設(shè)

    平臺為C6678開發(fā)板,使用sys/bios讀寫器件外設(shè)如SPI,UART,EMIF等,應(yīng)當(dāng)如何操作。 開發(fā)這些外設(shè),是否需要用戶自己編寫驅(qū)動
    發(fā)表于 06-21 02:54

    IC讀寫程序 (C語言源程序代碼)

    IC讀寫程序 (C語言源程序代碼)
    發(fā)表于 03-25 08:56 ?354次下載

    STM32的SD驅(qū)動及液晶驅(qū)動代碼資料

    STM32的SD驅(qū)動及液晶驅(qū)動代碼
    發(fā)表于 01-13 08:57 ?164次下載

    北京圓志科信讀寫模塊應(yīng)用手冊

    M50X系列SAM讀寫模塊采用高性能ASIC處理器基站;用戶不必關(guān)心射頻基站的復(fù)雜控制方法,只需通過簡單的選定UART,IIC等接口發(fā)送命令就可以實現(xiàn)對卡片完全的操作。該系列讀寫
    發(fā)表于 07-16 11:23 ?12次下載

    IC設(shè)備驅(qū)動模塊代碼

      面以我們采用的公用電話機通用的IC為例,通過已實現(xiàn)代碼來說明整個IC設(shè)備驅(qū)動模塊。   (1)數(shù)據(jù)結(jié)構(gòu)的確定   編輯頭文件IC
    發(fā)表于 09-01 17:28 ?1284次閱讀
    IC<b class='flag-5'>卡</b>設(shè)備<b class='flag-5'>驅(qū)動</b><b class='flag-5'>模塊</b>的<b class='flag-5'>代碼</b>

    IC讀寫仿真

    IC讀寫仿真IC讀寫仿真IC讀寫仿真
    發(fā)表于 11-10 16:49 ?5次下載

    單片機編程技巧之重用外設(shè)驅(qū)動代碼

    第六章為重用外設(shè)驅(qū)動代碼,本文內(nèi)容為6.5 鍵盤與數(shù)碼管接口。
    的頭像 發(fā)表于 11-14 05:16 ?8591次閱讀
    單片機編程技巧之重用<b class='flag-5'>外設(shè)</b><b class='flag-5'>驅(qū)動</b><b class='flag-5'>代碼</b>

    玩轉(zhuǎn)MicroSD讀寫模塊資料下載

    電子發(fā)燒友網(wǎng)為你提供玩轉(zhuǎn)MicroSD讀寫模塊資料下載的電子資料下載,更有其他相關(guān)的電路圖、源代碼、課件教程、中文資料、英文資料、參考設(shè)計、用戶指南、解決方案等資料,希望可以幫助到廣
    發(fā)表于 04-29 08:51 ?26次下載
    玩轉(zhuǎn)MicroSD<b class='flag-5'>卡</b><b class='flag-5'>讀寫</b><b class='flag-5'>模塊</b>資料下載

    6行代碼實現(xiàn)對TF讀寫功能

    前言shineblink core 開發(fā)板(簡稱Core)的庫函數(shù)支持TF讀寫功能,所以只需要調(diào)用兩三個API,即可實現(xiàn)TF的操作。PS:Core 僅用五、六行代碼即可實現(xiàn)Wifi
    發(fā)表于 12-05 19:06 ?10次下載
    6行<b class='flag-5'>代碼</b>實現(xiàn)對TF<b class='flag-5'>卡</b>的<b class='flag-5'>讀寫</b>功能

    Linux驅(qū)動開發(fā)-編寫RFID-RC522射頻刷卡模塊驅(qū)動

    當(dāng)前文章介紹如果在Linux系統(tǒng)下編寫MF-RC522模塊驅(qū)動,配合應(yīng)用層,完成IC卡號讀取,扇區(qū)讀寫,密碼驗證等等。當(dāng)前開發(fā)板采用友善之臂Tiny4412,芯片是三星的EXYNOS4
    的頭像 發(fā)表于 09-17 15:14 ?2880次閱讀
    Linux<b class='flag-5'>驅(qū)動</b>開發(fā)-<b class='flag-5'>編寫</b>RFID-RC522射頻刷卡<b class='flag-5'>模塊</b><b class='flag-5'>驅(qū)動</b>

    ZLG600A系列讀寫模塊入門指南

    電子發(fā)燒友網(wǎng)站提供《ZLG600A系列讀寫模塊入門指南.pdf》資料免費下載
    發(fā)表于 10-14 14:37 ?0次下載
    ZLG600A系列<b class='flag-5'>讀寫</b><b class='flag-5'>卡</b><b class='flag-5'>模塊</b>入門指南

    EtherCAT運動控制的硬件接線與C#的硬件外設(shè)讀寫與回零運動

    EtherCAT運動控制進行硬件接線與C#的硬件外設(shè)讀寫與回零運動
    的頭像 發(fā)表于 11-08 16:26 ?2269次閱讀
    EtherCAT運動控制<b class='flag-5'>卡</b>的硬件接線與C#的硬件<b class='flag-5'>外設(shè)</b><b class='flag-5'>讀寫</b>與回零運動

    stm32 CubeMx 實現(xiàn)SD/sd nand FATFS讀寫測試

    文章目錄stm32CubeMx實現(xiàn)SD/SDnandFATFS讀寫測試1.前言2.環(huán)境介紹2.1軟硬件說明2.2外設(shè)原理圖3.工程搭建3.1CubeMx配置3.2SDIO時鐘配置說明3.2
    的頭像 發(fā)表于 06-03 09:20 ?1768次閱讀
    stm32 CubeMx 實現(xiàn)SD<b class='flag-5'>卡</b>/sd nand FATFS<b class='flag-5'>讀寫</b>測試