【扩展模块】基于QT5的PN532_NFC读卡
【开发环境】1、ubuntu18.04
2、瑞米派SDK
3、QT5.12
【开发步骤】
一、根据瑞米派的原理图,与PN535_NFC的原理图,它们是兼容树霉派的标准接口。根据瑞米派的原理图,我这里确定ttySC4为与PN535_NFC的UART接口。
二、为了实现串口通信,我这里顺便用QT实现了一个串口助手的工程。基实现如下:
1、打开QT设计,新建一个工程,工程中配置GCC与G++为瑞米派的SDK指定的目录,如下图示:
2、配置qmake路径如下:
3、最后配置kit如下:
4、同时由于黙认的镜像包没有拷贝libQt5Serialport.so的这个库文件,
复制SDK的目录/opt/poky/3.1.20/sysroots/aarch64-poky-linux/usr/lib64$下面,他是有libQt5SerialPort.so.5这个文件的,所以直接复制到开发板:
[*]scp libQt5Serial* root@192.168.3.128:/usr/lib64/
[*]
5、设计界面如下:
上面是一个串口助手,可以实现串口的调试。
6、主要代码如下在.pro中添加serial的引用
QT += core gui serialport7、在mainwindow.h中添加相关头文件的引用,并使用设计器生成槽函数,添加一个接收的函数,其代码如下:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtSerialPort>
#include <QString>
#include <QSerialPortInfo>
#include <QMessageBox>
#include <QTimer>
#include <QPainter>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
QSerialPort *serialPort; //定义串口指针
private slots:
/*手动连接槽函数*/
void manual_serialPortReadyRead();
/*以下为mainwindow.ui文件中点击“转到槽”自动生成的函数*/
void on_openBt_clicked();
void on_btnSerialCheck_clicked();
void on_sendBt_clicked();
void on_btnClearSend_clicked();
void on_clearBt_clicked();
void on_chkTimeSend_stateChanged(int arg1);
void on_bntReadIC_clicked();
private:
Ui::MainWindow *ui;
// 发送、接收字节计数
long sendNum, recvNum;
QLabel *lblSendNum;
QLabel *lblRecvNum;
QLabel *lblPortState;
void setNumOnLable(QLabel *lbl, QString strS, long num);
// 定时发送-定时器
QTimer *timSend;
};
#endif // MAINWINDOW_H
8、在mainwindow.cpp代码如下:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QSerialPort"
#include "QSerialPortInfo"
#include "QMessageBox"
#include "QDateTime"
#include "QTimer"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QStringList serialNamePort;
serialPort = new QSerialPort(this);
connect(serialPort, SIGNAL(readyRead()), this,SLOT(manual_serialPortReadyRead()));/*手动连接槽函数*/
ui->serailCb->clear();
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()){
ui->serailCb->addItem(info.portName());
}
sendNum = 0;
recvNum = 0;
QStatusBar *sBar = statusBar();
lblSendNum = new QLabel(this);
lblRecvNum = new QLabel(this);
lblPortState = new QLabel(this);
lblPortState->setText("Conneted");
lblPortState->setStyleSheet("color:red");
lblSendNum->setMinimumSize(100,20);
lblRecvNum->setMinimumSize(100,20);
lblPortState->setMinimumSize(550,20);
setNumOnLable(lblSendNum,"S:",sendNum);
setNumOnLable(lblRecvNum,"R:",recvNum);
sBar->addPermanentWidget(lblPortState);
sBar->addPermanentWidget(lblSendNum);
sBar->addPermanentWidget(lblRecvNum);
// 定时发送-定时器
timSend = new QTimer;
timSend->setInterval(1000);// 设置默认定时时长1000ms
connect(timSend, &QTimer::timeout, this, [=](){
on_sendBt_clicked();
});
}
/*手动实现接收数据函数*/
void MainWindow::manual_serialPortReadyRead()
{
QByteArray recBuf = serialPort->readAll();;
QString str_rev;
// 接收字节计数
recvNum += recBuf.size();
// 状态栏显示计数值
setNumOnLable(lblRecvNum, "R: ", recvNum);
if(recvNum == 19){
ui->lblICID->setText(QString(recBuf.toHex().toUpper().mid(10,8)));
}
if(ui->chk_rev_hex->checkState() == false){
if(ui->chk_rev_time->checkState() == Qt::Checked){
QDateTime nowtime = QDateTime::currentDateTime();
str_rev = "[" + nowtime.toString("yyyy-MM-dd hh:mm:ss") + "] ";
str_rev += QString(recBuf).append("\r\n");
}
else{
// 在当前位置插入文本,不会发生换行。如果没有移动光标到文件结尾,会导致文件超出当前界面显示范围,界面也不会向下滚动。
//ui->recvEdit->appendPlainText(buf);
if(ui->chk_rev_line->checkState() == Qt::Checked){
str_rev = QString(recBuf).append("\r\n");
}
else
{
str_rev = QString(recBuf);
}
}
}else{
// 16进制显示,并转换为大写
QString str1 = recBuf.toHex().toUpper();//.data();
// 添加空格
QString str2;
for(int i = 0; i<str1.length (); i+=1)
{
str2 += str1.mid (i,1);
str2 += " ";
}
if(ui->chk_rev_time->checkState() == Qt::Checked)
{
QDateTime nowtime = QDateTime::currentDateTime();
str_rev = "[" + nowtime.toString("yyyy-MM-dd hh:mm:ss") + "] ";
str_rev += str2.append("\r\n");
}
else
{
if(ui->chk_rev_line->checkState() == Qt::Checked)
str_rev += str2.append("\r\n");
else
str_rev = str2;
}
}
ui->recvEdit->insertPlainText(str_rev);
ui->recvEdit->moveCursor(QTextCursor::End);
}
void MainWindow::setNumOnLable(QLabel *lbl, QString strS, long num)
{
QString strN;
strN.sprintf("%ld", num);
QString str = strS + strN;
lbl->setText(str);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_openBt_clicked()
{
/*串口初始化*/
QSerialPort::BaudRate baudRate;
QSerialPort::DataBits dataBits;
QSerialPort::StopBits stopBits;
QSerialPort::Parity checkBits;
// 获取串口波特率
if(ui->baundrateCb->currentText()=="2400")
baudRate=QSerialPort::Baud2400;
else if(ui->baundrateCb->currentText()=="4800")
baudRate=QSerialPort::Baud4800;
else if(ui->baundrateCb->currentText()=="9600")
baudRate=QSerialPort::Baud9600;
else if(ui->baundrateCb->currentText()=="19200")
baudRate=QSerialPort::Baud19200;
else if(ui->baundrateCb->currentText()=="38400")
baudRate=QSerialPort::Baud38400;
else if(ui->baundrateCb->currentText()=="57600")
baudRate=QSerialPort::Baud57600;
else if(ui->baundrateCb->currentText()=="115200")
baudRate=QSerialPort::Baud115200;
// 获取串口数据位
if(ui->databitCb->currentText()=="5")
dataBits=QSerialPort::Data5;
else if(ui->databitCb->currentText()=="6")
dataBits=QSerialPort::Data6;
else if(ui->databitCb->currentText()=="7")
dataBits=QSerialPort::Data7;
else if(ui->databitCb->currentText()=="8")
dataBits=QSerialPort::Data8;
// 获取串口停止位
if(ui->stopbitCb->currentText()=="1")
stopBits=QSerialPort::OneStop;
else if(ui->stopbitCb->currentText()=="1.5")
stopBits=QSerialPort::OneAndHalfStop;
else if(ui->stopbitCb->currentText()=="2")
stopBits=QSerialPort::TwoStop;
// 获取串口奇偶校验位
if(ui->checkbitCb->currentText() == "none"){
checkBits = QSerialPort::NoParity;
}else if(ui->checkbitCb->currentText() == "奇校验"){
checkBits = QSerialPort::OddParity;
}else if(ui->checkbitCb->currentText() == "偶校验"){
checkBits = QSerialPort::EvenParity;
}else{
}
// 初始化串口属性,设置 端口号、波特率、数据位、停止位、奇偶校验位数
serialPort->setPortName(ui->serailCb->currentText());
serialPort->setBaudRate(baudRate);
serialPort->setDataBits(dataBits);
serialPort->setStopBits(stopBits);
serialPort->setParity(checkBits);
// 根据初始化好的串口属性,打开串口
// 如果打开成功,反转打开按钮显示和功能。打开失败,无变化,并且弹出错误对话框。
if(ui->openBt->text() == "打开串口"){
if(serialPort->open(QIODevice::ReadWrite) == true){
ui->openBt->setText("关闭串口");
// 让端口号下拉框不可选,避免误操作(选择功能不可用,控件背景为灰色)
ui->serailCb->setEnabled(false);
}else{
QMessageBox::critical(this,"错误提示", "串口打开失败!!!\r\n该串口可能被占用\r\n请选择正确的串口" );
}
//statusBar 状态栏显示端口状态
QString sm = "%1 OPEND, %2, 8, NONE, 1";
QString status = sm.arg(serialPort->portName()).arg(serialPort->baudRate());
lblPortState->setText(status);
lblPortState->setStyleSheet("color:green");
}else{
serialPort->close();
ui->openBt->setText("打开串口");
ui->serailCb->setEnabled(true);
QString sm = "%1 ClOSED";
QString status = sm.arg(serialPort->portName());
lblPortState->setText(status);
lblPortState->setStyleSheet("color:red");
}
}
void MainWindow::on_btnSerialCheck_clicked()
{
ui->serailCb->clear();
foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
ui->serailCb->addItem(info.portName());
}
}
void MainWindow::on_sendBt_clicked()
{
QByteArray array;
if(ui->chk_send_hex->checkState() == Qt::Checked){
array = QByteArray::fromHex(ui->sendEdit->toPlainText().toUtf8().data());
}else{
array = ui->sendEdit->toPlainText().toLocal8Bit().data();
}
if(ui->chk_send_line->checkState() == Qt::Checked){
array.append("\r\n");
}
int a = serialPort->write(array);
if(a>0){
sendNum += a;
setNumOnLable(lblSendNum,"S:", sendNum);
}
}
void MainWindow::on_btnClearSend_clicked()
{
ui->sendEdit->clear();
sendNum = 0;
setNumOnLable(lblSendNum,"S:",sendNum);
}
void MainWindow::on_clearBt_clicked()
{
ui->recvEdit->clear();
sendNum = 0;
recvNum = 0;
setNumOnLable(lblSendNum,"S:",sendNum);
setNumOnLable(lblRecvNum, "R:", recvNum);
}
void MainWindow::on_chkTimeSend_stateChanged(int arg1)
{
if(arg1 == 0){
timSend->stop();
ui->txtSendMs->setEnabled(true);
}else{
if(ui->txtSendMs->text().toInt() >= 10){
timSend->start(ui->txtSendMs->text().toInt());
ui->txtSendMs->setEnabled(false);
}else{
ui->chkTimeSend->setCheckState(Qt::Unchecked);
QMessageBox::critical(this, "错误提示", "定时发送的最小间隔为 10ms\r\n请确保输入的值 >=10");
}
}
}
void MainWindow::on_bntReadIC_clicked()
{
QByteArray array;
QString sendstry = "00 00 FF 04 FC D4 4A 01 00 E1 00";
array = QByteArray::fromHex(sendstry.toUtf8().data());
serialPort->write(array);
}
其中on_bntReadIC_clicked,实现了发送获取发送此帧用于探测Mifare Classic 卡的命令。发送以后把IC卡帖进天线,就可以在卡号那里读出IC的卡号:
【总结】
这次米尔提供的PN532——NFC模块为标准树莓派的接口,他可以通过跳钱来使用SPI、I2C、UART来与NFC卡实现通信功能。同时瑞米派也提供了非常好的QT开发SDK。使得驱动非常之容易。接我会偿试使用刷卡实现远程门禁的认证的例程。
请问你有什么问题吗?是哪方面的,硬件还是软件?一般这种读卡模块是IIC或者SPI接口,接线正常的话,可以直接使用linux的接口编程 米尔小超人 发表于 2024-5-6 08:32
请问你有什么问题吗?是哪方面的,硬件还是软件?一般这种读卡模块是IIC或者SPI接口,接线正常的话,可以 ...
我发了帖子,怎么只剩一下个空标题,是论坛的问题吗?
页:
[1]