基于ESP32实现一个WIFI透传模块demo

article/2025/9/27 17:12:37

esp32作为一个热门芯片,网上的文章很多,sdk里的例子和官网的教程也是比较详细。不过作为新玩家,还是要先做一些小改动才更容易入门。所以这里就综合几个example代码,写一个简单的透传demo。
作为一个练手的demo,很多参数的校验被省略了,并且也不会刻意的去纠正用户的错误操作。为了简洁,本文中贴出来的代码中删减了诸如参数检测、共享资源保护之类的代码

环境

操作系统:ubuntu 20.04
虚拟机:VMare Workstation 16
IDE:vscode 1.73.1
vscode插件:Espressif IDF v1.5.1
board:淘宝上的ESP32-S3-DevKitC-1兼容板
外置串口板子:淘宝上的cp2102 6合1串口模块
串口终端/tcp server:sscom5

需求

通过外部的串口模块,连接ESP32-S3-DevKitC-1开发板上的IO4和5,与电脑进行通讯。
而串口指令,参考一下某透传模块的文档,提取并简化成了以下几条(每条指令后应该加上换行符,比如"\n"、“\r\n”,否则将不识别):

  • 扫描AP
指令ATWS
响应AP : <num>,<ssid>,<chl>,<sec>,<rssi>,<bssid>
[ATWS] OK
  • 连接到 AP
指令ATPN=<ssid>,<pwd>
响应成功
[ATPN] OK
失败
[ATPN] ERROR:<error_code>
error_code1: 命令格式错误
2: 参数错误
3: 连接 AP失败
4: dhcp 超时
5:无ap信息
  • 建立socket
指令ATPC=<mode>,<Remote Addr>,<Remote Port>
响应成功
[ATPC] OK
失败
[ATPC]:<error_code>
参数mode:
 0:TCP
error_code1: 命令格式错误
2: 参数错误
3: 连接 server失败
4: 尚未连接AP
注意连接成功后直接进入透传模式

代码

https://github.com/chenbb8/esp32_network123
代码clone下来后,还需要用到<新建esp32的vscode工程的三种方式>中的<将普通esp-idf工程升级成esp-vscode工程>这个方法,修改一下本地的程序。
并且还需要重新设置串口号/芯片型号。

代码结构概述

主要的文件,及其功能如下

|   |--app_main.c            入口app_main()函数所在文件,调用了WIFI和UART模块的初始化函数
|   |--app_socket_client.c   实现tcp socket功能
|   |--app_socket_client.h
|   |--app_wifi.c            WIFI功能
|   |--app_wifi.h
|   |--at_cmd.c              AT指令的解析和执行
|   |--at_cmd.h
|   |--project_common.h      全局包含的头文件
|   |--user_uart.c           UART功能
|   |--user_uart.h

注:如果文件是通过vscode来新建和删除的,会通过插件,自动的修改对应的CMakeLists.txt文件,省却了一些麻烦的操作。但有时候可能会因为git的文件冲突,而自动在CMakeLists.txt文件加入一些git生成的额外源文件。

而用户的串口数据与tcp client数据之间交互的关系如下
在这里插入图片描述
接下来跟着文章,一步步的解析整个工程的实现吧。

本文其实有好多个版本,从头记录着demo的搭建过程,跟github上master分支上的历史版本一一对应。不过因为感觉代码有点混乱,并且原本一步步搭建的文章写法与v1.0.0代码有出入;因此在新版本中将部分文件名还有一些必要的代码结构进行了修改,并且后面的章节都是基于v1.0.0版本编写的。

串口服务

参考例子esp-idf/examples/peripherals/uart/uart_echo

串口服务对应两个模块:user_uart / at_cmd。
其中user_uart模块下,初始化函数user_uart_init()主要功能就是创建user_uart_task任务,这个任务负责初始化串口,并将接收到的数据转发到at_cmd模块或者app_socket_client模块。
这里只贴出app_socket_client模块初始化部分的代码:

#define ECHO_TEST_TXD (4)
#define ECHO_TEST_RXD (5)
#define ECHO_TEST_RTS (UART_PIN_NO_CHANGE)
#define ECHO_TEST_CTS (UART_PIN_NO_CHANGE)#define ECHO_UART_PORT_NUM      (2)
#define ECHO_UART_BAUD_RATE     (115200)
#define ECHO_TASK_STACK_SIZE    (4*1024UL)//user uart模块的任务
static void user_uart_task(void *arg)
{/* Configure parameters of an UART driver,* communication pins and install the driver */uart_config_t uart_config = {.baud_rate = ECHO_UART_BAUD_RATE,.data_bits = UART_DATA_8_BITS,.parity    = UART_PARITY_DISABLE,.stop_bits = UART_STOP_BITS_1,.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,.source_clk = UART_SCLK_DEFAULT,};int intr_alloc_flags = 0;ESP_ERROR_CHECK(uart_driver_install(ECHO_UART_PORT_NUM, BUF_SIZE * 2, 0, 0, NULL, intr_alloc_flags));ESP_ERROR_CHECK(uart_param_config(ECHO_UART_PORT_NUM, &uart_config));ESP_ERROR_CHECK(uart_set_pin(ECHO_UART_PORT_NUM, ECHO_TEST_TXD, ECHO_TEST_RXD, ECHO_TEST_RTS, ECHO_TEST_CTS));// Configure a temporary buffer for the incoming datauint8_t *data = (uint8_t *) malloc(BUF_SIZE);//注册socket模块的回调函数app_socket_regist_cb(at_cmd_is_in_pass_mode, at_cmd_set_pass_mode);
...
}

其中app_socket_regist_cb()用于给app_socket_client模块注册回调,以便它可以获取当前是否为透传模式,并且可以在连接上server后自动设置成透传模式。
而at_cmd模块的at_cmd_recv_hand()函数在at模式下会被user_uart_task()任务所调用。
at_cmd_recv_hand()函数的功能是根据at_cmds[]获取需要调用哪个AT指令的处理函数。

typedef struct at_cmd_entry {const char  *cmd_str;//指令匹配字符串uint16_t    cmd_str_len;uint8_t     min_args;//指令最少的参数数量void (*process_cmd)(int argc, char** argv);//argc:参数数量 argv:指向存放参数字符串的指针数组const char  *cmd_desc_str;//指令描述const char  *cmd_args_numb_fail;//参数达不到最低要求时候的报错
} at_cmd_entry_t;
/* cmd 入口数组 */
at_cmd_entry_t at_cmds[] = {
//    cmd_str   cmd_str_len         min_args    process_cmd                 cmd_desc_str    cmd_args_numb_fail{ "ATWS",   sizeof("ATWS")-1,   0+1,        app_wifi_scan,              ATWS_DESC,      ATWS_ARGS_FAIL},{ "ATPN=",  sizeof("ATPN=")-1,  2+1,        app_wifi_sta_connect,       ATPN_DESC,      ATPN_ARGS_FAIL},{ "ATPC=",  sizeof("ATPC=")-1,  3+1,        app_socket_client_connect,  ATPC_DESC,      ATPC_ARGS_FAIL},
};

以上AT处理函数的类型,以app_wifi_sta_connect()为例:

void app_wifi_sta_connect(int argc, char** argv)

因此at_cmd_recv_hand()函数还需要将用户输入到串口中的参数,以’,'符号为界,区分成不同的段,每个段作为一个参数,写入到char** argv对应的数组中。具体参考工程,这里就不详细展开了。

扫描AP

参考例子esp-idf/examples/wifi/scan

通过vscode工程打开app_wifi.c,首先先看初始化

static EventGroupHandle_t s_wifi_event_group;
//WIFI相关功能的初始化
void app_wifi_init(void)
{
...s_wifi_event_group = xEventGroupCreate(); /*!新增代码1*/// Initialize Wi-Fi as staESP_ERROR_CHECK(esp_netif_init());ESP_ERROR_CHECK(esp_event_loop_create_default());esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();assert(sta_netif);wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();//禁用menuconfig中的CONFIG_ESP32_WIFI_NVS_ENABLEDcfg.nvs_enable = 0; /*!新增代码2*/ESP_ERROR_CHECK(esp_wifi_init(&cfg));/*!新增代码3 start*///设置回调函数esp_event_handler_instance_t instance_any_id;esp_event_handler_instance_t instance_got_ip;ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,ESP_EVENT_ANY_ID,&event_handler,NULL,&instance_any_id));ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,IP_EVENT_STA_GOT_IP,&event_handler,NULL,&instance_got_ip));
/*!新增代码3 end*/ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));ESP_ERROR_CHECK(esp_wifi_start());
}

这个app_wifi_init()同时服务于扫描AP连接AP两个功能,其中有"/*!新增代码 x/"注释部分的代码,属于连接AP章节讲解的内容。
在app_wifi.c中,有一个AT指令处理函数,对应着ATWS指令:

#define DEFAULT_SCAN_LIST_SIZE      50
wifi_ap_record_t ap_info[DEFAULT_SCAN_LIST_SIZE];
uint16_t ap_count = 0;
/* set scan method */
void app_wifi_scan(int argc, char** argv)
{
...uint16_t number = DEFAULT_SCAN_LIST_SIZE;memset(ap_info, 0, sizeof(ap_info));esp_wifi_scan_start(NULL, true);ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_info));ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_count));ESP_LOGI(TAG, "Total APs scanned = %u", ap_count);for (int i = 0; (i < DEFAULT_SCAN_LIST_SIZE) && (i < ap_count); i++) {app_wifi_print_scan(ap_info,i);}USER_UART_INFO("[ATWS] OK\n");
}

成功后,用app_wifi_print_scan()函数将结果打印出来;并且会将AP list存放在ap_info中,这在连接AP的环节中,还要从里面获取到对应SSID的加密方式。

连接AP

参考例子esp-idf/examples/wifi/getting_started/station

本章节和扫描AP章节共用app_wifi_init()函数,参考上章节中的代码,其中:

  • 新增代码1:初始化了事件组s_wifi_event_group
  • 新增代码2:我上传的代码没有附带menuconfig,而新生成的menuconfig默认通过的CONFIG_ESP32_WIFI_NVS_ENABLED选项,使能了自动连接AP的功能。所以这里禁用这个自动连接功能。
  • 新增代码3:用于配置在event_handler()中接受的event,这里是接受WIFI_EVENT和IP_EVENT两种类型。

ESP32 Wi-Fi 编程模型如下图所示:
在这里插入图片描述
上面提到的event_handler()就是Event task调用的callback,它当前的实现如下:

// 在Event task内调用的事件处理函数
static void event_handler(void* arg, esp_event_base_t event_base,int32_t event_id, void* event_data)
{if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {xEventGroupSetBits(s_wifi_event_group, WIFI_STA_START_BIT);//通知:sta初始化结束(暂时没用到)} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {esp_wifi_connect();s_retry_num++;ESP_LOGI(TAG, "retry to connect to the AP");} else {xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);//通知:连接AP失败}ESP_LOGI(TAG,"connect to the AP fail");} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));s_retry_num = 0;xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);//通知:连接AP成功}
}

在上面的代码中,分别通过WIFI_EVENT和IP_EVENT事件获取了连接AP的状态,并通过事件组s_wifi_event_group通知对应的任务。
在app_wifi.c中,还有一个AT指令处理函数,对应着ATPN指令:

// ATPN指令对应处理函数
void app_wifi_sta_connect(int argc, char** argv)
{
...char *ssid=argv[1], *password=argv[2];wifi_config_t wifi_config = {.sta = {.sae_pwe_h2e = WPA3_SAE_PWE_BOTH,},};strncpy ((char*)wifi_config.sta.ssid, (char*)ssid, sizeof(wifi_config.sta.ssid));strncpy ((char*)wifi_config.sta.password, (char*)password, sizeof(wifi_config.sta.password));if (wifi_get_authmode(&wifi_config.sta.threshold.authmode, ssid) != false){ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );ESP_LOGI(TAG, "wifi_init_sta finished.");s_retry_num = 0;//ap重连次数清零esp_wifi_connect();//触发首次连接AP/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,pdFALSE,pdFALSE,portMAX_DELAY);/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually* happened. */if (bits & WIFI_CONNECTED_BIT) {ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",ssid, password);USER_UART_INFO("[ATPN] OK\n");is_connect_ap = true;//已经连接上AP了} else if (bits & WIFI_FAIL_BIT) {ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",ssid, password);USER_UART_INFO("[ATPN] ERROR:3\n");//连接AP失败} else {ESP_LOGE(TAG, "UNEXPECTED EVENT");USER_UART_INFO("[ATPN] ERROR:3\n");//连接AP失败}}else{USER_UART_INFO("[ATPN] ERROR:5\n");//无ap信息}
}

上面的代码主要是通过调用wifi_get_authmode(),从之前wifi_scan()存入到ap_info[]中的数据,获取路由器的加密方式。
接着调用esp_wifi_connect()进行首次连接ap。
然后通过事件组s_wifi_event_group接受WIFI_CONNECTED_BIT或者WIFI_FAIL_BIT事件,以判断连接是否成功。

TCP CLIENT

参考例子esp-idf/examples/protocols/sockets/udp_client
如果想用基于select机制的非阻塞的recv/send,可以参考例子esp-idf/examples/protocols/sockets/non_blocking

本功能对应模块app_socket_client。
在app_socket_client.c中,有一个AT指令处理函数,对应着ATPC指令,它们的相关实现如下:

#define CLIENT_QUQUE_NUMB       5
#define CLIENT_QUQUE_DATA_SIZE  512
typedef struct {uint16_t len;uint8_t  data[CLIENT_QUQUE_DATA_SIZE];
} client_send_q_t;
#define INVALID_SOCKET          (-1)
static volatile int sock = INVALID_SOCKET;
static volatile struct sockaddr_in dest_addr;
static volatile QueueHandle_t client_send_queue;
/**
* @brief socket的重连
* @param[in] paddr:服务器相关信息
* @retval true:成功 false:失败
*/
static bool app_socket_client_reconnect(const struct sockaddr_in *paddr)
{
...if (sock != INVALID_SOCKET){close(sock);sock = INVALID_SOCKET;}sock =  socket(AF_INET, SOCK_STREAM, 0);int err = connect(sock, (struct sockaddr *)paddr, sizeof(struct sockaddr));ESP_LOGI(TAG, "sock=%d,addr=%x,port=%x", sock, (int)paddr->sin_addr.s_addr, paddr->sin_port);if (err != 0) {ESP_LOGE(TAG, "Socket unable to reconnect: errno %d", errno);close(sock);sock = INVALID_SOCKET;USER_UART_INFO("[ATPC] ERROR:3\n");//连接 server失败return false;}ESP_LOGI(TAG, "Successfully connected");return true;
}// ATPC指令对应处理函数
void app_socket_client_connect(int argc, char** argv)
{
...char *ip_addr=argv[2];char *ip_port=argv[3];static bool is_inited = false;if (is_inited) {//当前版本只允许创建一个clientESP_LOGE(TAG, "Socket is inited");return;}//初始化服务器信息,并发起首次连接dest_addr.sin_addr.s_addr = inet_addr((char*)ip_addr);dest_addr.sin_family = AF_INET;dest_addr.sin_port = htons((uint16_t)atoi((char*)ip_port));if (false == app_socket_client_reconnect((struct sockaddr_in*)&dest_addr)) {return;}is_inited = true;ESP_LOGI(TAG, "Successfully connected");USER_UART_INFO("[ATPC] OK\n");//create queueclient_send_queue = xQueueCreate(CLIENT_QUQUE_NUMB, sizeof(client_send_q_t));//设置进入透传模式if (app_socket_set_to_pass != NULL) {app_socket_set_to_pass();}xTaskCreate(app_socket_client_recv_task, "app_socket_client_recv_task", 4*1024UL, NULL, 12, NULL);xTaskCreate(app_socket_client_send_task, "app_socket_client_send_task", 4*1024UL, NULL, 11, NULL);return;
}

为了方便展示,本demo中实现的socket tcp client所使用的recv()/send()是默认的阻塞模式,因此app_socket_client_connect()在成功连接server后,还需要创建两个任务app_socket_client_recv_task和app_socket_client_send_task。前者阻塞接收server发来的数据;后者等待队列client_send_queue中的数据,有则发送:

//判断是否为透传模式的回调函数
bool (*app_socket_check_is_pass)(void) = NULL;
//设置进入透传模式的回调函数
void (*app_socket_set_to_pass)(void) = NULL;
// 通过socket client发送数据到server
void app_socket_client_send_data(uint8_t *data, uint16_t len)
{client_send_q_t send_buf;send_buf.len = len;if (send_buf.len > CLIENT_QUQUE_DATA_SIZE) {send_buf.len = CLIENT_QUQUE_DATA_SIZE;}memcpy(send_buf.data, data, send_buf.len);xQueueSend(client_send_queue, (void *) &send_buf, 0);
}//socket client 接收任务
static void app_socket_client_recv_task(void *arg)
{static uint8_t rx_buffer[CLIENT_QUQUE_DATA_SIZE];ESP_LOGI(TAG, "app_socket_client_recv_task");while (1){int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);// Error occurred during receivingif (len <= 0){if (len < 0) {ESP_LOGE(TAG, "recv failed: errno %d", errno);}if ( ((errno==ENOTCONN || errno==ECONNRESET)&&(len < 0)) || (len == 0) ){while (1) {//循环重连if (!app_socket_client_reconnect((struct sockaddr_in*)&dest_addr)) {vTaskDelay( 500/portTICK_PERIOD_MS );}else {break;}}}}else {ESP_LOGI(TAG, "Received %d bytes from %s:", len, inet_ntoa(dest_addr.sin_addr.s_addr));// 在透传模式下,接受到的数据传送到串口if (app_socket_check_is_pass != NULL){if (app_socket_check_is_pass()) {USER_UART_SEND(rx_buffer, len);}}}}
}//socket client 发送任务
static void app_socket_client_send_task(void *arg)
{static client_send_q_t send_buffer;ESP_LOGI(TAG, "app_socket_client_send_task");while (1){//等待需要发送的数据if (xQueueReceive(client_send_queue, (void *) &send_buffer, portMAX_DELAY) == pdTRUE){if (send_buffer.len > 0){int len = send(sock, send_buffer.data, send_buffer.len, 0);if (len <= 0){if (len < 0) {ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);}if ( ((errno==ENOTCONN || errno==ECONNRESET)&&(len < 0)) || (len == 0) ){while (1) {//循环重连if (!app_socket_client_reconnect((struct sockaddr_in*)&dest_addr)) {vTaskDelay( 500/portTICK_PERIOD_MS );}else {break;}}}}}}}
}

测试

为了方便演示,这里串口终端和tcp server使用的工具都是常用的sscom5
测试结果如下:
在这里插入图片描述

半夜三点多才写完(明天早上还有面试…惨了)路过点个赞呗~

有空,我会再在评论区里更新一下gitee.com或者百度网盘的包。


http://chatgpt.dhexx.cn/article/I4Xa0LLC.shtml

相关文章

十、stm32-ESP8266(串口透传、MCU透传、控制LED亮灭)

目录 一、固件库模板二、准备资料三、简介1. 引脚2. 无线组网2.1 ESP8266 在 SoftAP 模式2.2 ESP8266 在 station 模式2.3 ESP8266 在 SoftAP station 共存模式 3、透传功能4. 基本配置&#xff08;所有AT指令都必须换行&#xff09;4. 模式配置4.1 STA 模式4.2 AP 模式 四、实…

如何用 ESP-AT 进行多种场景下的 UDP 透传

> 此博客将会记录三种不同的测试场景下的 UDP 透传 ESP 设备开启 Wi-Fi AP UDP Server 模式ESP 设备开启 Wi-Fi AP UDP Client 模式ESP 设备开启 Wi-Fi Station UDP Client 模式ESP 设备开启 Wi-Fi Station UDP Server 模式 1 ESP 设备开启 Wi-Fi AP UDP Server 模式 说…

WIFI-TTL透传模块

简介 WiFi-TTL透传模块基于我司DT-ESPC2-12模块研发&#xff0c;引出串口TTL、EN、STATE 等引脚。产品内置我司最新版本的串口透传固件可完成设备TTL 端口到WiFi/云的数据实时透传。本模块可直接取代原有的有线串口&#xff0c;实现嵌入式设备数据采集和控制。 TTL-WiFi 模块…

vue透传

太香了 背景介绍 透传是一个通讯层面的概念&#xff0c;指的是在通讯中不管传输的业务内容如何&#xff0c;只负责将传输的内容由源地址传输到目的地址&#xff0c;而不对业务数据内容做任何改变。 其实透传这个概念&#xff0c;我最早是从上面一个领导那里听到的&#xff0…

Ra-08透传固件应用

目录 1、功能介绍2、硬件接线3、固件烧录4、应用说明指令说明指令使用示例应用示例 5、联系我们 1、功能介绍 Ra-08透传固件主要功能有&#xff0c;设置发送或者接收模式&#xff0c;配置各个射频参数&#xff0c;设置本地地址与发送的目标地址&#xff0c;设置进入睡眠模式等…

EC800G透传模式

透传&#xff1a;指与传输网络的介质、调制解调方式、传输方式、传输协议无关的一种数据传送方式。1.准备 安信可透传云http://netlab.luatos.com/ QCOM_V1.6 LTE Standard TCP/IP 应用指导 2.AT指令格式介绍 2.1场景配置 该命令可用来配置、、以及其他TCP/IP 场景参数。Qo…

【无线通信】一文讲透串口透传

而随着万物互联的深入&#xff0c;想要实现智能设备的通信&#xff0c;串口透传就是一种非常高效的通信方式。 ** 什么是串口透传&#xff1f; ** 透传&#xff1a;透明传输&#xff08;SerialNet&#xff09;。即在传输过程中&#xff0c;对外界透明&#xff0c;不管所传输的…

ESP8266配置透传模式(AT指令)

ESP8266使用AT指令的前提是模块已烧录AT固件&#xff0c;固件可以在官网下载&#xff0c;固件烧录这里也直接略过&#xff0c;可以参考其他博文 AT指令恢复出厂设置 用AT指令将ESP8266恢复出厂设置&#xff08;因为之前配置了什么也不确定&#xff0c;直接恢复出厂&#xff09…

透传,无线透传

透传: 透传&#xff0c;即透明传输&#xff0c;指的是在通讯中不管传输的业务内容如何&#xff0c;只负责将传输的内容由源地址传输到目的地址&#xff0c;而不对业务数据内容做任何改变。 无线透传模块&#xff1a; 透明传输模块&#xff0c;透明传输就是在传输过程中&#x…

关于ESP8266的透传模式测试(一)——TCP Client透传模式

一、前言 本次测试所使用的是正点原子的ATK-ESP8266 WIFI模块。直接使用官方提供的固件使用AT指令来配置模块并使用。 模块默认为AT指令状态&#xff0c;模拟波特率为115200&#xff08;8bit数据位&#xff0c;1bit停止位&#xff09;。 硬件连接 使用USB转TTL方式&#xf…

一文了解透传云基础知识

一文了解透传云基础知识 一&#xff1a;透传云定义&#xff0c; 首先了解下透传的定义 透传&#xff1a;透明传输。即在传输过程中&#xff0c;不管所传输的内容、数据协议形式&#xff0c;不对数据做任何处理&#xff0c;只是把需要传输的内容数据传输到目的。 透传云&#xf…

一个网工的十年奋斗史 - 移民篇

我在茶余饭后总能听到&#xff1a;某同事出国以后的生活多好&#xff0c;什么时候买了个别墅大house&#xff0c;什么时候晒了一下蓝天白云没有雾霾&#xff0c;让人羡慕不已。 可是我们也同样忽略了移民背后的努力和艰辛。殊不知对于移民的人来说&#xff0c;需要舍弃很多。试…

准备全面转入SAP和SOA领域

同事跑过来说他撞死了一只袋鼠。 为什么什么事都有&#xff1f; Whatever... 这周5最后一天工作&#xff0c;除了今天早上工作紧张点&#xff0c;已经完全没有什么事情了。爽死了&#xff0c;终于可以不工作了&#xff0c;可以天天在家睡大觉啦。哈哈哈。真是工作后才知道…

天使投资人给阿里新贵们的一些建议

作者曾为 Facebook 早期员工&#xff0c;现为天使投资人。 这几天被阿里的同志们的喜事刷屏&#xff0c;让我想起来当年 Facebook 上市的场景。都是一个众望所归的 IPO&#xff0c;但 Facebook 弄砸了&#xff0c;阿里很成功&#xff01; Congratulations&#xff01; 当然&…

在淘宝做前端的这三年 — 第三年

关注“重度前端” 专注前端、专注全栈、输出价值 助力前端深度学习 ━━━━ 更加深入内容发布业务 自从去年掌握了一些业务分析方法&#xff0c;今年工作更喜欢做业务了。由于阿里员工自己不能开淘宝帐号运营&#xff0c;所以我开了个公众号做竞品调研&#xff0c;站在一个创…

【转载】大龄码农的新西兰移民之路

大龄码农的新西兰移民之路 【转载】博主地址&#xff1a;https://www.cnblogs.com/yanxiaodi/p/MoveToNewZealand.html 最近一年没怎么发博客&#xff0c;确实在忙一件事情——移民新西兰。如今已顺利入职&#xff0c;新西兰绿卡正在申请过程中&#xff0c;终于有时间将最近一年…

ENVI波段合成逆运算——波段拆分

APP Store中查找工具&#xff0c;第8页“将多波段图像拆分成多个单波段文件 V5.3”。 点击 Install App安装插件。重启ENVI后&#xff0c;可以看到Toolbox / Extensions下有Split to Multiple Single-Band Files工具。 ENVI中打开需要进行波段拆分的文件。 点击Split to Multi…

遥感基础——红外波段分类

红外波长的分类 红外线是波长介乎微波与可见光之间的电磁波&#xff0c;波长为0.75&#xff5e;1000 μm&#xff0c;其中&#xff0c;近红外、短波红外、中波红外、长波红外所在区间如下&#xff1a; - 近红外 (Near Infrared, NIR) : 0.75~1.1 μm - 短波红外 (Short …

频段划分

电磁波频段的划分 射频&#xff08;300KHz-300MHz&#xff09;&#xff1a;包括LF&#xff0c;MF&#xff0c;HF&#xff0c;VHF 微波&#xff08;300MHz-3000GHz&#xff09;&#xff1a;包括UHF&#xff0c;SHF&#xff0c;EHF&#xff0c;PHF 微波频段的划分 波段频率范围…

雷达篇(四)雷达工作波段

目录 1、简介 2、波段划分 3、各波段雷达功能 4、波长计算公式 1、简介 不同波段电磁波的传播方式和特点各有不同&#xff0c;所以它们的用途也不同。电磁波段划分如图 1所示。 在雷达行业&#xff0c;雷达工作频率划分成为若干波段&#xff0c;由低到高的顺序依次是高频&a…