Tiny6410與RFID讀卡器通訊,並實現LED模擬控制和QT顯示(階段總結)
阿新 • • 發佈:2019-01-22
本裝置現階段實現的基本功能如下:(1)RFID讀卡器接收到便籤資訊並通過串列埠傳送給6410開發板,6410根據《XSS協議》對資料進行封裝,其作為tcp client通過socket 與伺服器進行通訊,這類6410只是將串列埠資料轉發給網口,只是一個單向的通訊過程。
(2)另一類是是tcp client發給server後,還需要接收server的回覆。接收到的回覆資訊後要進行兩類操作:控制功能(LED燈)和介面顯示(觸控式螢幕顯示)。
(1)首先介紹通訊功能
這裡麵包括單向和雙向通訊過程,在雙向通訊過程中控制LED和生成txt檔案,供qt顯示時使用。
注意:用了一些自己編寫的API,後面會將所有工程檔案上傳,方便學習使用,這裡只介紹核心程式碼。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/stat.h> #include <fcntl.h> #include <assert.h> #include <netdb.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include "../wrap.h" #define SERV_PORT 2000 int main(int argc,char ** argv) { int led_fd,k;//LEDs int sockfd,n_selt; int n,i; FILE *matchfile; // declare FILE pointers生成的檔案的描述符 int fp,comnum;//串列埠檔案描述符,從串列埠讀到的個數 //char buf[100]; char com_buf[17]={0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00};//儲存從串列埠讀到的裝置號,天線號,ID號 char buf_send[18]={0xAA,0x01,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xEE};//通訊協議2_1:向上位機發送裝置號,ID號,請求下灰 char buf_rece[14];//通訊協議2_2:上位機返回匹配資訊,是否允許下灰14 struct sockaddr_in servaddr; fd_set rfds;//,wfds; struct timeval timeout={900,0};//900s led_fd = open( "/dev/leds", 0); // LED燈初始化 if (led_fd<0) { printf("opne device error\n"); exit(1); } else printf("open successful\n"); for(k=0; k< 4; k++) //關閉所有LEDS ioctl(led_fd,0,k);//第二個引數是開1|關0,第三個引數是led標號 從0~3 fp=open_port(fp,2);//接ARM11Tiny6410開發板靠近USB口和黃色視訊輸出線的串列埠 /*設定串列埠:波特率9600,資料位8位,無校驗位,停止位1位*/ if(set_opt(fp,9600,8,'N',1)<0) { perror("Set_opt error!\n"); return; } sockfd=Socket(AF_INET,SOCK_STREAM,0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; inet_pton(AF_INET, "192.168.1.100", &servaddr.sin_addr); servaddr.sin_port = htons(SERV_PORT); Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); while(1){ sleep(1); while( (comnum=read(fp,com_buf,sizeof(com_buf))) == 0 ){//從串列埠讀取RFID,沒有就延時再讀 sleep(1); } printf("reading for com is %d\n",comnum); buf_send[2] = com_buf[1]; //將從串列埠讀到的RFID資料儲存,新增裝置號 for(i=2; i<14; i++) buf_send[i+1] = com_buf[i]; //新增ID號 printf("Sending to server:\n"); for(i=0; i< 18; i++) printf("%X ",buf_send[i]); printf("\n"); //tt: write(sockfd, buf_send, sizeof(buf_send)); if(buf_send[2] > 0x03){ //4-15號裝置對應的PLC才會收到資料 usleep(1000); FD_ZERO(&rfds); FD_SET(sockfd,&rfds); // FD_ZERO(&wfds); // FD_SET(sockfd,&wfds); n_selt=select(sockfd+1,&rfds,NULL,NULL,&timeout); switch(n_selt){ case -1: perror("select error\n"); exit(0);break; case 0: perror("time out\n");break; //goto tt ; default: if(FD_ISSET(sockfd,&rfds)){ printf("Receving from server:\n"); n = read(sockfd, buf_rece, sizeof(buf_rece)); if ( (matchfile = fopen("match.txt", "w")) == NULL ) //檔案初始化match.txt,引數w:沒有就新建,每次都覆蓋 { fprintf(stderr, "I couldn't open the file \"match.txt\"\n"); exit(2); } for(i=0;i<sizeof(buf_rece);i++){ //車牌號,灰級,匹配資訊(控制檯)顯示部分 if((i>=3)&&(i<=8)){ printf("%c ",buf_rece[i]); fprintf(matchfile,"%c",buf_rece[i]); //儲存6位車牌號到match.txt } else printf("%X ",buf_rece[i]); } printf("\n"); fprintf(matchfile,"%c",','); //寫入一個分割符號 fprintf(matchfile,"%c",buf_rece[9]+0x30); //灰級1 2 3 fprintf(matchfile,"%c",','); //寫入一個分割符號 if(0x11 == buf_rece[10]) fprintf(matchfile,"%c",'1'); //匹配 1 else fprintf(matchfile,"%c",'2'); //不匹配2 if (fclose(matchfile) != 0) //不關閉的話,檔案裡面沒有內容 fprintf(stderr,"Error matchfile closing files\n"); if(0x11 == buf_rece[10]) //控制部分 { for(k=0; k< 4; k++) ioctl(led_fd,1,k); //匹配成功,開燈 sleep(10); for(k=0; k< 4; k++) ioctl(led_fd,0,k); //延時30s關閉 } else { for(k=0; k< 4; k++) ioctl(led_fd,0,k); } } } } } Close(sockfd); return 0; }
if(buf_send[2] > 0x03){ //4-15號裝置對應的PLC才會收到資料,說明1 2 3號裝置進行單項通訊;4號及4號以上的裝置進行的是雙向通訊。
(2)然後介紹qt顯示部分
其工作原理是每隔500ms讀取match.txt檔案一次並把其內容顯示到觸控式螢幕上
1)介紹main.cpp,標紅的
//中文支援
三行語句是讓程式支援中文顯示的。
2)介紹widget.h,標紅的語句#include <QtGui/QApplication> #include "widget.h" #include <QTextCodec> //UTF-8 Head file int main(int argc, char *argv[]) { QApplication a(argc, argv); //中文支援 QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")); QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8")); //支援Tr中文 QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));//支援中文檔名顯示 Widget w; w.show(); return a.exec(); }
void on_fileChanged();
是宣告一個自定義的槽函式#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_fileChanged();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
3)介紹widget.cpp,這是程式最核心的部分
#include "widget.h"
#include "ui_widget.h"
#include <QTextCodec>
#include <QTextStream>
#include <QFile>
#include <QString>
#include <QDebug>
#include <QFileSystemWatcher>
#include <QtGui>
#include <QTimer>
#include <QBitArray>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(on_fileChanged()));
timer->start(500);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_fileChanged()
{
QTextCodec * code=QTextCodec::codecForName("utf8");
QFile file("match.txt");
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
qDebug()<<"QT Cannot open file for Reading";
return;
}
QTextStream stream(&file);
stream.setCodec(code);
ui->lineEdit->clear();
ui->lineEdit_2->clear();
ui->lineEdit_3->clear();
while(stream.atEnd()==0)
{
QString line=stream.readLine();
QStringList list=line.split(",");
ui->lineEdit->setText(tr("鄂")+list.at(0));
int i=list.at(1).toInt();
switch(i)
{
case 1: ui->lineEdit_2->setText(tr("一級"));break;
case 2: ui->lineEdit_2->setText(tr("二級"));break;
case 3: ui->lineEdit_2->setText(tr("三級"));break;
case 4: ui->lineEdit_2->setText(tr("原灰"));break;
default: break;
}
switch(list.at(2).toInt())
{
case 1:ui->lineEdit_3->setText(tr("匹配"));break;
case 2:ui->lineEdit_3->setText(tr("不匹配"));break;
default: break;
}
}
}
match。txt檔案內容如下圖
(3)最後進行整合
要讓所有的程式按照預期的執行,第一步是關掉Tiny6410開機自啟動的led流水燈,不然不能獲得led燈的控制權了;第二步關掉Tiny6410開機自啟動的Qtopia,不然回造成顯示介面的重疊混亂;第三步後臺執行我們自己寫的qt程式;第四步啟動arm版上的通訊程式(注:需要先啟動tcp server),至此整個通訊所有的準備工作都完成了。
我將上面的四步工作整合成一個sh檔案,操作更加簡便。
start_qt_client.sh
#!/bin/sh
/etc/rc.d/init.d/leds stop
killall qpe
killall quicklauncher
killall qss # Three to close Qtopia
qt ./match & # run in background
./all_client