- 我的博客:https://blog.csdn.net/qq_37388044
- 我的知乎:https://www.zhihu.com/people/bbtganmin
- 联系方式:知乎私信
转载或者引用本文内容请注明来源及原作者!
目录
前言
最近在研究ESP32的自动下载电路,参照官方的开发板电路图自己画了一块板。因为用不到JTAG功能,所以用 CH340C 代替了官方使用的 FT2232H USB转串口芯片。
开发ESP32的同学都知道,模块下载固件时,是需要先将GPIO0拉低再重启模块,让模块进入下载模式。这就意味着串口能控制ESP32重启,主要通过串口RTS和DTR控制。
正好我要写的Qt上位机就需要有一个让设备重启的功能,那么Qt要怎么去控制RTS和DTR这两个信号呢?
一、串口的RTS和DTR是什么?
RS-232C接口定义(DB9)
1 载波检测 DCD(Data Carrier Detect)
2 接收数据 RXD(Received Data)
3 发送数据 TXD(Transmit Data)
4 数据终端准备好 DTR(Data Terminal Ready)
5 信号地 SG(Signal Ground)
6 数据准备好 DSR(Data Set Ready)
7 请求发送 RTS(Request To Send)
8 清除发送 CTS(Clear To Send)
9 振铃提示 RI(Ring Indicator)
当然,在这里它们的定义并不重要。
我们要关注的是 " RTS = Request To Send " 和 " DTR = Data Terminal Ready " 。
二、QSerialPort 中有控制RTS和DTR的接口吗?
我们打开QSerialPort的头文件,搜索RTS,找不到相关函数?
这时我留意到这四个函数:
于是我简单封装了一下函数:
void bbtSerialPort::setDTR(bool state)
{
if(serialPort->isOpen())
serialPort->setDataTerminalReady(state);
}
void bbtSerialPort::setRTS(bool state)
{
if(serialPort->isOpen())
serialPort->setRequestToSend(state);
}
再写两个 QCheckBox 控件
QCheckBox *RTSCheckBox = new QCheckBox("RTS");
QCheckBox *DTRCheckBox = new QCheckBox("DTR");
connect(RTSCheckBox, &QCheckBox::stateChanged, [=](int state){
if(!serialPort->isOpen()) return ;
if((Qt::CheckState)state == Qt::Checked) setRTS(true);
else if((Qt::CheckState)state == Qt::Unchecked) setRTS(false);
});
connect(DTRCheckBox, &QCheckBox::stateChanged, [=](int state){
if(!serialPort->isOpen()) return ;
if((Qt::CheckState)state == Qt::Checked) setDTR(true);
else if((Qt::CheckState)state == Qt::Unchecked) setDTR(false);
});
效果图:(串口的其他操作这里就不多讲了)
经验证,这两个函数就是用来控制RTS和DTR信号的。当 state 为 true 时,引脚为低电平,为 false 时,引脚为高电平。
三、通过串口让ESP32重启
1、方法一:ESP32软复位
在"esp_system.h"中有软复位函数:
/**
* @brief Restart PRO and APP CPUs.
*
* This function can be called both from PRO and APP CPUs.
* After successful restart, CPU reset reason will be SW_CPU_RESET.
* Peripherals (except for WiFi, BT, UART0, SPI1, and legacy timers) are not reset.
* This function does not return.
*/
void esp_restart(void) __attribute__ ((noreturn));
可以通过串口发送自定义指令让 ESP32 自己重启。
2、方法二:通过RTS和DTR控制模块的EN脚(CHIP_PU脚)
先来看看电路图:
三极管原理在这就不多说了,要想让模块重启,就需要将EN脚先拉低再拉高。
- 一开始,DTR和RTS都是1,看电路右边的表:EN 和 IO0 都为1。
- 保持DTR为高,RTS拉低:此时 EN 拉低,IO0 不变。
- 保持DTR为高,RTS拉高:此时 EN 拉高,IO0 不变。
那么在Qt上的操作是:(注意: true 为低电平, false 为高电平。)
QPushButton *resetButton = new QPushButton("重启设备");
connect(resetButton, &QPushButton::clicked, this, [=]() {
setDTR(false);
setRTS(true);
msleep(50);
setRTS(false);
});
这里的延时是为了避免EN位低后EN脚上的电容还供电一段时间,可能会导致重启失败。这要看个人情况,我试了一下不加延时也是可以的。
至于延时的函数,网上有很多实现的方法,我这是其中一种:
void bbtSerialPort::msleep(quint32 msec)
{
QEventLoop loop;//定义一个新的事件循环
QTimer::singleShot(msec, &loop, SLOT(quit()));//创建单次定时器,槽函数为事件循环的退出函数
loop.exec();//事件循环开始执行,程序会卡在这里,直到定时时间到,本循环被退出
}