#include "bsp_rc522.h" #include // 站点UID白名单(可扩展) static const uint8_t g_station_1_uid[] = STATION_1_UID; static const uint8_t g_station_2_uid[] = STATION_2_UID; station_id_t rc522_match_station(const uint8_t *uid, uint8_t uid_len) { if (uid == NULL || uid_len == 0) return STATION_NONE; // 匹配站点1 if (uid_len == sizeof(g_station_1_uid) && memcmp(uid, g_station_1_uid, uid_len) == 0) { return STATION_1; } // 匹配站点2 if (uid_len == sizeof(g_station_2_uid) && memcmp(uid, g_station_2_uid, uid_len) == 0) { return STATION_2; } // 可继续添加更多站点匹配 return STATION_NONE; } #include "bsp_rc522.h" #include "spi.h" #include #include /* ========================= RC522 寄存器定义 ========================= */ #define RC522_REG_COMMAND 0x01U #define RC522_REG_COM_I_EN 0x02U #define RC522_REG_DIV_I_EN 0x03U #define RC522_REG_COM_IRQ 0x04U #define RC522_REG_DIV_IRQ 0x05U #define RC522_REG_ERROR 0x06U #define RC522_REG_STATUS2 0x08U #define RC522_REG_FIFO_DATA 0x09U #define RC522_REG_FIFO_LEVEL 0x0AU #define RC522_REG_CONTROL 0x0CU #define RC522_REG_BIT_FRAMING 0x0DU #define RC522_REG_COLL 0x0EU #define RC522_REG_MODE 0x11U #define RC522_REG_TX_MODE 0x12U #define RC522_REG_RX_MODE 0x13U #define RC522_REG_TX_CONTROL 0x14U #define RC522_REG_TX_ASK 0x15U #define RC522_REG_CRC_RESULT_H 0x21U #define RC522_REG_CRC_RESULT_L 0x22U #define RC522_REG_T_MODE 0x2AU #define RC522_REG_T_PRESCALER 0x2BU #define RC522_REG_T_RELOAD_H 0x2CU #define RC522_REG_T_RELOAD_L 0x2DU /* ========================= RC522 命令定义 ========================= */ #define RC522_CMD_IDLE 0x00U #define RC522_CMD_CALC_CRC 0x03U #define RC522_CMD_TRANSCEIVE 0x0CU #define RC522_CMD_SOFT_RESET 0x0FU /* ========================= PICC 命令定义 ========================= */ #define PICC_CMD_REQA 0x26U #define PICC_CMD_SEL_CL1 0x93U #define PICC_CMD_SEL_CL2 0x95U #define PICC_CMD_SEL_CL3 0x97U #define PICC_CMD_HLTA 0x50U #define PICC_CMD_CT 0x88U #define RC522_SPI_TIMEOUT_MS 20U static rc522_card_info_t g_last_card; static uint32_t g_run_led_hold_until_ms = 0U; static uint32_t g_last_new_event_tick_ms = 0U; static volatile uint8_t g_irq_pending = 1U; #if (RC522_RUN_LED_ON_LEVEL == GPIO_PIN_SET) #define RC522_RUN_LED_OFF_LEVEL GPIO_PIN_RESET #else #define RC522_RUN_LED_OFF_LEVEL GPIO_PIN_SET #endif static void rc522_set_run_led(uint8_t on) { #if (RC522_RUN_LED_ENABLE == 1U) HAL_GPIO_WritePin(RUN_LED_GPIO_Port, RUN_LED_Pin, (on != 0U) ? RC522_RUN_LED_ON_LEVEL : RC522_RUN_LED_OFF_LEVEL); #else (void)on; #endif } static void rc522_update_run_led_state(void) { #if (RC522_RUN_LED_ENABLE == 1U) uint32_t now = HAL_GetTick(); if ((int32_t)(g_run_led_hold_until_ms - now) > 0) { rc522_set_run_led(1U); } else { rc522_set_run_led(0U); } #endif } static uint8_t rc522_uid_equal(const rc522_card_info_t *a, const rc522_card_info_t *b) { if (a == NULL || b == NULL) { return 0U; } if (a->uid_len != b->uid_len) { return 0U; } if (a->uid_len == 0U || a->uid_len > RC522_UID_MAX_LEN) { return 0U; } if (memcmp(a->uid, b->uid, a->uid_len) != 0) { return 0U; } return 1U; } static uint8_t rc522_cache_is_fresh(void) { if (g_last_card.valid == 0U) { return 0U; } if ((HAL_GetTick() - g_last_card.last_seen_tick_ms) > RC522_CACHE_EXPIRE_MS) { return 0U; } return 1U; } /* ------------------------- 底层 SPI 辅助 ------------------------- */ static void rc522_cs_low(void) { HAL_GPIO_WritePin(SDA_GPIO_Port, SDA_Pin, GPIO_PIN_RESET); } static void rc522_cs_high(void) { HAL_GPIO_WritePin(SDA_GPIO_Port, SDA_Pin, GPIO_PIN_SET); } static rc522_status_t rc522_write_reg(uint8_t reg, uint8_t value) { uint8_t tx[2]; tx[0] = (uint8_t)((reg << 1U) & 0x7EU); tx[1] = value; rc522_cs_low(); if (HAL_SPI_Transmit(&hspi1, tx, 2U, RC522_SPI_TIMEOUT_MS) != HAL_OK) { rc522_cs_high(); return RC522_ERR_SPI; } rc522_cs_high(); return RC522_OK; } static rc522_status_t rc522_read_reg(uint8_t reg, uint8_t *value) { uint8_t tx[2]; uint8_t rx[2] = {0}; if (value == NULL) { return RC522_ERR_PARAM; } tx[0] = (uint8_t)(((reg << 1U) & 0x7EU) | 0x80U); tx[1] = 0x00U; rc522_cs_low(); if (HAL_SPI_TransmitReceive(&hspi1, tx, rx, 2U, RC522_SPI_TIMEOUT_MS) != HAL_OK) { rc522_cs_high(); return RC522_ERR_SPI; } rc522_cs_high(); *value = rx[1]; return RC522_OK; } static rc522_status_t rc522_set_bitmask(uint8_t reg, uint8_t mask) { uint8_t val = 0; rc522_status_t st = rc522_read_reg(reg, &val); if (st != RC522_OK) { return st; } return rc522_write_reg(reg, (uint8_t)(val | mask)); } static rc522_status_t rc522_clear_bitmask(uint8_t reg, uint8_t mask) { uint8_t val = 0; rc522_status_t st = rc522_read_reg(reg, &val); if (st != RC522_OK) { return st; } return rc522_write_reg(reg, (uint8_t)(val & (uint8_t)(~mask))); } static rc522_status_t rc522_antenna_on(void) { return rc522_set_bitmask(RC522_REG_TX_CONTROL, 0x03U); } /* ------------------------- 核心通信流程 ------------------------- */ static rc522_status_t rc522_calculate_crc(const uint8_t *data, uint8_t len, uint8_t *crc_out) { uint8_t irq = 0; uint32_t start = HAL_GetTick(); if (data == NULL || crc_out == NULL) { return RC522_ERR_PARAM; } rc522_write_reg(RC522_REG_COMMAND, RC522_CMD_IDLE); rc522_write_reg(RC522_REG_DIV_IRQ, 0x04U); rc522_write_reg(RC522_REG_FIFO_LEVEL, 0x80U); for (uint8_t i = 0; i < len; i++) { rc522_write_reg(RC522_REG_FIFO_DATA, data[i]); } rc522_write_reg(RC522_REG_COMMAND, RC522_CMD_CALC_CRC); do { rc522_read_reg(RC522_REG_DIV_IRQ, &irq); if ((HAL_GetTick() - start) > 20U) { return RC522_ERR_TIMEOUT; } } while ((irq & 0x04U) == 0U); rc522_read_reg(RC522_REG_CRC_RESULT_L, &crc_out[0]); rc522_read_reg(RC522_REG_CRC_RESULT_H, &crc_out[1]); return RC522_OK; } static rc522_status_t rc522_transceive(const uint8_t *send_data, uint8_t send_len, uint8_t *back_data, uint8_t *back_len, uint8_t valid_bits) { uint8_t irq_en = 0x77U; uint8_t wait_irq = 0x30U; uint8_t irq = 0; uint8_t error = 0; uint8_t fifo_level = 0; uint8_t control = 0; uint32_t start = HAL_GetTick(); if (send_data == NULL || send_len == 0U || back_len == NULL) { return RC522_ERR_PARAM; } rc522_write_reg(RC522_REG_COMMAND, RC522_CMD_IDLE); rc522_write_reg(RC522_REG_COM_I_EN, (uint8_t)(irq_en | 0x80U)); rc522_write_reg(RC522_REG_COM_IRQ, 0x7FU); rc522_write_reg(RC522_REG_FIFO_LEVEL, 0x80U); for (uint8_t i = 0; i < send_len; i++) { rc522_write_reg(RC522_REG_FIFO_DATA, send_data[i]); } rc522_write_reg(RC522_REG_BIT_FRAMING, valid_bits); rc522_write_reg(RC522_REG_COMMAND, RC522_CMD_TRANSCEIVE); rc522_set_bitmask(RC522_REG_BIT_FRAMING, 0x80U); do { rc522_read_reg(RC522_REG_COM_IRQ, &irq); if ((HAL_GetTick() - start) > 30U) { rc522_clear_bitmask(RC522_REG_BIT_FRAMING, 0x80U); return RC522_ERR_TIMEOUT; } } while ((irq & wait_irq) == 0U && (irq & 0x01U) == 0U); rc522_clear_bitmask(RC522_REG_BIT_FRAMING, 0x80U); rc522_read_reg(RC522_REG_ERROR, &error); if ((error & 0x13U) != 0U) { return RC522_ERR_INTERNAL; } rc522_read_reg(RC522_REG_FIFO_LEVEL, &fifo_level); if (fifo_level == 0U) { *back_len = 0U; return RC522_NO_CARD; } if (back_data != NULL) { uint8_t to_read = fifo_level; if (to_read > *back_len) { to_read = *back_len; } for (uint8_t i = 0; i < to_read; i++) { rc522_read_reg(RC522_REG_FIFO_DATA, &back_data[i]); } *back_len = to_read; } else { *back_len = 0U; } rc522_read_reg(RC522_REG_CONTROL, &control); (void)control; return RC522_OK; } static rc522_status_t rc522_request_a(uint16_t *atqa) { uint8_t cmd = PICC_CMD_REQA; uint8_t recv[2] = {0}; uint8_t recv_len = sizeof(recv); if (atqa == NULL) { return RC522_ERR_PARAM; } /* REQA 是 7bit 命令,BitFramingReg 低 3 位写 0x07 */ rc522_status_t st = rc522_transceive(&cmd, 1U, recv, &recv_len, 0x07U); if (st != RC522_OK) { return st; } if (recv_len != 2U) { return RC522_NO_CARD; } *atqa = (uint16_t)(((uint16_t)recv[0] << 8U) | recv[1]); return RC522_OK; } static uint8_t rc522_get_sel_cmd_by_level(uint8_t level) { if (level == 1U) { return PICC_CMD_SEL_CL1; } if (level == 2U) { return PICC_CMD_SEL_CL2; } return PICC_CMD_SEL_CL3; } static rc522_status_t rc522_anticoll_level(uint8_t level, uint8_t uid_part[5]) { uint8_t sel_cmd = rc522_get_sel_cmd_by_level(level); uint8_t send_buf[2] = {sel_cmd, 0x20U}; uint8_t recv[5] = {0}; uint8_t recv_len = sizeof(recv); rc522_status_t st = rc522_transceive(send_buf, 2U, recv, &recv_len, 0x00U); if (st != RC522_OK) { return st; } if (recv_len != 5U) { return RC522_ERR_INTERNAL; } uint8_t bcc = (uint8_t)(recv[0] ^ recv[1] ^ recv[2] ^ recv[3]); if (bcc != recv[4]) { return RC522_ERR_BCC; } memcpy(uid_part, recv, 5U); return RC522_OK; } static rc522_status_t rc522_select_level(uint8_t level, const uint8_t uid_part[5], uint8_t *sak) { uint8_t send_buf[9] = {0}; uint8_t crc[2] = {0}; uint8_t recv[3] = {0}; uint8_t recv_len = sizeof(recv); if (sak == NULL) { return RC522_ERR_PARAM; } send_buf[0] = rc522_get_sel_cmd_by_level(level); send_buf[1] = 0x70U; send_buf[2] = uid_part[0]; send_buf[3] = uid_part[1]; send_buf[4] = uid_part[2]; send_buf[5] = uid_part[3]; send_buf[6] = uid_part[4]; rc522_status_t st = rc522_calculate_crc(send_buf, 7U, crc); if (st != RC522_OK) { return st; } send_buf[7] = crc[0]; send_buf[8] = crc[1]; st = rc522_transceive(send_buf, 9U, recv, &recv_len, 0x00U); if (st != RC522_OK) { return st; } if (recv_len < 1U) { return RC522_ERR_INTERNAL; } *sak = recv[0]; return RC522_OK; } static void rc522_halt(void) { uint8_t send_buf[4] = {PICC_CMD_HLTA, 0x00U, 0x00U, 0x00U}; uint8_t crc[2] = {0}; uint8_t recv_len = 0; if (rc522_calculate_crc(send_buf, 2U, crc) != RC522_OK) { return; } send_buf[2] = crc[0]; send_buf[3] = crc[1]; (void)rc522_transceive(send_buf, 4U, NULL, &recv_len, 0x00U); } /* ------------------------- 对外接口 ------------------------- */ rc522_status_t rc522_init(void) { memset(&g_last_card, 0, sizeof(g_last_card)); g_run_led_hold_until_ms = 0U; g_last_new_event_tick_ms = 0U; g_irq_pending = 1U; /* SPI 片选空闲电平应为高 */ rc522_cs_high(); rc522_set_run_led(0U); /* RST: 硬件复位脉冲 */ HAL_GPIO_WritePin(RST_GPIO_Port, RST_Pin, GPIO_PIN_RESET); HAL_Delay(5); HAL_GPIO_WritePin(RST_GPIO_Port, RST_Pin, GPIO_PIN_SET); HAL_Delay(50); /* 软复位 */ if (rc522_write_reg(RC522_REG_COMMAND, RC522_CMD_SOFT_RESET) != RC522_OK) { return RC522_ERR_SPI; } HAL_Delay(50); /* 定时器配置: 与常见 RC522 初始化配置兼容 */ rc522_write_reg(RC522_REG_T_MODE, 0x8DU); rc522_write_reg(RC522_REG_T_PRESCALER, 0x3EU); rc522_write_reg(RC522_REG_T_RELOAD_L, 30U); rc522_write_reg(RC522_REG_T_RELOAD_H, 0U); rc522_write_reg(RC522_REG_TX_ASK, 0x40U); rc522_write_reg(RC522_REG_MODE, 0x3DU); rc522_write_reg(RC522_REG_TX_MODE, 0x00U); rc522_write_reg(RC522_REG_RX_MODE, 0x00U); /* 开启天线 */ return rc522_antenna_on(); } rc522_status_t rc522_poll(rc522_card_info_t *out_card) { rc522_card_info_t temp = {0}; uint8_t level_data[5] = {0}; uint8_t uid_pos = 0U; uint8_t level = 1U; rc522_status_t st; rc522_update_run_led_state(); st = rc522_request_a(&temp.atqa); if (st != RC522_OK) { return st; } while (level <= 3U) { st = rc522_anticoll_level(level, level_data); if (st != RC522_OK) { return st; } st = rc522_select_level(level, level_data, &temp.sak); if (st != RC522_OK) { return st; } if (level_data[0] == PICC_CMD_CT) { if ((uid_pos + 3U) > RC522_UID_MAX_LEN) { return RC522_ERR_INTERNAL; } temp.uid[uid_pos++] = level_data[1]; temp.uid[uid_pos++] = level_data[2]; temp.uid[uid_pos++] = level_data[3]; } else { if ((uid_pos + 4U) > RC522_UID_MAX_LEN) { return RC522_ERR_INTERNAL; } temp.uid[uid_pos++] = level_data[0]; temp.uid[uid_pos++] = level_data[1]; temp.uid[uid_pos++] = level_data[2]; temp.uid[uid_pos++] = level_data[3]; } /* SAK bit2=1 表示还有下一层级 UID */ if ((temp.sak & 0x04U) == 0U) { break; } level++; } if (uid_pos == 0U) { return RC522_ERR_INTERNAL; } temp.valid = 1U; temp.uid_len = uid_pos; temp.last_seen_tick_ms = HAL_GetTick(); if (!rc522_uid_equal(&temp, &g_last_card)) { g_last_new_event_tick_ms = temp.last_seen_tick_ms; } g_last_card = temp; g_run_led_hold_until_ms = temp.last_seen_tick_ms + RC522_RUN_LED_HOLD_MS; rc522_set_run_led(1U); g_irq_pending = 0U; if (out_card != NULL) { *out_card = temp; } rc522_halt(); return RC522_OK; } uint8_t rc522_get_last_card(rc522_card_info_t *out_card) { if (out_card == NULL) { return 0U; } if (!rc522_cache_is_fresh()) { return 0U; } *out_card = g_last_card; return 1U; } void rc522_clear_last_card(void) { memset(&g_last_card, 0, sizeof(g_last_card)); g_run_led_hold_until_ms = 0U; g_last_new_event_tick_ms = 0U; rc522_set_run_led(0U); } uint8_t rc522_has_valid_card(void) { return rc522_cache_is_fresh(); } uint8_t rc522_get_new_card(rc522_card_info_t *out_card) { if (out_card == NULL) { return 0U; } if (!rc522_cache_is_fresh()) { return 0U; } if (g_last_new_event_tick_ms != g_last_card.last_seen_tick_ms) { return 0U; } *out_card = g_last_card; g_last_new_event_tick_ms = 0U; return 1U; } uint8_t rc522_uid_to_string(const rc522_card_info_t *card, char *out_str, uint16_t out_len) { uint16_t need_len; uint16_t pos = 0; if (card == NULL || out_str == NULL || card->uid_len == 0U || card->uid_len > RC522_UID_MAX_LEN) { return 0U; } /* 每字节2字符,字节间空格(uid_len-1),再加结尾\0 */ need_len = (uint16_t)((card->uid_len * 2U) + (card->uid_len - 1U) + 1U); if (out_len < need_len) { return 0U; } for (uint8_t i = 0; i < card->uid_len; i++) { int n = snprintf(&out_str[pos], (size_t)(out_len - pos), "%02X", card->uid[i]); if (n <= 0) { return 0U; } pos = (uint16_t)(pos + (uint16_t)n); if (i != (uint8_t)(card->uid_len - 1U)) { if (pos + 1U >= out_len) { return 0U; } out_str[pos++] = ' '; out_str[pos] = '\0'; } } return 1U; } rc522_status_t rc522_service(rc522_card_info_t *out_card) { rc522_update_run_led_state(); if (!rc522_cache_is_fresh()) { g_last_card.valid = 0U; } #if (RC522_USE_IRQ_TRIGGER == 1U) if (g_irq_pending == 0U) { return RC522_NO_CARD; } #endif return rc522_poll(out_card); } void rc522_irq_callback(uint16_t GPIO_Pin) { if (GPIO_Pin == IOR_Pin) { g_irq_pending = 1U; } }