news 2026/4/21 3:40:28

纯技术干货:多卡种兼容读卡器(DAIC-MJ-RW)通用性说明及对接数据格式+二次开发数据协议SDK。通用性:多奥门禁控制器/考勤机/智能通道门禁控制器/消费机/在线巡更读头/梯控主板/电子班牌/等

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
纯技术干货:多卡种兼容读卡器(DAIC-MJ-RW)通用性说明及对接数据格式+二次开发数据协议SDK。通用性:多奥门禁控制器/考勤机/智能通道门禁控制器/消费机/在线巡更读头/梯控主板/电子班牌/等

分析这个多卡种兼容读卡器(DAIC-MJ-RW)的技术协议,并提供一个完整的SDK实现参考。

一、数据协议解析

1.1 帧结构详解

字段长度说明
Header1字节固定0x02
Length1字节数据总长度(含Length字段到Checksum字段)
Card Type1字节见下方卡片类型表
Card Data4-8字节卡号序列号(大端模式)
XOR Checksum1字节Length→Checksum所有字节的异或校验
Footer1字节固定0x03

1.2 卡片类型对照表

#define CARD_TYPE_IC_MIFARE 0x10 // IC卡 (Mifare Classic) #define CARD_TYPE_EM4100 0x01 // EM4100 ID卡 #define CARD_TYPE_B_CARD 0x21 // B卡 #define CARD_TYPE_CID 0x20 // CID卡 #define CARD_TYPE_FELICA_ICLASS 0x32 // Felica / iCLASS #define CARD_TYPE_ISO15693 0x31 // ISO15693标签 #define CARD_TYPE_HID_PROX 0x03 // HID Prox卡 #define CARD_TYPE_ISO14443A 0x25 // ISO14443A CPU卡

1.3 帧长度规范

卡类型Length值Card Data长度示例总帧
IC卡/ID卡0x094字节02 09 10 A1B2C3D4 XX 03
Felica/iCLASS0x0D8字节02 0D 32 A1B2C3D4E5F60718 XX 03

二、XOR校验算法

计算公式:

Checksum = Length ⊕ CardType ⊕ Data[0] ⊕ Data[1] ⊕ ... ⊕ Data[n]

C语言实现:

uint8_t calc_xor_checksum(const uint8_t *data, uint8_t len) { uint8_t checksum = 0; for (uint8_t i = 0; i < len; i++) { checksum ^= data[i]; } return checksum; } // 验证完整帧 bool verify_frame(const uint8_t *frame, uint8_t frame_len) { if (frame[0] != 0x02 || frame[frame_len-1] != 0x03) return false; uint8_t data_len = frame_len - 3; // 去掉头尾和校验字节本身 uint8_t calc_sum = calc_xor_checksum(frame + 1, data_len); return calc_sum == frame[frame_len - 2]; }

三、完整SDK实现(C语言)

3.1 头文件定义daic_mj_rw.h

#ifndef DAIC_MJ_RW_H #define DAIC_MJ_RW_H #include <stdint.h> #include <stdbool.h> #ifdef __cplusplus extern "C" { #endif /* ========== 卡类型定义 ========== */ typedef enum { CARD_EM4100 = 0x01, // EM4100 (125KHz) CARD_HID_PROX = 0x03, // HID Prox CARD_IC_MIFARE = 0x10, // Mifare Classic CARD_CID = 0x20, // CID CARD_B_CARD = 0x21, // B卡 CARD_CPU_14443A = 0x25, // ISO14443A CPU卡 CARD_ISO15693 = 0x31, // ISO15693 CARD_FELICA_ICLASS = 0x32, // Felica / iCLASS } CardType_t; /* ========== 卡数据结构 ========== */ typedef struct { CardType_t type; // 卡片类型 uint8_t sn[8]; // 序列号(最大8字节) uint8_t sn_len; // 实际序列号长度 uint64_t card_id; // 转换为数值(便于存储) uint32_t timestamp; // 读取时间戳 } CardInfo_t; /* ========== 回调函数类型 ========== */ typedef void (*OnCardReadCallback)(const CardInfo_t *card); /* ========== API接口 ========== */ // 初始化读卡器接口 (UART参数: 9600bps, 8N1) int daic_reader_init(const char *uart_port); // 关闭读卡器 void daic_reader_deinit(void); // 注册卡片读取回调 void daic_register_callback(OnCardReadCallback cb); // 手动轮询解析(非中断模式使用) void daic_parse_byte(uint8_t byte); // 发送蜂鸣器/LED控制指令(扩展功能) int daic_send_control(uint8_t beep_ms, uint8_t led_color); #ifdef __cplusplus } #endif #endif /* DAIC_MJ_RW_H */

3.2 核心实现daic_mj_rw.c

#include "daic_mj_rw.h" #include <string.h> #include <stdio.h> /* ========== 帧解析状态机 ========== */ typedef enum { STATE_IDLE, // 等待帧头 STATE_LENGTH, // 读取长度 STATE_TYPE, // 读取类型 STATE_DATA, // 读取数据 STATE_CHECK, // 读取校验 STATE_FOOTER // 等待帧尾 } ParseState_t; static struct { ParseState_t state; uint8_t buffer[32]; // 帧缓冲 uint8_t idx; // 当前索引 uint8_t data_len; // 期望数据长度 uint8_t rec_len; // 接收到的长度 } parser = {0}; static OnCardReadCallback g_callback = NULL; /* ========== 卡号数值转换 ========== */ static uint64_t bytes_to_uint64(const uint8_t *data, uint8_t len) { uint64_t val = 0; for (uint8_t i = 0; i < len; i++) { val = (val << 8) | data[i]; } return val; } /* ========== 获取卡类型名称 ========== */ const char* card_type_name(CardType_t type) { switch(type) { case CARD_EM4100: return "EM4100"; case CARD_HID_PROX: return "HID Prox"; case CARD_IC_MIFARE: return "IC Mifare"; case CARD_CID: return "CID"; case CARD_B_CARD: return "B Card"; case CARD_CPU_14443A: return "ISO14443A CPU"; case CARD_ISO15693: return "ISO15693"; case CARD_FELICA_ICLASS: return "Felica/iCLASS"; default: return "Unknown"; } } /* ========== 获取数据长度 ========== */ static uint8_t get_card_data_len(uint8_t frame_len) { // Length字段值 = 1(Length) + 1(Type) + N(Data) + 1(Checksum) // 所以 Data长度 = Length - 3 return frame_len - 3; } /* ========== 验证XOR校验 ========== */ static bool verify_xor(const uint8_t *frame, uint8_t frame_len) { uint8_t checksum = 0; // 计算从Length到Data末尾的异或 for (uint8_t i = 1; i < frame_len - 2; i++) { checksum ^= frame[i]; } return checksum == frame[frame_len - 2]; } /* ========== 处理完整帧 ========== */ static void process_frame(const uint8_t *frame, uint8_t len) { // 基础验证 if (frame[0] != 0x02 || frame[len-1] != 0x03) return; if (!verify_xor(frame, len)) { printf("[DAIC] XOR校验失败\n"); return; } CardInfo_t card = {0}; card.type = frame[2]; // Card Type字段 uint8_t data_len = get_card_data_len(frame[1]); card.sn_len = data_len; // 复制序列号 memcpy(card.sn, &frame[3], data_len); // 转换为数值ID card.card_id = bytes_to_uint64(card.sn, card.sn_len); // 回调通知 if (g_callback) { g_callback(&card); } else { // 默认输出 printf("[DAIC] 检测到 %s, ID: 0x%llX\n", card_type_name(card.type), card.card_id); } } /* ========== 字节流解析(状态机) ========== */ void daic_parse_byte(uint8_t byte) { switch (parser.state) { case STATE_IDLE: if (byte == 0x02) { parser.buffer[0] = byte; parser.idx = 1; parser.state = STATE_LENGTH; } break; case STATE_LENGTH: parser.buffer[parser.idx++] = byte; parser.data_len = byte; // Length字段值 parser.rec_len = byte + 2; // 总长度 = Length + Header + Footer parser.state = STATE_TYPE; break; case STATE_TYPE: parser.buffer[parser.idx++] = byte; parser.state = STATE_DATA; break; case STATE_DATA: parser.buffer[parser.idx++] = byte; // 检查是否收完数据部分(还需要2字节:Checksum + Footer) if (parser.idx >= parser.rec_len - 1) { parser.state = STATE_CHECK; } break; case STATE_CHECK: parser.buffer[parser.idx++] = byte; parser.state = STATE_FOOTER; break; case STATE_FOOTER: if (byte == 0x03) { parser.buffer[parser.idx++] = byte; process_frame(parser.buffer, parser.idx); } // 重置状态机 parser.state = STATE_IDLE; parser.idx = 0; break; } // 超时保护/长度溢出保护 if (parser.idx >= sizeof(parser.buffer)) { parser.state = STATE_IDLE; parser.idx = 0; } } /* ========== 回调注册 ========== */ void daic_register_callback(OnCardReadCallback cb) { g_callback = cb; }

3.3 示例测试代码

C

#include "daic_mj_rw.h" void on_card_read(const CardInfo_t *card) { printf("================================\n"); printf("卡类型: %s (0x%02X)\n", card_type_name(card->type), card->type); printf("序列号长度: %d 字节\n", card->sn_len); printf("序列号(Hex): "); for (int i = 0; i < card->sn_len; i++) { printf("%02X ", card->sn[i]); } printf("\n卡号数值: %llu\n", card->card_id); printf("================================\n\n"); } int main() { // 注册回调 daic_register_callback(on_card_read); // 模拟接收数据:IC卡 卡号A1B2C3D4 uint8_t ic_card_frame[] = {0x02, 0x09, 0x10, 0xA1, 0xB2, 0xC3, 0xD4, 0xE5, 0x03}; // 计算校验:09^10^A1^B2^C3^D4 = E5 printf("模拟IC卡读取:\n"); for (int i = 0; i < sizeof(ic_card_frame); i++) { daic_parse_byte(ic_card_frame[i]); } // 模拟Felica卡 8字节卡号 uint8_t felica_frame[] = {0x02, 0x0D, 0x32, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0xXX, 0x03}; // 需要重新计算校验值 return 0; }


四、多设备集成方案

4.1 系统架构图

┌─────────────────────────────────────────────────────────┐ │ 统一管理平台 │ │ (门禁/考勤/消费/梯控/巡更) │ └─────────────────────────────────────────────────────────┘ │ ┌───────────────┼───────────────┐ ▼ ▼ ▼ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ 门禁控制器 │ │ 梯控主板 │ │ 消费机 │ │DAIC-MJ-RW │ │DAIC-MJ-RW │ │DAIC-MJ-RW │ └────────────┘ └────────────┘ └────────────┘ │ │ │ └───────────────┴───────────────┘ │ ┌────────────┐ │ 读卡器总线 │ │(RS485/CAN) │ └────────────┘

4.2 多语言SDK封装

Python版本(适用于树莓派/Linux上位机):

import serial import struct from dataclasses import dataclass from enum import IntEnum from typing import Callable, Optional class CardType(IntEnum): EM4100 = 0x01 HID_PROX = 0x03 IC_MIFARE = 0x10 CID = 0x20 B_CARD = 0x21 CPU_14443A = 0x25 ISO15693 = 0x31 FELICA_ICLASS = 0x32 @dataclass class CardInfo: card_type: CardType serial_number: bytes card_id: int def __repr__(self): hex_sn = self.serial_number.hex().upper() return f"CardInfo(type={self.card_type.name}, ID={hex_sn})" class DAICReader: HEADER = 0x02 FOOTER = 0x03 def __init__(self, port: str = '/dev/ttyUSB0', baudrate: int = 9600): self.ser = serial.Serial(port, baudrate, timeout=0.1) self.callback: Optional[Callable[[CardInfo], None]] = None self._buffer = bytearray() def set_callback(self, cb: Callable[[CardInfo], None]): self.callback = cb @staticmethod def calc_xor(data: bytes) -> int: checksum = 0 for b in data: checksum ^= b return checksum def parse_frame(self, frame: bytes) -> Optional[CardInfo]: if len(frame) < 6 or frame[0] != self.HEADER or frame[-1] != self.FOOTER: return None length = frame[1] data_section = frame[1:-2] # Length到Data末尾 received_checksum = frame[-2] if self.calc_xor(data_section) != received_checksum: return None card_type = CardType(frame[2]) data_len = length - 3 # Length - Type - Checksum字段 sn = frame[3:3+data_len] card_id = int.from_bytes(sn, 'big') return CardInfo(card_type, sn, card_id) def run(self): while True: if self.ser.in_waiting: data = self.ser.read(self.ser.in_waiting) self._buffer.extend(data) # 查找帧头帧尾 while len(self._buffer) >= 6: try: start = self._buffer.index(self.HEADER) end = self._buffer.index(self.FOOTER, start) frame = self._buffer[start:end+1] card = self.parse_frame(frame) if card and self.callback: self.callback(card) self._buffer = self._buffer[end+1:] except ValueError: break # 使用示例 if __name__ == "__main__": reader = DAICReader('/dev/ttyUSB0') def on_card(card: CardInfo): print(f"刷卡事件: {card}") # 业务逻辑:开门、扣费、考勤记录等 reader.set_callback(on_card) reader.run()

多卡种兼容读卡器支持多奥设备及一卡通系统,采用UART通信,支持IC/FeliCa卡,具备标准数据帧结构与XOR校验


五、常见问题排查

flowchart TD
A[用户刷卡] --> B[DAIC-MJ-RW读卡器]

B --> C{选择输出接口}

C -- 模式1: 即插即用 --> D[“韦根接口<br>(Wiegand 26/34)”]
C -- 模式2: 深度定制 --> E[“UART串口<br>(TTL电平)”]

D --> F[“标准门禁/梯控控制器<br>(如多奥DAIC-MJ-MB等)”]
D --> G[“第三方门禁/安防系统<br>(支持韦根输入)”]

E --> H[“微控制器<br>(如STM32, Arduino)”]
E --> I[“单板计算机<br>(如树莓派)”]
E --> J[“工业PLC/机器人控制器”]
E --> K[“自定义应用软件<br>(通过USB转串口)”]

F & G --> L[执行动作:开门/呼梯/通行]
H & I & J & K --> M[“获取原始数据包<br>(卡型 + 卡号)<br>进行自定义逻辑处理”]

现象可能原因解决方案
收不到数据UART参数错误检查波特率是否为9600,停止位1,无校验
校验失败干扰/线缆过长缩短RS232线缆,或改用RS485差分传输
卡号解析错误大小端问题确认序列号按大端模式(高位在前)解析
特定卡型不识别未支持该卡型记录Type值,添加到卡型表中
漏卡/重复读状态机未重置添加超时机制,超时后强制重置状态机
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/17 23:19:35

屹晶微 EG44273 低压高速低侧单通道驱动芯片技术解析

在现代高频、高密度电源与电机控制系统中&#xff0c;一个兼具高速响应、强劲驱动能力与极致紧凑体积的低侧栅极驱动器&#xff0c;往往是实现高效、可靠功率转换的关键。EG44273 正是为此类需求而精心打造的解决方案。它采用超小型的 SOT23-5封装&#xff0c;在4V-20V的宽电压…

作者头像 李华
网站建设 2026/4/12 15:33:00

屹晶微 EG27519 高速低侧单通道驱动芯片(带EN使能)技术解析

在复杂且对可靠性要求极高的功率系统中&#xff0c;除了强劲的驱动性能与高速响应外&#xff0c;一个独立且可靠的全局控制接口同样至关重要。EG27519 在继承EG27517系列 4A对称峰值电流与纳秒级开关速度的卓越基因基础上&#xff0c;新增了低电平有效的独立EN&#xff08;使能…

作者头像 李华
网站建设 2026/4/18 1:30:10

屹晶微 EG1416 低压高速低侧单通道驱动芯片技术解析

在追求高功率密度与高效能的现代电源与电机控制系统中&#xff0c;一个基础而可靠的驱动单元往往是构建复杂功率架构的基石。EG1416 作为一款经典的低侧单通道栅极驱动芯片&#xff0c;以其简洁的设计、均衡的性能和出色的功耗控制&#xff0c;在4V-20V的宽电压范围内提供了2A的…

作者头像 李华
网站建设 2026/4/18 19:29:52

云渲染会影响最终效果吗?一次把常见误解说清楚

很多人第一次接触云渲染&#xff0c;最担心的不是速度&#xff0c;而是一句话&#xff1a; “云渲染出来的效果&#xff0c;会不会和我本地不一样&#xff1f;”结论先放这&#xff1a; 正规云渲染&#xff0c;本质就是读取你本地的渲染参数&#xff0c;算力换了&#xff0c;结…

作者头像 李华
网站建设 2026/4/18 21:00:40

Product Hunt 每日热榜 | 2026-02-04

1. Atoms 标语&#xff1a;把你的创意变成热销的产品&#xff01; 介绍&#xff1a;Atoms是一个充满活力的团队&#xff0c;专注于将你的创意转化为商业机会。我们会研究市场&#xff0c;设计产品&#xff0c;构建前端和后端&#xff0c;连接认证和支付系统&#xff0c;最后交…

作者头像 李华