随着科技技术的快速发展,单片机的应用越来越广泛,在医疗、工厂、机械之类方面起着重要的作用,单片机的编程非常灵活,在生活的应用中起着重要的作用。
更多的尤其是企业和教育机构,人们更多的使用射频识别设备进行打卡,实现员工上班和下班的考勤工作记录,不仅方便了工作人员的考勤操作,也为企业或教育机构的管理提供了便利的工具,从而真正的实现工作人员上班打卡记录和下班打卡记录的操作,一改传统的人员手工记录操作,使数据信息更加的真实性,准确性和易于操作性。
提示:以下是本篇文章正文内容,下面案例仅供参考
以STC89C52单片机即8051单片机的增强版为核心,起着控制作用。系统包括LCD液晶显示屏电路、复位电路、晶振电路、蜂鸣器警报电路、RC522射频识别电路。
设计思路分为四个模块:STC89C52RC、LCD显示电路、蜂鸣器警报电路、射频识别电路。
基于RFID的考勤管理系统,主要用于员工的打卡登记。
当IC卡接触射频识别模块RC522时,液晶显示屏显示员工姓名和卡号显示上班打卡成功,同一张IC卡再一次接触射频模块时,液晶显示屏显示员工姓名和卡号显示下班打卡成功。每次刷卡成功时,蜂鸣器响。
上位机里面可以查看到刷卡的记录信息。
STC89C52是一种带8K字节闪烁可编程可擦除只读存储器的低电压、高性能COMOS8的微处理器。
STC89C52内部有一个用于构成振荡器的高增益反相放大器,引脚RXD和TXD分别是放大器的输入端和输出端。时钟可以由内部方式产生或外部方式产生。在RXD和TXD引脚上外接定时元件,内部振荡器就产生自激振荡。定时元件通常采用石英晶体和电容组成并联谐振电路。STC89C52系列单片机具有一下功能:
兼容MCS51指令系统
32个双向I/O口
3个16位可编程定时/计数器中断
2个串行中断
2个外部中断源
2个读写中断口线
VCC:电源输入,接+5V电源
GND:接地线
XTAL1:片内振荡电路的输入端
XTAL2:片内振荡电路的输出端
PSEN:外部存储器读选通信号
EA/VPP:程序存储器的内外部选通,接低电平从外部程序存储器读指令,如果接高电平则从内部程序存储器读指令。
RST/VPD:复位引脚,引脚上出现2个机器周期的高电平将使单片机复位。
ALE/PROG:地址锁存允许信号,当访问外部存储器时,地址锁存允许的输出电平用于锁存地址的地位字节。在FLASH编程期间,此引脚用于输入编程脉冲。在平时,ALE端以不变的频率周期输出正脉冲信号,此频率为振荡器频率的1/6。因此它可用作对外部输出的脉冲或用于定时目的。
P0口:P0口是一组8 位漏极开路型双向I/O口,也即地址/数据总线复用口。作为输出口用时,每位能吸收电流的方式驱动8个TTL逻辑门电路,对端口写“1”可作为高阻抗输入端用。
P1口:P1口是一个内部提供上拉电阻的8位双向I/O口,P1口缓冲器能接收输出4TTL门电流。P1口管脚写入1后,被内部上拉为高,可用作输入,P1口被外部下拉为低电平时,将输出电流,这是由于内部上拉的缘故。在FLASH编程和校验时,P1口作为第八位地址接收。
P2口:P2口为一个内部上拉电阻的8位双向I/O口,P2口缓冲器可接收,输出4个TTL门电流,当P2口被写“1”时,其管脚被内部上拉电阻拉高,且作为输入。并因此作为输入时,P2口的管脚被外部拉低,将输出电流。这是由于内部上拉的缘故。P2口当用于外部程序存储器或16位地址外部数据存储器进行存取时,P2口输出地址的高八位。在给出地址“1”时,它利用内部上拉优势,当对外部八位地址数据存储器进行读写时,P2口输出其特殊功能寄存器的内容。P2口在FLASH编程和校验时接收高八位地址信号和控制信号。
P3口:P3口是一组带有内部上拉电阻的8位双向I/O口。P3口输出缓冲级可驱动4个TTL逻辑门电路。对P3口写入“1”时,它们被内部上拉电阻拉高并可作为输入端口。做输入端时,被外部拉低的P3口将用上拉电阻输出电流。P3口除了作为一般的I/O口线外,还有重要的第二功能。
表1-1 P3组主要功能描述
端口引脚 | 第二功能 |
---|---|
P3.0 | RXD(串行输入口) |
P3.1 | TXD(串行输出口) |
P3.2 | INT0*(外中断0) |
P3.3 | INT1*(外中断1) |
P3.4 | T0(定时/计数器0外部输入) |
P3.5 | T1(定时/计数器1外部输入) |
P3.6 | WR*(外部数据存储器写选通) |
P3.7 | RD*(外部数据存储器读选通) |
MFRC522是高度集成的非接触式读写卡芯片,发送模块利用调制和解调的原理,将他们完全集成到各种非接触式通信方法和协议中。
可以用来处理兼容ISO 14443A卡和应答机的信号,数字电路部分处理完整的ISO 14443A帧和错误检测。MFRC522支持更高速的非接触式通信,双向数据传输速率高达424kbit/s。
TVDD:发送器电源,给TX1和TX2的输出级供电。
TX1:发送器1,传递调制的13.56MHz的能量载波信号。
TX2:发送器2,传递调制的13.56MHz的能量载波信号。
TVSS:发送器地,TX1和TX2的输出级的地。
DVSS:数字地
SDA:串行数据线
IRQ:中断请求,输出用来指示的一个中断事件。
OSCIN:晶振输入,振荡器的反相放大器的输入,外部产生的时钟的输入。
OSCOUT:晶振输出,振荡器的反相放大器输出。
RX:接收器输入,接收RF信号的管脚
表2-1 中断标志及情况
中断标志 | 中断源 | 中断标志置位情况 |
---|---|---|
TimerIRq | 定时器 | 定时器计数从1到0 |
TxIRaq | 发送器 | 一次数据流发送结束 |
CRCIRq | CRC协处理器 | 已处理完FIFO缓冲区的所有数据 |
RxIRq | 接收器 | 一次数据流接收结束 |
IdleIRq | 命令寄存器 | 执行完一个命令 |
HiAlertIRq | FIFO缓冲区 | FIFO缓冲区已满 |
LoAlertIRq | FIFO缓冲区 | FIFO缓冲区为空 |
ErrIRq | 非接触式UART | 检测到一个错误 |
LCD液晶显示屏具有4位/8位并行,2线或3线串行多种接口,可显示16*16点汉字,16*8点ASCII字符集,低电压低功耗。
V0:屏幕亮度调整
RS:当RS=’H’ DB7-DB0显示数据,当RS=’L’ DB7-DB0显示指令数据。
R/W:当R/W=’H’,E=’H’,数据被读到DB7-DB0。
E(SCLK):使能信号
PSB: H:8位或4位并口方式,L:串口方式。
(1)若信息字段代码为1011001,对应〖m(x)=x〗^6+x^4+x^3+1;假设生成多项式为g(x)=x^4+x^3+1,对应g(x)代码为11001,x^4 〖m(x)=x〗^10+x^8+x^7+x^4,对应代码为10110010000
(2)采用多项式除法x^4 m(x)/g(x),得到余数1010,校验字段1010
(3)发送方发送的传输字段为10110011010,前7位信息字段,后4位校验字段
(4)接收方使用相同的生成码进行校验,接收到的多项式如果能除尽,则正确。
Private Sub Command1_Click()
Dim sql As String
Dim rs_login As New ADODB.Recordset
If Trim(Text1.Text) = "" Then '判断输入的用户名是否为空
MsgBox "没有这个用户", vbOKOnly + vbExclamation, ""
Text1.SetFocus
Else
sql = "select * from 用户信息表 where 用户名='" & Text1.Text & "'"
rs_login.Open sql, conn, adOpenKeyset, adLockPessimistic
If rs_login.EOF = True Then
MsgBox "没有这个用户", vbOKOnly + vbExclamation, ""
Text1.SetFocus
Else '检验密码是否正确
If Trim(rs_login.Fields(1)) = Trim(Text2.Text) Then
userID = Text1.Text
' userpow = rs_login.Fields(2)
rs_login.Close
Unload Me
Form1.Show
Else
MsgBox "密码不正确", vbOKOnly + vbExclamation, ""
Text2.SetFocus
End If
End If
End If
cnt = cnt + 1
If cnt = 3 Then
Unload Me
End If
Exit Sub
End Sub
Private Sub Command2_Click()
Unload Me
End Sub
Private Sub Form_Load()
Dim connectionstring As String
connectionstring = "provider=Microsoft.Jet.oledb.4.0;" & _
"data source=信息.mdb"
conn.Open connectionstring
cnt = 0
End Sub
Dim vHour%, vState$
'Public qq As Variant
Dim Con As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim sq1 As String
Dim tt As Variant
Dim tt2 As Variant
Dim num As Variant
Dim gg As Variant
'Dim g4 As Variant
Dim a As String
Dim b As String
Dim c As String
'Dim MyInt As Variant
Private Sub COM1_Click() '串口号选择
Combo1.ListIndex = 0
End Sub
Private Sub COM2_Click() '串口号选择
Combo1.ListIndex = 1
End Sub
Private Sub COM3_Click() '串口号选择
Combo1.ListIndex = 2
End Sub
Private Sub COM4_Click() '串口号选择
Combo1.ListIndex = 3
End Sub
Private Sub COM5_Click() '串口号选择
Combo1.ListIndex = 4
End Sub
Private Sub Command1_Click()
Set recRecordset1 = Adodc2.Recordset '复制记录集
Dim sFilterStr As String
Dim xhtj As String '学号条件
Dim xmtj As String '姓名条件
Dim bjtj As String '班级条件
'查询时,若字段不填,则默认查询全部
If Trim(Text6.Text) = "" Then
xhtj = ""
Else
xhtj = "卡号 like '*" & Trim(Text6.Text) & "*'"
End If
If Trim(Text7.Text) = "" Then
xmtj = ""
Else
xmtj = "姓名 like '*" & Trim(Text7.Text) & "*'"
End If
If Trim(Text8.Text) = "" Then
bjtj = ""
Else
xbtj = "班级 like '*" & Trim(Text8.Text) & "*'"
End If
If Trim(Text6.Text) <> "" And Trim(Text7.Text) <> "" Then
xmtj = " and " & xmtj
End If
If (Trim(Text6.Text) <> "" Or Trim(Text7.Text) <> "") And Trim(Text8.Text) <> "" Then
xbtj = " and " & xbtj
End If
sFilterStr = Trim(sFilterStr & xhtj & xmtj & xbtj)
If sFilterStr = "" Then
Adodc2.RecordSource = "select * from 刷卡时间 order by 卡号"
Adodc2.Refresh
Else
recRecordset1.Filter = sFilterStr
End If
DataGrid1.Visible = True
'Adodc2.RecordSource = "select * from 刷卡时间 order by 刷卡时间 desc"
' Adodc2.Refresh
Set DataGrid1.DataSource = Adodc2
End Sub
Private Sub MSComm1_OnComm()
Select Case MSComm1.CommEvent
Case comEvReceive ' 收到 RThreshold # of
Dim hk As Variant
hk = MSComm1.Input
If hk = "Y" Then
tt = 2
MSComm1.RThreshold = 8
tt2 = 1
' Text3.Text = "一号读卡器"
End If
gg = hk
If tt = 2 Then
If gg <> "Y" Then
Text6.Text = gg
Con.Open "provider=Microsoft.jet.OLEDB.4.0;data source=" & App.Path & "\信息.mdb"
sq1 = "select * from 信息 where 卡号='" + gg + "'"
rs.Open sq1, Con
If rs.EOF Then
Text3.Text = ""
Text1.Text = ""
Text2.Text = ""
Text4.Text = ""
Text9.Text = ""
Text10.Text = ""
If MSComm1.PortOpen = True Then '防止串口没有打开 打开发送出错
If tt2 = 1 Then
MSComm1.Output = "D" '给单片机发送E 开关
MSComm1.OutBufferCount = 0 '发送缓冲区清空
End If
' If tt2 = 2 Then
'MSComm1.Output = "F" '给单片机发送E 开关
'MSComm1.OutBufferCount = 0 '发送缓冲区清空
End If
' End If
MSComm1.RThreshold = 1
' MsgBox "此卡号不存在,请检查...", vbExclamation, "查询"
Con.Close
Set rs = Nothing
Set Con = Nothing
Exit Sub
Else
Text1.Text = rs.Fields("姓名")
'Text3.Text = rs.Fields("几栋几楼")
Text2.Text = rs.Fields("性别")
Text3.Text = rs.Fields("部门")
Text9.Text = rs.Fields("工号")
Text10.Text = rs.Fields("状态")
' Text12.Text = rs.Fields("库存")
num = Text12.Text
Text4.Text = vState & a & "/" & b & "/" & c & "/" & Time
If MSComm1.PortOpen = True Then '防止串口没有打开 打开发送出错
If tt2 = 1 Then
MSComm1.Output = "E" '给单片机发送E 开关
MSComm1.OutBufferCount = 0 '发送缓冲区清空
End If
' If tt2 = 2 Then
'MSComm1.Output = "G" '给单片机发送E 开关
' MSComm1.OutBufferCount = 0 '发送缓冲区清空
'' End If
End If
End If
rs.Close
Con.Close
Set rs = Nothing
Set Con = Nothing
If Text10.Text = "上班" Then
If MSComm1.PortOpen = True Then '防止串口没有打开 打开发送出错
MSComm1.Output = "A" '给单片机发送E 开关
MSComm1.OutBufferCount = 0 '发送缓冲区清空
End If
Con.connectionstring = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & App.Path & "\信息.mdb;Persist Security Info=False"
Con.Open
Set rs = Con.Execute("UPDATE 信息 SET 状态= '下班' where 卡号='" + gg + "'")
' Set rs = Con.Execute("UPDATE 信息 SET 库存='" + Text11.Text + "'where 卡号='" + gg + "'")
Con.Close
End If
If Text10.Text = "下班" Then
If MSComm1.PortOpen = True Then '防止串口没有打开 打开发送出错
MSComm1.Output = "B" '给单片机发送E 开关
MSComm1.OutBufferCount = 0 '发送缓冲区清空
End If
Con.connectionstring = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & App.Path & "\信息.mdb;Persist Security Info=False"
Con.Open
Set rs = Con.Execute("UPDATE 信息 SET 状态= '上班' where 卡号='" + gg + "'")
' Set rs = Con.Execute("UPDATE 信息 SET 库存='" + Text11.Text + "'where 卡号='" + gg + "'")
Con.Close
End If
MSComm1.RThreshold = 1
tt = 1
tt2 = 0
Adodc1.connectionstring = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & App.Path & "\信息.mdb;Persist Security Info=False"
Adodc1.RecordSource = "select * from 刷卡时间"
Adodc1.Refresh
Adodc1.Recordset.AddNew '添加新纪录
Adodc1.Recordset("部门").Value = Text3.Text
Adodc1.Recordset("性别").Value = Text2.Text
Adodc1.Recordset("工号").Value = Text9.Text
Adodc1.Recordset("状态").Value = Text10.Text
Adodc1.Recordset("姓名").Value = Text1.Text
Adodc1.Recordset("卡号").Value = Text6.Text
Adodc1.Recordset("刷卡时间").Value = Text4.Text
' Adodc1.Recordset("库存").Value = Text11.Text
Adodc1.Recordset.Update '保存
End If
End If
MSComm1.InBufferCount = 0
Adodc2.Refresh
DataGrid1.Visible = False
Command1.Visible = True
End Select
End Sub
Private Sub oo_Click() '设置波特率9600 2
MSComm1.Settings = "9600,n,8,1"
End Sub
Private Sub qw_Click() '设置波特率56000
MSComm1.Settings = "56000,n,8,1"
End Sub
Private Sub Timer1_Timer()
Text5.Text = vState & a & "/" & b & "/" & c & "/" & Time
End Sub
Private Sub Form_Load()
Adodc1.connectionstring = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & App.Path & "\信息.mdb;Persist Security Info=False"
Adodc1.RecordSource = "select * from 信息"
Timer1.Interval = 10
Data = Now
a = Format(Data, "yyyy")
b = Format(Data, "mm")
c = Format(Data, "dd")
End Sub
Private Sub KSGZ_Click()
g4 = g4 + 1
If g4 = 1 Then
'Call dd_Click
'Combo1.ListIndex = 0
'MSComm3.CommPort = 3
MSComm1.InBufferSize = 8 '设置返回接收缓冲区的大小,以字符为单位。
MSComm1.OutBufferSize = 2
If MSComm1.PortOpen = True Then '关串口
End If
MSComm1.RThreshold = 1 '设置并返回产生oncomm事件的字符数,以字符为单位. Rthreshold 为 1,接收缓冲区收到每一
'个字符都会使 MSComm 控件产生 OnComm 事件。
'MSComm1.SThreshold = 1 '
MSComm1.InputLen = 0 '设置从接收缓冲区读取的字数,为0读取整个缓冲区
MSComm1.InputMode = comInputModeText '以文本方度接收
MSComm1.InBufferCount = 0 '清空接收缓冲区
' MSComm1.PortOpen = True
End If
On Error GoTo BLAK
If MSComm1.PortOpen = True Then
MSComm1.PortOpen = False
MSComm1.CommPort = Combo1.ListIndex + 1
MSComm1.PortOpen = True
Else
MSComm1.CommPort = Combo1.ListIndex + 1
MSComm1.PortOpen = True
End If
Exit Sub
BLAK:
MsgBox "串口不存在或者被占用!", vbOKOnly, "提示信息"
End Sub
Private Sub tt_Click() '设置波特率4800
MSComm1.Settings = "4800,n,8,1"
End Sub
Private Sub ttee_Click()
Form5.Show
End Sub
Private Sub ttt_Click()
Form2.Show
End Sub
Private Sub TZGZ_Click()
If MSComm1.PortOpen = True Then
MSComm1.PortOpen = False
End If
End Sub
Private Sub uu_Click()
Form2.Show
End Sub
Private Sub uu22_Click()
Form4.Show
End Sub
Private Sub ww_Click() '设置波特率1200 2
MSComm1.Settings = "1200,n,8,1"
End Sub
Private Sub xx_Click() '设置波特率2400 2
MSComm1.Settings = "2400,n,8,1"
End Sub
Private Sub yy_Click() '设置波特率4800 2
MSComm1.Settings = "4800,n,8,1"
End Sub
Altium Designer主要进行原理图设计、电路仿真、PCB绘制编辑、拓扑逻辑自动布线、信号完整性分析 和设计输 出等设计。
在PCB部分,多通道复制、实时的、阻抗控制布线功能;SitusTM自动布线器等新功能以外,还着重在:差分对布线,FPGA器件差分对管脚的动态分配, PCB和FPGA之间的全面集成,从而实现了自动引脚优化和非凡的布线效果。还有PCB文件切片,PCB多个器件集体操作,复杂BGA器件的多层自动扇出,提供 了对高密度封装(如 BGA)的交互布线功能, 总线布线功能,器件精确移动,快速铺铜等功能
交互式编辑、出错查询、布线和可视化功能,从而能更快地实现电路板布局,支持高速电路设计,具有成熟的布线后信号完整性分析工具.对差分信号提供系统范围内的支持,可对高速内连的差分信号对进行充分定义、管理和交互式布线。支持包括对在FPGA项目内部定义的LVDS信号的物理设计 进行自动映射。
在原理图部分,可以将一些不同的对象拷贝到原理图当中,原理图文件切片,多个器件集体操作,文本筐的直接编辑,箭头的添加,器件精确移动,总线走线,自动网标选择等!在信号仿真部分,提供完善的混合信号仿真,在对 XSPICE 标准的支持之外,还支持对Pspice模型和电路的仿真。对FPGA设计提供了丰富的IP内核,包括各种处理器、存储器、外设、接口、以及虚拟仪器。
嵌入式设计部分,增强了JTAG器件的实时显示功能,增强型基于FPGA的逻辑分析仪,可以支持32位或64位的信号输入。除了现有的多种处理器内核外,还增强了对更多的32位微处理器的支持,可以使嵌入式软件设计在软处理器,FPGA内部嵌入的硬处理器,分立处理器之间无缝的迁移。使用了Wishbone开放总线连接器允许在FPGA上实现的逻辑模块可以透明的连接到各种处理器上。
发生碰撞的原因:
(1)当多个标签同时接受命令,又同时发出信息,给阅读器造成信息的交叉干扰,以致分不清对象,造成冲突。
(2)多个读写器读同一张标签,同样也会发送信息的碰撞,造成冲突。
防碰撞分析:
(1)PCD为选择的防冲突类型和串联级别分配了带有编码的SEL。
(2)PCD分配了带有值为‘20’的NVB。
(3)PCD发送SEL和NVB。
(4)工作场内的所有PICC应使用它们的完整的UID CLn响应。
(5)假设场内的PICC拥有唯一序列号,那么,如果一个以上的PICC响应,则冲突发生。
(6)PCD应识别出第一个冲突的位置。
(7)PCD分配了带有值的NVB,该值规定了UID CLn有效比特数。这些有效位应是PCD所决定的冲突发生之前被接收到的UID CLn的一部分再加上(0)b或(1)b。典型的实现是增加(1)b。
(8)PCD发送SEL和NVB,后随有效位本身。
(9)只有PICC的UID CLn中的一部分等于PCD所发送的有效位时,PICC才应发送其UID CLn的其余部分。
(10)如果出现进一步的冲突,则重复步骤6~9。最大的环数目是32。
(11)如果不出现进一步的冲突,则PCD分配带有值为‘70’的NVB。
(12)PCD发送SEL和NVB,后随UID CLn的所有40个位,后面又紧跟CRC_A校验和。
(13)它的UID CLn与40个比特匹配,则该PICC以其SAK表示响应。
(14)如果UID完整,则PICC应发送带有清空的串联级别位的SAK,并从READY状态转换到ACTIVE状态。
(15)PCD应检验SAK(选择确认)的串联比特是否被设置,以决定带有递增串联级别的进一步防冲突环是否应继续进行。如果PICC的UID是已知的,则PCD可以跳过步骤2~10来选择该PICC,而无需执行防冲突环。
(1)应用程序通过RFID读写器向电子标签发送认证请求。
(2)电子标签收到请求后向读写器发送一个随机数B。
(3)读写器收到随机数B后,向电子标签发送要验证的密钥加密B的数据包,其中包含了读写器生成的另一个随机数A。
(4)电子标签收到数据包后,使用芯片内部存储的密钥进行解密,解出随机数B并校验与之发出的随机数B是否一致。
(5)如果一致,则RFID使用芯片内部存储的密钥对A进行加密并发送给读写器。
(6)读写器收到数据包后,进行解密,解出A并与之前的A比较是否一致。
(7)如果每一个环节都成功,则验证成功,否则验证失败。
刷卡上班测试
刷卡下班测试
上位机上班结果显示
上位机下班结果显示
多功能按键界面
注销界面
设计最大的亮点就是模块化设计,将执行功能的各个部分封装成一个个模块,即子函数。
在主函数中编写需要调用功能的子函数名即可执行相应的功能,目的是便于修改,减小了对程序大规模的修改,降低了程序编写过程中的出错率。
设计的硬件图考虑到实际应用的需求和视觉审美,尽最大程度的减少电路设计过程中线路的繁杂和无条理性,所以选择标号的方式,既能使电路处于连通的状态又能使电路整体整洁美观。
防碰撞原理的分析是本次设计的最大难点,RC522射频识别采用防碰撞算法去解决读写器同时读多个标签时的冲突问题,采用了流程图的方法,尽可能直观形象的分析防碰撞的原理以及操作过程。逻辑加密卡三次认证的原理通过采用示意图将读写器对标签读写操作前的认证得到了较好的分析和操作。
[1]黄广林.我国单片机技术的应用及发展趋势[J]. 电子技术与软件工程,2017(19):254
[2]周晓光,王晓华.射频识别(RFID)技术原理与应用实例[M].人民邮电出版社,2006.5:35-37.
[3] 李淑琴,范蟠果.射频识别非接触式IC卡读卡器的设计[J].计算机测量与控制,2007,29(3): 378-380.
[4] 严光文,张其善.射频识别卡读写模块的设计[J].北京航空航天大学学报,2003,41(2):74-76.
[5] 安剑,孙秀梅,巩建华.Visual Basic项目开发全程实录.清华大学出版社,2011
[6] 严光文,张其善.射频识别卡读写模块的设计[J].北京航空航天大学学报,2003,41(2):74-76.
[7] 郭天祥.新概念52单片机C语言教程——入门、提高、开发、拓展全攻略[M].北京:电子工业出版社,2008
/**
*函数将我们的寻卡命令PICC_REQIDL装填到要发送的数组,通过
*PcdComMF522函数发送出去,如果此时在PCD有效范围内没有寻找到卡,则函数返回MI_ERR
*若函数返回MI_OK,并且ulen为0x10为两个字节则说明寻卡成功,返回的两个字节被装填入CardRevBuf数组。
*/
char PcdRequest(unsigned char req_code,unsigned char *pTagType)
{
char status;
unsigned int unLen;
unsigned char ucComMF522Buf[MAXRLEN];
ClearBitMask(Status2Reg,0x08);//寄存器包含接收器和发送器和数据模式检测器的状态标志
WriteRawRC(BitFramingReg,0x07);//不启动数据发送
SetBitMask(TxControlReg,0x03);//TX1,TX2输出信号将传递经发送数据调制的13.56MHz的能量载波信号。
ucComMF522Buf[0] = req_code;
status=PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,
ucComMF522Buf,&unLen);//通过522发送req_code命令,并接收返回数据,存到ucComMF522Buf中。
if ((status == MI_OK) && (unLen == 0x10))//因为2个字节是16bit
{
*pTagType = ucComMF522Buf[0];
*(pTagType+1) = ucComMF522Buf[1];
}
else
{ status = MI_ERR; }
return status;
}
/**
*防冲突操作就是将防冲突命令通过PcdComMF522函数与PICC卡进行交互。防冲突命令是两个字节,
*其中第一个字节为Mifare_One卡的防冲突命令字PICC_ANTICOLL1(0X93),
*第二个字节为0x20
*选择代码SEL(1个字节),SEL规定了串联级别CLn。
*有效位的数目NVB(1个字节),NVB规定了PCD所发送的CLn的有效位的数目。
*/
char PcdAnticoll(unsigned char *pSnr)
{
char status;
unsigned char i,snr_check=0;
unsigned int unLen;
unsigned char ucComMF522Buf[MAXRLEN];
ClearBitMask(Status2Reg,0x08);//寄存器包含接收器和发送器和数据模式检测器的状态标志
WriteRawRC(BitFramingReg,0x00);//不启动数据发送,接收的LSB为存放在位0.接受到的第二位防在位1,定义发送的最后一个字节的位数为8
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;
}
//选定卡片
char PcdSelect(unsigned char *pSnr)
{
char status;
unsigned char i;
unsigned int unLen;
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]);//计算CRC装填至ucComMF522Buf[7]
ClearBitMask(Status2Reg,0x08);//寄存器包含接收器和发送器和数据模式检测器的状态标志。
status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,9,
ucComMF522Buf,&unLen);
if ((status == MI_OK) && (unLen == 0x18))//成功返回SAK,包括1字节的SAK和2字节的CRC_A。
{ status = MI_OK; }
else
{ status = MI_ERR; }
return status;
}
void main( )
{
InitializeSystem1( );
OperationCard = 0;
tt=4;
OperationCard = READCARD;
STC_send_bluetooth('J');
InitializeSystem( );
Init_ST7920(); //初始化
ClrScreen();
STC_send_bluetooth('J');
while (1)
{
if (CmdValid)
{
CmdValid = FALSE;
UartProcess();
}
KeyScan();//键盘扫描
if(tt==1)
{
LCD_PutString(0,1," ");
LCD_PutString(0,2," 注册界面 ");
LCD_PutString(0,3," ");
LCD_PutString(0,4," ");
CtrlProcess();//控制处理}
}
if(tt==4)
{
LCD_PutString(0,1," ");
LCD_PutString(0,2," 欢迎使用员工 ");
LCD_PutString(0,3," 考勤管理系统 ");
LCD_PutString(0,4," ");
CtrlProcess();//控制处理}
}
if(tt==5)
{
LCD_PutString(0,1," ");
LCD_PutString(0,2," 注销界面 ");
LCD_PutString(0,3," ");
LCD_PutString(0,4," ");
CtrlProcess();//控制处理}
}
LED=1;
BEEP=1;
iii=0;
}
}
#include
#include
#include "delay.h"
sbit RS = P1^7; //控制端口
sbit RW = P1^6;
sbit E = P1^5;
sbit PSB = P3^2;
sbit PAUSE = P0^3;
sbit RES = P0^2;
#define DataPort P2 //单片机 P2<------> 液晶DB0-DB7
void Check_Busy()
{
RS=0;
RW=1;
E=1;
DataPort=0xff;
while((DataPort&0x80)==0x80);//忙则等待
E=0;
}
void Write_Cmd(unsigned char Cmd)
{
Check_Busy();
RS=0;
RW=0;
E=1;
DataPort=Cmd;
DelayUs2x(5);
E=0;
DelayUs2x(5);
}
void Write_Data(unsigned char Data)
{
Check_Busy();
RS=1;
RW=0;
E=1;
DataPort=Data;
DelayUs2x(5);
E=0;
DelayUs2x(5);
}
void Init_ST7920()
{
DelayMs(40); //大于40MS的延时程序
PSB=1; //设置为8BIT并口工作模式
DelayMs(1); //延时
RES=0; //复位
DelayMs(1); //延时
RES=1; //复位置高
DelayMs(10);
Write_Cmd(0x30); //选择基本指令集
DelayUs2x(50); //延时大于100us
Write_Cmd(0x30); //选择8bit数据流
DelayUs2x(20); //延时大于37us
Write_Cmd(0x0c); //开显示(无游标、不反白)
DelayUs2x(50); //延时大于100us
Write_Cmd(0x01); //清除显示,并且设定地址指针为00H
DelayMs(15); //延时大于10ms
Write_Cmd(0x06); //指定在资料的读取及写入时,设定游标的移动方向及指定显示的移位,光标从右向左加1位移动
DelayUs2x(50); //延时大于100us
}
void LCD_PutString(unsigned char x,unsigned char y,unsigned char *s)
{
switch(y)
{
case 1: Write_Cmd(0x80+x);break;
case 2: Write_Cmd(0x90+x);break;
case 3: Write_Cmd(0x88+x);break;
case 4: Write_Cmd(0x98+x);break;
default:break;
}
while(*s>0)
{
Write_Data(*s);
s++;
DelayUs2x(50);
}
}
void ClrScreen()
{
Write_Cmd(0x01);
DelayMs(15);
}
资源文件下载链接:
基于RFID考勤系统单片机程序
基于RFID考勤系统流程图、原理图
基于RFID考勤系统上位机