接觸QT三年有余,期間因為工作需要斷斷續續學習過,2010年開始接觸,當時好像是4.7版本,現在都已經到5.2版本了,更新真快,前陣子安裝了下5.2版本,還是有很多變化的,不過感覺好像編譯速度慢了很多,而且編譯出來的可執行文件需要附帶的DLL多了很多,感覺不爽,所以還是回到了4.7版本的開發,一個重要原因是現在大部分的開發板都移植好了4.7版本的運行庫,可以方便的將WINDOWS程序移植到嵌入式linux下,5.0以上的版本貌似還沒有哪家公司移植到了嵌入式linux上,估計有很多個人已經移植過。
QT也是一套C++框架,和VC++類似,和VC一樣有個好處就是編譯好的可執行程序,一般不需要安裝什么框架的,附帶DLL就行,內存要求非常低,這個很適合在嵌入式設備上面跑。之前用.NET做了三年的項目開發,每當在客戶電腦上面安裝一個幾十兆的框架時,甚是不爽,經過了三年多的比較,最終選用QT作為以后的開發首選。經過EnigmaVirtualBox7.0.exe這個工具的壓縮,還可以將可執行程序封包到一個EXE,屢試不爽!
之前一直在網絡上面參考別人的代碼,現在也該拿出自己的一些東西來分享分享了,這個系列將會粗略的講解一些工具和小項目的開發過程及遇到的難題和解決辦法,將會全部開源並提供下載地址,其實這個開發之旅是有過一定的基礎的,所以基礎的東西可能都是一筆帶過。需要讀者自己下載源碼去研究,閱讀別人的代碼還是可以學習到很多東西的,就算是一個循環一個簡單的文本存儲,都會有一些技巧在里面,我開源出來的代碼不一定都是沒問題的,但是確實是經過自己幾經雕琢封裝好的,還是有一定借鑒價值哦!
用DS7400主機調試工具作為開發之旅的第一個項目,是因為之前用.NET寫過,而且陸續有很多人看到過加過我QQ咨詢過,自己也用在多個商業項目中,所以把這個單獨提取出來發布出來,直接一個可執行程序無需任何框架就可以在windows98以上的電腦上跑,甚是爽!
項目名稱:DS7400主機調試工具
開發環境:WIN7+QT4.7+QT CREATOR2.8+MINGW
技術實現:通過串口與DS7400報警主機通信,解析協議並作出處理
實現功能:主機布防撤防,防區故障斷開旁路報警等
運行截圖:
粗略步驟:
第一步:准備QT串口通信文件,QT4.7沒有包含串口通信的相關類,到了5.1后面的版本才有,所以需要引入第三方的串口類,毫無疑問在QT中網上用的絕大部分都是這幾個文件win_qextserialport.h,win_qextserialport.cpp,qextserialbase.h,qextserialbase.cpp,源碼都已經提供,在對應項目中右鍵選擇添加現有文件,選擇這四個文件。
第二步:添加主界面,放置好對應控件,並命名。
第三步:自定義報警按鈕控件,就是一旦布防撤防報警等狀態出現的時候,對應顏色改變,這里我是用的貼圖,有狀態改變時,對應背景圖改變,源碼里的mybuttonalarm類還封裝了三種報警按鈕樣式。核心代碼很簡單如下:
void myButtonAlarm::paintEvent(QPaintEvent *event) { QPainter painter(this); QPixmap pixMap(this->CurrentImage); QFont font("Arial",10,QFont::Bold,true); QRectF rect(0,0,32,47); painter.setFont(font); painter.drawPixmap(0,0,32,32,pixMap); painter.drawText(rect,Qt::AlignBottom | Qt::AlignCenter,this->defenceID); }
就是將對應圖片和文字畫上去。
第四步:封裝DS7400主機通信類。
博世DS7400主機通信協議格式
格式依次為: 85 18 09 6B(示例)
第一位為標識,第二位為事件類型(0E布防0D撤防07報警等),第三位為防區號(對應16進制轉換成10進制加一,例如09轉成10進制為09,再加一是10,對應010防區),第四位是校驗碼
布防:85 0E 00 74
報警主機:123 主機防區/分區:1 報警主機消息:AREA_ARM_DS7400
撤防:85 0D 00 77
報警主機:123 主機防區/分區:1 報警主機消息:AREA_DISARM_DS7400
取消報警:85 0C 00 76
報警主機:123 主機防區/分區:1 報警主機消息:CANCEL_ALARM_DS7400
正常:A0 02 5D
接收到DS7400主機狀態報告
09防區:撤防狀態與布防狀態
正常斷開:85 18 08 6A
報警主機:123 主機防區/分區:9 報警主機消息:ZONE_OPEN_DS7400
正常連上:85 19 08 6B
報警主機:123 主機防區/分區:9 報警主機消息:ZONE_RESTORE_DS7400
報警斷開:85 18 08 6A 85 07 08 75
報警主機:123 主機防區/分區:9 報警主機消息:ZONE_OPEN_DS7400
報警主機:123 主機防區/分區:9 報警主機消息:BURGLAR_ZONE_ALARM_DS7400
報警連上:85 19 08 6B 85 11 08 63
報警主機:123 主機防區/分區:9 報警主機消息:ZONE_RESTORE_DS7400
報警主機:123 主機防區/分區:9 報警主機消息:ZONE_ALARM_RESTORE_DS7400
旁路:85 0F 08 7D
報警主機:123 主機防區/分區:9 報警主機消息:FORCED_BYPASS_DS7400
第五步:實例化串口類,通信。
void frmMain::on_btnOpen_clicked() { if (ui->btnOpen->text()=="打開串口") { QString port=ui->cboxPortName->currentText(); DS7400->SetHostID(""); DS7400->SetHostName(""); DS7400->SetHostType(""); DS7400->SetHostAddr(1); DS7400->SetHostConnectType("COM"); DS7400->SetHostConnectValue(port); if (DS7400->Open()) { connect(DS7400,SIGNAL(Connect(QString)),this,SLOT(Connect())); connect(DS7400,SIGNAL(DisConnect(QString)),this,SLOT(DisConnect())); connect(DS7400,SIGNAL(BuFang(QString,int)),this,SLOT(BuFang())); connect(DS7400,SIGNAL(CheFang(QString,int)),this,SLOT(CheFang())); connect(DS7400,SIGNAL(BaoJing(QString,QString)),this,SLOT(BaoJing(QString,QString))); connect(DS7400,SIGNAL(DuanKai(QString,QString)),this,SLOT(DuanKai(QString,QString))); connect(DS7400,SIGNAL(GuZhang(QString,QString)),this,SLOT(GuZhang(QString,QString))); connect(DS7400,SIGNAL(HuiFu(QString,QString)),this,SLOT(HuiFu(QString,QString))); connect(DS7400,SIGNAL(PangLu(QString,QString)),this,SLOT(PangLu(QString,QString))); ui->btnOpen->setText("關閉串口"); this->AddMessage("打開串口成功"); } else { this->AddMessage("打開串口失敗"); } } else { DS7400->Close(); disconnect(DS7400,SIGNAL(Connect(QString)),this,SLOT(Connect())); disconnect(DS7400,SIGNAL(DisConnect(QString)),this,SLOT(DisConnect())); disconnect(DS7400,SIGNAL(BuFang(QString,int)),this,SLOT(BuFang())); disconnect(DS7400,SIGNAL(CheFang(QString,int)),this,SLOT(CheFang())); disconnect(DS7400,SIGNAL(BaoJing(QString,QString)),this,SLOT(BaoJing(QString,QString))); disconnect(DS7400,SIGNAL(DuanKai(QString,QString)),this,SLOT(DuanKai(QString,QString))); disconnect(DS7400,SIGNAL(GuZhang(QString,QString)),this,SLOT(GuZhang(QString,QString))); disconnect(DS7400,SIGNAL(HuiFu(QString,QString)),this,SLOT(HuiFu(QString,QString))); disconnect(DS7400,SIGNAL(PangLu(QString,QString)),this,SLOT(PangLu(QString,QString))); ui->btnOpen->setText("打開串口"); this->AddMessage("關閉串口成功"); } }
第六步:實現具體槽函數
void frmMain::AddMessage(QString Message) { ui->txtData->append(QString("收到消息:%1 時間:%2") .arg(Message) .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"))); } void frmMain::Connect() { this->AddMessage("主機上線"); } void frmMain::DisConnect() { this->AddMessage("主機下線"); } void frmMain::BuFang() { int count=ui->gboxMain->children().count(); for (int i=0;i<count;i++) { myButtonAlarm *btn=(myButtonAlarm *)ui->gboxMain->children().at(i); btn->SetDefenceStatus(DefenceStatusBuFang); } this->AddMessage("主機布防"); } void frmMain::CheFang() { int count=ui->gboxMain->children().count(); for (int i=0;i<count;i++) { myButtonAlarm *btn=(myButtonAlarm *)ui->gboxMain->children().at(i); btn->SetDefenceStatus(DefenceStatusCheFang); } this->AddMessage("主機撤防"); } void frmMain::BaoJing() { int count=ui->gboxMain->children().count(); for (int i=0;i<count;i++) { myButtonAlarm *btn=(myButtonAlarm *)ui->gboxMain->children().at(i); btn->SetDefenceStatus(DefenceStatusBaoJing); } this->AddMessage("主機報警"); } void frmMain::PangLu() { int count=ui->gboxMain->children().count(); for (int i=0;i<count;i++) { myButtonAlarm *btn=(myButtonAlarm *)ui->gboxMain->children().at(i); btn->SetDefenceStatus(DefenceStatusPangLu); } this->AddMessage("主機旁路"); } void frmMain::DuanKai() { int count=ui->gboxMain->children().count(); for (int i=0;i<count;i++) { myButtonAlarm *btn=(myButtonAlarm *)ui->gboxMain->children().at(i); btn->SetDefenceStatus(DefenceStatusDuanKai); } this->AddMessage("主機斷開"); } void frmMain::GuZhang() { int count=ui->gboxMain->children().count(); for (int i=0;i<count;i++) { myButtonAlarm *btn=(myButtonAlarm *)ui->gboxMain->children().at(i); btn->SetDefenceStatus(DefenceStatusGuZhang); } this->AddMessage("主機故障"); } void frmMain::BaoJing(QString hostID, QString defenceID) { int count=ui->gboxMain->children().count(); for (int i=0;i<count;i++) { myButtonAlarm *btn=(myButtonAlarm *)ui->gboxMain->children().at(i); if (btn->GetDefenceID()==defenceID) { btn->SetDefenceStatus(DefenceStatusBaoJing); break; } } this->AddMessage(QString("%1防區報警").arg(defenceID)); } void frmMain::DuanKai(QString hostID, QString defenceID) { int count=ui->gboxMain->children().count(); for (int i=0;i<count;i++) { myButtonAlarm *btn=(myButtonAlarm *)ui->gboxMain->children().at(i); if (btn->GetDefenceID()==defenceID) { btn->SetDefenceStatus(DefenceStatusDuanKai); break; } } this->AddMessage(QString("%1防區斷開").arg(defenceID)); } void frmMain::GuZhang(QString hostID, QString defenceID) { int count=ui->gboxMain->children().count(); for (int i=0;i<count;i++) { myButtonAlarm *btn=(myButtonAlarm *)ui->gboxMain->children().at(i); if (btn->GetDefenceID()==defenceID) { btn->SetDefenceStatus(DefenceStatusGuZhang); break; } } this->AddMessage(QString("%1防區故障").arg(defenceID)); } void frmMain::HuiFu(QString hostID, QString defenceID) { int count=ui->gboxMain->children().count(); for (int i=0;i<count;i++) { myButtonAlarm *btn=(myButtonAlarm *)ui->gboxMain->children().at(i); if (btn->GetDefenceID()==defenceID) { btn->SetDefenceStatus(DefenceStatusCheFang); break; } } this->AddMessage(QString("%1防區恢復").arg(defenceID)); } void frmMain::PangLu(QString hostID, QString defenceID) { int count=ui->gboxMain->children().count(); for (int i=0;i<count;i++) { myButtonAlarm *btn=(myButtonAlarm *)ui->gboxMain->children().at(i); if (btn->GetDefenceID()==defenceID) { btn->SetDefenceStatus(DefenceStatusPangLu); break; } } this->AddMessage(QString("%1防區旁路").arg(defenceID)); }
這里采用QString(“”)而不是tr(“”) ,之前看過某人說過要慎用tr,確實,tr是用來國際化的,如果需要字符串拼接,可以用QString(“%1”).arg(“”)這種占位符形式,很方便。和.NET里面的string.Forrmat用法一樣。
博客園上傳資源大小有限,所以放到了CSDN上面,如有不便還請見諒,可以向私人索取!
可執行文件下載地址:http://download.csdn.net/detail/feiyangqingyun/6708143
源碼猛點這里:http://download.csdn.net/detail/feiyangqingyun/6708149