【QT 自研上位机 与 ESP32下位机联调>>>串口控制GPIO-基础样例-联合文章】

【QT 自研上位机 与 ESP32下位机联调>>>串口控制GPIO-基础样例-联合文章】

  • 1、概述
  • 2、实验环境
  • 3、 自我总结
  • 4、 实验过程
    • 1、验证上位机QT程序
      • 1、下载样例代码
      • 2、修改qt程序
      • 3、运行测试验证
    • 2、验证下位机ESP32程序
      • 1、下载样例代码
      • 2、更改ESP32代码,编译下载
      • 3、验证
    • 3、联合调试-ESP32和qt上位机
      • 1、硬件连接
      • 2、验证
  • 5、代码连接
  • 6、细节部分
      • (1)常见错误解决办法:
      • (2)ESP32工程下载后,先清理下
      • (3)逻辑分析仪,需要跳变信号触发
      • (4)逻辑分析仪,触发触发选择不点下面两个
  • 7、总结

1、概述

最为新手,想要快速入门相关设备,比如ESP32,可能最好的方式就是直接手动去敲一遍代码,而串口算是单片机入门中,必不可少的一个基础课程,很多通讯,以及打印各种信息,都需要,而加入一些交互,能让我们更好调试单片机。

我打算出3章,像之前STM32那种单片机,调试串口一样。
本次第三章,和上位机进行联合调试。

第一章,也就是串口基础篇,简单调试ESP32,进行交互。
第二章,将会结合GPIO,进行一些简单外围控制。
第三章,将会结合上位机,使用自制上位机进行联合调试。

2、实验环境

ESP32说明:ESP32-S3 是一款集成 2.4 GHz Wi-Fi 和 Bluetooth 5 (LE) 的 MCU 芯片,支持远距离模式 (Long Range)。ESP32-S3 搭载 Xtensa® 32 位 LX7 双核处理器,主频高达 240 MHz,内置 512 KB SRAM (TCM),具有 45 个可编程 GPIO 管脚和丰富的通信接口。ESP32-S3 支持更大容量的高速 Octal SPI flash 和片外 RAM,支持用户配置数据缓存与指令缓存。

硬件信息:开发板 ESP32-S3-DevKitM-1(EPS32-S3-wroom-1模块)
调试环境:Windows下
串口工具:USB转串口TTL/232等
其他硬件:逻辑分析仪,杜邦线,两个usb-type-c连接线等。
在这里插入图片描述

3、 自我总结

有了调试串口的经验,再加上调试IO的经验,其实我们就很容易合在一起,就像那个很有意思的笑话,苹果的英文单词和笔的单词,组合在一起的就是笔记本了。
如下,请允许我在原本应该严肃的科技博文中,加入一个搞笑的部分。
在这里插入图片描述
但是这个道理是相通的,我们学习一个东西的时候,其实一块一块学的,或者说以小见大。
举个例子,我们之前学习了ESP32的串口,

【PC电脑windows编写代码-学习uart0串口编写代码-串口程序-ESP32-简单通讯交互-基础样例学习】

同时又做了ESP32的IO实验,

【PC电脑windows-学习样例generic_gpio-拓展GPIO-ESP32的GPIO程序-问题解决-GPIO输出实验-基础样例学习(2)】

那么现在组合起来就可以了。

自己之前就有做联合文章的经历,从上位机,到下位机,一整条链路,一次性打通,学习每个部分,最后组合在一起,其实多少有些分繁琐而简化。

就像之前文章一样。

【QT 自研上位机 与 STM32F4xx下位机联调>>>can通信测试-基础样例-联合文章】

【QT 自研上位机 与 STM32F103下位机联调>>>串口uart通信测试-基础样例-联合文章】

也就有了本次实验,以及这篇文章。

4、 实验过程

1、验证上位机QT程序

上位机这块我们采用之前的串口工厂简单修改,来完成我们的目标。
【QT 5 调试软件+串口相关初试串口+基础样例】

1、下载样例代码

(1)下载代码
代码连接:https://download.csdn.net/download/qq_22146161/86722251
使用qt开,然后硬件转换器短接。
在这里插入图片描述
qt运行原件如下,可以看到能收到自己发出的“123”
在这里插入图片描述

2、修改qt程序

我们简单改写程序,发出990和991,好和ESP32配合

(1)ui界面修改
在这里插入图片描述
(2)转到槽函数
在这里插入图片描述
在这里插入图片描述

(3)加入代码
在这里插入图片描述

3、运行测试验证

在这里插入图片描述

2、验证下位机ESP32程序

样例用的下ESP32,如下文章中的。同样的也是验证下。

【PC电脑windows编写代码-ESP32-串口控制GPIO编写代码-简单通讯交互控制IO-进阶样例学习-2】

1、下载样例代码

代码链接:https://download.csdn.net/download/qq_22146161/88678030

2、更改ESP32代码,编译下载

我们在990这条命令上,专门做了个双IO拉低拉高,这样好检验。

#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/uart.h"
#include "string.h"
#include "driver/gpio.h"

#define TX_PIN 18
#define RX_PIN 19
#define BUF_SIZE 1024

const char *expected_string0 = "990";
const char *expected_string1 = "991";
const char *expected_string2 = "992";
const char *expected_string3 = "993";
const char *expected_string4 = "994";
const char *expected_string5 = "995";
const char *expected_string6 = "996";

#define GPIO_OUTPUT_IO_0    35
#define GPIO_OUTPUT_IO_1    36
#define GPIO_OUTPUT_IO_2    37
#define GPIO_OUTPUT_IO_3    38

 #define GPIO_OUTPUT_PIN_SEL  ((1ULL<<GPIO_OUTPUT_IO_0) |(1ULL<<GPIO_OUTPUT_IO_1) | (1ULL<<GPIO_OUTPUT_IO_2) | (1ULL<<GPIO_OUTPUT_IO_3)) // 配置GPIO_OUT位寄存器

void gpio_init(void)
{
    gpio_config_t io_conf;  // 定义一个gpio_config类型的结构体,下面的都算对其进行的配置
    io_conf.intr_type = GPIO_INTR_DISABLE;  // 禁止中断  
    io_conf.mode = GPIO_MODE_OUTPUT;            // 选择输出模式
    io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL; // 配置GPIO_OUT寄存器
    io_conf.pull_down_en = 0;                   // 禁止下拉
    io_conf.pull_up_en = 1;                     // 禁止上拉

    gpio_config(&io_conf);                      // 最后配置使能
}

void app_main(void) {

    gpio_init();
    // 配置UART参数
    
    uart_config_t uart_config = {
        .baud_rate = 115200,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE
    };
    uart_param_config(UART_NUM_0, &uart_config);



    // 设置UART1使用的TX和RX引脚
    uart_set_pin(UART_NUM_0, TX_PIN, RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

    // 安装UART驱动程序,使用默认缓冲区大小
    uart_driver_install(UART_NUM_0, BUF_SIZE * 2, BUF_SIZE * 2, 0, NULL, 0);

    // 发送和接收数据的缓冲区
    uint8_t *data = (uint8_t *)malloc(BUF_SIZE);

        const char *test_str0 = "write_this_is_990";
        const char *test_str1 = "write_this_is_991";
        const char *test_str2 = "write_this_is_992";
        const char *test_str3 = "write_this_is_993";
        const char *test_str4 = "write_this_is_994";
        const char *test_str5 = "write_this_is_995";
        const char *test_str6 = "write_this_is_996";

    while (1) {
        // 发送数据
        const char *test_str = "Hello from UART01!";
        uart_write_bytes(UART_NUM_0, test_str, strlen(test_str));

        // 从UART接收数据
        int length = 0;
        ESP_ERROR_CHECK(uart_get_buffered_data_len(UART_NUM_0, (size_t *)&length));
        length = uart_read_bytes(UART_NUM_0, data, length, 20 / portTICK_PERIOD_MS);

        if (length > 0) {
            data[length] = 0; // 确保字符串以null终止
            printf("Received data: '%s'\n", (char *)data);
             gpio_set_level(GPIO_OUTPUT_IO_0, 0);            // 把这个GPIO输出地电平
             vTaskDelay(10 / portTICK_PERIOD_MS);
             gpio_set_level(GPIO_OUTPUT_IO_0, 1);          
             vTaskDelay(10 / portTICK_PERIOD_MS);
                //控制第一个IO上下
                if(strstr ((const char *)data, expected_string0)!=NULL )
                {
                      uart_write_bytes(UART_NUM_0, test_str0, strlen(test_str0));
                      gpio_set_level(GPIO_OUTPUT_IO_0, 0);            // 把这个GPIO输出地电平
                      vTaskDelay(1000 / portTICK_PERIOD_MS);
                      gpio_set_level(GPIO_OUTPUT_IO_1, 0);            // 把这个GPIO输出地电平
                      vTaskDelay(1000 / portTICK_PERIOD_MS);
                      gpio_set_level(GPIO_OUTPUT_IO_1, 1);            // 把这个GPIO输出地高平
                      vTaskDelay(1000 / portTICK_PERIOD_MS);
                      gpio_set_level(GPIO_OUTPUT_IO_0, 1);            // 把这个GPIO输出地高平
                      vTaskDelay(1000 / portTICK_PERIOD_MS);
                        printf("this is 990!");
                       // break;
                }
                if(strstr ((const char *)data, expected_string1) !=NULL )
                {
                    uart_write_bytes(UART_NUM_0, test_str1, strlen(test_str1));
                    gpio_set_level(GPIO_OUTPUT_IO_0, 0);            // 把这个GPIO输出低电平
                        printf("this is 991!");
                      //  break;
                }
                //控制第二个IO上下
                if(strstr ((const char *)data, expected_string2)!=NULL )
                {
                    uart_write_bytes(UART_NUM_0, test_str2, strlen(test_str2));
                    gpio_set_level(GPIO_OUTPUT_IO_1, 1);            // 把这个GPIO输出高电平
                        printf("this is 992!");
                     //   break;
                }
                if(strstr ((const char *)data, expected_string3)!=NULL )
                {
                    uart_write_bytes(UART_NUM_0, test_str3, strlen(test_str3));
                    gpio_set_level(GPIO_OUTPUT_IO_1, 0);            // 把这个GPIO输出低电平
                        printf("this is 993!");
                     //   break;
                }
                //控制第三个IO上下
                if(strstr ((const char *)data, expected_string4)!=NULL )
                {
                    uart_write_bytes(UART_NUM_0, test_str4, strlen(test_str4));
                    gpio_set_level(GPIO_OUTPUT_IO_2, 1);            // 把这个GPIO输出高电平
                        printf("this is 994");
                     //   break;
                }
                if(strstr ((const char *)data, expected_string5)!=NULL )
                {
                    uart_write_bytes(UART_NUM_0, test_str5, strlen(test_str5));
                    gpio_set_level(GPIO_OUTPUT_IO_2, 0);            // 把这个GPIO输出低电平
                        printf("this is 995!");
                     //   break;
                }
                //单独功能
                if(strstr ((const char *)data, expected_string6)!=NULL )
                {
                    uart_write_bytes(UART_NUM_0, test_str6, strlen(test_str6));
                    //gpio_set_level(GPIO_OUTPUT_IO_2, 0);            // 把这个GPIO输出低电平
                        printf("this is 996!");
                     //   break;
                }
   

       
            
        }

        vTaskDelay(2000 / portTICK_PERIOD_MS);
    }
}

在这里插入图片描述

下载完了按下复位

3、验证

硬件连接

3/5V IN ---  ESP32-18
3V OUT  ---  ESP32-19
GND     ---  GND

在这里插入图片描述
然后使用一个串口软件打开,看看是否能收到消息。

在这里插入图片描述

3、联合调试-ESP32和qt上位机

1、硬件连接

其实到目前位置,硬件连接已经完成了。
当然我们还需要接上逻辑分析仪

3/5V IN ---  ESP32-18
3V OUT  ---  ESP32-19
GND     ---  GND

//逻辑分析仪
GND  ---- GND
0通道 ---- ESP32-35
GND  ---- GND
1通道 ---- ESP32-36

2、验证

(1)上位机软件和逻辑分析仪截图说明
如下,为上位机发送990后,上位机>>>通过通讯>>>单片机>>>IO控制>>>逻辑分析仪,整条链路。
在这里插入图片描述
(1)代码和逻辑分析仪截图说明
这块要简单分析下代码,35GPIO先跳变了下,然后拉低3S,在此期间36GPIO拉低了1S。
在这里插入图片描述

5、代码连接

一套解决办法吧,需要代码的自取。
代码链接:https://download.csdn.net/download/qq_22146161/88689386

6、细节部分

(1)常见错误解决办法:

调试单片机的时候,或者说调试串口的时候,其实很难问题穷尽,但是一些方式,可以帮我们更快定位。

  1. UART配置错误:确保你的UART配置与你所使用的引脚和硬件设置相匹配。检查波特率、数据位、校验位和停止位是否正确配置。
  2. GPIO引脚不正确或被占用:检查你用作UART的GPIO引脚是否正确,并且没有被其他功能(如SPI、I2C或内置功能)占用。
  3. UART驱动安装问题:确保UART驱动正确安装,没有内存分配错误或其他问题。
  4. 缓冲区问题:检查是否有足够的空间在UART的发送缓冲区中存储要发送的数据。如果缓冲区已满,可能需要增加缓冲区大小或等待缓冲区可用。
  5. 硬件问题:检查你的ESP32开发板和任何连接的串行设备是否存在硬件故障。
    电源和接地问题:确保所有设备都有适当的电源和接地。

为了解决这个问题,可以尝试以下步骤:

  • 重新检查UART配置:确保UART的初始化和配置正确无误。
  • 检查GPIO引脚:验证所选择的GPIO引脚是否适合用作UART,且未被占用。
  • 检查驱动安装:确保使用 uart_driver_install 函数正确安装了UART驱动。
  • 增加缓冲区大小:如果需要,可以在调用 uart_driver_install 时增加缓冲区大小。
  • 硬件检查:检查ESP32开发板和相关硬件是否有任何明显的损坏或连接问题。

(2)ESP32工程下载后,先清理下

自己在下载过程中,发现直接编译也就是“idf.py build”的时候,会提示下,最好先清理下,然后重新编译。

在这里插入图片描述

(3)逻辑分析仪,需要跳变信号触发

如下,逻辑分析仪,在使用的时候,还是需要注意一下,它需要一个跳变信号,否则就会像下图一样,一直等待。
在这里插入图片描述
而且实际抓取信号,只后半部分,被拉高部分。
在这里插入图片描述
所以我们时间调试时,只要收到消息,先来个跳变信号触发下。
在这里插入图片描述

(4)逻辑分析仪,触发触发选择不点下面两个

实际想直接进行采集的,就把下面两个也点上了,实际测试应该是不选择下面两个
在这里插入图片描述

7、总结

如此一来,ESP32也有联合文章了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/296147.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RocketMQ源码 发送消息源码分析

前言 DefaultMQProducer 是默认生产者组件&#xff0c;是生产者客户端中&#xff0c;绝大部分关于生产者和broker、nameSrv进行网络通信的功能入口。其中&#xff0c;包含发送各种形式&#xff08;同步、异步、事务、顺序&#xff09;的消息&#xff0c;针对发送消息部分的实现…

第11章 GUI Page462~476 步骤二十三 步骤二十四 Undo/Redo ②“添加操作”支持“Undo/Redo”

工程二 1.为AddAction类添加Undo() Redo() GetName()成员函数 2.实现AddAction类的Undo() Redo()函数 3.运行效果&#xff0c;但是日志窗口没有记录 原因&#xff1a;AddAction(EditAction* newAction)函数没有实现&#xff0c;另外参数是EditAction类型 所以我们还需要在基…

基于PyTorch的Transformer组件实现

最近看了不少介绍LLM工作原理的文章&#xff0c;发现每一篇都会试图跟读者讲明白作为baseline的Transformer架构到底长啥样。但是好像比较少有代码实现的示例和具体的例子帮助理解。于是自己也想尝试着写一篇含有代码实现和具体例子解释的文章&#xff0c;希望能够给喜欢编程朋…

金蝶Apusic应用服务器 loadTree JNDI注入漏洞

产品介绍 金蝶Apusic是一款企业级应用服务器&#xff0c;支持Java EE技术&#xff0c;适用于各种商业环境。 漏洞概述 由于金蝶Apusic应用服务器权限验证不当&#xff0c;使用较低JDK版本&#xff0c;导致攻击者可以向loadTree接口执行JNDI注入&#xff0c;远程加载恶意类&a…

C++学习day--25 俄罗斯方块游戏图像化开发

项目分析 项目演示、项目分析 启动页面 启动页面&#xff1a; 分析&#xff1a; 开发环境搭建 1&#xff09;安装vc2010, 或其他vs版本 2&#xff09;安装easyX图形库 代码实现: # include <stdio.h> # include <graphics.h> void welcome(void) { initgraph(55…

LINUX服务器防火墙nf_conntrack问题一例

一、故障现象 业务反馈服务异常,无法响应请求&#xff0c;从系统日志 dmesg 或 /var/log/messages 看到大量以下记录&#xff1a;kernel: nf_conntrack: table full, dropping packet. 二、问题分析 业务高峰期服务器访问量大&#xff0c;内核 netfilter 模块 conntrack 相关参…

听GPT 讲Rust源代码--compiler(19)

File: rust/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs 该文件&#xff08;rust/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs&#xff09;是Rust编译器针对MIPS架构上的Linux系统的目标描述文件。它的作用是定义了在这个目标上编译时的一些配置…

mysql之数据类型、建表以及约束

目录 一. CRUD 1.1 什么是crud 1.2 select(查询) 1.3 INSERT(新增) 1.4 UPDATE(修改&#xff09; 1.5 DELETE(删除) 二. 函数 2.1 常见函数 2.2 流程控制函数 2.3聚合函数 三. union与union all 3.1 union 3.2 union all 3.3 具体不同 3.4 结论 四、思维导图 一. CRUD 1.1…

建站指南,如何将拥有的域名自定义链接到wordpress

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 在Dynadot上&#xff0c;我们可已经账户中管理的…

OpenHarmony之消息机制实现

OpenHarmony之消息机制实现 背景 在之前的介绍&#xff08;OpenHarmony之HDF驱动框架&#xff09;中&#xff0c;了解到OpenHarmony的消息机制主要有以下两种&#xff1a; 用户态应用发送消息到驱动。用户态应用接收驱动主动上报事件。 下面我们分别来看看两种机制用户态的…

使用 dbgate 在 sealos 上完美管理 mysql pgsql 等数据库

先登录 sealos 创建数据库&#xff0c;可以创建个 pgsql: 再到模版市场启动 dbgate: 配置数据库的连接信息&#xff0c;即可搞定收工 sealos 以kubernetes为内核的云操作系统发行版&#xff0c;让云原生简单普及 laf 写代码像写博客一样简单&#xff0c;什么docker kubernete…

Linux系统使用超详细(七)~定时任务:crontab

目录 一、定时任务简介 1.1cron工具概述 1.2crontab命令简述 二、crontab安装与检查 2.1安装步骤 2.2查看crontab的状态 2.3查看crontab服务 三、crontab命令 3.1常用命令 3.2定时任务的写法 3.3实例 四、添加定时任务 4.1使用crontab -e命令 4.2创建一个独立的定…

银河麒麟Kylin-Server-V10-SP3使用ISO镜像搭建本地内网YUM/DNF源cdrom/http

机房服务器安装一般是内网环境&#xff0c;需要配置本地的YUM/DNF源。本文介绍通过ISO镜像搭建内网环境的UM/DNF源 准备工作&#xff1a; 提前准备好Kylin-Server-V10-SP3的ISO镜像文件。 本机IP地址&#xff1a;192.168.40.201 镜像存放目录/data/iso/Kylin-Server-V10-SP3-Ge…

编写一个弹跳小球的程序,小球在窗口中四处反弹(python)

import pygame import random# 初始化Pygame pygame.init()# 窗口尺寸 width 800 height 600# 创建窗口 screen pygame.display.set_mode((width, height)) pygame.display.set_caption("Bouncing Ball")# 小球初始位置和速度 ball_radius 20 ball_color (255, …

前端页面的生命周期

性能问题呈现给用户的感受往往就是简单而直接的&#xff1a;加载资源缓慢、运行过程卡顿或响应交互延迟等。而在前端工程师的眼中&#xff0c;从域名解析、TCP建立连接到HTTP的请求与响应&#xff0c;以及从资源请求、文件解析到关键渲染路径等&#xff0c;每一个环节都有可能因…

iOS苹果和Android安卓测试APP应用程序的区别差异

在移动应用开发中&#xff0c;测试是一个至关重要的环节。无论是iOS苹果还是Android安卓&#xff0c;测试APP应用程序都需要注意一些差异和细节。本文将详细介绍iOS和Android的测试差异&#xff0c;包括操作系统版本、设备适配、测试工具和测试策略&#xff0c;并回答一些新手容…

web3d-three.js场景设计器-TransformControls模型控制器

场景设计器-TransformControls 控制器 该控制器可以指定模型进入可控制模式-如图有三种控制方式 translate --移动模式 rotate -- 旋转模式 scale -- 缩放模式 方便布局过程中快捷对模型进行摆放操作。 引入方式 import { TransformControls } from three/examples/jsm/…

深入Pandas(二):高级数据处理技巧

文章目录 系列文章目录引言时间序列分析可视化示例 高级数据分析技术分组与聚合操作时间序列分析 高级数据操作数据合并与重塑示例&#xff1a;数据合并merge示例&#xff1a;数据合并concat示例&#xff1a;数据重塑 - 透视表 高级索引技巧 结论 系列文章目录 Python数据分析…

C++《异常》

前言&#xff1a;C有一套独立的异常处理机制,今天就来做详细的介绍try,catch这两个词等 在C语言中处理错误的方式和缺陷有&#xff1a; 返回错误码。 缺陷&#xff1a; 1.错误码不好设置&#xff0c;比如&#xff1a;除0操作&#xff0c;就不好返回错误码。如果返回一个数字&…

uniapp微信小程序投票系统实战 (SpringBoot2+vue3.2+element plus ) -小程序微信用户登录实现

锋哥原创的uniapp微信小程序投票系统实战&#xff1a; uniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )_哔哩哔哩_bilibiliuniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )共计21条视频…