|
【开发环境】
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这个文件的,所以直接复制到开发板:
5、设计界面如下:
上面是一个串口助手,可以实现串口的调试。
6、主要代码如下在.pro中添加serial的引用
- QT += core gui serialport
复制代码 7、在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。使得驱动非常之容易。接我会偿试使用刷卡实现远程门禁的认证的例程。
|
|