本应用笔记解释了如何在DS5250安全微控制器上轻松实现磁条卡读取和解码。本文还演示了如何开发将磁条卡读取功能与安全微控制器的更高级别安全性和加密功能相结合的应用。本例使用DS5250评估(EV)板与磁条读卡器接口。提供源代码,可轻松移植到Maxim其他基于8051的微控制器。
概述
背面带有磁性编码条纹的卡通常称为磁条卡,用于大量银行、储值和其他金融应用。信用卡、ATM 卡和借记卡都是典型的磁条卡,有时还嵌入了智能卡芯片。其他例子是其他例子,例如用于游戏、复印机和公共交通的许多礼品卡、安全卡或房间钥匙卡以及储值卡。当使用标准ISO格式时,这些磁条卡的最大容量约为160字节,通常不会存储大量数据。与智能卡或便携式闪存驱动器相比,磁条卡的存储容量足以满足最常使用这些卡的金融和银行应用。此外,磁条卡坚固耐用,价格低廉,不需要内部电源,并且相对容易读取。
本应用笔记介绍如何使用DS5250安全微控制器与磁条读卡器接口。之所以选择DS5250,是因为它提供了构建读取磁条卡的通用器件(即销售点(POS)终端)所需的关键安全和加密功能。
磁条读卡器包含执行低级任务的电路:将磁条上的磁通量解码为比特流。DS5250管理更高层次的任务:将这些位转换为字符,然后读取和验证数据字段。
硬件和软件要求
硬件
本示例应用使用DS5250评估(EV)板(修订版B),修改如下:
示例应用程序还需要以下硬件:
读卡器—MagTek 三轨刷卡读卡器,带 3V 解码器 ASIC;部件号 21030001 修订版 G 或更高版本
两个上拉电阻(约10kΩ)
线性稳压器(能够从5V电源产生3V至3.6V电压)
用于测试的磁条卡(ATM卡,信用卡等)
以下各节介绍示例应用程序的实现。完整的示例C代码可从Analog的FTP站点下载。
连接读卡器
MagTek 读卡器有五个接口引脚(包括电源和接地):
引脚 1 - 频闪
该信号始终是读卡器的输入。它由主微控制器驱动,以输出卡数据位并置位复位序列。
引脚 2 - 数据
该信号通常用作读卡器的输出。它携带来自磁道 A/B/C 的卡数据位,这些磁道由 STROBE 信号计时输出。在某些情况下(例如,当置位复位序列时),该信号可由主微控制器驱动。
引脚 3 — VDD
为读卡器供电(2.7V 至 3.6V)。
引脚 4 - 接地
引脚 5 - 接地
由于STROBE和数据引脚工作在3V电平,DS5250不能用标准端口引脚直接驱动它们。因此,使用端口0的引脚(工作在漏极开路模式),当DS5250对引脚进行三电平时,电阻将信号电平拉至3.6V。DS5250直接从数据线读取数据信号,因为最小VIHDS5250端口引脚的电平足够低,可以兼容3V I/O电平。(请参考DS5250数据资料了解更多详细信息。
读卡器工作在 3V 电平;它不能直接由DS5250使用的5V电源供电。由于DS5250评估板不提供3V电源,因此使用单独的线性稳压器(如MAX1658)为读卡器供电。参见图1。
图1.例如应用程序的连接。
执行复位序列
首次上电后,主微控制器必须重置读卡器,然后才能接受刷卡。每次刷卡后也必须执行此重置序列,以清除内部读卡器ASIC的内存,并使读卡器准备好接受新的刷卡。
为了复位读卡器,主微控制器(即本应用中的DS5250)必须按以下顺序驱动频闪和数据。(有关确切的电压电平和时序参数,请参阅 MagTek 文档。
DATA 和 STROBE 都从高(空闲)状态开始。
强制数据降低。
在数据保持低电平的情况下,将频闪驱动为低电平,然后再次驱动为高电平。
再次将频闪驱动为低电平,然后释放数据,使其浮高。
在数据浮动高电平时,将频闪驱动为低电平,然后再次高电平。此时,读卡器被重置并处于低功耗等待状态。
将频闪驱动为低,然后再次高。此操作“武装”读卡器并准备接受刷卡。
// Generate a long delay for card reset and read intervals. void longDelay() { int i, j; for (i = 1; i < 5; i++) { for (j = 1; j < 5000; j++) { ; } } } // Generate a shorter delay (used between STROBE/DATA transitions). void delay() { int i; for (i = 1; i < 1000; i++) { ; } } // Release the DATA line (P0.0) and allow it to float high. void dataHigh() { P0 |= 0x01; delay(); } // Drive the DATA line (P0.0) low. void dataLow() { P0 &= 0xFE; delay(); } // Release the STROBE line (P0.1) and allow it to float high. void strobeHigh() { P0 |= 0x02; delay(); } // Drive the STROBE line (P0.1) low. void strobeLow() { P0 &= 0xFD; delay(); } void resetCardReader() { dataHigh(); strobeHigh(); longDelay(); dataLow(); // Force DATA low. longDelay(); strobeLow(); // Drive STROBE low, then high again. strobeHigh(); strobeLow(); // Drive STROBE low, then release DATA. dataHigh(); longDelay(); strobeHigh(); // Drive STROBE low and high again two more times strobeLow(); // to complete the reset and leave the card reader strobeHigh(); // in the ready state, prepared to scan a card. strobeLow(); }
检测刷卡
一旦读卡器重置并布防,它就可以接受刷卡了。MagTek 读卡器在刷卡时执行整个读卡周期;主微控制器无需干预。卡条上所有三个磁道(磁道 A、磁道 B 和磁道 C)的全部内容都存储在读卡器 IC 上。在读卡周期结束后,主微控制器可以一次一位地输出这些数据。
读卡器经历一个握手周期,以通知主设备何时开始读卡并完成。
循环从频闪低电平和数据高浮动(空闲状态)开始。
当读卡器检测到磁条在读卡器头上移动时,它开始扫描读卡。它将数据线驱动为低电平,以通知主站刷卡已经开始。
主站的响应是将STROBE驱动为高电平,然后再次降低。
读卡器将数据再次驱动高电平。
读卡周期完成后,读卡器再次将数据驱动为低电平。此操作告知主节点刷卡已完成,并且卡数据已准备好打卡。
// Wait for the DATA line to be driven low by the card reader. void waitForDataLow() { int i = 0xFF; dataHigh(); // Make sure that DATA is floating high. while ((i & 1) == 1) { i = P0; } } .... resetCardReader(); printf("\r\n"); printf("Waiting for card swipe...\r\n"); printf("\r\n"); waitForDataLow(); // DATA low indicates that card swipe has begun. strobeHigh(); longDelay(); strobeLow(); longDelay(); waitForDataLow(); // DATA low indicates that card swipe is complete.
读取和解码卡数据
刷卡完成并且所有卡数据由读卡器ASIC解码和存储后,读卡器将DATA线驱动为低电平。如上所述,此操作会提醒DS5250卡数据已准备好打卡。此时,DS5250可以按顺序检索卡数据中的每个位,方法是将STROBE驱动为高电平,然后驱动低电平,以便每个位输出。在STROBE被驱动为高电平然后被驱动为低电平之后,下一个位由读卡器ASIC在数据线上计时。ASIC 将数据驱动高电平 0 位,将数据驱动低电平 1 位。
// Clock a single bit value out of the card reader by driving STROBE high, // then low, and reading the DATA line. int readBit() { int i; strobeHigh(); // Drive STROBE high. strobeLow(); // Drive STROBE low (DATA line now contains bit). i = P0; if ((i & 1) == 0) { return 1; // Low on DATA line indicates a 1 bit. } else { return 0; // High on DATA line indicates a 0 bit. } }
从读卡器输出的前 16 位是一个“前导码”,指示读卡器 ASIC 的版本。应用程序可以丢弃这些位,因为它们不表示卡数据。
翻译轨道 A
在 16 位前导码之后,DATA 线路上时钟输出的下一个 704 位包含从磁条卡上的磁道 A 读取的数据。使用标准 ISO 格式编码时,磁道 A 最多包含 76 个字符,使用 7 位字符集,其中包括字母数字和各种其他符号。
每个 7 位字符首先输出最低有效位 (LSB)。最高位(即第七位)是奇偶校验位,可以选择用于验证卡数据的完整性。不考虑奇偶校验位,其余 6 位定义可在磁道 A 上编码的 64 个字符之一。例如,000000b 表示空格字符,000001b 表示感叹号。char7bit[64] 字符数组显示在下面的代码中。
// 0123456789012345678901234567890123456789012345678901234567890 123 char char7bit[64] = " !'#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"; // Clock out and decode a 7-bit character from the track memory, returning the // character value. 7-bit (alphanumeric) characters are found on Track A only. char read7BitChar() { int i, c; // Each character is composed of 7 bits, which we clock out of the track memory // beginning with the least significant bit. Bit 7 is parity, which is ignored. c = 0; for (i = 1; i < 128; i *= 2) { c |= (readBit() * i); } c &= 0x3F; return char7bit[c]; // Decode/return the character using the 7-bit table. } .... // Track A - 76 characters, 7 bits per alphanumberic character including parity. printf("Track A > "); for (i = 0; i < 76; i++) { putchar(read7BitChar()); } printf("\r\n\r\n"); // At this point, we have read 532 bits of the 704-bit Track A memory on the // card reader IC. Flush the remaining 172 bits. for (i = 0; i < 172; i++) { readBit(); }
轨道 A 上保存的实际数据因卡类型而异。此外,轨道 A 可以包含字母字符。因此,轨道A通常用于存储持卡人的姓名,可能的地址,帐号和其他数字信息。如上面的代码所示,在时钟输出磁道B数据之前,必须读出磁道A存储器的所有704位(即使并非所有位都包含编码数据)。
翻译轨道 B
磁道 B 的编码与磁道 A 类似,不同之处在于这些字符是 5 位(4 位,加 1 位奇偶校验位)编码,而不是 7 位。轨道 B 字符集仅包含数字字符和符号,如下面的 char5bit[16] 字符数组所示。
// 0123456789012345 char char5bit[16] = "0123456789:;<=>?"; // Clock out and decode a 5-bit character from the track memory, returning the // character value. 5-bit (numeric+symbol) characters are found on Tracks B and C. char read5BitChar() { int i, c; // Each character is composed of 5 bits, which we clock out of the track memory // beginning with the least significant bit. Bit 5 is parity, which is ignored. c = 0; for (i = 1; i < 32; i *= 2) { c |= (readBit() * i); } c &= 0x0F; return char5bit[c]; // Decode/return the character using the 5-bit table. } .... // Track B - 40 characters, 5 bits per numeric/symbol character including parity. printf("Track B > "); for (i = 0; i < 40; i++) { putchar(read5BitChar()); } printf("\r\n\r\n");
与磁道 A 结束时一样,在继续读取磁道 C 之前,必须读取磁道 B 存储器中的所有剩余位(如果需要磁道 C)。由于代码已经从磁道 B 存储器读取了 200 位(40 个字符 x 5 位),因此在访问磁道 C 数据之前,必须额外输出 504 位。
翻译轨道 C
磁道 C 以与磁道 B 相同的方式编码,并使用与磁道 B 相同的字符集,最多 107 个 编码的 7 位字符。轨道C最初旨在包含一个可重写的数据区域以支持离线金融交易,但它并不常用。大多数磁条卡不包含磁道C上的编码数据。
结论
磁条卡用于各种金融、访问控制、政府和储值应用。通过在DS5250评估板中增加一个简单的MagTek刷卡读卡器和少量支持硬件,可以开发将磁条卡读取功能与安全微控制器的更高级别的安全性和加密功能相结合的应用。使用Keil的μVision C编译器,可以在DS5250安全微控制器上轻松实现磁条卡读取和解码演示的应用。
审核编辑:郭婷
// Generate a long delay for card reset and read intervals. void longDelay() { int i, j; for (i = 1; i < 5; i++) { for (j = 1; j < 5000; j++) { ; } } } // Generate a shorter delay (used between STROBE/DATA transitions). void delay() { int i; for (i = 1; i < 1000; i++) { ; } } // Release the DATA line (P0.0) and allow it to float high. void dataHigh() { P0 |= 0x01; delay(); } // Drive the DATA line (P0.0) low. void dataLow() { P0 &= 0xFE; delay(); } // Release the STROBE line (P0.1) and allow it to float high. void strobeHigh() { P0 |= 0x02; delay(); } // Drive the STROBE line (P0.1) low. void strobeLow() { P0 &= 0xFD; delay(); } void resetCardReader() { dataHigh(); strobeHigh(); longDelay(); dataLow(); // Force DATA low. longDelay(); strobeLow(); // Drive STROBE low, then high again. strobeHigh(); strobeLow(); // Drive STROBE low, then release DATA. dataHigh(); longDelay(); strobeHigh(); // Drive STROBE low and high again two more times strobeLow(); // to complete the reset and leave the card reader strobeHigh(); // in the ready state, prepared to scan a card. strobeLow(); }
检测刷卡
一旦读卡器重置并布防,它就可以接受刷卡了。MagTek 读卡器在刷卡时执行整个读卡周期;主微控制器无需干预。卡条上所有三个磁道(磁道 A、磁道 B 和磁道 C)的全部内容都存储在读卡器 IC 上。在读卡周期结束后,主微控制器可以一次一位地输出这些数据。
读卡器经历一个握手周期,以通知主设备何时开始读卡并完成。
- 循环从频闪低电平和数据高浮动(空闲状态)开始。
- 当读卡器检测到磁条在读卡器头上移动时,它开始扫描读卡。它将数据线驱动为低电平,以通知主站刷卡已经开始。
- 主站的响应是将STROBE驱动为高电平,然后再次降低。
- 读卡器将数据再次驱动高电平。
- 读卡周期完成后,读卡器再次将数据驱动为低电平。此操作告知主节点刷卡已完成,并且卡数据已准备好打卡。
// Wait for the DATA line to be driven low by the card reader. void waitForDataLow() { int i = 0xFF; dataHigh(); // Make sure that DATA is floating high. while ((i & 1) == 1) { i = P0; } } .... resetCardReader(); printf("\r\n"); printf("Waiting for card swipe...\r\n"); printf("\r\n"); waitForDataLow(); // DATA low indicates that card swipe has begun. strobeHigh(); longDelay(); strobeLow(); longDelay(); waitForDataLow(); // DATA low indicates that card swipe is complete.
读取和解码卡数据
刷卡完成并且所有卡数据由读卡器ASIC解码和存储后,读卡器将DATA线驱动为低电平。如上所述,此操作会提醒DS5250卡数据已准备好打卡。此时,DS5250可以按顺序检索卡数据中的每个位,方法是将STROBE驱动为高电平,然后驱动低电平,以便每个位输出。在STROBE被驱动为高电平然后被驱动为低电平之后,下一个位由读卡器ASIC在数据线上计时。ASIC 将数据驱动高电平 0 位,将数据驱动低电平 1 位。
// Clock a single bit value out of the card reader by driving STROBE high, // then low, and reading the DATA line. int readBit() { int i; strobeHigh(); // Drive STROBE high. strobeLow(); // Drive STROBE low (DATA line now contains bit). i = P0; if ((i & 1) == 0) { return 1; // Low on DATA line indicates a 1 bit. } else { return 0; // High on DATA line indicates a 0 bit. } }
从读卡器输出的前 16 位是一个“前导码”,指示读卡器 ASIC 的版本。应用程序可以丢弃这些位,因为它们不表示卡数据。
翻译轨道 A
在 16 位前导码之后,DATA 线路上时钟输出的下一个 704 位包含从磁条卡上的磁道 A 读取的数据。使用标准 ISO 格式编码时,磁道 A 最多包含 76 个字符,使用 7 位字符集,其中包括字母数字和各种其他符号。
每个 7 位字符首先输出最低有效位 (LSB)。最高位(即第七位)是奇偶校验位,可以选择用于验证卡数据的完整性。不考虑奇偶校验位,其余 6 位定义可在磁道 A 上编码的 64 个字符之一。例如,000000b 表示空格字符,000001b 表示感叹号。char7bit[64]字符数组显示在下面的代码中。
// 0123456789012345678901234567890123456789012345678901234567890 123 char char7bit[64] = " !'#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"; // Clock out and decode a 7-bit character from the track memory, returning the // character value. 7-bit (alphanumeric) characters are found on Track A only. char read7BitChar() { int i, c; // Each character is composed of 7 bits, which we clock out of the track memory // beginning with the least significant bit. Bit 7 is parity, which is ignored. c = 0; for (i = 1; i < 128; i *= 2) { c |= (readBit() * i); } c &= 0x3F; return char7bit[c]; // Decode/return the character using the 7-bit table. } .... // Track A - 76 characters, 7 bits per alphanumberic character including parity. printf("Track A > "); for (i = 0; i < 76; i++) { putchar(read7BitChar()); } printf("\r\n\r\n"); // At this point, we have read 532 bits of the 704-bit Track A memory on the // card reader IC. Flush the remaining 172 bits. for (i = 0; i < 172; i++) { readBit(); }
轨道 A 上保存的实际数据因卡类型而异。此外,轨道 A 可以包含字母字符。因此,轨道A通常用于存储持卡人的姓名,可能的地址,帐号和其他数字信息。如上面的代码所示,在时钟输出磁道B数据之前,必须读出磁道A存储器的所有704位(即使并非所有位都包含编码数据)。
翻译轨道 B
磁道 B 的编码与磁道 A 类似,不同之处在于这些字符是 5 位(4 位,加 1 位奇偶校验位)编码,而不是 7 位。轨道 B 字符集仅包含数字字符和符号,如下面的char5bit[16]字符数组所示。
// 0123456789012345 char char5bit[16] = "0123456789:;<=>?"; // Clock out and decode a 5-bit character from the track memory, returning the // character value. 5-bit (numeric+symbol) characters are found on Tracks B and C. char read5BitChar() { int i, c; // Each character is composed of 5 bits, which we clock out of the track memory // beginning with the least significant bit. Bit 5 is parity, which is ignored. c = 0; for (i = 1; i < 32; i *= 2) { c |= (readBit() * i); } c &= 0x0F; return char5bit[c]; // Decode/return the character using the 5-bit table. } .... // Track B - 40 characters, 5 bits per numeric/symbol character including parity. printf("Track B > "); for (i = 0; i < 40; i++) { putchar(read5BitChar()); } printf("\r\n\r\n");
与磁道 A 结束时一样,在继续读取磁道 C 之前,必须读取磁道 B 存储器中的所有剩余位(如果需要磁道 C)。由于代码已经从磁道 B 存储器读取了 200 位(40 个字符 x 5 位),因此在访问磁道 C 数据之前,必须额外输出 504 位。
翻译轨道 C
磁道 C 以与磁道 B 相同的方式编码,并使用与磁道 B 相同的字符集,最多 107 个 编码的 7 位字符。轨道C最初旨在包含一个可重写的数据区域以支持离线金融交易,但它并不常用。大多数磁条卡不包含磁道C上的编码数据。
结论
磁条卡用于各种金融、访问控制、政府和储值应用。通过在DS5250评估板中增加一个简单的MagTek刷卡读卡器和少量支持硬件,可以开发将磁条卡读取功能与安全微控制器的更高级别的安全性和加密功能相结合的应用。使用Keil的μVision C编译器,可以在DS5250安全微控制器上轻松实现磁条卡读取和解码演示的应用。
-
微控制器
+关注
关注
48文章
7482浏览量
151010 -
解码器
+关注
关注
9文章
1129浏览量
40670 -
读卡器
+关注
关注
2文章
409浏览量
39341
发布评论请先 登录
相关推荐
评论