目录
基于C#的一卡通管理系统
【实验目的】
【实验设备】
【实验内容】
【实验步骤】
实验准备
第一部分 界面布局设计
第二部分 添加串口通讯函数及高频标签操作功能函数(部分代码)
第五部分 实验运行效果
基于C#的一卡通管理系统
【实验目的】
- 熟悉 Visual Studio 的使用
- 熟练掌握 C#语言 WinForm 开发
- 熟悉 13.56M TypeA 标签卡操作协议
【实验设备】
1、硬件:13.56M 高频 RFID 模块、ISO14443 TypeA 标签卡,miniUSB 线,PC 电脑;
2、软件: PC 机操作系统 Windows(XP、7、10) + Visual Studio 2022开发环境
【实验内容】
在Visual Studio 平台上使用C#语言Winform 开发基于 13.56M TypeA 标签卡的一卡通管理系统。
【实验步骤】
实验准备
1、在visual Studio 2022中安装和配置C#环境
参考博客:C#学习visual Studio 2022安装与配置详细过程_vs2022怎么配置c#环境-CSDN博客
第一部分 界面布局设计
1、设计界面布局,需要设计一个主界面。通过 Visual Studio 自带的组件完成布局操作。主界面布局参考:(主要包含 Label、TextBox、ComboBox、RadioButton、GroupBox、Button、StatusStrip、ToolStripStatusLabel 组件)
2、各组件属性与事件设置



第二部分 添加串口通讯函数及高频标签操作功能函数(部分代码)
1、在主界面代码中,添加动态获取电脑上的串口并自动添加到串口设置列表中的函数,代码如下:
private void initComComboBox()
{
RegistryKey keyCom =
Registry.LocalMachine.OpenSubKey("Hardware\\DeviceMap\\SerialComm");
mSerialComboBox.Items.Clear();
if (keyCom != null)
{
string[] sSubKeys = keyCom.GetValueNames();
foreach (string sName in sSubKeys)
{
string sValue = (string)keyCom.GetValue(sName);
mSerialComboBox.Items.Add(sValue); mSerialComboBox.SelectedIndex = 0;
}
}
}
2、然后添加串口操作函数,包括打开串口,关闭串口,串口发送和串口接收,其中串口接收使用线程来完成,使用的非阻塞方式,所以间隔 50 毫秒读取一次串口数据,将串口数据存储到缓冲区 byteRecBuff 内,代码如下:
//打开串口
private void openSerial()
{
try
{
SwitchCOMThread(mSerialComboBox.Text);
btnSerialConnect.Enabled = false;
btnSerialDisconnect.Enabled = true;
showMsg("串口:连接成功!");
}
catch (Exception ex)
{
showMsg("串口:" + ex.Message);
}
}
//关闭串口
private void closeSerial()
{
try
{
if (mSerialPort.IsOpen)
{
mSerialPort.Close();
}
//清空缓冲区
iDataIn = 0;
iDataOut = 0;
btnSerialConnect.Enabled = true;
btnSerialDisconnect.Enabled = false;
showMsg("串口:断开连接!");
}
catch (Exception ex)
{
showMsg("串口:" + ex.Message);
}
}
//串口数据发送
private bool serialSend(byte[] msg)
{
if (mSerialPort.IsOpen)
{
try
{
mSerialPort.Write(msg, 0, msg.Length);
return true;
}
catch (Exception ex)
{
showMsg("串口:" + ex.Message);
return false;
}
}
else
{
showMsg("串口:请先建立连接!");
}
return false;
}
//串口数据接收
private void serialReceive()
{
if (mSerialPort.IsOpen)
{
try
{
int i = 0;
int iDataLen = mSerialPort.BytesToRead;
if (iDataLen > 50) iDataLen = 50;
//读取缓冲区的数据到数组
mSerialPort.Read(bytesData, 0, iDataLen);
if (bLock == false)
{
bLock = true;
if (iDataIn + iDataLen <= MaxLen)
{
for (i = 0; i < iDataLen; i++)
{
byteRecBuff[iDataIn + i] = bytesData[i];
}
iDataIn += iDataLen;
}
else if (iDataIn + iDataLen == MaxLen)
{
for (i = 0; i < iDataLen; i++)
{
byteRecBuff[iDataIn + i] = bytesData[i];
}
iDataIn = 0;
}
else
{
for (i = iDataIn; i < MaxLen; i++)
{
byteRecBuff[i] = bytesData[i - iDataIn];
}
for (i = 0; i < iDataLen - MaxLen + iDataIn; i++)
{
byteRecBuff[i] = bytesData[i + MaxLen - iDataIn];
}
iDataIn = iDataLen - MaxLen + iDataIn;
}
bLock = false;
}
}
catch (Exception ex)
{
showMsg("串口:" + ex.Message);
bLock = false;
}
}
//接收数据线程
private void serialThreadReceive()
{
while (bThread)
{
serialReceive(); Thread.Sleep(50);
}
}
//启动接收线程
private void recvThreadStart()
{
Thread newthread = new Thread(new ThreadStart(serialThreadReceive));
newthread.Start();
}
//关闭接收线程
private void recvThreadStop()
{
bThread = false;
}
3、再添加从串口缓冲区内将数据读取并初步提取的函数,代码如下:
private void scanData()
{
if (bLock == false)
{
bLock = true;
int iValidLen, iPacketLen;
while (iDataIn != iDataOut)
{
if (byteRecBuff[dataOutAdd(0)] == (byte)0x00 && byteRecBuff[dataOutAdd(1)]== (byte)0x00 && byteRecBuff[dataOutAdd(2)] == (byte)0xFF)//判断包头
{
if (byteRecBuff[dataOutAdd(3)] == (byte)0x00)
{
iDataOut = dataOutAdd(6);
bLock = false;
//包含有效数据长度
iValidLen = validReceiveLen();
if (iState == 0 && iValidLen < 8)
{
HF1356MReadUid();
}
return;
}
else
{
//包含有效数据长度
iValidLen = validReceiveLen();
if (iValidLen < 8)
{
bLock = false;
return;
}
iPacketLen = byteRecBuff[dataOutAdd(3)] + 7;
if (iValidLen < iPacketLen)
{
bLock = false;
return;
}
// 判断数据包是否完整
if (iPacketLen > 7 && iPacketLen < 40)
{
//读出一个数据包
byte[] Packet = new byte[iPacketLen];
for (int i = 0; i < iPacketLen; i++)
{
Packet[i] = byteRecBuff[dataOutAdd(i)];
}
handleData(Packet);
iDataOut = dataOutAdd(iPacketLen);
bLock = false;
return;
}
}
}
iDataOut = dataOutAdd(1);
}
bLock = false;
}
//返回数据缓冲区内的有效数据长度
private int validReceiveLen()
{
if (iDataOut < iDataIn)
{
return (iDataIn - iDataOut);
}
else if (iDataOut > iDataIn)
{
return (MaxLen - iDataOut + iDataIn);
}
return 0;
}
//返回后面第 iNum 有效数据的位置
private int dataOutAdd(int iNum)
{
int ret = 0;
if (iDataOut + iNum < MaxLen)
{
ret = iDataOut + iNum;
}
else if (iDataOut + iNum > MaxLen)
{
ret = iDataOut + iNum - MaxLen;
}
return ret;
}
第五部分 实验运行效果
1、将实验箱通电,使用 MiniUSB 线连接 PC 机和 13.56M 模块,同时将模块上的拨码开关拨到右边(USB),这样才能保证模块和 PC 能够正常通讯;
2、运行程序“EcardSystem.exe”,程序运行成功后主登录界面,此时暂时无法操作扣费系统也无法操作充值系统,如下图:
3、软件中选择正确的串口号(在设备管理器当中查看 USB 转串口的串口号,如果未出现串口号,需要先安装 CP2102 USB 转串口驱动)并点击连接,此时程序会自动发送唤醒模块的指令,如果唤醒成功,扣费系统和充值系统就可以正常使用了;