代码基于嘉立创开源项目的硬件,板子直接白嫖的嘉立创打样,硬件链接如下ic卡、饭卡、手机NFC的门禁 - 嘉立创EDA开源硬件平台 (oshwhub.com)
硬件外设使用了RC522,SG90,LED灯,蜂鸣器还有三个按键。代码是基于STC官方24年的H库开发,使用内部晶振22.1184Mhz,是在公司摸鱼写的加密工程所以只有代码以下是核心代码代码请按自身需求修改:
main.c
/*---------------------------------------------------------------------*/
/* --- STC MCU Limited ------------------------------------------------*/
/* --- STC 1T Series MCU Demo Programme -------------------------------*/
/* --- Mobile: (86)13922805190 ----------------------------------------*/
/* --- Fax: 86-0513-55012956,55012947,55012969 ------------------------*/
/* --- Tel: 86-0513-55012928,55012929,55012966 ------------------------*/
/* --- Web: www.STCAI.com ---------------------------------------------*/
/* --- BBS: www.STCAIMCU.com -----------------------------------------*/
/* --- QQ: 800003751 -------------------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了STC的资料及程序 */
/*---------------------------------------------------------------------*/
#include "config.h"
#include "STC8G_H_GPIO.h"
#include "STC8G_H_Timer.h"
#include "STC8G_H_Delay.h"
#include "STC8G_H_UART.h"
#include "STC8G_H_SPI.h"
#include "STC8G_H_NVIC.h"
#include "STC8G_H_Switch.h"
#include "STC8G_H_Exti.h"
#include "STC8H_PWM.h"
#include "RAM.h"
#include "Touch.H"
#include "rc522.h"
/************* 功能说明 **************
本例程基于STC8H8K64U为主控芯片的实验箱8进行编写测试,STC8G、STC8H系列芯片可通用参考.
通过串口发送数据给MCU1,MCU1将接收到的数据由SPI发送给MCU2,MCU2再通过串口发送出去.
设置方法 2:
两个设备初始化时都设置 SSIG 为 0,MSTR 设置为0,此时两个设备都是不忽略 SS 的从机模式。
当其中一个设备需要启动传输时,先检测 SS 管脚的电平,如果时候高电平,
就将自己设置成忽略 SS 的主模式,自己的 SS 脚输出低电平,拉低对方的 SS 脚,即可进行数据传输。
MCU1 MCU2
|-----------------| |-----------------|
| MISO |-----------| MISO |
--| TX MOSI |-----------| MOSI TX |--
| SCLK |-----------| SCLK |
--| RX SS |-----------| SS RX |--
|-----------------| |-----------------|
下载时, 选择时钟 22.1184MHz (可以在配置文件"config.h"中修改).
******************************************/
/************* 本地常量声明 **************/
/************* 本地变量声明 **************/
bit UartReceived=0;
/************* 本地函数声明 **************/
/************* 外部函数和变量声明 *****************/
/******************** IO口配置 ********************/
void GPIO_config(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //结构定义
GPIO_InitStructure.Pin = GPIO_Pin_All; //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7, 或操作
GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P1,&GPIO_InitStructure); //初始化
GPIO_InitStructure.Pin = GPIO_Pin_All; //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7, 或操作
GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P2,&GPIO_InitStructure); //初始化
GPIO_InitStructure.Pin = GPIO_Pin_LOW | GPIO_Pin_5 | GPIO_Pin_6; //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7, 或操作
GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P3,&GPIO_InitStructure); //初始化
GPIO_InitStructure.Pin = GPIO_Pin_4 | GPIO_Pin_7; //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7, 或操作
GPIO_InitStructure.Mode = GPIO_OUT_PP; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P3,&GPIO_InitStructure); //初始化
}
/************************ 定时器配置 ****************************/
void Timer_config(void)
{
TIM_InitTypeDef TIM_InitStructure; //结构定义
//定时器0做16位自动重装, 中断频率为1000HZ,中断函数从P6.7取反输出50KHZ方波信号.
TIM_InitStructure.TIM_Mode = TIM_16BitAutoReload; //指定工作模式, TIM_16BitAutoReload,TIM_16Bit,TIM_8BitAutoReload,TIM_16BitAutoReloadNoMask
TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_1T; //指定时钟源, TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext
TIM_InitStructure.TIM_ClkOut = DISABLE; //是否输出高速脉冲, ENABLE或DISABLE
TIM_InitStructure.TIM_Value = 65536UL - (MAIN_Fosc / 1000UL); //初值, 100000UL
TIM_InitStructure.TIM_Run = ENABLE; //是否初始化后启动定时器, ENABLE或DISABLE
Timer_Inilize(Timer0,&TIM_InitStructure); //初始化Timer0 Timer0,Timer1,Timer2,Timer3,Timer4
NVIC_Timer0_Init(ENABLE,Priority_0); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
}
/**************** 串口初始化函数 *****************/
void UART_config(void)
{
COMx_InitDefine COMx_InitStructure; //结构定义
COMx_InitStructure.UART_Mode = UART_8bit_BRTx; //模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx
COMx_InitStructure.UART_BRT_Use = BRT_Timer1; //选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)
COMx_InitStructure.UART_BaudRate = 115200ul; //波特率, 一般 110 ~ 115200
COMx_InitStructure.UART_RxEnable = ENABLE; //接收允许, ENABLE或DISABLE
COMx_InitStructure.BaudRateDouble = DISABLE; //波特率加倍, ENABLE或DISABLE
UART_Configuration(UART1, &COMx_InitStructure); //初始化串口1 UART1,UART2,UART3,UART4
NVIC_UART1_Init(ENABLE,Priority_1); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
UART1_SW(UART1_SW_P30_P31); //UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44
}
/**************** SPI初始化函数 *****************/
void SPI_config(void)
{
SPI_InitTypeDef SPI_InitStructure;
SPI_InitStructure.SPI_Enable = ENABLE; //SPI启动 ENABLE, DISABLE
SPI_InitStructure.SPI_SSIG = DISABLE; //片选位 ENABLE, DISABLE
SPI_InitStructure.SPI_FirstBit = SPI_MSB; //移位方向 SPI_MSB, SPI_LSB
SPI_InitStructure.SPI_Mode = SPI_Mode_Slave; //主从选择 SPI_Mode_Master, SPI_Mode_Slave
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //时钟相位 SPI_CPOL_High, SPI_CPOL_Low
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //数据边沿 SPI_CPHA_1Edge, SPI_CPHA_2Edge
SPI_InitStructure.SPI_Speed = SPI_Speed_4; //SPI速度 SPI_Speed_4,SPI_Speed_16,SPI_Speed_64,SPI_Speed_2/SPI_Speed_32
SPI_Init(&SPI_InitStructure);
NVIC_SPI_Init(ENABLE,Priority_3); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
SPI_SW(SPI_P12_P13_P14_P15); //SPI_P12_P13_P14_P15,SPI_P22_P23_P24_P25,SPI_P54_P40_P41_P43,SPI_P35_P34_P33_P32
SPI_SS = 1;
}
/*************** 串口初始化函数 *****************/
void PWM_config(void)
{
PWMx_InitDefine PWMx_InitStructure;
PWMA_Prescaler(15);//预分频 22118400 / 16 = 1382400
PWMx_InitStructure.PWM_Mode = CCMRn_PWM_MODE1; //模式, CCMRn_FREEZE,CCMRn_MATCH_VALID,CCMRn_MATCH_INVALID,CCMRn_ROLLOVER,CCMRn_FORCE_INVALID,CCMRn_FORCE_VALID,CCMRn_PWM_MODE1,CCMRn_PWM_MODE2
PWMx_InitStructure.PWM_Duty = PWMA_Duty.PWM1_Duty; //PWM占空比时间, 0~Period
PWMx_InitStructure.PWM_EnoSelect = ENO1P ; //输出通道选择, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8P
PWM_Configuration(PWM1, &PWMx_InitStructure); //初始化PWM, PWMA,PWMB
/* 频率 = 1382400 / (27647 + 1) = 50 hz */
PWMx_InitStructure.PWM_Period = 27647; //周期时间, 0~65535
PWMx_InitStructure.PWM_DeadTime = 0; //死区发生器设置, 0~255
PWMx_InitStructure.PWM_MainOutEnable= ENABLE; //主输出使能, ENABLE,DISABLE
PWMx_InitStructure.PWM_CEN_Enable = ENABLE; //使能计数器, ENABLE,DISABLE
PWM_Configuration(PWMA, &PWMx_InitStructure); //初始化PWM通用寄存器, PWMA,PWMB
PWM1_SW(PWM1_SW_P10_P11); //PWM1_SW_P10_P11,PWM1_SW_P20_P21,PWM1_SW_P60_P61
NVIC_PWM_Init(PWMA,DISABLE,Priority_0);
}
/******************** INT配置 ********************/
//void Exti_config(void)
//{
// EXTI_InitTypeDef Exti_InitStructure; //结构定义
// Exti_InitStructure.EXTI_Mode = EXT_MODE_Fall;//中断模式, EXT_MODE_RiseFall,EXT_MODE_Fall
// Ext_Inilize(EXT_INT0,&Exti_InitStructure); //初始化
// NVIC_INT0_Init(ENABLE,Priority_0); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
//}
/******************** task A **************************/
void main(void)
{
u8 i;
EAXSFR(); /* 扩展寄存器访问使能 */
GPIO_config();
Timer_config();
UART_config();
SPI_config();
PWM_config();
// Exti_config();
RC522_Init();
EA = 1;
gMCUREAL.BEEP_RUN = 1;
PWMA_Duty.PWM1_Duty = DOOR_OFF; //PWM的高电平时间 = 0.5ms +(转动角度/180°)*2ms 周期20ms
LED1 = 1;
UpdatePwm(PWMA, &PWMA_Duty);
PrintString1("STC8 UART1与SPI透传程序\r\n"); //UART1发送一个字符串
while (1)
{
if(gMCUREAL.KeyCtl) //按键按下马上发送
{
if(gMCUREAL.KeyCtl == 1)
PrintString1("按键 增加\r\n"); //UART1发送一个字符串
else if(gMCUREAL.KeyCtl == 2)
PrintString1("按键 删除\r\n"); //UART1发送一个字符串
else if(gMCUREAL.KeyCtl == 3)
{
PrintString1("按键 开门\r\n"); //UART1发送一个字符串
gMCUREAL.MOTOR_RUN = 1;
}
gMCUREAL.BEEP_RUN = 1;
gMCUREAL.KeyCtl = 0;
}
if(COM1.RX_TimeOut > 0)
{
if(--COM1.RX_TimeOut == 0)
{
if(COM1.RX_Cnt > 0)
{
UartReceived = 1; //设置串口接收标志
}
}
}
if(!gMCUREAL.MOTOR_RUN)
CardHanding();
if(Task200ms) //200ms
{
Task200ms = 0;
LED1 = !LED1;
}
if(Task2ms)
{
Task2ms = 0;
KEY_task(); //按键扫描
}
}
}
touch.c
#include "Touch.H"
/************************************************************************/
/* 函数: void KEY_task(void) */
/* 描述: 触摸按键任务 */
/* 参数: None. */
/* 返回: None. */
/* 版本: V1.0 2023-07-11 */
/************************************************************************/
void KEY_task(void)
{
if(CardADD == 0) //低电平按下 增加
{
if(TK_cnt[0] < KeyTim)
TK_cnt[0]++;
}
else
{
if(TK_cnt[0] >= KeyTim)
{
gMCUREAL.KeyCtl = 1;
}
TK_cnt[0] = 0;
}
if(CardDEL == 0) //低电平按下 删除
{
if(TK_cnt[1] < KeyTim)
TK_cnt[1]++;
}
else
{
if(TK_cnt[1] >= KeyTim) //50ms
{
gMCUREAL.KeyCtl = 2;
}
TK_cnt[1] = 0;
}
if(CardOPE == 0) //低电平按下 开门
{
if(TK_cnt[2] < KeyTim)
TK_cnt[2]++;
}
else
{
if(TK_cnt[2] >= KeyTim)
{
gMCUREAL.KeyCtl = 3;
}
TK_cnt[2] = 0;
}
}
/**************************************** END ****************************************************/
touch.h
#ifndef __Touch_H
#define __Touch_H
#include "config.h"
#include "RAM.h"
#define KeyTim 15 //50ms 按下
void KEY_task(void);
#endif
RAM.c
#include "RAM.H"
/************* 本地变量声明 **************/
TYP_MCUREAL gMCUREAL;
/************* 本地变量声明 **************/
u16 xdata TK_cnt[3] = {0}; // 按键计数值, 16位
u16 xdata RC_cnt[2] = {0}; // 卡号计数
u16 xdata MOTOR_cnt = 0; //锁复位计数
u16 xdata ms_timer = 0;
bit Task2ms = 0;
//bit Task10ms = 0;
bit Task200ms = 0;
u8 xdata ID_ASC[8] = {0};//ascii显示卡号
u8 xdata g_ucTempbuf[4] = {0};
/************************************** END **************************************/
RAM.h
#ifndef __RAM_H
#define __RAM_H
#include "config.h"
// 宏定义
#define PWMA_PERIOD 27647
#define DOOR_ON PWMA_PERIOD*0.1f
#define DOOR_OFF PWMA_PERIOD*0.05f
typedef struct
{
u8 KeyCtl; //按键控制 0 无 1 增加 2 删除 3 开门
u8 BEEP_RUN: 1; //蜂鸣器运行 1 运行 0停止
u8 MOTOR_RUN: 1; //马达运行 1 运行 0停止
// u8 RC; //卡号核对标志位
} TYP_MCUREAL; // gMCUREAL;
extern TYP_MCUREAL gMCUREAL;
extern u16 xdata TK_cnt[3]; // 按键计数值, 16位
extern u16 xdata RC_cnt[2]; // 卡号计数
extern u16 xdata MOTOR_cnt; //锁复位计数
extern u16 xdata ms_timer;
extern bit Task2ms;
//extern bit Task10ms;
extern bit Task200ms;
extern u8 xdata ID_ASC[8];//ascii显示卡号
extern u8 xdata g_ucTempbuf[4];
sbit CardADD = P3^6; //增加 SW2
sbit CardDEL = P3^5; //删除 SW1
sbit CardOPE = P3^2; //开门 SW3
sbit BEEP = P3^7; //蜂鸣器
sbit LED1 = P3^4; //LED1
#endif
/************************************** END **************************************/
RC522.c
#include "rc522.h"
#define MAXRLEN 18
extern uint8 xdata g_ucTempbuf[4];
extern uint8 xdata ID_ASC[8];
u8 xdata UI0[4]= {0x83,0xAF,0x4A,0x29}; // 此处为6张卡的信息,UI0到UI5
u8 xdata UI1[4]= {0xF3,0xB5,0x6E,0x14};
void delay2(unsigned int z)
{
unsigned int x,y;
for(x=z; x>0; x--)
for(y=110; y>0; y--);
}
/***************************************************************************
* 描 述 : 寻卡
* 参 数 : req_code[IN]:寻卡方式
* 0x52 = 寻感应区内所有符合14443A标准的卡
* 0x26 = 寻未进入休眠状态的卡
* pTagType[OUT]:卡片类型代码
* 0x4400 = Mifare_UltraLight
* 0x0400 = Mifare_One(S50)
* 0x0200 = Mifare_One(S70)
* 0x0800 = Mifare_Pro(X)
* 0x4403 = Mifare_DESFire
* 返回值 : 成功返回MI_OK
**************************************************************************/
char RC522_Request(uint8 req_code,uint8 *pTagType)
{
char status;
uint16 unLen;
xdata uint8 ucComMF522Buf[MAXRLEN];
ClearBitMask(Status2Reg,0x08);
WriteRawRC(BitFramingReg,0x07);
SetBitMask(TxControlReg,0x03);
ucComMF522Buf[0] = req_code;
status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,&unLen);
if ((status == MI_OK) && (unLen == 0x10))
{
*pTagType = ucComMF522Buf[0];
*(pTagType+1) = ucComMF522Buf[1];
}
else
{
status = MI_ERR;
}
return status;
}
/
//功 能:防冲撞
//参数说明: pSnr[OUT]:卡片序列号,4字节
//返 回: 成功返回MI_OK
/
char RC522_Anticoll(uint8 *pSnr)
{
char status;
uint8 i,snr_check=0;
unsigned int unLen;
xdata uint8 ucComMF522Buf[MAXRLEN];
ClearBitMask(Status2Reg,0x08);
WriteRawRC(BitFramingReg,0x00);
ClearBitMask(CollReg,0x80);
ucComMF522Buf[0] = PICC_ANTICOLL1;
ucComMF522Buf[1] = 0x20;
status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,2,ucComMF522Buf,&unLen);
if (status == MI_OK)
{
for (i=0; i<4; i++)
{
*(pSnr+i) = ucComMF522Buf[i];
snr_check ^= ucComMF522Buf[i];
}
if (snr_check != ucComMF522Buf[i])
{
status = MI_ERR;
}
}
SetBitMask(CollReg,0x80);
return status;
}
/
//功 能:选定卡片
//参数说明: pSnr[IN]:卡片序列号,4字节
//返 回: 成功返回MI_OK
/
char PcdSelect(unsigned char *pSnr)
{
char status;
unsigned char i;
unsigned int unLen;
xdata unsigned char ucComMF522Buf[MAXRLEN];
ucComMF522Buf[0] = PICC_ANTICOLL1;
ucComMF522Buf[1] = 0x70;
ucComMF522Buf[6] = 0;
for (i=0; i<4; i++)
{
ucComMF522Buf[i+2] = *(pSnr+i);
ucComMF522Buf[6] ^= *(pSnr+i);
}
CalulateCRC(ucComMF522Buf,7,&ucComMF522Buf[7]);
ClearBitMask(Status2Reg,0x08);
status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,9,ucComMF522Buf,&unLen);
if ((status == MI_OK) && (unLen == 0x18))
{
status = MI_OK;
}
else
{
status = MI_ERR;
}
return status;
}
/
//功 能:验证卡片密码
//参数说明: auth_mode[IN]: 密码验证模式
// 0x60 = 验证A密钥
// 0x61 = 验证B密钥
// addr[IN]:块地址
// pKey[IN]:密码
// pSnr[IN]:卡片序列号,4字节
//返 回: 成功返回MI_OK
/
//char PcdAuthState(unsigned char auth_mode,unsigned char addr,unsigned char *pKey,unsigned char *pSnr)
//{
// char status;
// unsigned int unLen;
// unsigned char i;
// xdata uint8 ucComMF522Buf[MAXRLEN];
// ucComMF522Buf[0] = auth_mode;
// ucComMF522Buf[1] = addr;
// for (i=0; i<6; i++)
// { ucComMF522Buf[i+2] = *(pKey+i); }
// for (i=0; i<6; i++)
// { ucComMF522Buf[i+8] = *(pSnr+i); }
// // memcpy(&ucComMF522Buf[2], pKey, 6);
// // memcpy(&ucComMF522Buf[8], pSnr, 4);
//
// status = PcdComMF522(PCD_AUTHENT,ucComMF522Buf,12,ucComMF522Buf,&unLen);
// if ((status != MI_OK) || (!(ReadRawRC(Status2Reg) & 0x08)))
// { status = MI_ERR; }
//
// return status;
//}
/
//功 能:读取M1卡一块数据
//参数说明: addr[IN]:块地址
// pData[OUT]:读出的数据,16字节
//返 回: 成功返回MI_OK
/
//char PcdRead(unsigned char addr,unsigned char *pData)
//{
// char status;
// unsigned int unLen;
// unsigned char i;
// xdata uint8 ucComMF522Buf[MAXRLEN];
// ucComMF522Buf[0] = PICC_READ;
// ucComMF522Buf[1] = addr;
// CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
//
// status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
// if ((status == MI_OK) && (unLen == 0x90))
// // { memcpy(pData, ucComMF522Buf, 16); }
// {
// for (i=0; i<16; i++)
// { *(pData+i) = ucComMF522Buf[i]; }
// }
// else
// { status = MI_ERR; }
//
// return status;
//}
/
//功 能:写数据到M1卡一块
//参数说明: addr[IN]:块地址
// pData[IN]:写入的数据,16字节
//返 回: 成功返回MI_OK
/
//char PcdWrite(unsigned char addr,unsigned char *pData)
//{
// char status;
// unsigned int unLen;
// unsigned char i;
// xdata uint8 ucComMF522Buf[MAXRLEN];
//
// ucComMF522Buf[0] = PICC_WRITE;
// ucComMF522Buf[1] = addr;
// CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
//
// status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
// if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
// { status = MI_ERR; }
//
// if (status == MI_OK)
// {
// //memcpy(ucComMF522Buf, pData, 16);
// for (i=0; i<16; i++)
// { ucComMF522Buf[i] = *(pData+i); }
// CalulateCRC(ucComMF522Buf,16,&ucComMF522Buf[16]);
// status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,18,ucComMF522Buf,&unLen);
// if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
// { status = MI_ERR; }
// }
//
// return status;
//}
/
//功 能:命令卡片进入休眠状态
//返 回: 成功返回MI_OK
/
void PcdHalt(void)
{
xdata uint8 ucComMF522Buf[MAXRLEN];
ucComMF522Buf[0] = PICC_HALT;
ucComMF522Buf[1] = 0;
CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
}
/
//用MF522计算CRC16函数
/
void CalulateCRC(unsigned char *pIndata,unsigned char len,unsigned char *pOutData)
{
unsigned char i,n;
ClearBitMask(DivIrqReg,0x04);
WriteRawRC(CommandReg,PCD_IDLE);
SetBitMask(FIFOLevelReg,0x80);
for (i=0; i<len; i++)
{
WriteRawRC(FIFODataReg, *(pIndata+i));
}
WriteRawRC(CommandReg, PCD_CALCCRC);
i = 0xFF;
do
{
n = ReadRawRC(DivIrqReg);
i--;
}
while ((i!=0) && !(n&0x04));
pOutData[0] = ReadRawRC(CRCResultRegL);
pOutData[1] = ReadRawRC(CRCResultRegM);
}
/
//功 能:复位RC522
//返 回: 成功返回MI_OK
/
char RC522_Reset(void)
{
MF522_RST=1;
_nop_();
MF522_RST=0;
_nop_();
MF522_RST=1;
delay2(20);
WriteRawRC(CommandReg,PCD_RESETPHASE);
_nop_();
WriteRawRC(ModeReg,0x3D); //和Mifare卡通讯,CRC初始值0x6363
WriteRawRC(TReloadRegL,30);
WriteRawRC(TReloadRegH,0);
WriteRawRC(TModeReg,0x8D);
WriteRawRC(TPrescalerReg,0x3E);
WriteRawRC(TxAutoReg,0x40);
return MI_OK;
}
/
//功 能:读RC632寄存器
//参数说明:Address[IN]:寄存器地址
//返 回:读出的值
/
unsigned char ReadRawRC(unsigned char Address)
{
unsigned char i, ucAddr;
unsigned char ucResult=0;
MF522_SCK = 0;
MF522_SDA = 0;
ucAddr = ((Address<<1)&0x7E)|0x80;
for(i=8; i>0; i--)
{
MF522_MOSI = ((ucAddr&0x80)==0x80);
MF522_SCK = 1;
ucAddr <<= 1;
MF522_SCK = 0;
}
for(i=8; i>0; i--)
{
MF522_SCK = 1;
ucResult <<= 1;
ucResult|=(bit)MF522_MISO;
MF522_SCK = 0;
}
MF522_SDA = 1;
MF522_SCK = 1;
return ucResult;
}
/***************************************************************************
* 描 述 : 写RC632寄存器
* 参 数 : Address[IN]:寄存器地址 value[IN]:写入的值
* 返回值 : 无
**************************************************************************/
void WriteRawRC(unsigned char Address, unsigned char value)
{
unsigned char i, ucAddr;
MF522_SCK = 0;
MF522_SDA = 0;
ucAddr = ((Address<<1)&0x7E);
for(i=8; i>0; i--)
{
MF522_MOSI = ((ucAddr&0x80)==0x80);
MF522_SCK = 1;
ucAddr <<= 1;
MF522_SCK = 0;
}
for(i=8; i>0; i--)
{
MF522_MOSI = ((value&0x80)==0x80);
MF522_SCK = 1;
value <<= 1;
MF522_SCK = 0;
}
MF522_SDA = 1;
MF522_SCK = 1;
}
/***************************************************************************
* 描 述 : 置RC522寄存器位
* 参 数 : reg[IN]:寄存器地址 mask[IN]:置位值
* 返回值 : 无
**************************************************************************/
void SetBitMask(unsigned char reg,unsigned char mask)
{
char tmp = 0x0;
tmp = ReadRawRC(reg);
WriteRawRC(reg,tmp | mask); // set bit mask
}
/***************************************************************************
* 描 述 : 清RC522寄存器位
* 参 数 : reg[IN]:寄存器地址
* mask[IN]:清位值
* 返回值 : 无
**************************************************************************/
void ClearBitMask(uint8 reg,uint8 mask)
{
char tmp = 0x0;
tmp = ReadRawRC(reg);
WriteRawRC(reg, tmp & ~mask); // clear bit mask
}
/***************************************************************************
* 描 述 : 通过RC522和ISO14443卡通讯
* 参 数 : Command[IN]:RC522命令字
* pInData[IN]:通过RC522发送到卡片的数据
* InLenByte[IN]:发送数据的字节长度
* pOutData[OUT]:接收到的卡片返回数据
* *pOutLenBit[OUT]:返回数据的位长度
* 返回值 : 无
**************************************************************************/
char PcdComMF522(unsigned char Command,
unsigned char *pInData,
unsigned char InLenByte,
unsigned char *pOutData,
unsigned int *pOutLenBit)
{
char status = MI_ERR;
unsigned char irqEn = 0x00;
unsigned char waitFor = 0x00;
unsigned char lastBits;
unsigned char n;
unsigned int i;
switch (Command)
{
case PCD_AUTHENT:
irqEn = 0x12;
waitFor = 0x10;
break;
case PCD_TRANSCEIVE:
irqEn = 0x77;
waitFor = 0x30;
break;
default:
break;
}
WriteRawRC(ComIEnReg,irqEn|0x80);
ClearBitMask(ComIrqReg,0x80);
WriteRawRC(CommandReg,PCD_IDLE);
SetBitMask(FIFOLevelReg,0x80);
for (i=0; i<InLenByte; i++)
{
WriteRawRC(FIFODataReg, pInData[i]);
}
WriteRawRC(CommandReg, Command);
if (Command == PCD_TRANSCEIVE)
{
SetBitMask(BitFramingReg,0x80);
}
i = 600;//根据时钟频率调整,操作M1卡最大等待时间25ms
do
{
n = ReadRawRC(ComIrqReg);
i--;
}
while ((i!=0) && !(n&0x01) && !(n&waitFor));
ClearBitMask(BitFramingReg,0x80);
if (i!=0)
{
if(!(ReadRawRC(ErrorReg)&0x1B))
{
status = MI_OK;
if (n & irqEn & 0x01)
{
status = MI_NOTAGERR;
}
if (Command == PCD_TRANSCEIVE)
{
n = ReadRawRC(FIFOLevelReg);
lastBits = ReadRawRC(ControlReg) & 0x07;
if (lastBits)
{
*pOutLenBit = (n-1)*8 + lastBits;
}
else
{
*pOutLenBit = n*8;
}
if (n == 0)
{
n = 1;
}
if (n > MAXRLEN)
{
n = MAXRLEN;
}
for (i=0; i<n; i++)
{
pOutData[i] = ReadRawRC(FIFODataReg);
}
}
}
else
{
status = MI_ERR;
}
}
SetBitMask(ControlReg,0x80); // stop timer now
WriteRawRC(CommandReg,PCD_IDLE);
return status;
}
/***************************************************************************
* 描 述 : 开启天线,每次启动或关闭天线发射之间应至少有1ms的间隔
* 参 数 : 无
* 返回值 : 无
**************************************************************************/
void PcdAntennaOn(void)
{
uint8 i;
i = ReadRawRC(TxControlReg);
if (!(i & 0x03))
{
SetBitMask(TxControlReg, 0x03);
}
}
/***************************************************************************
* 描 述 : 关闭天线
* 参 数 : 无
* 返回值 : 无
**************************************************************************/
void PcdAntennaOff(void)
{
ClearBitMask(TxControlReg, 0x03);
}
//
//设置RC522的工作方式
//
char M500PcdConfigISOType(unsigned char type)
{
if (type == 'A') //ISO14443_A
{
ClearBitMask(Status2Reg,0x08);
WriteRawRC(ModeReg,0x3D);
WriteRawRC(RxSelReg,0x86);
WriteRawRC(RFCfgReg,0x7F);
WriteRawRC(TReloadRegL,30);
WriteRawRC(TReloadRegH,0);
WriteRawRC(TModeReg,0x8D);
WriteRawRC(TPrescalerReg,0x3E);
delay2(400);
PcdAntennaOn();
}
else {
return -1;
}
return MI_OK;
}
void hexToasc(uint8 *a,uint8 *b,uint16 hlong)
{
uint8 i;
for(i=0; i<hlong; i++) //16进制转化成ASCII
{
if(a[i]/16>9) b[i*2]=a[i]/16+'7';
else b[i*2]=a[i]/16+'0';
if(a[i]%16>9) b[i*2+1]=a[i]%16+'7';
else b[i*2+1]=a[i]%16+'0';
}
}
void RC522_Init(void)
{
RC522_Reset();
PcdAntennaOff();
M500PcdConfigISOType( 'A' );
}
uint8 CardHanding(void)
{
uint8 status,i;
status = RC522_Request(PICC_REQIDL, g_ucTempbuf);//寻卡,返回卡的类型:2个字节
// if (status != MI_OK)
// {
// RC522_Reset();
// PcdAntennaOff();
// PcdAntennaOn();
// return 0;
// }
status = RC522_Anticoll(g_ucTempbuf);//防冲撞,返回卡的序列号:4字节
if(status == MI_OK)
for(i=0; i<4; i++)
{
// hexToasc(g_ucTempbuf,ID_ASC,4); //发送卡号,4个字节 只有接收到读卡命令才发送
// TX1_write2buff(g_ucTempbuf[i]);
if(g_ucTempbuf[i] == UI0[i])
RC_cnt[0]++;
else if(g_ucTempbuf[i] == UI1[i])
RC_cnt[1]++;
}
if(RC_cnt[0] == 4 || RC_cnt[1] == 4)
{
RC_cnt[0] = 0;
RC_cnt[1] = 0;
// gMCUREAL.RC = 0;
gMCUREAL.MOTOR_RUN = 1;
PrintString1("卡片 开门\r\n"); //UART1发送一个字符串
}
status = PcdSelect(g_ucTempbuf);//选定卡片
if(status != MI_OK) return 0;
// PcdHalt();
return 0;
}
RC522.h
#ifndef __RC522_H_
#define __RC522_H_
#include "config.h"
#include "string.h"
#include "STC8G_H_Delay.h"
#include "STC8G_H_UART.h"
#include "RAM.H"
/**********************
引脚别名定义
***********************/
sbit MF522_SDA = P1^6; //SDA
sbit MF522_SCK = P1^5; //SCK
sbit MF522_MOSI = P1^3; //MOSI
sbit MF522_MISO = P1^4; //MISO
sbit MF522_RST = P1^2; //RST
char RC522_Reset(void);
void PcdAntennaOn(void);
void PcdAntennaOff(void);
char RC522_Request(unsigned char req_code,unsigned char *pTagType);
char RC522_Anticoll(unsigned char *pSnr);
char PcdSelect(unsigned char *pSnr);
char PcdAuthState(unsigned char auth_mode,unsigned char addr,unsigned char *pKey,unsigned char *pSnr);
char PcdRead(unsigned char addr,unsigned char *pData);
char PcdWrite(unsigned char addr,unsigned char *pData);
char PcdValue(unsigned char dd_mode,unsigned char addr,unsigned char *pValue);
char PcdBakValue(unsigned char sourceaddr, unsigned char goaladdr);
void PcdHalt(void);
char PcdComMF522(unsigned char Command,
unsigned char *pInData,
unsigned char InLenByte,
unsigned char *pOutData,
unsigned int *pOutLenBit);
void CalulateCRC(unsigned char *pIndata,unsigned char len,unsigned char *pOutData);
void WriteRawRC(unsigned char Address,unsigned char value);
unsigned char ReadRawRC(unsigned char Address);
void SetBitMask(unsigned char reg,unsigned char mask);
void ClearBitMask(unsigned char reg,unsigned char mask);
char M500PcdConfigISOType(unsigned char type);
void RC522_Init(void);
uint8 CardHanding(void);
void hexToasc(uint8 *a,uint8 *b,uint16 hlong);
/
//MF522命令字
/
#define PCD_IDLE 0x00 //取消当前命令
#define PCD_AUTHENT 0x0E //验证密钥
#define PCD_RECEIVE 0x08 //接收数据
#define PCD_TRANSMIT 0x04 //发送数据
#define PCD_TRANSCEIVE 0x0C //发送并接收数据
#define PCD_RESETPHASE 0x0F //复位
#define PCD_CALCCRC 0x03 //CRC计算
/
//Mifare_One卡片命令字
/
#define PICC_REQIDL 0x26 //寻天线区内未进入休眠状态
#define PICC_REQALL 0x52 //寻天线区内全部卡
#define PICC_ANTICOLL1 0x93 //防冲撞
#define PICC_ANTICOLL2 0x95 //防冲撞
#define PICC_AUTHENT1A 0x60 //验证A密钥
#define PICC_AUTHENT1B 0x61 //验证B密钥
#define PICC_READ 0x30 //读块
#define PICC_WRITE 0xA0 //写块
#define PICC_DECREMENT 0xC0 //扣款
#define PICC_INCREMENT 0xC1 //充值
#define PICC_RESTORE 0xC2 //调块数据到缓冲区
#define PICC_TRANSFER 0xB0 //保存缓冲区中数据
#define PICC_HALT 0x50 //休眠
/
//MF522 FIFO长度定义
/
#define DEF_FIFO_LENGTH 64 //FIFO size=64byte
/
//MF522寄存器定义
/
// PAGE 0
#define RFU00 0x00
#define CommandReg 0x01
#define ComIEnReg 0x02
#define DivlEnReg 0x03
#define ComIrqReg 0x04
#define DivIrqReg 0x05
#define ErrorReg 0x06
#define Status1Reg 0x07
#define Status2Reg 0x08
#define FIFODataReg 0x09
#define FIFOLevelReg 0x0A
#define WaterLevelReg 0x0B
#define ControlReg 0x0C
#define BitFramingReg 0x0D
#define CollReg 0x0E
#define RFU0F 0x0F
// PAGE 1
#define RFU10 0x10
#define ModeReg 0x11
#define TxModeReg 0x12
#define RxModeReg 0x13
#define TxControlReg 0x14
#define TxAutoReg 0x15
#define TxSelReg 0x16
#define RxSelReg 0x17
#define RxThresholdReg 0x18
#define DemodReg 0x19
#define RFU1A 0x1A
#define RFU1B 0x1B
#define MifareReg 0x1C
#define RFU1D 0x1D
#define RFU1E 0x1E
#define SerialSpeedReg 0x1F
// PAGE 2
#define RFU20 0x20
#define CRCResultRegM 0x21
#define CRCResultRegL 0x22
#define RFU23 0x23
#define ModWidthReg 0x24
#define RFU25 0x25
#define RFCfgReg 0x26
#define GsNReg 0x27
#define CWGsCfgReg 0x28
#define ModGsCfgReg 0x29
#define TModeReg 0x2A
#define TPrescalerReg 0x2B
#define TReloadRegH 0x2C
#define TReloadRegL 0x2D
#define TCounterValueRegH 0x2E
#define TCounterValueRegL 0x2F
// PAGE 3
#define RFU30 0x30
#define TestSel1Reg 0x31
#define TestSel2Reg 0x32
#define TestPinEnReg 0x33
#define TestPinValueReg 0x34
#define TestBusReg 0x35
#define AutoTestReg 0x36
#define VersionReg 0x37
#define AnalogTestReg 0x38
#define TestDAC1Reg 0x39
#define TestDAC2Reg 0x3A
#define TestADCReg 0x3B
#define RFU3C 0x3C
#define RFU3D 0x3D
#define RFU3E 0x3E
#define RFU3F 0x3F
/
//和MF522通讯时返回的错误代码
/
#define MI_OK 0
#define MI_NOTAGERR (-1)
#define MI_ERR (-2)
#endif
STC8G_H_Timer.c
//========================================================================
// 函数: Timer0_ISR_Handler
// 描述: Timer0中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2020-09-23
//========================================================================
void Timer0_ISR_Handler (void) interrupt TMR0_VECTOR //进中断时已经清除标志
{
// TODO: 在此处添加用户代码
ms_timer++;
if(ms_timer >= one_ms) //one_ms
{
ms_timer = 0;
}
if(ms_timer%send_speed == 0) //200ms运行一次
{
Task200ms = 1;
if(gMCUREAL.BEEP_RUN)
{
BEEP = 0;
gMCUREAL.BEEP_RUN = 0;
}
else
BEEP = 1;
}
if(ms_timer%high_speed == 0) //2ms运行一次
{
Task2ms = 1;
if(gMCUREAL.MOTOR_RUN)
{
if(MOTOR_cnt == 0)
{
PWMA_Duty.PWM1_Duty = DOOR_ON; //PWM的高电平时间 = 0.5ms +(转动角度/180°)*2ms 周期20ms
UpdatePwm(PWMA, &PWMA_Duty);
}
MOTOR_cnt++;
if(MOTOR_cnt > 5000) //10s复位舵机
{
PWMA_Duty.PWM1_Duty = DOOR_OFF; //PWM的高电平时间 = 0.5ms +(转动角度/180°)*2ms 周期20ms
UpdatePwm(PWMA, &PWMA_Duty);
gMCUREAL.MOTOR_RUN = 0;
}
}
else
MOTOR_cnt = 0;
}
}