0%

截止2022年1月23日,以下是ST公司的产品线,下图通过Flash大小和Nucleo类型对产品进行了一定划分。

img

NECLEO-L476RG DATA BRIEF

Necleo系列开发板下面有很多型号,且每个型号的板子(除开芯片以外)设计应该都是大同小异的,所以最底层板子也就有了自己的型号。

而 NecleoL476RG 开发板的底板型号为 MB1136 。且下方所有Necleo的产品都自带 ST-LINK/V2-1 调试器。

image-20220122193806691

ST-LINK/V2-1

支持USB软件 重新检查(re-enumeration) 、支持虚拟COM口、支持大容量储存、支持超过 100mA 电流的电源管理,但是不支持 SWIM 接口且最小输入电压为 3V

注意:一旦激活了 ST-LINK/V2-1 的目标读出保护功能,就会阻止目标应用运行事后运行(prevents the target application from running afterward.)目标读出保护必须被关闭(must be kept disabled on board)。

可以根据跳线帽的两种状态来使用 ST-LINK/V2-1:

  • 在线编程和调试STM32(Program/debug the on-board STM32),此时 CN2 的两个跳线帽都连接着,处于在线编程状态(默认)。
  • 使用连接到SWD连接器CN4的电缆对外部应用板中的MCU进行编程/调试,此时 CN2 的两个跳线帽都不连接,以允许 CN4 (即 SWD 接口)连接至外部连接器。
image-20220123183857115

LAYOUT

image-20220123182028068

image-20220123182139437

CHIP BREIEF

STM32 Nucleo L476RG 所使用的芯片是 STM32L476RGT6U,其中 L4 是系列号,76 是产线,R 是指64pin,C 是指 256Kbytes 的 Flash内存大小。

下方为《STM32 Nucleo-64 boards data brief》提供的 产品芯片命名方法

image-20220122195540612

REFERENCE

  1. NUCLEO-L476RG

INSTALL FONTS ON DEBIAN LINUX

We can install True Type or Open Type fonts(.ttf / .otf / .ttc) in DEBIAN LINUX, like ubuntu or kali.

DOWNLOAD FONT FROM WEBSITE

  1. Download Cascadia Code from https://github.com/microsoft/cascadia-code/releases and unzip it.
  2. We got 3 folders here: /otf/ , /ttf/ and woff2 , and we only need `ttf

COPY FILES TO SYSTEM FONT DIRECTORY

Font fils are generally installed in either the system font directory on the path /usr/share/fonts/ or in a user font directory that is frequently on one of the following paths:

  • ~/.local/share/fonts/
  • ~/usr/local/share/fonts/
  1. Execute the following command to copy the fonts to system path
1
sudo cp -r ttf /usr/share/fonts/CascadiaCode

GENERATE FONT CHACHE

We need to build font infomation caches for apps using fontconfig for their font handling.

1
2
cd /usr/share/fonts/CascadiaCode
fc-cache -f -v

NOTE

If you cannot execute fc-cache command , copy and execute the following command in terminal.

1
sudo apt install fontconfig

VERIFY THE FONT INSTALLATION

Confirm that the fonts are installed by displaying the paths and style definitions with fc-list command filtered on the font family name with grep .

1
fc-list | grep "Cascadia Code"

CUSTOMIZE VSCODE

  1. Get to Setting
image-20220122161611892
  1. Search font in the bar
image-20220122161750043
  1. Add 'Cascadia Code', to the Editor: Font Family .
  2. Restart vscode.

基础技能

  1. ARM架构芯片的样例代码加载、编译、烧录、调试工作熟悉。
  2. bitbucket 如何使用(是否需要配置SSH、repository如何pull和push、add、commit等) √
  3. confluence 如何使用(任务的查看、提交、文章的发布、协作等等)

IDE for Realtek

VSCODE ARM

image-20220112105541195
image-20220112110410253
image-20220112110533598
image-20220112110507665
image-20220112105734831

KEIL ARM

将Realtek RTL8762D SDK中的项目单独摘出来,放到某个文件夹下进行管理时,需要单独更改好几处内容:

  1. C/C++的Include Path
  2. 源文件的Source Path
  3. APP Image(.bin 生成文件),即 after_build_common.bat 的路径和内容。

如下所示,把单独某个Project摘出来时会产生很多感叹号。

image-20220112111951120

头文件路径修改

此时需要进入设置中进行头文件路径修改

image-20220112133356533

选择 C/C++ 选项卡下的 Include Paths 进行修改。

image-20220112133505056

原来的路径设置都是使用相对路径进行的,此时需要将 sbee2-sdk-v1.0.0 文件夹放到与你项目文件同盘的某个文件夹下,最好不要相距太远。

image-20220112133731688

可以使用 VS Code将 .uvprojx 文件打开,使用搜索和替换工具对相关头文件的路径进行替换。

源文件路径修改

修改方法同头文件,

image-20220117094508419

bat文件路径修改

.bat 文件是用于在 .o 文件生成后的链接脚本。所以如果该脚本自身路径和脚本内的包含路径出错,可能会导致无法编译出对应的 app_MP_adk##### 文件。

image-20220117095506866

下方为样例代码原来的设置情况:

image-20220120134642405

Option-User 设置中,可以查看到 After Build/Rebuild 相关的设置,其中 Run #1 则是 Realtek MP Tools 需要烧录 EVB开发板相关的脚本文件。

image-20220117095438927

将单独摘放出来的项目文件夹 pixart_i2csbee2-sdk-v1.0.0sbee2_wristband_sdk_upperstack_img 放到同一个文件夹下。

image-20220117110446703

因此修改 .uvprojx 文件内容下 after_build_common.bat 的路径时,将该路径修改为如下的相对路径即可:

1
..\sbee2-sdk-v1.0.0\tool\after_build_common.bat $J #L @L
image-20220117104943624

保存修改后的 .uvprojx 文件,可以看到 Keil V5 自动更新了相关设置。如下:

image-20220117104955125

after_build_common.bat 控制着自动生成Realtek 的 MP Tool 需要使用的 APP Bin文件,如果该 Run #1 没有启用,则无法生产该文件。

image-20220117105247314

.bat 文件下所有的 ..\..\..\tool\ 都要修改成 ..\sbee2-sdk-v1.0.0\tool\,如果项目文件夹和SDK文件夹路径有异,则需要适当修改。

image-20220117105040885

启用完成之后即可生成对应 app_MP_adk##### 文件

image-20220117105414578

HARDWARES

ADAPTER

SPECIFICATION

A4芯片,即KA8G2芯片用的转接板需要接入5V电压,LDO会转换电压。

而PAT9126JA芯片则使用两个3.3V进行接入。

CHIP & BOARD

开发测试板为 Realtek RTL8762D EVB KIT。

型号: RTL8762DW

SENSOR - KA8G2

KAG2 is a high performance and ultra low power CMOS-processed optical image sensor with integrated digital image process circuits. It is based on an optical navigation technology which measures changes in position by optically acquiring sequential surface images(frames) and mathematically determining the speed, the direction and the magnitude of motion. The displacement delta_X and delta_Y information are available in registers which are accessible through SPI serial interface. A host controller reads and translates the data from the SPI serial interface into RF signals before sending them to the host PC.

SPECIFICATION

image-20220113150323525

HARDWARE LINKING

image-20220112172532934
企业微信截图_16391255852712

CHIP INITIATE

这个芯片启动时,需要对一些寄存器进行写入以初始化。下方为二维数组,sensor_init_regs[][0] 为寄存器地址,sensor_init_regs[][1] 为寄存器需要写入的数据。

1
2
3
4
5
6
7
8
9
uint8_t sensor_init_regs[7][2] = {
{0X09, 0XA5},
{0X26, 0X34},
{0X19, 0X04},
{0X6D, 0X39},
{0X0D, 0X20},
{0X0E, 0X20},
{0X09, 0X00}
};

初始化时,需要注意以下问题:

  1. 某些主控芯片在使用两线SPI进行数据写入时,会有要求使用 7bit 地址,且 MSB 为 1 。此时需要判断是否需要认为修改地址的 MSB为 1 ,例如 Realtek 的 RTL8762DW 芯片就不需要人为修改,人为修改会导致波形异常。而某些芯片需要人为写入MSB。
  2. 在每一次写入寄存器之后,强烈建议进行延时,可以使用 delay(0xFFFF),(尝试过 0xFF 太短,不能完成初始化写入)。

SENSOR - PAT9126JA

  1. 需要确定 ID_SEL 引脚的连接情况,是拉高、接地还是悬空。分别对应的 CHIP ID 都是不一样的,可能是0x73  0x75  0x79 三者之一。

transformer 上的 VCC3.3V

SPECIFICATION

这个芯片有两种电压要求,默认为高电压版本 3.3V ,可以通过SPI写入寄存器和硬件并线来达到降低至 1.8V 低电压的模式。

HADWARE LINKING

OpticalSensorTransfer_I2C

SDK & Tools

此处有 2个SDK包 和 3个tool包,分别是:

  1. sbee2-sdk-v1.0.0.zip
  2. sbee2_wristband_sdk_upperstack_img.zip
  3. MPPackTool_v2.0.5.2.zip
  4. 日志输出软件:DebugAnalyzer-v4.0.0.14.zip
  5. 代码烧录软件:BeeMPTool_kits_v1.0.5.0.zip

BUILD / FLASH / LOG

BUILD

点击 build 按钮即可进行代码构建。

image-20220113090856565

build 完毕之后可以看到下方的成功提示 0 Error(s), 0 Warning(s)

image-20220113091008941

FLASH

FLAHS需要经过 configuration 、 detect 和 download 三步

configuration

根据《RTL8762D SDK User Guide CN》文件,RTL8762D 的 EVB KIT 是可以支持 JLINK 的(如下图所示)。

image-20220113095321215

但这里并未使用 JLINK,而是使用 Realtek 专门的工具 BeeMPTool_kits, 通过 UART 进行烧录。

image-20220113095804076

打开 MPTool.exe ,并选中对应的芯片型号 RTL8762D

image-20220113095854784

在这里选择 调试 模式进行烧录

image-20220113095949881

Config Set 中选择 Confirm ,不需要修改什么东西。

image-20220113100100098

此处需要设置 Flash 地址映射文件 flash map.ini

image-20220113100324900
image-20220113101953154

下方为 《RTL8762D SDK User Guide CN》文件中,9.1章节对五个images文件进行了描述。

image-20220113102036834

FILE TYPE DESCRIPTION FILE PATH
System Config File - 来自 BeeMPTool_kits \BeeMPTool_kits_v1.0.5.0\BeeMPTool\ConfigFile\
Bank0 OTA Header File - 来自 sbee2_wristband_sdk_upperstack_img \sbee2_wristband_sdk_upperstack_img\src\app\wristband\firmware\
Bank0 Secure Boot Loader Image - 来自 sbee2_wristband_sdk_upperstack_img \sbee2_wristband_sdk_upperstack_img\src\app\wristband\firmware\
Bank0 ROM Patch Image - 来自 sbee2_wristband_sdk_upperstack_img \sbee2_wristband_sdk_upperstack_img\src\app\wristband\firmware\
Bank0 APP Image - 来自 sbee2-sdk-v1.0.0 sbee2-sdk-v1.0.0\board\evb\io_sample\SPI3WIRE\spi3wire_polling\bin

关于app image文件选择

在Build完成后,会生成三个 .bin 文件,如果选择错误,会提示 MD5 check error!Image type doesn't match IC type. ,选择正确的话会提示 File check OK

image-20220113111301561

detect

detect 的时候需要注意:

  1. 将 EVB kit上的 J15 LOG口接地,否则会检测失败
  2. 如果出现 Failed 字样,则按一下 EVB KIT 上的红色的 RESET 按钮进行复位后再尝试。
image-20220113111054035
image-20220113103853161

download

最后选择 download 下载即可。

image-20220113104047601

UPPERSTACK FLASH

自带的 \sbee2-sdk-v1.0.0\doc\ 路径下的教程是,都是有 Bank0 Upperstack Image 需要烧录的。

image-20220120140307997

步骤如下:

  1. 使用 \sbee2_wristband_sdk_upperstack_img\src\app\wristband\firmware\upperstack_img 路径下的 .ini 文件作为 layout 文件。(而之前使用的flash map.ini 地址为 \sbee2_wristband_sdk_upperstack_img\src\app\wristband\firmware\

  2. 指定 \sbee2_wristband_sdk_upperstack_img\src\app\wristband\firmware\upperstack_img 路径下的 .bin 文件作为 Upperstack Image 文件。

  3. \sbee2_wristband_sdk_upperstack_img\board\evb_stack_img\wristband\flash_map.h 文件作为项目工程里的唯一内存映射文件依赖。flash_map.h 被放在 mem_config.h 头文件下,间接被 syetem_rtl876x.h 引用。

LOG

RTL8762D 的 EVB KIT 不支持 JTAG 方式进行观察,(听说是)通信过程容易被打断。

这里使用 UART 和 EVB KIT 上的 J15 口来观察 LOG数据。

LOG软件

使用专用工具 DebugAnalyzer 进行日志输出。

  1. 选择合适的串口,即使用 FT232 的UART口,将该芯片口的 RX 连接至 RTL8762D 板子上的 J15 口。并在电脑中选中对应的 FT232 设备。
image-20220113093030488
  1. 需要设置 App Trace File
image-20220113093723962
  1. 观察日志输出
image-20220113104331739

COM SETTING

UART SETTING

image-20220113111953878

PERIPHERAL

3-WIRED SPI

以下是主控板 RTL8762D 的SDK对3线SPI的相关设置结构体。

1
2
3
4
5
6
7
8
9
10
11
12
13
typedef struct
{
uint32_t SPI3WIRE_SysClock; /*!< Specifies system clock */
uint32_t SPI3WIRE_Speed; /*!< Specifies SPI clock. */
uint32_t SPI3WIRE_Mode; /*!< Specifies SPI operation mode.
This parameter can be a value of @ref THREE_WIRE_SPI_mode */
uint32_t SPI3WIRE_ReadDelay; /*!< Specifies the delay time from the end of address phase to the start of read data phase.
This parameter can be a value of 0x0 to 0x1f, delay time = (SPI3WIRE_ReadDelay+1)/(2*SPI3WIRE_Speed) */
uint32_t SPI3WIRE_OutputDelay; /*!< Specifies SPI output delay 1T or not.
This parameter can be a value of @ref THREE_WIRE_SPI_OE_delay_config */

uint32_t SPI3WIRE_ExtMode; /*!< Specifies extended timing window for SPI output enable = 0. */
} SPI3WIRE_InitTypeDef;

WRITING-DELAY

\[ 1s = 1^3ms = 1^6us = 1^9ns\\ 1Hz = 1^{-3}KHz = 1^{-6}MHz = 1^{-9}GHz \]

在3线SPI的数据线读取过程中,在前一段地址帧结束且尚未开始读取数据前,会有一段延时。由 spiReadDelayspiWireSpeed 两个参数控制。 \[ DelayTime = (spiReadDelay +1) / (2* spiWireSpeed) \tag{延时计算公式} \] 例如, 当 spiWireSpeed = 8e5 时, 设置 spiReadDelay = 0x03 ,此时 可以在中间延时 2.5us

CLOCK_FREQ

将RTL8762D的SPI通信时钟频率从 2E7 更改为 1E6 后可以短时间正常通信,但是稍微过一段时间就出现了不稳定,度数全为 0 ,且复位后读取的 chipID 也为 0x00, 0x00

1
2
3
// the actual frequency of spi is set by `SPI3_WIRE_SysClock`
// `1E6` means 1MHz, and `2E7` means 20MHz.
SPI3WIRE_InitStruct.SPI3WIRE_SysClock = 1E6;
image-20220119152741283

TIMING

\[ Sysclk = 1e7 \\ wirespeek = 8e5 \]

2-WIRED SPI

To recover the correct communication of SPI, the host controller can de-assert the SCLK for at least tRESYNC (1us min), and then keep SCLK asserted for a certain time interval tWDT (1.7ms, min) as shown in below Figure . to force the SPI control circuits of the sensor to reset.

image-20220120154724619

DEBUG RECORDS

image-20220112163300158

0x05 // 0000 0101

// 1000 0101

DELTA_X & DELTA_Y UNREAD

Motion  DYOVF  DXOVF 并未读出,未检测到移动。

image-20220114110802052

Operation_Mode = 0xB8, cofiguration = 0x17 均为默认

image-20220114111325286
image-20220114111114776

0xB8 使 设备处于睡眠模式,configuration = 0x17 使设备未处于 sleep3powerDown 为正常模式,即未断电。

所以需要修改 Operation_Mode0x01

在设置了下方的语句之后,LOG记录传送回来的 OperationMode 对应的数据为 0xFC0xB81111 11001011 1000) 。

默认情况下 OperationMode0xB81011 1000

异常情况下 OperationMode0xFC1111 1100

即第 2 位和 第 6 位会变,查数据手册,只有第 2 位(Slp2mu_Enh)有影响,该位控制芯片强制进入 睡眠2 模式。

1
spi3wire_writebyte(REG_KA8G2_OPERATION_MODE, KA8G2_OM_RUN);  // edited by liew in 20211114
image-20220114135400211
image-20220114135647079

从《KA8G2 optical mouse sensor》中的 MOTION Pin Function 可以看出,Motion 寄存器即运动检测标志相关寄存器。

image-20220114142319440

主控板IO口数据异常

下方为利用SDK进行 读数据 的相关操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
int main(void){
extern uint32_t random_seed_value;
srand(random_seed_value);
spi3wire_demo();
DBG_DIRECT("TEST_20220120");

while (1){
for(uint8_t i = 0; i< 0xFF; i++){
spi3wire_writebyte(0x7F, i);
delaySys(0xF);
}
}
}

并用逻辑分析仪进行捕获和分析,发现数据异常:

image-20220120151632286

经过检查,发现时序解码无误,所有波形的高低和解码结果一致。

image-20220120151645002

但是相连的数据之间数据差异较大。

image-20220120151638254

查看LOG也发现数据的确有按照预定的逻辑进行循环:

20220120

但是逻辑分析仪采出来的数据就是异常。

经过分析,是因为逻辑分析仪的采样率为 1MHz ,与SPI外设的频率 1e6 一致。

修改了逻辑分析仪的采样率为 2MHz ,提高了1倍,采样出来的逻辑就正常了。

image-20220120162227888

但是之前的项目只用了写数据的函数。示波器波形和逻辑分析仪都能正常。

改了项目主循环中的语句为读数据之后,就出现异常了。

问题推断

通过注释部分语句,进行间歇性测试和波形观察。

发现,spi读取语句 uint8_t spi3wire_readbyte(uint8_t address) 可能是波形不正常的原因。

硬件查找主控板和底板的引脚问题:

  1. 找到扩展板上的GPIO口对应核心板上的哪个口
  2. 使用示波器探头直接接触对应的GPIO口并查看波形,查看主控板和底板之间是否存在问题。

发现示波器探头从底板更换至主控板之后,示波器所显示波形并无差异。

GITEE: https://gitee.com/isletspace/esp32iot

本项目是使用 微信小程序+腾讯云+乐鑫开发板+5V-多路-继电器+220V-AC-电器 的模式对家庭中的硬件进行检测和控制,本项目涉及到 网络前端服务器后端网络通信物联网硬件控制 方面的相关知识。

需要实现的功能

  1. 开发板能够自动连接家庭WiFi
  2. 开发板能够通过MQTT协议与后台服务器取得联系
  3. 开发板能够定时自动获取时钟并校准
  4. 开发板能够根据MQTT协议控制外围电路
  5. 开发板能够根据已经设置的参数与实时的传感器参数比对,并在一定环境条件内开启/关闭相关电路
  6. 手机可以通过微信小程序发送MQTT数据至服务器

软件开发平台:Mac

硬件开发IDE:Arduino

硬件准备

  1. 4路5V红板(光耦/高低电平)继电器 *1
  2. DHT11温度模块 *2
  3. 加热器 *1
  4. ESP32-WROOM-32开发板 *1

其他:

  1. 杜邦线
  2. 电烙铁
  3. 锡丝
  4. 松香
  5. 面包板

芯片模组比对选型

ESP32-WROOM-32X(此处 X 代表不确定) 和 ESP32-WROVER-X(此处 X 代表不确定) 在性能上基本一模一样,包括核心数、最大时钟频率、Flash大小、支持的接口类型 和 特殊传感器等等。除了在 PSRAM、工作温度范围、天线、WiFi最高频率 和 模组尺寸上有所区别外。 ESP32-WROVER-X 则具有PSRAM 和 最大的面积(18mm × 31.4mm × 3.3mm)。

官方展示的ESP32模组性能参数对比

芯片选型

无脑选了ESP32-WROOM-32SE,反正自己用,而且便宜(¥21.5包邮)。

芯片基本信息

Arduino所展示的开发板可调参数

Arduino IDE准备

使用 Arduino IDE 进行开发,但开发配置相关的 .json 文件 及其安装包都在 github.com 上,但因为加速器的加速层级可能和IDE拉取资源包所用的数据层级不在同一个上面,无法代理,就白天基本上无法下载,凌晨(正经程序员谁tm熬夜)才有机会下载东西。

英文版下的 首选项Preferences

修改附加开发板管理网址

然后去 开发板管理器 中搜索 esp32 进行安装。

目录-开发板-开发板管理器
搜索关键词“esp32”

解决github问题

方法一

本来应该用如下链接进行配置的:

1
https://dl.espressif.com/dl/package_esp32_index.json 

自己扒拉了一遍该文件中可能包含的所有资源包(主要是 github.com 上的),然后修改了 .json 文件,放到自己的桶里,然后放出来使用,还好这个文件里有明确提到要哪些资源不然也没法扒拉。

1
https://code.islet.space/espressif/dl/package_esp32_index.json

注意:Mac系统下可能会因为曾经下载过的缓存文件无法生效(如果自行修改了网站上的 .json 文件的话),需要自行清除缓存,打开 ~/Library/ArduinoXX/cache/ 并对应删除该网站的文件夹即可,如 code.islet.space 。(这里的 ArduinoXX 中的 XX 需要自己去看自己的文件夹,应该是受版本控制的)

修改链接后可以正常下载

方法二

自己去github,用浏览器或者下载器下好了以后放到 用户目录--资源库--程序缓存--指定位置(如下)。

1
~/Library/ArduinoXX/staging/packages/

这个文件夹也就需要放这么多文件吧。

资源库缓存指定位置下的文件

亲测,第二种方法更好用。

提示安装成功

Visual Studio Code IDE准备

总的来说,VS Code的IDE配置会比Arduino更为复杂,VS Code下载毫无压力,且VS Code使用习惯之后更加方便。

至少前期配置工作来说,VS Code更为友好。

Espressif IDF插件安装

首先去插件市场搜索 Espressif IDF 插件进行安装,然后点击 查看 -> 命令面板

image-20211228182209737

到这里需要输入 configure esp-idf extension 以进入该插件的配置页面。

image-20211228182314161

必要工具安装

然后它就会提示你需要安装几个必要插件,有 Git / Python / CMake 和 Ninja。这些都可以从Espressif的 官方文档 中获取到安装步骤。

image-20211228182508965

下方为四个工具的官方下载链接,前三个都可以通过官方下载软件包进行安装,第四个 Ninja 我安装不成功,是通过 Mac Ports 进行安装的。

GIT : https://git-scm.com/

PYTHON : https://www.python.org/downloads/

CMAKE : https://cmake.org/download/

NINJA : https://github.com/ninja-build/ninja/releases

需要注意的是,CMAKE 和 Ninja 安装完还需要加入到系统环境变量 PATH 中去,Windows系统下的系统环境变量添加比较方便,下方为 Mac 系统下 CMake 的系统环境变量添加方法。

CMAKE命令行

打开Mac系统下的 CMake GUI,点击 Tools --> How to Install For Command Line Use ,可以查看到三种将 CMake 添加到命令行中去运行的方法。

点击“工具”菜单中的“如何为命令行使用进行安装”
可以查看到三种安装方法

使用的是第二种方法,向命令行输入 sudo "/Applications/CMake.app/Contents/bin/cmake-gui" --install 并输入管理员密码即可。

然后通过 cmake --version 可以查看到版本号说明安装成功,但需要注意的是 whereis cmake 还是没有用。

操作结果

工具安装验证

四个必须要安装的软件都已经安装完毕,通过 --version 可以查看版本号。

安装验证

配置继续

四个必要工具安装完毕之后,关闭 ESP-IDF Setup 页面,然后重新在 命令面板 输入 configure esp-idf extension 以进入该插件的配置页面。

再次进入配置页面

此处选择 EXPRESS 即可,里面会要求选择从哪个服务器下载(自己看情况选择Github / Espressif)、IDF版本(默认选最新)、IDF放置路径、工具路径、使用的Python3路径 等几个信息,选完了就进入下一界面,会自动下载安装 ESP-IDF。

详细配置页面

耐心等待下载完毕即可,我用 Espressif 服务器下载不下来,然后改用 Github 进行下载的。

image-20211228185748221

下载过程页面如下:

image-20211228190058612
image-20211228190027057

最后提示的安装成功:

image-20211228190438498

示例项目载入

命令面板 中输入 show examples projects

image-20211228190651117

即可调出 ESP-IDF的示例代码项目列表。

image-20211228190738993

选择 blink 作为测试代码。

image-20211228190839371

项目构建

这里可以用命令面板输入 esp build your project ,也可以点击GUI下方的 image-20211231124940242进行构建。

命令面板构建

构建完成后,会生成 build 文件夹,下次构建时CMake会查看变动的文件然后只编译变动过的代码。

也可以删除该 build 文件夹,使其全部重新构建,会比较费时。

build过程

点击下方的闪电按钮烧录按钮即可烧录,烧录成功提示如下:

烧录过程

连接WiFi

下图为使用示例代码更改的项目代码文件内容:

项目文件内容示例

利用ESP自带的示例代码station 进行调试和更改,需要注意以下几点:

  1. 不用去更改 isletSpaceIotMain.c 中的 SSIDPASS ,只需要在 sdkconfig 文件中进行更改即可(如下图)。

  2. 所有的 WiFi设置参数 都可以在 sdkconfig 文件中进行修改,如需要连接 AP 的 名称和密码,还有自身设备所显示的名称。

  3. 修改文件名之后,需要对两个 CMakeList.txt文件 和 一个Makefile 文件中的项目和文件名进行修改(如下图)。

如果修改代码名称需要修改main文件夹下的CMakeList文件
如果修改项目名称需要修改根目录下的CMakeList
如果修改项目名称需要修改根目录下的Makefile

MENUCONFIG 或者说 sdkconfig ,一个是图形界面的,一个是纯文本形式的。

用menuconfig的话只需要找到下方的齿轮按钮即可。

image-20211231130402110

可以找到WiFi相关的配置位置:

image-20211231130507316

sdkconfig 文件中的设备名称进行修改。

image-20211228223040901

修改完毕后可以在路由器 AP 的后台查看到已经连接的设备的名称,如下。

image-20211228223134009

MQTT协议

根据 Espressif 官网的 ESP-MQTT 开发文档可知,MQTT 协议支持以下几种形式:

  • MQTT over TCP

  • MQTT over SSL with mbedtls

  • MQTT over Websocket

  • MQTT over Websocket Secure.

各MQTT协议形式(与对应SDK里的 MQTT示例代码)及其所使用的端口号不同:

  • protocols/mqtt/tcp: MQTT over tcp, default port 1883
  • protocols/mqtt/ssl: MQTT over tcp, default port 8883
  • protocols/mqtt/ssl_psk: MQTT over tcp using pre-shared keys for authentication, default port 8883
  • protocols/mqtt/ws: MQTT over Websocket, default port 80
  • protocols/mqtt/wss: MQTT over Websocket Secure, default port 443

MQTT事件结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* MQTT event configuration structure
*/
typedef struct {
esp_mqtt_event_id_t event_id; /*!< MQTT event type */
esp_mqtt_client_handle_t client; /*!< MQTT client handle for this event */
void *user_context; /*!< User context passed from MQTT client config */
char *data; /*!< Data associated with this event */
int data_len; /*!< Length of the data for this event */
int total_data_len; /*!< Total length of the data (longer data are supplied with multiple events) */
int current_data_offset; /*!< Actual offset for the data associated with this event */
char *topic; /*!< Topic associated with this event */
int topic_len; /*!< Length of the topic for this event associated with this event */
int msg_id; /*!< MQTT messaged id of message */
int session_present; /*!< MQTT session_present flag for connection event */
esp_mqtt_error_codes_t *error_handle; /*!< esp-mqtt error handle including esp-tls errors as well as internal mqtt errors */
bool retain; /*!< Retained flag of the message associated with this event */
} esp_mqtt_event_t;

typedef esp_mqtt_event_t *esp_mqtt_event_handle_t;

MQTT相关示例代码

了解完官方开发文档中的信息,就可以知道MQTT示例代码里的这些文件夹命名含义,以及自己需要打开哪个示例代码了。

image-20211228223617579

MENUCONFIG 页面可以看到MQTT的相关配置信息。

image-20211229011902429

MQTT服务器开发

自行购买了腾讯云的服务器,然后完成了配置(步骤略),发现自测“主题订阅”不成功。

image-20211229033019004

然后刚好发现服务器的 Ubuntu 20 系统使用的防火墙是 iptables ,顺利打开 1883 端口。

1
sudo iptables -A INPUT -p tcp --dport 1883 -j ACCEPT

然后查看打开情况。

image-20211229032825212

顺便在服务器页面也打开相关配置。

image-20211229032753559

最后自测成功:

image-20211229032920902
image-20211229032953396

小程序开发(未完)

因为个人使用腾讯云注册了自己的域名 islet.space,且小程序也属于腾讯自家产品,为了后续开发的兼容性和便利性,就同步参阅了腾讯云的 物联网自主品牌小程序开发文档

image-20211227202550338

微信开发者工具

微信开发者工具下载页面:https://cloud.tencent.com/document/product/1081/47685

image-20211227202759080
image-20211227203058077

后台设置

物联网开发平台

DEBUG

烧录和调试过程报错

出现这种情况,可能是所选芯片不正确导致。

烧录错误提示

解决过程

重新选择了芯片,然后将烧录方法改为 UART ,重新烧录即可成功。

在插件中选择”扩展设置“
选择需要调试的设备类型
选择烧录方式
烧录成功提示

头文件查找错误

这个bug始终没有解决,之后再说吧。。。

提示无该文件

WIFI初始化出错

将WiFi-station的代码搬到 MQTT-TCP中,发现 wifiStationInit() 函数初始化错误,报错的行数是 117

wifi初始化函数出错

经检查,发现该函数示例代码的一部分,并未改动,且未添加其他自定义的 .h.c 文件进行编译,应该不存在人为修改错误。

检查函数定义

因为仅修改了本 isletSpaceIotMain.c 文件,就在本文件中搜索 esp_event_loop_create_default 关键字,发现在 app_main() 中也有该语句,初步判断可能是两次调用导致错误,就注释了 298 行 和 299 行进行重新编译和烧录,问题解决,设备可以正常连接到路由器。

注释重复语句

MQTT服务器连接错误

在设备成功接入WiFi后,发现MQTT客户端无法连接至服务器。给出的错误提示是 There are no transports valid ,大致意思即连接不可用。

Monitor提示无可用传输

经过检查,发现原来填写在 sdkconfig 文件中的 Broker URL 链接为 https://iot.islet.space ,而实际上,官网给出的配置方式如下:

查看官方URI定义

打开项目配置菜单,修改为 mqtt://iot.islet.space ,并重新 Build 和 Flash。

修改URL

可以发现错误已解决,设备已经正常连接至服务器。

Monitor提示成功

尝试在对应主题下发布信息进行测试:

尝试发布信息

通过终端Monitor可以观察到,设备正常接收到数据:

设备接收成功

eventHandler未进入

image-20211229182911935

参考

  1. Mac 安装 CMake 配置及环境配置
  2. Quick User Guide for the ESP-IDF VS Code Extension
  3. ESP-IDF 编程指南
  4. ESP-MQTT

请先确保电脑上已经安装了必须的软件,如 node.jsgit ,因为日常需要使用 代码数学公式流程图搜索 等工具,所以下方的插件安装也主要是与此相关的。

注意:以下仅适用于 hexo-next 主题。

插件安装

先放一个博客 islet.space 需要使用到的插件,都需要使用 npm 进行安装。

本博客使用到的一些插件

将下方这段脚本保存至 hexo_install.sh 文件中,并使用 chmod +x hexo_install.sh 命令为其添加执行权限,并使用 ./hexo_install.sh 进行执行即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# uninstall the unnecessary renderer,like marked and kramed
sudo npm uninstall hexo-renderer-marked --save
sudo npm uninstall hexo-renderer-kramed --save


# install the necessary plugins for hexo
sudo npm install @fancyapps/fancybox --save
sudo npm install @fortawesome/fontawesome-free --save
sudo npm install @next-theme/pjax --save
sudo npm install @next-theme/plugins --save
sudo npm install hexo-deployer-git --save
sudo npm install hexo-filter-mermaid-diagrams --save
sudo npm install hexo-generator-searchdb --save
sudo npm install hexo-math --save
sudo npm install hexo-renderer-ejs --save
sudo npm install hexo-renderer-pandoc --save
sudo npm install hexo-renderer-stylus --save

插件启用

pandoc

若要启用pandoc进行渲染,除了之前必须要卸载旧的渲染器(如 markedkramed 外),还需要去github页面下载一个pandoc的渲染器软件并进行安装。

pandoc下载链接:https://github.com/jgm/pandoc/releases

mermaid

mermaid需要显示的话也需要安装插件,需要在hexo-next主题文件夹下的 _config.yml 文件中进行启用,如下:

mermaid在主题配置文件中的启用

latex

latex数学公式可以由 pandoc 渲染器进行渲染,只需要在hexo-next主题文件夹下的 _config.yml 文件中启用 mathjax ,如下:

数学公式在主题配置文件中的启用

搜索功能功能不仅需要安装插件,还需要分别在博客文件夹根目录中的 _config.yml 和 hexo-next主题文件夹下的 _config.yml 文件中进行启用,如下:

博客根目录配置文件下的启用

注意:此处的 db.json 需要在 public 文件夹中也有一份的时候启用;如果 db.json 无法使用,则更换为 search.xml 。因为 db.jsonsearch.xml 是由插件生成的搜索数据库(可以这么看)。

hexo主题配置文件下的启用

因为也是人力资源管理专业出身,所以基于面试者(员工)角度来写这篇文章的时候,其实是左右手互博的感觉。

特殊性说明,本文所描述的岗位背景其实是 嵌入式DSP裸机软件(驱动)开发

注意:下面标灰色的部分都是跟HR工作相关的概念,如果看不太懂可以跳过。

面试流程

技术类岗位招聘通常会遇到 2~3轮面试 和一次 HR提供Offer 的环节,最经典的流程如下:

graph LR
简历投送 --> ID1((HR面)) --> ID2((项目面)) --> ID3((技术面)) --> 拿Offer

面试原则

面试者需要在面试过程中适当包装和美化一下自己的工作经历,但是还是需要秉承着相对诚实的原则。

为什么说是相对诚实的原则

你可以说“自己的工作很难但按时完成”,“自己独立完成”,“自主编写代码” 等等他人较难去鉴别的工作,这些都是一个人工作能力不错的表现。但假如把自己没做过的项目放进去,一旦被问技术面的时候问到细节就会露馅。即使面试时没有露馅,工作时露馅了,大概率也会被面试官知道的。

一个HR有可能是在一家公司专门从事招聘的专员,也有可能是为多家公司做招聘的猎头(专门从事招聘工作的人员,通常是成立一个猎头公司,专门帮其他公司找人才)。一旦技术面的时候夸大自己的工作经验,技术面也会跟HR反馈你的夸大情况,然后你就再也不能通过该猎头或者专员找到其他的工作了,相当于自己白白损失了一个资源口。

而,嵌入式开发之类的技术岗位(目前)是绝对的版本答案之一,企业通过猎头找人才已经是常态,因此绝对不能有这种作死行为。

HR面

由专门/兼职做人力资源的工作人员负责,主要有以下流程:

  1. 说明招聘信息(包括所招聘的岗位的基本要求和职责、企业背景、团队情况和项目情况)
  2. 在职情况(千万不能说自己已经离职,否则你就会很掉价,因为HR会觉得你急于找到新工作而压低你的价格——对,就是你的薪酬,你的卖身一个月的价格,当然也有其他方法可以来试着压低你的薪酬,后面再谈)
  3. 询问面试者的离职原因(以判断该员工是否足够稳定,因为薪酬给的更高的员工其离职后给企业造成的离职成本会更高,因此需要该员工足够稳定,后面详谈如何回答离职原因)
  4. 询问面试者当前的工作内容(以确定该员工与所招聘岗位的匹配度,就是说,面试者目前的工作内容如果和他招聘的岗位的工作内容差异太大,他就不会想要再继续去问了,这点应该比较容易懂吧。当然,面试者也不能明明不匹配就瞎说自己会该工作技能,不然就是坑自己也坑别人,这里尽量坦白一些比较好)
  5. 询问面试者的求职意向及工作意愿(就是会问面试者是否愿意从事本岗,一般到这里如果没有回答“愿意”,都没得聊了)
  6. 询问面试者期待的薪资及目前薪资(这一点在招聘网站看可以看到该企业所招聘的岗位能提供的薪资范围,通常也就是个薪酬区间,后面详谈如何回答这部分内容。询问目前薪资就是来确定你的人力成本,进而探寻能够压缩你人力成本空间的可能性的。)
  7. 约定下一步面试时间(这一点应该没什么好说,通常都是电话技术面或视频技术面,确认好双方有空闲的时间)
  8. 其他(会问是不是符合一些硬性条件,比如统招本科(就是学信网能够查到本科学历信息),毕业时间等等)

如何回答离职原因

这一部分看似回答很简单,其实会藏着很多坑。

首先,要明白为什么需要HR面,为什么面试第一个打来的都是HR,而不是技术员工直接打过来。

从企业运行的角度考虑,每一时刻的企业运作都是需要运行成本的,包括场地成本、设备成本(采购、折旧、损耗等等)、物料成本、人力成本(招聘成本、培训成本、薪酬成本等)等等,就特别多,专人专事这个大家都能理解。

如果一个员工匆忙从一家企业离职,该员工入职前的招聘成本、入职时的培训成本和所需要支付的薪酬成本就会拜拜支出,不能给企业带来盈利,但企业在招聘一个员工前后所支出的成本又是实实在在支出了的,就会造成巨大损失(绿厂就不是,就完全不担心这一点,因为给的太少了(通俗点就是成本不高),打着500强名号,韭菜一茬一茬就随便割,又不会特地挽留员工离职,而且全公司现状都是培训工作做得差,成本就不高)。

(个人觉得)企业当然不能实现所有人终身雇佣,没有新鲜血液是不行的,一定比例的人员流动可以给企业带来活力(这个原因我就不必讲了吧)。HR是学过这些东西的,需要站在企业角度去帮企业考虑招聘什么样子的人会让企业更加稳定,人员稳定(流失减少,并控制在一定范围内)就能帮助企业降低运行成本。

因此,面试者需要体现出自己的稳定性,证明自己是一个不太会轻易离职的人,并说明是一些客观的因素(并不是自己的原因)造成了面试者的离职。当然,面试者自己在一家企业就业时,也不应该轻易离职,如果是高校毕业者,最好在第一家企业从事1年及以上再离职(建议!)。以下列举了几个较为客观(不能说绝对客观)的原因:

  • 办公室氛围太过压抑,缺少团队活动
  • 团队协作性太差
  • 领导风格太过压迫和强势

一些员工的主观原因(或者说是令HR反感的原因),这些话是绝对不能说的,绝对禁区!

  • 自己不喜欢目前的工作
  • 工作太难了

一些员工可以说的话:

  • 自己不太挑工作,比较看重团队氛围和工作环境(一般有自信点的HR都会觉得这点没问题,“不太挑工作”的前提是,也得是自己觉得对口的才行,别不对口你不挑个啥。比如,做MCU/ARM/SOC/DSP的相通性较高,说自己不挑可以,但是跨行业太大也敢说自己不挑那就是找事儿)(另,不太挑工作其实对HR来说是个好品质,但自己也得好好掂量掂量自己)

如何回答目前薪资及期望薪资

HR之所以需要问你的目前薪资,不仅是了解本行业或者某个岗位在某个地区的大致薪酬情况(以对比公司招聘员工的薪酬竞争优势),也是在探寻面试者的薪酬上涨或可以压缩的空间。

面试者首先需要了解(或者说准备好)几点信息:

  1. 该行业该岗位在某个地区的 普遍薪资范围 是如何(当然不能拿最高薪资来当做普遍薪资,得看自己的能力和对应岗位的工作难度)
  2. 所面试的公司提供的薪酬范围
  3. 自己所期待的薪资底线
  4. 自己目前薪资

首先是,如果HR问目前薪资。面试者可以适当夸大自己目前的薪资,税后薪资可能都很低,可以说税前,多说几千没关系,不要与对方公司提供的薪酬底线相差太大即可。如果HR说自己公司有30%或者40%的涨薪幅度限制,那么可以放心,该HR觉得你岗位匹配度较高,只是想通过这个来压一压你的成本而已。

此时,你可以说自己期待在某个地区某个岗位的薪酬底线,低于这个就不行。HR态度一般都会更为委婉些。

如果你通过面试,到了拿offer的环节,HR还是会再跟你谈一遍。豪气的公司(一种薪酬策略,用高于行业平均水平的薪资招聘员工,但也要求更高)一般开价都会比你要求的更高,但这是后面的事情了。

HR面结束之后

(如果你对HR提供的岗位较为满意,接收了技术面/项目面的预约)需要记住一些最基础、关键、有用的信息。这些HR面时都已经说明了,最好是拿个小本本记好,这是对面试企业的一个尊重,也是为了防止后面出现的一些莫名其妙的(跟你面试岗位无关的)问题把你问倒。

  1. 岗位工作地点(很多大企业全国都有研究中心和技术中心,可以选择的,看对方给你提供的是哪个城市的就业岗位)
  2. 对方面试官的名字(至少记住姓啥)
  3. 对方的公司名称及背景(比如是帮别人做外包的还是做自研的,有没有上市或者有没有股权激励,成立多久了之类的)
  4. 岗位基本信息 (任职要求和工作职责等)

项目面和技术面

普遍情况下,二轮/三轮面试都会问你一些技术和项目上的东西,根据所闻内容的不同,将其分别称呼为 技术面项目面

有些公司会将这两轮分开,面试的先后顺序不一,总得占比是项目经历会问得更多一些,技术面的占比较少。

有些公司也会将项目面和技术面合在一起(就是同一次面试里就有技术面和项目面),夹杂交替着问。

项目面

主要是问你从事(主要负责或者协助负责)过的一些项目/经历,了解你对研发的产品、芯片、硬件、软件、工具、设备的认知。项目面会有三种类型的提问:

  1. 工具认知提问。了解面试者对工具使用的经验。
  2. 问题解决提问。了解面试者对一些解决问题的方法和经历。
  3. 情景假设提问。考验面试者解决问题的思路。

项目面的面试形式:一般都是电话提问和视频提问。

面试时长:单轮面试时间都是在15分钟以上,最长30分钟左右。

工具认知提问

就是会问你开发过程中遇到的一些工具模块是如何使用的,一些算法或者逻辑的原理。这部分比较简单,都是经验而已。

例如,面试官问我ADC的使用,我就如实回答我是如何用ADC的,以及我对ADC模块的认知。

问题解决提问

有很大概率(不一定是所有公司都会问的),会问你一些“发现问题解决问题”的经验。这里面试官主要是想知道以下几点情况:

  1. 面试者对工作问题的解决思路。是否足够清晰,有什么角度可以去考虑,需要面试者自己去总结,然后可以清晰地向他人阐述。
  2. 面试者在解决问题时的耐心。面试者需要介绍一个以上的案例,向面试官说明问题现象,自己的思考方式、检查方法、解决方法、过程 和 结果 等等。
  3. 面试者的经验。你能说出自己在遇到一些问题(比如调试问题)时的解决思路,或者看待问题(较为全面)的角度时,就说明了你已经具有足够经验了。

如果面试官问你“发现问题解决问题”的经验,你回答自己不知道,不太记得,忘记了这些话,就妥妥失败了。

因为这些工作问题的发现、解决和记录工作,在日常工作过程中其实都是可以稍微花点时间去完成的(这并不难,只是你有没有耐心而已),如果面试者自己没有做这部分 经验积累工作,那就很吃亏,大部分人都有相关的工作经验,自己不会去 总结 而已。

情景假设提问

面试官可能会抛出情景题,例如问你给你一个芯片,2周之内完成开发,你需要怎么准备,有什么计划。其实就是一个经验问题,或者思路问题。回答方法我就不详细说了。

技术面

技术面,就是会问一些项目之下的一些底层技术问题,一般来说都不会太难,也偶尔会有一些面试官问的问题比较偏门(开发过程中较难出现的问题)。例如,我经历过的偏门提问,会问C语言的野指针出现和排查,C++的继承概念等等(这些是我项目上比较难涉及到的)。

但大部分情况下,这些技术提问,都是提问一些你做过的东西,比如你做过某种通信协议的开发,请你表述以下该协议的相关内容(例如,时序、通信格式(通信起始和结束的变化)、电气特性(电平、电压范围)等)。这些其实也是经验的一部分,真的做过的话就应该自己做做笔记,一定会有点印象的,不应该去抱佛脚。

面试原则:问到你会的,你就自信回答。问到偏门的,开发过程中较少出现/遇到和使用的,你就如实回答就好了,不要不懂装懂。

技术面的面试形式:可能是让你线上答卷,现场答卷,也可以是电话提问、视频提问。

面试时长:同项目面,也可能夹杂着在项目面中间进行提问。

拿Offer

拿到Offer后,你可能需要向HR详细确认的信息:

  1. 每天上班时间,从几点到几点
  2. 每个月的薪资计算时间是从几号到几号
  3. 每个月的薪资发放日期、时间
  4. 是否双休、年假情况
  5. 每天的加班强度、每个月的加班强度、加班薪资等
  6. 每年发放多少个月的薪资(就是年终奖发放情况,好一点的是15薪以上,最基本的13薪)
  7. 每个(税前)月薪资是多少(可能需要关心一下社保和公积金的缴纳情况等)

基本信息了解完毕之后,需要自己有意识地去提问的一些问题:

  1. 近期可以签订合同的最晚时间(合同期限一般都是3年,这个就比较不用担心)
  2. 期望入职时间(自己期望什么时候入职,对方期望最晚什么时候入职,可否协调程度)
  3. 涨薪计划(入职后会有哪些涨薪激励计划,或之前其他股权发放啊、年终奖增长等等)
  4. 绩效计划(可能这时候不太愿意说,但是入职后可以去了解)

双十一豪豪酱买了群晖DS220j家用NAS服务器,为了方便工作文件的备份传输,让电脑(PC、Mac)能用上远程网络驱动,就需要让服务器穿透内网,并申请一个独立域名,想着就用腾讯云和家里的小米路由器AX3600来干吧。下方是对硬件上需要的一些要求:

光猫:使用 桥接模式,具有 独立公网IP

路由器:使用 PPPoE模式 进行拨号、支持 端口映射端口转发DMZ

群晖NAS:支持 DDNSUPnP 协议、支持 证书使用范围管理

前期准备工作

更改工作模式

光猫路由器 都支持 路由模式桥接模式,都支持多个无线接入和有线接入,但因为自己购买的路由器具有更多不一样的功能,例如支持UPnP等,而且光猫是连接物理光纤进行上网的,而自己购买的路由器不能直接连接光纤上网,还得依赖于光猫,所以可以认为是两种不一样的工作硬件。

如果光猫已经工作在桥接模式(通过查看路由器后台的 上网方式 是否为PPPoE,如果是则说明自己购买的路由器工作在路由模式,电信光猫工作在桥接模式)。一般没有此类服务器需求的家庭网络,都是让光猫工作在路由拨号模式(即路由模式)的,而路由器则工作在桥接模式,此情况则需要将两个硬件设备的工作模式进行互换,参考以下步骤:

  1. 打电话给电信营业厅 (0000)10000 (前方的 (0000) 是自己的市区号),确认一下光猫是路由模式还是桥接模式,如果是路由模式,则将其改成桥接模式。
  2. 确认改成桥接模式后,询问宽带的账户和密码,在路由器后台输入账户密码并连接测试,确保路由器工作在拨号模式,而光猫工作在桥接模式。

目前国内家庭宽带都是默认内网IP,想要公网IP就只能向运营商申请了,这并不需要额外的收费。电信手上的IP资源最多,也最大方。我也是照着别人的说法,打电话给电信客服,说装监控需要公网IP,客服登记之后,过几个小时就打电话说已经换好了,干净利落,服务好。目前好像还没见到过电信要不到公网IP的情况。

——《BT下载教程 篇一:BT下载大提速! 获取公网IP和端口映射转发简单教程

image-20211113000614809

多重NAT改成公网IP

同样是打给电信,然后申请公网IP,电信客服专员一般会在一个小时内处理完毕,然后就可以得到公网IP了。

“谁拨号,谁就有公网IP” ——即此时如果路由器已经成功设置了路由模式(使用PPPoE拨号上网),则可以在路由器后台查看到其公网IP地址,如:

image-20211113001927548

DDNS域名绑定

虽然已经获得公网IP,但是该IP还是会随机变动,还会需要使用DDNS服务将公网IP映射到对应域名上,而群辉服务器则提供此功能,此处需要自己申请一个域名(此步骤省略)。进入群辉服务器后台,开启DDNS功能,将域名和随机公网IP绑定和更新。

另外,需要自己上所用的服务器上开启API Token,并提供给群辉DDNS服务(类似于授权,可以由DDNS服务自己检测家庭网络的公网IP,并自动绑定最新的公网IP)。

API Token申请

下方以腾讯云的DNSPOD为例,点击DNSPOD中的 API密钥,进行 新建密钥 即可,将对应的 SecretIdSecretKey 复制下来。

image-20211113002208036
image-20211113001142315

DDNS添加

将获取到的 SecretId 填写到 用户名/电子邮件 中, 将 SecretKey 填写到 密码/密钥 中。

image-20211113001623814

经过前面的步骤,可以看到群晖NAS服务器自动测试的 DDNS状态正常 即可。

image-20211112175853513

端口映射和转发

端口映射:Port Mapping, 即将内网中的主机的一个端口映射到外网主机的一个端口,以提供相应的服务。当用户访问外网IP的这个端口时,服务器自动将请求映射到对应局域网内部的机器上。

端口转发:Port Forwarding, 即将外网对应 EA 端口上收到的数据转发到内网某个主机对应的某个 IA 端口上,或者反过来将内网某个主机 IB 端口的数据转发到对应外网的 EB端口 上。

UPnP协议:Universal Plug and Play,即 即插即用。主要是微软在推行的一个标准,适用于家庭网络,用于设备间的发现和连接。UPnP 最大的愿景就是希望实现任何设备只要一接入网络就能被网络中的所有其它设备发现,做到完全的即插即用。UPnP是一个多层协议构成的框架体系,每一层都以相邻的下层为基础,同时又是相邻上层的基础。直至达到应用层为止。

手动端口转发或自动端口转发

手动端口转发:

自动端口转发:

image-20211112180357037
image-20211112175632036
image-20211112180450097

配置DMZ

通过配置DMZ,我们可以将需要保护的Web应用程序服务器和数据库系统放在内网中,把没有包含敏感数据、担当代理数据访问职责的主机放置于DMZ中,这样就为应用系统安全提供了保障。

DMZ使包含重要数据的内部系统免于直接暴露给外部网络而受到攻击,攻击者即使初步入侵成功,还要面临DMZ设置的新的障碍。

image-20211112172411026

DMZ开启前

image-20211112172343953

DMZ开启后

虽然也是随机公网IP,但是可以使用DMZ将连接到路由器的设备映射到外网上。

image-20211112175925384

安全证书设置

设置安全证书及其使用范围,不要使用自我签名的证书,所有浏览器都会识别和阻止你访问的

经过前面DDNS的 API token 配置之后,群晖NAS能够获取到对应域名的免费证书,并提供页面进行管理,将所有使用到的应用安全验证证书都设置为对应云服务提供商提供的证书即可。

image-20211112180133874

后台服务器访问

经过上面复杂的折腾之后,就可以使用自定义的域名进行后台登录和管理了。

输入 https://nax.xxx.xxx:5000 即可进行后台服务器的访问,也可以使用 ping 进行测试,如下:

image-20211113002928045

远程驱动器设置

  1. 在文件管理器中右键点击 此电脑 的属性
  2. 然后点击 映射网络驱动器
image-20211112174837538
  1. 选择本地的 虚拟驱动号 进行设置
  2. 输入 网络地址端口号,格式如 https://nas.xxx.xxx:5006
image-20211112175022321
  1. 按照提示输入群晖提供的账户名和密码即可进行连接
image-20211112174513370
  1. 连接完毕即可查看到对应的网络驱动器
image-20211112174559989

参考

  1. 【干货】什么是端口转发?什么是端口映射?如何设置端口映射?
  2. DMZ
  3. upnp协议简介(一)

本笔记不是全面的C++学习笔记,而是基于个人在原有的C语言基础和浅薄的C++的开发经验上的补足笔记。

本笔记仅供个人学习记录,不提供完整学习指导,如有需要请自行阅读《C++ Primer Plus》。

本文会参考 GNU C++ 进行代码调试,部分文档内容会参考 MS C++ 进行理解。

简介

C++融合了三种不同的编程方式:

  • 面向过程编程(继承于C)
  • 面向对象编程
  • 泛型编程(Generic Programming),即C++模板(Template)

过程 VS 对象

面向过程编程(Process Oriented Programming),即 结构化编程过程结构化编程,是指根据执行的操作来构思一个程序。程序任务需要解决的问题按照 “1、2、3、4” 这样的顺序一一编写,如果程序任务过大,则将较大的任务拆解成较小的可以理清结构逻辑的小任务去完成。C语言的编程开发思路就是使用程序模块(函数)来表示各个任务模块。

面向对象编程(Object Oriented Programming),简称 OOP。

结构化编程在程序逻辑的清晰度和可靠性上占据优势,但是在代码量上和面向对象相比不占优势

为了应付代码量的挑战,与强调算法的过程性编程不同,OOP强调数据。过程性编程试图使问题满足语言要求,OOP则是使语言满足问题的要求。

(Class) 是规定了 数据操作数据类型(Data Type)。类所创建的实体称为对象。

OOP 强调的是编程的数据方面,GP编程强调的是 独立于特定数据类型,即强调 通用非特定 类型。

image-20211027135117490

系统的位数

  • 系统的位数是由什么决定的?包括嵌入式系统的8位、16位、32位和通用系统的32位和64位?

位数 是由CPU的最大寻址空间决定的。

New Features in C++

以下主要从C++和C的区别点进行记录,是个人之前从未掌握过的知识,另外也会记录C++的一些高级用法。

Statement

  • C与C++的语句申明位置有哪些差异?

C语言的变量声明通常都应位于函数或过程开始位置(Pascal也是),而C++并没有该限制,因此这点可以说是C++的优点也可以是缺点。

Range-based for

C++11 引入了一种崭新的 for() 循环形式,可以逐一迭代某个给定的 区间数组集合(range, array or collection) 内的每一个元素。而其他语言可能称之为 foreach 循环,其一般性用法如下:

1
2
3
for(decl:coll){
statement
}

其中:

  • decl 是给定之 coll 集合中的每个元素的声明。
  • statement 会针对给定之 decl 进行执行

使用样例(下左)及其输出结果(下右)如:

image-20211030084723644

而且上面这种是基于 C-style array 的新旧语法搭配的 C++,实际上如果 coll 集合提供成员函数 begin()end() ,那么使用 for(decl:coll) 时便等同于使用 for(auto _pos=coll.begin(), _end=coll.end(); _pos!=_end;++_pos)

Data Type

  • 数据类型的大小由什么决定?数据类型大小(即占空内存空间)与系统位数、编译器的关联性?
  • 嵌入式系统与通用系统的数据类型大小差异在哪?
  • double 和 float 在内存上的差异?

在 C++ 中, 变量(Variable) 一词通常用于 引用 标量数据类型 的 实例,而 其他类型(class / struct)的实例通常称为 对象(Object)。

C++ 是 强类型语言 ,也是 静态类型

在代码中声明变量时,必须 显式指定其类型,或使用 关键字指示编译器从初始值表达式 auto 推断类型。 在代码中声明函数时,必须指定每个参数的类型及其返回值;如果函数未返回任何 void 值,则必须指定 。当使用允许任意类型参数的函数模板时例外。

基本(内置)类型

基本数据类型,简称 基本类型基类型

下图显示了 Microsoft C++ 实现中的内置类型的相对大小:

多个内置类型的相对大小(以字节为单位)的关系图。

下表列出了最常用的基本类型及其在 Microsoft C++ 实现中的大小:

类型 大小 评论
int 4 个字节 整数值的默认选择。
double 8 个字节 浮点值的默认选择。
bool 1 个字节 表示可为 true 或 false 的值。
char 1 个字节 用于早期 C 样式字符串或 std:: 字符串对象中无需转换为 UNICODE 的 ASCII 字符。
wchar_t 2 个字节 表示可能以 UNICODE 格式进行编码的“宽”字符值(Windows 上为 UTF-16,其他操作系统上可能不同)。 这是用于 std::wstring 类型字符串的字符类型。
unsigned char 1 个字节 C++ 没有内置字节类型。 使用 unsigned char 表示字节值。
unsigned int 4 个字节 位标志的默认选项。
long long 8 个字节 表示非常大的整数值。

类型数据的宽度(Width),即占用内存大小是由 计算机字长编译程序 决定的。计算机字长提供了硬件计算精度的支持,编译程序则提供了源程序到机器码的转换。

下方为C/C++ 在通用系统或嵌入式系统中的常见数据类型的大小,所有值的单位均为 bit

BASIC DATA TYPE 8 bit MCU 16bit MCU (51) 32bit (x86) 32bit (TI F28004x)
CLA ON
32bit (TI F28004x)
CLA OFF
64bit (x86)
in C++ (g++)
64bit (x86)
in C (gcc)
char 8 8 8 8 8 8
short 16 16 16 8 16 16
int 16 32 32 16 32 32
long 32 32 32 16 64 64
long long / 64 64 32 64 64
float 32 32 32 32 32 32
double 32 64 16 64 64
long double / 32 128 128

下方内容转自网络,待验证。

(x86平台下)long intlong,给人的感觉好像是长整型,但实际上,它和 int 一样,只有32位。cppreference 给出的定义如下,但在实际的使用中,longint 几乎没有区别。

int - basic integer type. The keyword int may be omitted if any of the modifiers listed below are used. If no length modifiers are present, it’s guaranteed to have a width of at least 16 bits. However, on 32/64 bit systems it is almost exclusively guaranteed to have width of at least 32 bits. long - target type will have width of at least 32 bits.

实际上经过测试:在 x86_64 平台下,C 和 C++ 中的 long 长度都是要比 int 更长的,即 int 默认为 32bit 宽度,long64bit 宽度。

image-20211028101248341

Embedded System

嵌入式C语言中常用的数据类型如下图所示,而不同的

image-20211027155153218

double / float

IEEE二进制浮点数算术标准IEEE 754)是20世纪80年代以来最广泛使用的浮点数运算标准,为许多CPU与浮点运算器所采用。这个标准定义了表示浮点数的格式(包括负零-0)与反常值(denormal number)),一些特殊数值(无穷(Inf)与非数值(NaN)),以及这些数值的“浮点数运算符”;它也指明了四种数值舍入规则和五种例外状况(包括例外发生的时机与处理方式)。

IEEE 754规定了四种表示浮点数值的方式:单精确度(32位)、双精确度(64位)、延伸单精确度(43比特以上,很少使用)与延伸双精确度(79比特以上,通常以80比特实做)。只有32位模式有强制要求,其他都是选择性的。大部分编程语言都有提供IEEE浮点数格式与算术,但有些将其列为非必需的。例如,IEEE 754问世之前就有的C语言,现在有包括IEEE算术,但不算作强制要求(C语言的float通常是指IEEE单精确度,而double是指双精确度)。

该标准的全称为IEEE二进制浮点数算术标准(ANSI/IEEE Std 754-1985),又称IEC 60559:1989,微处理器系统的二进制浮点数算术(本来的编号是IEC 559:1989)。后来还有“与基数无关的浮点数”的“IEEE 854-1987标准”,有规定基数为2跟10的状况。现在最新标准是“IEEE 854-2008标准”。

Variable

C++ 与 ANSI C(C99标准)不同之处,在于后者只保证名称中的前63个字符有意义,即使第64个字符不同,但是只要前63个字符相同的变量则被认为是相同的。

在某些情况下,其他程序员会使用的变量命名风格及其意义:

  • strsz 前缀:表示以空字符结束的字符串
  • b 前缀:表示布尔值
  • p 前缀:表示指针
  • c 前缀:表示单个字符

Class

:(用户定义/标准的)数据类型规范,详细描述了如何表示信息以及对数据执行的操作。

对象:是根据类规范创建的实体(好似之于变量和基本数据类型)。

就像函数可以来自函数库一样,类也可以来自 类库。从技术上说,大部分类库都没有被内置到C++语言中,而是语言标准指定的类。类定义 位于类库文件中,并没有被内置到编译器里(有需要可以修改,虽然不建议)。

C++之所以如此有吸引力,很大程度上是由于存在大量支持UNIX、Macintosh 和 Windows 编程的类库。

类描述 指定了可以对类对象执行的所有操作。要对特定对象执行这些允许的操作有两种方法,一是直接使用类方法(本质即函数调用),二是重定义运算符(如 cincout 使用的 >><<

Function

被调用的函数称为 被调用函数(called function),包含函数调用的函数称为 调用函数(calling function)。

函数原型:即 函数声明,函数原型或声明只描述函数接口,指仅有函数头和分号 ; 而没有函数体的语句。函数原型定义了需要传递给函数的参数以及函数本身需要返回的值的类型。

库文件:存放了函数编译代码的文件。

头文件:包含了函数原型的文件。

image-20211028085847535

在有些语言中,有返回值的函数被称为 函数(function),无返回值的函数被称为 过程(procedure) 或 子程序(subroutine)。

但在C/C++中,都被称为 函数

Main Function

  • 有什么有些IDE中的main函数的括号里是带参数的?

是否在 主函数main() 参数括号 () 中使用关键字 void ,在C++和C中有明显的区别:

  • 在C++中,让括号空着和在括号中写 void 等效。
  • 而在C中,让括号空着意味着对是否接受参数保持沉默。

int main(int argc, const char * argv[]) 是UNIX和linux中的标准写法。int main() 只是默许的用法。

使用main函数时经常都是不带参数的,因此main 后的括号都是空括号。实际上,main函数可以带参数,这个参数可以认为是 main函数的 形式参数

C语言规定

  1. main函数的参数只能有两个,习惯上这两个参数写为 argcargv。因此,main函数的函数头可写为:main (argc,argv)
  2. argc (第一个形参)必须是 整型变量argv (第二个形参)必须是指向字符串的 指针数组

由于main函数不能被其它函数调用,因此不可能在程序内部取得实际值。那么,在何处把实参值赋予main函数的形参呢?

实际上,main函数的参数值是从 操作系统命令行/Terminal 上获得的。当我们要运行一个可执行文件时,输入空格,输入文件名,再输入实际参数即可把这些实参传送到main的形参中去。

argc 的数值会随着通过命令行传递给可执行文件的参数的增加而增加,即 argc 其实是代表着 参数的数量

image-20211027144512641

编译指令

using 是编译指令的关键字,

参考

  1. C++ Primer Plus
  2. int main(int argc, const char * argv[])
  3. C++ 类型系统
  4. IEEE二进制浮点数算术标准(IEEE 754)

WSL

在windows的 linux子系统下安装的具有图形界面的软件都可以在windows上打开,但是如果直接在MS商店安装的 kali linux 子系统是最精简版本,很多开发者需要用的软件(如 gcc / make / vim 等)都不存在,需要使用官方提供的完整安装命令去安装一些必须程序。

按照官方指示安装完必要程序后,可以在文件管理器里看到 linux 子系统的根目录,一定程度上很方便windows的用户使用linux系统并用图形化界面管理其文件。

image-20211027103100831

百度云盘安装

百度云盘是个人经常使用到的工具,在linux系统上也会安装,但wsl系统的话,多少可能会因为某些依赖文件缺失导致安装失败。

缺失的文件可以通过先更新源库(sudo apt update)再进行安装的方式解决,但有些时候可能是源库的问题,导致该依赖的包不存在(如下)。

image-20211027104129827

因此需要通过手动下载(利用 wget )该依赖包,然后自行安装(利用 sudo dpkg -i )的方式来解决,其中百度云盘缺失的依赖文件及其包连接如下:

  • libappindicator3-1:http://mirrors.ustc.edu.cn/debian/pool/main/liba/libappindicator/libappindicator3-1_0.4.92-3.1_amd64.deb
  • libindicator3-7:http://mirrors.ustc.edu.cn/debian/pool/main/libi/libindicator/libindicator3-7_0.5.0-2_amd64.deb
  • libdbusmenu-glib4:http://ftp.br.debian.org/debian/pool/main/libd/libdbusmenu/libdbusmenu-glib4_18.10.20180917~bzr490+repack1-1_amd64.deb
  • libdbusmenu-gtk3-4:http://ftp.br.debian.org/debian/pool/main/libd/libdbusmenu/libdbusmenu-gtk3-4_18.10.20180917~bzr490+repack1-1_amd64.deb

安装完毕之后即可正常进行软件使用了,虽然 wsl 的界面还是差强人意了些,哈哈。

image-20211027104032244

Traceroute(路由追踪)的原理及实现

traceroute 和 tracert 是Linux和Windows平台下用于追踪网络设备距离远近的工具,向目标设备发包,从 TTL=1 开始向外发包,逐渐增加 TTL 的值,直到目标主机。在介绍traceroute和tracert的原理之前,需要了解几个技术名词:

IP,协议是TCP/IP协议族中最核心的部分,它的作用是在两台主机之间传输数据,所有上层协议的数据(HTTP、TCP、UDP等)都会被封装在一个个的IP数据包中被发送到网络上。

ICMP,即 Internet Control Message Protocol,互联网控制报文协议,它常用于传递错误信息,ICMP协议是IP层的一部分,它的报文也是通过IP数据包来传输的。

TTL,即 time-to-live,是IP数据包中的一个字段,它指定了数据包最多能经过几次路由器。从我们源主机发出去的数据包在到达目的主机的路上要经过许多个路由器的转发,在发送数据包的时候源主机会设置一个TTL的值,每经过一个路由器TTL就会被减去一,当TTL为0的时候该数据包会被直接丢弃(不再继续转发),并发送一个超时ICMP报文给源主机。

实现方案

tracert (windows)只支持基于 ICMP 报文发送,而 traceroute(Linux/Mac) 支持多种报文协议(UDP、ICMP、TCP)的发送,但不带任何选项(Options)时默认使用的是UDP。(具体参数和选项自行请自行 man 以查看手册)

下方所示图片分别为 tracert (windows)的帮助手册,以及在traceroute(Linux)上分别使用三种协议追踪 baidu.com 的结果截图。后续仅对UDP及ICMP追踪做较为详细的说明。

tracert的帮助说明

使用 TCP 报文的 traceroute:

基于TCP报文的traceroute

使用 ICMP 报文的 traceroute:

基于ICMP报文的traceroute

使用 UDP 报文的 traceroute:

基于UDP报文的traceroute

基于UDP实现

在基于UDP的实现中,客户端发送的数据包是通过UDP协议来传输的,使用了一个大于 30000 的端口号,服务器在收到这个数据包的时候会返回一个端口不可达的ICMP错误信息,客户端通过判断收到的错误信息是TTL超时还是端口不可达来判断数据包是否到达目标主机,具体的流程如图:

image-20211022085752243

实现流程

  1. 客户端发送一个TTL为 1 ,端口号大于 30000 的UDP数据包,到达第一站路由器之后TTL被减去 1 ,返回了一个超时的ICMP数据包,客户端得到第一跳路由器的地址。
  2. 客户端发送一个TTL为 2 的数据包,在第二跳的路由器节点处超时,得到第二跳路由器的地址。
  3. 客户端发送一个TTL为 3 的数据包,数据包成功到达目标主机,返回一个端口不可达错误,traceroute结束。

Linux和macOS系统自带了一个traceroute指令,可以结合Wireshark抓包来看看它的实现原理。首先对百度的域名进行traceroute:traceroute www.baidu.com,每一跳默认发送三个数据包,我们会看到下面这样的输出:

image-20211022085720428

对该域名的IP:115.239.210.27进行traceroute,此时Wireshark抓包的结果如下:

image-20211022085739900

抓包结果

注意看红框处的内容,跟第一张图对比,可以看到traceroute程序首先通过UDP协议向目标地址115.239.210.27发送了一个TTL为1的数据包,然后在第一个路由器中TTL超时,返回一个错误类型为Time-to-live exceeded的ICMP数据包,此时我们通过该数据包的源地址可知第一站路由器的地址为10.242.0.1。之后只需要不停增加TTL的值就能得到每一跳的地址了。

然而一直跑下去会发现,traceroute并不能到达目的地,当TTL增加到一定大小之后就一直拿不到返回的数据包了:

image-20211022085834275

结果全是丢失,其实这个时候数据包已经到达目标服务器了,但是因为安全问题大部分的应用服务器都不提供UDP服务(或者被防火墙挡掉),所以我们拿不到服务器的任何返回,程序就理所当然的认为还没有结束,一直尝试增加数据包的TTL。

目前在网上找到许多开源iOS traceroute实现大多都是基于UDP的方案,实际用起来并不能达到想要的效果,所以我们需要采用另一种方案来实现。

基于ICMP实现

上述方案失败的原因是由于服务器对于UDP数据包的处理,所以在这一种实现中我们不使用UDP协议,而是直接发送一个ICMP回显请求(echo request)数据包,服务器在收到回显请求的时候会向客户端发送一个ICMP回显应答(echo reply)数据包,在这之后的流程还是跟第一种方案一样。这样就避免了我们的traceroute数据包被服务器的防火墙策略墙掉。

采用这种方案的实现流程如下:

image-20211022085752243

实现流程

  1. 客户端发送一个TTL为1的ICMP请求回显数据包,在第一跳的时候超时并返回一个ICMP超时数据包,得到第一跳的地址。
  2. 客户端发送一个TTL为2的ICMP请求回显数据包,得到第二跳的地址。
  3. 客户端发送一个TTL为3的ICMP请求回显数据包,到达目标主机,目标主机返回一个ICMP回显应答,traceroute结束。

可以看出与第一种实现相比,区别主要在发送的数据包类型以及对于结束的判断上,大体的流程还是一致的。