本框架在QT4.8.6版本环境下编写。

一、业务逻辑的诞生

1.1 了解一下什么是AT指令

1.2 思考在QT上如何处理AT指令

看了下网上大多数人实现的在Linux下的4G模块AT指令收发控制,以及在QT上实现的,还有某些厂商实现的解析框架,其实就是在处理串口的收发,但未免做得有点糙,问题点也很多,比如很多人压根就没做指令回复的超时处理,万一要是发生了,那将给整个程序带来致命性的伤害。

最近的项目上需要在QT上处理AT指令的发送和回复,基于这样的环境,于是我决定实现两条线程,一条用于处理设备的初始化,一条用于处理在主进程指令的发送,由于AT指令收发存在延时,所以直接在主进程上延时,QT主进程就卡死了,这就是为什么我一定要用线程去处理的结果。

1.3 特别提醒

如果是在Linux操作串口设备,qt也要有相应的权限,使用如下指令即可。

sudo qtcreator &

二、移植通用串口框架到QT上

三、Gobal_Item_flag.h

该文件主要是用于串口通信模块(支持AT指令)、以及一些全局参数的定义。

#ifndef GOBAL_ITEM_FLAG_H

#define GOBAL_ITEM_FLAG_H

#include "posix_qextserialport.h"

#define __NBIOT

#define DEV_NAME "/dev/ttyUSB0"

#define RECV_DATA_LEN 1024

extern char recv_buffer[RECV_DATA_LEN];

//AT_CMD_DEFINE Start

#ifdef __NBIOT

#define AT_TEST_OK "AT"

#define GET_IMSI "AT+CIMI"

#define GET_SIGNAL "AT+CSQ"

#define GET_SUPPORT_NBAND "AT+NBAND=?"

#define GET_CURRENT_NBAND "AT+NBAND?"

#define SET_NBAND "AT+NBAND=5"

#define GET_CGATT "AT+CGATT"

#define CREATE_TCP_SOCKET "AT+NSOCR=STREAM,6,56000,1"

#define CONNECT_TCP_SERVER "AT+NSOCO=1,120.78.136.134,9002"

#define HARDWARE_RESET "AT+NRB"

#elif __ESP8266

#define AT_TEST_OK "AT"

#define AT_SET_MODE "AT+CWMODE=%d"

#define AT_CONNECT_ROUTER "AT+CWJAP=\"%s\",\"%s\""

#define AT_CONNECT_SERVER "AT+CIPSTART=\"%s\",\"%s\",%d"

#define AT_SET_CIP_MODE "AT+CIPMODE=1"

#define AT_ENTER_CIP_MODE "AT+CIPSEND"

#elif __ME3630

#define AT_TEST_OK "AT"

#define CREATE_TCP_SOCKET "AT+ZIPCALL=1"

#define CONNECT_TCP_SERVER "AT+ZIPOPEN=1,0,120.78.136.134,9001"

#define AT_SEND_DATA "AT+ZIPSEND=1,%s";

#endif

//AT_CMD_DEFINE End

#endif // GOBAL_ITEM_FLAG_H

四、网络接口线程定义

头文件network_interface.h

#ifndef NETWORK_INTERFACE_H

#define NETWORK_INTERFACE_H

#include

#include

#include

#include

#include "Gobal_Item_flag.h"

class NetWork_Interface : public QThread

{

Q_OBJECT

public:

explicit NetWork_Interface(QObject *parent = 0);

~NetWork_Interface();

//if Status is True,Thread is stop,else is Runing

void NetWork_Thread_change(bool Status);

int Send_AT_Cmd(QString cmd_buffer,const char *success_ack,const char *error_ack,int timeout);

private:

Posix_QextSerialPort *NetWork_Port ;

volatile bool Stop_flag ;

int Uart_Init(const char *dev_name,BaudRateType BaudRate,DataBitsType DataBits, \

ParityType ParityBits,StopBitsType StopBits,FlowType FlowControl,int TimeOut);

protected:

void run();

signals:

public slots:

};

#endif // NETWORK_INTERFACE_H

这里实现了串口的初始化,线程状态的控制,线程函数执行以及AT指令的发送函数。

接口实现network_interface.cpp

#include "network_interface.h"

//全局串口数据接收缓存区

char recv_buffer[RECV_DATA_LEN] = {0};

//串口初始化

int NetWork_Interface::Uart_Init(const char *dev_name,BaudRateType BaudRate,DataBitsType DataBits, \

ParityType ParityBits,StopBitsType StopBits,FlowType FlowControl,int TimeOut)

{

this->NetWork_Port = new Posix_QextSerialPort(dev_name,QextSerialBase::Polling);

if(NetWork_Port->open(QIODevice::ReadWrite))

{

this->NetWork_Port->setBaudRate(BaudRate);

this->NetWork_Port->setDataBits(DataBits);

this->NetWork_Port->setParity(ParityBits);

this->NetWork_Port->setStopBits(StopBits);

this->NetWork_Port->setFlowControl(FlowControl);

this->NetWork_Port->setTimeout(TimeOut);

return 0 ;

}

return 1 ;

}

NetWork_Interface::NetWork_Interface(QObject *parent) :

QThread(parent)

{

int ret = Uart_Init(DEV_NAME,BAUD9600,DATA_8,PAR_NONE,STOP_1,FLOW_OFF,200);

if(0 != ret)

{

qDebug() << "Open Device Fail..." ;

this->NetWork_Thread_change(true);

return ;

}

//改变线程的状态为执行

this->NetWork_Thread_change(false);

}

NetWork_Interface::~NetWork_Interface()

{

this->NetWork_Port->close();

delete this->NetWork_Port;

}

//Change Thread Status

void NetWork_Interface::NetWork_Thread_change(bool Status)

{

Stop_flag = Status ;

}

//Runing Init Thread

void NetWork_Interface::run()

{

qDebug() << "Open Device Success....Start Uart_Recv Thread";

//Init Device

while(!Stop_flag)

{

QThread::msleep(200);

}

}

/AT指令收发

/*

cmd_buffer:要发送的AT指令,不需要带\r\n

success_ack:成功的预言字符串

error_ack:错误的语言字符串

timeout:超时,意思是如果发送超过timeout定义的,即返回超时失败。

return : 0 成功 1失败 -1超时

*/

int NetWork_Interface::Send_AT_Cmd(QString cmd_buffer,const char *success_ack,const char *error_ack,int timeout)

{

char *cmd = NULL;

char *send_cmd = NULL ;

QByteArray Byte_Data,temp;

temp.clear();

memset(recv_buffer,0,1024);

cmd_buffer.append("\r\n");

Byte_Data = cmd_buffer.toLatin1();

send_cmd = Byte_Data.data();

this->NetWork_Port->write(send_cmd);

while(timeout--)

{

temp.clear();

memset(recv_buffer,0,1024);

temp = this->NetWork_Port->readAll();

cmd = temp.data();

strcpy(recv_buffer,cmd);

if(strstr(recv_buffer,error_ack) != NULL)

{

qDebug() << "ackerror:" << recv_buffer ;

return 1 ;

}

if(strstr(recv_buffer,success_ack) != NULL)

{

qDebug() << "acksuccess:" << recv_buffer ;

return 0 ;

}

QThread::msleep(1);

}

qDebug() << "ackerror:AT cmd recv TimeOut";

return -1 ;

}

五、网络控制线程定义

网络控制线程头文件

#ifndef NETWORK_CONTROL_THREAD_H

#define NETWORK_CONTROL_THREAD_H

#include

#include "network_interface.h"

class NetWork_Control_Thread : public QThread

{

Q_OBJECT

public:

explicit NetWork_Control_Thread(QObject *parent = 0);

~NetWork_Control_Thread();

void NetWork_Thread_change(bool Status);

private:

volatile bool Stop_flag ;

NetWork_Interface *netWork_Ptr ;

protected:

void run();

signals:

public slots:

};

#endif // NETWORK_CONTROL_THREAD_H

网络控制线程接口实现

#include "network_control_thread.h"

NetWork_Control_Thread::NetWork_Control_Thread(QObject *parent) :

QThread(parent)

{

this->NetWork_Thread_change(false);

//在这里实例化网络接口线程

this->netWork_Ptr = new NetWork_Interface ;

//启动网络接口线程

this->netWork_Ptr->start();

}

NetWork_Control_Thread::~NetWork_Control_Thread()

{

this->NetWork_Thread_change(true);

delete this->netWork_Ptr ;

}

//改变线程的状态

void NetWork_Control_Thread::NetWork_Thread_change(bool Status)

{

this->Stop_flag = Status ;

}

//线程执行函数

void NetWork_Control_Thread::run()

{

//发送AT测试指令

this->netWork_Ptr->Send_AT_Cmd(AT_TEST_OK,"OK","ERROR",200);

while(!this->Stop_flag)

{

qDebug() << "NetWork_Control_Thread is Runing....";

QThread::msleep(1000);

}

}

六、AT指令框架测试

mainwindown.h

#ifndef MAINWINDOW_H

#define MAINWINDOW_H

#include

#include "network_control_thread.h"

namespace Ui {

class MainWindow;

}

class MainWindow : public QMainWindow

{

Q_OBJECT

public:

explicit MainWindow(QWidget *parent = 0);

~MainWindow();

private:

Ui::MainWindow *ui;

NetWork_Control_Thread *network_control_ptr ;

};

#endif // MAINWINDOW_H

mainwindown.cpp

#include "mainwindow.h"

#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :

QMainWindow(parent),

ui(new Ui::MainWindow)

{

ui->setupUi(this);

//实例化网络控制线程

this->network_control_ptr = new NetWork_Control_Thread ;

//启动网络控制线程===>启动后将会自动启动网络接口线程

this->network_control_ptr->start();

}

MainWindow::~MainWindow()

{

delete this->network_control_ptr;

delete ui;

}

运行结果,这里我用的是NBIOT的BC28模块进行测试,本例程只提供测试框架,开发者需自行添加自己的业务逻辑处理。

以下是我利用这个框架写的一个类似上位机的软件,可以读取模块的基本信息:

本文同步分享在 博客“Engineer-Bruce_Yang”(CSDN)。

如有侵权,请联系 support@oschina.cn 删除。

本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

Linux驱动实现AT指令,QT Linux实现AT指令处理框架相关推荐

  1. 从串口驱动到Linux驱动模型,想转Linux的必会!

    关注.星标公众号,直达精彩内容 ID:技术让梦想更伟大 整理:李肖遥 本文通过对Linux下串口驱动的分析.由最上层的C库.到操作系统系统调用层的封装.再到tty子系统的核心.再到一系列线路规程.再到 ...

  2. linux驱动日志格式,( 转)嵌入式Linux驱动Makefile

    天气: 晴朗 心情: 高兴 ( 转)嵌入式Linux驱动开发笔记 1.1        模块的编译 Linux驱动一般以模块module的形式来加载,首先需要把驱动编译成模块的形式.简单的例子, Be ...

  3. linux驱动(一):linux驱动框架

    编写linux驱动先看一下驱动框架是什么样子的. 驱动编写和应用层编写有什么区别呢? (一)首先 入口函数的问题.应用层编写我们的入口就是main函数,但在驱动编写时不是这样的,有两种情况, 1.缺省 ...

  4. 嵌入式linux驱动开发实战教程,嵌入式Linux驱动开发实战视频教程

    嵌入式Linux驱动开发实战教程(内核驱动.看门狗技术.触摸屏.视频采集系统) 适合人群:高级 课时数量:109课时 用到技术:嵌入式 Linux 涉及项目:驱动开发.看门狗技术.触摸屏.视频采集 咨 ...

  5. mt7601u linux驱动编译,移植MT7601U AP Linux 驱动至Orangepi-PC2开发板

    简单一下记录移植MT7601U AP Linux 驱动至Orangepi-PC2开发板的过程. 二  环境描述 1.Orangpi-PC2开发板(Linux Orangepi 3.10.65 #12 ...

  6. 华为笔记本linux驱动支持,华为笔记本电脑对Linux 5.5内核的支持得到改善

    原标题:华为笔记本电脑对Linux 5.5内核的支持得到改善 随着即将到来的Linux 5.5内核周期,华为笔记本电脑将在支持方面有所改进. 作为X86平台驱动程序更新的一部分,Huawei WMI驱 ...

  7. linux驱动内核哪个文件夹,linux设备驱动归纳总结(一):内核的相关基础概念...

    linux设备驱动归纳总结(一):内核的相关基础概念 1. 内核与 linux 设备驱动的作用与关系 内核:用于管理软硬件资源,并提供运行环境.如分配 4G 虚拟空间等. linux 设备驱动:是连接 ...

  8. exfat linux 驱动_(实例)Linux 内核添加exfat驱动

    背景: 由于exfat是常用的文件系统格式,而Linux由于版权的问题,没有在官方中添加有关的驱动. 但是 微软也同意开源了,所以比较新的 Linux 会支持这一块. 为了支持exfat的驱动,我们需 ...

  9. linux驱动的中断函数,嵌入式Linux驱动开发(四)——字符设备驱动之中断方式以及中断方式获取按键值...

    之前我们完成了关于通过查询的方式获取按键键值的驱动程序,可以参考:嵌入式Linux开发--裸板程序之中断控制器. 虽然读取键值没有什么问题,但是测试程序占用CPU过高,一直在不断的查询,资源消耗过大, ...

最新文章

  1. LayoutParams cannot be resolved to a type
  2. anki 新的卡片类型_梁宝川:这一类型Anki卡片,你做了吗?
  3. 电子科技大学计算机学院保研夏令营,电子科技大学计算机科学与工程学院网络空间安全保研夏令营...
  4. Angular Component之间的事件通知机制
  5. linux命令终极系列awk
  6. java 保留html_好程序员Java培训分享Java包是什么?
  7. java lang保_android – Gson中的RuntimeException解析JSON:无法调用受保护的java.lang.ClassLoader()而没有args...
  8. 最新安卓手机性价比榜公布:Redmi连夺三冠
  9. [PyTorch] 神经网络处理图像
  10. 微型计算机原理与接口技术综述论文,微型计算机原理接口与技术综述论文汇编.doc...
  11. 媒体选择与发布实践总结
  12. Java对接苹果账号授权登录
  13. android 音量调节不起作用,Android音量控制
  14. HTML+CSS静态页面网页设计作业——甜品奶茶店(19页) HTML5网页设计成品_学生DW静态网页设计_web课程设计网页制作
  15. 浅谈嵌入式MCU软件开发之S32K1xx系列MCU启动过程及重映射代码到RAM中运行方法详解
  16. 1.5.33 计算分数加减表达式的值
  17. 圣地亚哥分校 计算机,美国加州大学圣地亚哥分校计算机科学专业.pdf
  18. 小波系数等值线图和小波方差图绘制教学
  19. 18 -Flask构建弹幕微电影网站- 部署上线
  20. word如何设置上标形式_word怎样设置上标

热门文章

  1. [对比]Android的差异设计和iOS的统一设计规范
  2. 生物信息学入门 根据表达矩阵和差异表达基因列表制作差异表达矩阵
  3. 客户端计算机硬件需求,票据交易系统客户端安装配置手册一、客户端计算机硬件要求.PDF...
  4. 机器人碰撞检测几何模型设计
  5. 【DBSDFZOJ 4460】666(DP)
  6. MAC上Pycharm破解导致无法打开
  7. “智”和“慧”的区别是什么?
  8. 安科瑞ANet通信管理机在电力监控系统中的应用-Susie 周
  9. 计算机网络中常见的端口号整理
  10. 为什么Facebook无法取消QAnon