bboysoul的博客 -

我关注的项目这周更新了什么-20230930

简介 每周五更新,所有的更新也会发送到我的频道 https://t.me/bboyapp 规则 pre release的不记录 只记录重要的更新 上一版本版本的bugfix不记录,比如某一个项目最新版本是7.0.0 上一个版本6.0.0发布了一个bugfix 6.0.1 那么不会记录 比如lens发布了一个新版本,那么openlens也会发布一个新版本,此时只会记录lens发布的信息,不会记录openlens发布的信息

AI生成摘要 本文是一份每周五更新的项目列表,包括各种开源软件的最新版本和更新信息。其中包括pingvin-share、oauth2-proxy、alist、grafana-agent、kaniko、umami、memos、ingress-nginx、yt-dlp、jellyfin、pyTelegramBotAPI、hugo、home-assistant、minio、ClusterSecret、SafeLine、perses、opengist、1Panel、moby、cert-manager、k8s-csi-s3、keda、eraser、k8tz、grafana等。同时,本文提到了一些更新规则和注意事项。

相关推荐 去reddit讨论

Power's Wiki -

Homelab - 在线代码编辑器 code-server

code-server 是一个能在浏览器中运行的 VS Code。相比于桌面端的优势是,你可以用任意设备在线码字,包括手机与平板这一类无法直接安装 VS Code 的设备。 部署(Docker Compose) 首先创建 compose.yaml 文件,并粘贴以下内容: yaml title="compose.yaml" version: "2.1" services: code-server: container_name: ${STACK_NAME}_app image: ghcr.io/linuxserver/code-server:${APP_VERSION} ports: - ${APP_PORT}:8443 volumes: - ${STACK_DIR}/config:/config - ${DATA_DIR_LOCAL}:/DATA environment: # 需要以 root 权限运行,否则无法读取其他 docker 目录或宿主机 root 目录 - PUID=0 - PGID=0 - TZ=Asia/Shanghai - PASSWORD=${APP_PASSWORD} #optional - SUDO_PASSWORD=${APP_SUDO_PASSWORD} #optional #- SUDO_PASSWORD_HASH= #optional #- PROXY_DOMAIN=code.wiki-power.com #optional restart: unless-stopped (可选)推荐在 compose.yaml 同级目录下创建 .env 文件,并自定义你的环境变量。如果不想使用环境变量的方式,也可以直接在 compose.yaml 内自定义你的参数(比如把 ${STACK_NAME} 替换为 code-server)。 ```dotenv title=".env" STACK_NAME=code-server STACK_DIR=xxx # 自定义项目储存路径,例如 ./code-server DATA_DIR_LOCAL=xxx # 自定义挂载本地目录,例如 /DATA code-server APP_VERSION=latest APP_PORT=xxxx # 自定义访问端口,选择不被占用的即可 APP_PASSWORD=xxx # 登录密码 APP_SUDO_PASSWORD=xxx # 超级用户权限密码 ``` 最后,在 compose.yaml 同级目录下执行 docker compose up -d 命令即可启动编排的容器。 配置说明 配置 git 安装完成后,如果需要使用 Git,对用户名和邮箱初始化配置,请参考文章 Git 学习笔记。 读写权限问题 如果在操作文件时遇到 Error: EACCES: permission denied 错误,可以打开终端,输入以下命令赋予当前用户所有权: shell sudo chown -R 用户名 文件夹路径 例如,以下是给 abc 用户赋予当前目录的所有权的操作: shell sudo chown -R abc . 设置 root 账户密码 如果需要用到 root 账户,可以使用以下命令初始化其密码: shell sudo passwd root 参考与致谢 官网 文档 / GitHub repo Docker Hub 原文地址:https://wiki-power.com/ 本篇文章受 CC BY-NC-SA 4.0 协议保护,转载请注明出处。

AI生成摘要 code-server是一个能在浏览器中运行的VS Code编辑器,可以在任意设备上在线码字。部署时需要创建compose.yaml文件,并配置相关参数。可以使用环境变量或直接在compose.yaml中自定义参数。配置完成后,执行docker compose up -d命令启动容器。配置git和解决读写权限问题的方法也在文章中提到。

相关推荐 去reddit讨论

Power's Wiki -

Basics of Mixed Signal Test

Mixed signal contains both analog and digital signals. Devices processing mixed signal typically include ADCs, DACs, analog switches and multiplexers, sample-and-hold amplifiers, and so on. As a part of it, analog signals is signals we use in the real world such as voice or tempurature, it's continuous in both time and amplitude. To process analog signals into computers, we need to convert them to digital signals, as it's discrete in both time and amplitude. Sampling Theory Sampling theory applies to the signal to be periodic, or errors will be introduced. Nyquist Theorem We use Nyquist Theorem(奈奎斯特定理) to gain the minimum sampling frequency when sampling signals: $$ F_s≥2F_i $$ We must sample at a rate higher than twice the highest frequency of interest, to be able to recreate a signal from its samples and avoid losing information. If we sample at a frequency that lower that the Nyquist rate, it will exhibit a phenomenon called aliasing(混叠)(unwanted components) when we try to convert it back to a continuous time signal, and some of the frequencies in the original signal may be lost. To minimize aliasing problem, we need to remove the frequency greater than $\frac{F_s}{2}$ of the signal, via the anti-aliasing filter (e.g. low-pass-filter): Coherent Sampling If a time sample set does not contain a precise integer number of cycles, spectral leakage(频谱泄露) will occur. Coherent sampling(相干采样) is to ensure the continuity of sampling and prevent spectral leakage, it guarantees that a sample set (a series of samples which represent the analog signal) has a fixed and well defined relationship between the sample frequency $F_s$, the number of samples $N$, the test signal frequency $F_i$, and the number of test signal periods sampled $M$: $$ \frac{M}{N}=\frac{F_i}{F_s} $$ The total time required to take all samples is called the Unit Test Period (UTP) and requires $M$ cycles of the test signal, which has frequency $F_i$. For an example, if we want to calculate the $F_s$ of continuous repeating sinewave, where $F_i$ is 1kHz, $M=3$ and $N=16$: So we can conclude that $F_s=5.333kHz$. Important tips of coherent sampling: Increasing $M$ and/or $N$ will increase both accuracy and test time. $M$ and $N$ needs to be an integer. $N$ needs to be a power of 2 when using Fast Fourier Transform (FFT). $M$ and $N$ are recommended to be mutually prime(互质)so that each sample gives unique information. Described in the following. If $M$ and $N$ are not mutually prime ($M=3,N=12$), samples are taken at the same position in every cycle, so there is no new information: If $M$ and $N$ aremutually prime ($M=3,N=16$), so they are mutually prime and every sample is discrete, so it gives unique information: Common Frequency Analysis Algorithms For $N$ time-domain signal samples, there are $N$ frequency-domain signal values, and there are $N/2$ frequency-domain power spectrum values. A typical spectral components example is shown below: There are several parameters for describing spectral components as follows: Signal To Noise Ratio (SNR)(信噪比) Total Harmonic Distortion (THD)(总谐波失真) Signal to Noise and Distortion (SINAD)(信纳比) Intermodulation Distortion (IM)(互调失真) Spurious Free Dynamic Range (SFDR)(无杂散动态范围) Signal To Noise Ratio (SNR) Signal To Noise Ratio (SNR) is derived by storing the value of the fundamental (signal power) first: Then remove the DC component and harmonics (usually up to 5): Next sum all bins of the remaining power spectrum (the noise power) measured by the RMS value (Root Mean Squared, The analog voltage that is equal to a DC voltage containing the same amount of energy, for a sine wave, the RMS value is 0.707 times the peak value): Ultimately we can conclude that: $$ {SNR}(dB)=10log_{10}(\frac{{Fundamental}}{{Noise\ Power}}) $$ SNR is usually expressed in decibels (dB), and is often a positive value (assuming the Fundamental Power is much larger than the Noise Power). Total Harmonic Distortion (THD) Total Harmonic Distortion (THD) is derived by keeping a running sum of the total harmonic power (usually only the first five harmonics, start at the second harmonic): And we can conclude that: $$ {THD}(dB)=10log_{10}(\frac{{Harmonic \ Power}}{{Fundamental}}) $$ THD is often a negative value (assuming the Fundamental Power is much larger than the total Harmonic Power). Signal to Noise and Distortion (SINAD) Signal to Noise and Distortion (SINAD) is the same methodology as computing SNR, but now the power of the harmonics is added into, and only zero out the DC component. $$ {SINAD}=\frac{S}{N+D} $$ And we can conclued that: $$ \because {SNR}=\frac{S}{N}, {THD}=\frac{D}{S} $$ $$ \therefore {SNR}^{-1}+{THD}=\frac {N}{S}+\frac {D}{S}=\frac {N+D}{S}={SINAD}^{-1} $$ $$ \therefore {SINAD}=({SNR}^{-1}+{THD})^{-1} $$ Intermodulation Distortion (IM) Intermodulation Distortion (IM) occurs when two or more signals are used in a non-linear system. The spectrum will not only consist of the original signals, but will also contain the sum and difference of the input signals along with their harmonics. Spurious Free Dynamic Range (SFRD) Spurious Free Dynamic Range (SFRD) is derived by finding the highest element after the fundamental (ignoring the DC component): Note that the highest element may or may not be a harmonic. So we can conclude that: $$ {SFDR}(dB)=10log_{10}(\frac{{Fundamental}}{{Next \ Highest}}) $$ The Spurious Free Dynamic Range is a positive value (assuming the Fundamental Power is much larger than the next highest Spur Power. Architecture of Generic Mixed Signal Tester In the generic mixed signal tester, the AWG (AC src) and WD (AC dig) are both connected to the DUT via relay interconnects through the channel board. Arbitrary Waveform Generator (AWG) Arbitrary Waveform Generator (AWG) is a low distortion signal generator. It contains a DAC to generate an analog signal from the digital data. LPF (Low Pass Filter) is to smooth the waveform and remove high frequency components. A set of data points for a given waveshape is stored in the waveform source memory, each time a clock occurs, a data point will pass to the DAC. Important parameters of AWG: Maximum Peak to Peak Voltage output Waveform resolution (DAC resolution) Band-width Waveform source memory depth Output Impedance Noise, THD, SNR Waveform Digitizer (WD) Waveform Digitizer (WD) samples analog signals, and converts them into digital values. It performs the opposite operation to the AWG. It converts analog signal into digital samples that represent the original analog signal. The low-pass filter limits the bandwidth of the signal in order to remove unwanted frequency components like noise and spurs, also provides anti-aliasing by attenuating spurs that would be aliased into the pass band of the filter during the ADC conversion. Important parameters of WD: Maximum Peak to Peak input Voltage range Waveform resolution (ADC resolution) Band-width Waveform capture memory depth Input Impedance Noise, THD, SNR, spur Clock The analog and digital clocks are derived from a system wide reference clock. If there is no clock synchronization signal, the timing offset may lead to incorrect results. Digital Signal Processor (DSP) Digital Signal Processor (DSP) is a specialized microprocessor to performs mathematical operations on arrays of digital numbers. Various algorithms like DFT and FFT are performed on DSP to transform time domain information into the frequency domain. The architecture of a DSP is optimized to allow fast multiplication, summing, logarithm calculations, squaring, and square root calculations. The tester will carry the stored captured signal to the DSP processor through data buses. References & Acknowledgements Fundamentals of Testing Using ATE The-Fundamentals-of-Mixed-Signal-Testing_Brian-Lowe Original: https://wiki-power.com/ This post is protected by CC BY-NC-SA 4.0 agreement, should be reproduced with attribution.

AI生成摘要 混合信号测试的基础知识包括模拟信号和数字信号。混合信号处理设备通常包括ADC、DAC、模拟开关和多路复用器、采样保持放大器等。采样理论适用于信号周期性的情况,否则会引入误差。奈奎斯特定理用于确定采样信号的最小采样频率,必须高于感兴趣的最高频率的两倍,以便从样本中重新创建信号并避免信息丢失。相干采样用于确保采样的连续性和防止频谱泄露,它保证了采样频率、样本数、测试信号频率和采样的测试信号周期数之间的固定和明确定义的关系。常见的频率分析算法包括信噪比、总谐波失真、信纳比、互调失真和无杂散动态范围。混合信号测试仪的架构包括任意波形发生器、波形数字化器、时钟和数字信号处理器。

相关推荐 去reddit讨论

Power's Wiki -

BeagleBone 系列 - 使用 BBIO 库开发

安装 Adafruit-BBIO sudo apt-get update sudo apt-get install build-essential python3-dev python3-pip -y sudo pip3 install Adafruit_BBIO 基本程序框架 ```py import time import Adafruit_BBIO.GPIO as GPIO RELAY = "P9_22" # GPIO P9_22 GPIO.setup(RELAY, GPIO.OUT) while True: GPIO.output(RELAY, GPIO.HIGH) time.sleep(1) GPIO.output(RELAY, GPIO.HIGH) time.sleep(1) ``` GPIO 调用库: py import Adafruit_BBIO.GPIO as GPIO 设置引脚输入 / 输出 py GPIO.setup("P8_14", GPIO.OUT) 输入 / 输出 可选 GPIO.IN/GPIO.OUT。 设置输出高 / 低电平 py GPIO.output("P8_14", GPIO.HIGH) 高 / 低 电平可选 GPIO.HIGH/GPIO.LOW,或 1/0。 引脚输入模式 查看输入端口的状态: py if GPIO.input("P8_14"): print("HIGH") else: print("LOW") 等待边沿输入,参数有 GPIO.RISING/GPIO.FALLING/GPIO.BOTH: ```py GPIO.wait_for_edge(channel, GPIO.RISING) 或 GPIO.wait_for_edge(channel, GPIO.RISING, timeout) ``` 监测输入 py GPIO.add_event_detect("P9_12", GPIO.FALLING) if GPIO.event_detected("P9_12"): print "event detected!" 延时 延时 1 秒: py import time time.sleep(1) PWM 输出 ```py import Adafruit_BBIO.PWM as PWM PWM.start(通道, 占空比, 默认频率=2000, 极性=0) PWM.start("P9_14", 50) 也可以自己定义频率和极性 PWM.start("P9_14", 50, 1000, 1) ``` 其中,占空比的有效值为 0.0-100.0,start 函数用于激活该通道上的 PWM。 当启动 PWM 之后,就可单独设置占空比或频率了: py PWM.set_duty_cycle("P9_14", 25.5) PWM.set_frequency("P9_14", 10) 用完之后,也可以停止 PWM 输出,或清除信息: py PWM.stop("P9_14") PWM.cleanup() ADC 输入 在这个框架里面,ADC 有三个函数方法:setup,read 和 read_raw。在读取数据之前,要先 setup。 在 BeagleBone 上,以下引脚可以使用 ADC: "AIN4", "P9_33" "AIN6", "P9_35" "AIN5", "P9_36" "AIN2", "P9_37" "AIN3", "P9_38" "AIN0", "P9_39" "AIN1", "P9_40" 注意:ADC 的最大电压为 1.8V,ADC 的地是 GNDA_ADC (P9_34) 引脚。如果需要检测 3.3V,可以用电阻分压,就像下图,把 0-3.3V 分到 0-1.65V 以读取模拟值。 初始化 ADC ```py import Adafruit_BBIO.ADC as ADC ADC.setup() ``` 读取模拟值 ```py value = ADC.read("P9_40") 或 value = ADC.read("AIN1") ``` 这框架有个 bug,需要连续读两次,才能获取最新的的模拟值。 读回来的结果是一个 0-1.0 之间的值,可以乘以 1.8 以转换成电压值。如果不想这么麻烦,也可以用 read_raw 来直接读出真实电压值。 I2C 通信 使用 I2C,只需要导入库,设置 I2C 地址,选择是哪个 I2C(默认是 I2C-1)。 ```py from Adafruit_I2C import Adafruit_I2C i2c = Adafruit_I2C(0x77) ``` I2C 功能需要安装 python 包 python-smbus,但目前这个包只兼容 python 2 版本。我们可以用 smbus2 替换使用。 SPI 通信 导入 SPI 库: py from Adafruit_BBIO.SPI import SPI 其他 安装 Adafruit-BBIO 时,如果失败可选手动安装: sudo apt-get update sudo apt-get install build-essential python3-dev python3-pip -y git clone git://github.com/adafruit/adafruit-beaglebone-io-python.git cd adafruit-beaglebone-io-python sudo python3 setup.py install 升级 Adafruit-BBIO: sudo pip3 install --upgrade Adafruit_BBIO 因为 python-smbus 这个依赖的原因,I2C 仅限在 python2 下使用。 参考与致谢 Python Adafruit_GPIO.I2C Examples Adafruit-BBIO 1.2.0 Setting up IO Python Library on BeagleBone Black 原文地址:https://wiki-power.com/ 本篇文章受 CC BY-NC-SA 4.0 协议保护,转载请注明出处。

AI生成摘要 本文介绍了如何在BeagleBone上使用BBIO库进行开发。首先需要安装Adafruit-BBIO库,然后可以使用GPIO库进行引脚的设置和输入/输出操作。还介绍了如何使用PWM库进行PWM输出,以及如何使用ADC库进行模拟值的读取。此外,还介绍了如何使用I2C和SPI进行通信。最后提到了安装和升级Adafruit-BBIO库的方法。

相关推荐 去reddit讨论

Power's Wiki -

AD 基本操作 - 多板系统设计 🚧

使用多板系统设计的原因是,一个硬件项目内可能包含多块 PCB、各种装配元素例如外壳,如果仅仅从每块板的角度去设计,最终做出来的产品有可能会出现配合误差或干涉。在设计多元素的硬件项目时,我们最好使用机电协同。对于硬件工程师来说,可以不用 SolidWorks 等软件,直接在 Altium Designer 里实现。 创建多板项目 首先,新建多板项目类型文件(.PrjMbd),在项目下创建基于原理图的逻辑设计文件(.MbsDoc)和基于 PCB 的文件(.MbaDoc),然后先保存。在文件系统的层面上把多个单独的 PCB 项目文件夹拷贝到 .PrjMbd 同级目录下,例如: 输入逻辑设计 输入逻辑设计是根据 PCB 上的物理连接器来进行的。在此之前,我们需要先给项目原理图内的连接器添加参数(点开连接器的属性,添加 Parameters,名字为 System,值为 Connector)。 创建模块并链接项目 在逻辑设计文件(.MbsDoc)内放置模块,并双击它弹出属性,选择对应的源 PCB 项目。 导入子项目的接口数据 单机鼠标右键,选择 设计 - 从子项目导入,就可以自动导入参数为连接器的端口。 添加模块间的逻辑连接 使用快捷键 P - W,绘制连接线。 点击连接线,就可以在属性面板修改两个模块对应的详细端口连接。 如果一个连接器需要连接对应多块板,那么可以在属性里面拆分某个端口。 物理多板装配 从逻辑设计文件导入 PCB 使用快捷键 D - I,就可以从逻辑设计文件导入项目对应的的 PCB 模拟装配 拖动每个 PCB 的坐标轴,就可以进行模拟装配了。 生成生产数据 🚧 参考与致谢 PCB 中进行多板设计会是怎样的体验? 输入逻辑系统设计 创建物理多板装配 生成多板设计的生产数据 原文地址:https://wiki-power.com/ 本篇文章受 CC BY-NC-SA 4.0 协议保护,转载请注明出处。

AI生成摘要 本文介绍了使用多板系统设计的原因以及在Altium Designer中创建多板项目的步骤。首先,需要创建多板项目类型文件,并在项目下创建基于原理图和PCB的文件。然后,将多个单独的PCB项目文件夹拷贝到项目文件夹中。接下来,根据PCB上的物理连接器进行输入逻辑设计,并给连接器添加参数。在逻辑设计文件中放置模块,并链接到对应的源PCB项目。然后,导入子项目的接口数据,并添加模块间的逻辑连接。最后,进行物理多板装配,导入PCB并进行模拟装配,最终生成生产数据。

相关推荐 去reddit讨论

Power's Wiki -

Homelab - 支持公有云的图床系统 Cloudreve

Cloudreve 是一个支持多家云存储驱动的公有云文件系统,支持用本地、从机、七牛、阿里云 OSS、腾讯云 COS、又拍云、OneDrive、S3 兼容协议作为储存端,可对接 Aria2 离线下载,多用户,拖拽上传 / 管理,在线预览 / 编辑,WebDAV 等。典型的使用场景是个人图床或网盘文件管理。 部署(Docker Compose) 我们首先需要创建目录结构。切换到存放 Cloudreve 的目录下(例如 /DATA/AppData/cloudreve)并执行: shell mkdir -vp cloudreve/{uploads,avatar,data} \ && touch cloudreve/conf.ini \ && touch cloudreve/cloudreve.db \ && mkdir -p aria2/config \ && mkdir -p cloudreve/data/aria2 \ && chmod -R 777 cloudreve/data/aria2 \ && mkdir data 首先创建 compose.yaml 文件,并粘贴以下内容: yaml title="compose.yaml" version: "3.8" services: cloudreve: container_name: ${STACK_NAME}_app image: cloudreve/cloudreve:${APP_VERSION} ports: - "${APP_PORT}:5212" volumes: - temp_data:/data - ${STACK_DIR}/cloudreve/uploads:/cloudreve/uploads - ${STACK_DIR}/cloudreve/conf.ini:/cloudreve/conf.ini - ${STACK_DIR}/cloudreve/cloudreve.db:/cloudreve/cloudreve.db - ${STACK_DIR}/cloudreve/avatar:/cloudreve/avatar restart: unless-stopped depends_on: - aria2 aria2: container_name: ${STACK_NAME}_aria2 image: p3terx/aria2-pro:${ARIA2_VERSION} volumes: - ${STACK_DIR}/aria2/config:/config - ${STACK_DIR}/data:/var/lib/docker/volumes/cloudreve_temp_data/_data environment: - RPC_SECRET=${ARIA2_RPC_SECRET} - RPC_PORT=${ARIA2_RPC_PORT} restart: unless-stopped volumes: temp_data: driver: local driver_opts: type: none device: ${STACK_DIR}/temp_data o: bind (可选)推荐在 compose.yaml 同级目录下创建 .env 文件,并自定义你的环境变量。如果不想使用环境变量的方式,也可以直接在 compose.yaml 内自定义你的参数(比如把 ${STACK_NAME} 替换为 cloudreve)。 ```dotenv title=".env" STACK_NAME=cloudreve STACK_DIR=xxx # 自定义项目储存路径,例如 ./cloudreve cloudreve APP_VERSION=latest APP_PORT=xxxx # 自定义访问端口,选择不被占用的即可 aria2 ARIA2_VERSION=latest ARIA2_RPC_SECRET=xxx # ARIA2 密码 ARIA2_RPC_PORT=6800 ``` 最后,在 compose.yaml 同级目录下执行 docker compose up -d 命令即可启动编排的容器 配置说明 首次启动时,会自动创建初始的管理员账号,可以在 log 中找到。如果错过了,请删除目录下的 cloudreve.db,重新启动主程序以初始化新的管理员账户。 我采用的图像命名规则:{year}{month}{day}{hour}{minute}{second}{ext}。 参考与致谢 官网 文档 论坛 GitHub repo Docker Hub Demo site 原文地址:https://wiki-power.com/ 本篇文章受 CC BY-NC-SA 4.0 协议保护,转载请注明出处。

AI生成摘要 Cloudreve是一个支持多家云存储驱动的公有云文件系统,支持多种储存端和功能。部署时需要创建目录结构并使用compose.yaml文件配置容器。首次启动时会自动创建管理员账号。

相关推荐 去reddit讨论

Power's Wiki -

Homelab - 免费的内网穿透替代方案 Cloudflared

Cloudflared 是一个免费的内网穿透方案,用于外网访问无公网 IP 的主机。 必需条件: 虽然 Cloudflared 是免费的,但需要绑定 VISA/PayPal。 域名 NameServer 需要指向 Cloudflare 需要启用 Cloudflare CDN(国内访问速度偏慢) 优点: 不需要公网 IP 的服务器 不需要防火墙、反向代理 不需要备案就可以使用 80 和 443 端口 不需要自行申请 SSL 证书 免费 缺点: 国内访问速度慢 相对依赖 Cloudflare 平台 部署(Docker Compose) 首先创建 compose.yaml 文件,并粘贴以下内容: yaml title="compose.yaml" version: "3" services: cloudflared: container_name: ${STACK_NAME}_app image: cloudflare/cloudflared:${APP_VERSION} network_mode: host restart: unless-stopped command: tunnel run environment: - TUNNEL_TOKEN=${APP_TUNNEL_TOKEN} (可选)推荐在 compose.yaml 同级目录下创建 .env 文件,并自定义你的环境变量。如果不想使用环境变量的方式,也可以直接在 compose.yaml 内自定义你的参数(比如把 ${STACK_NAME} 替换为 cloudflared)。 ```dotenv title=".env" STACK_NAME=cloudflared cloudflared APP_VERSION=latest APP_TUNNEL_TOKEN=xxx # 替换为你的 token ``` 最后,在 compose.yaml 同级目录下执行 docker compose up -d 命令即可启动编排的容器。 配置说明 访问 Cloudflare Zero Trust 面板,在左侧栏选择 Access - Tunnels,点击 Create a tunnel 创建隧道,填写隧道名称(用于区分不同的物理机器)然后保存。记录下 token 后填写在 compose.yaml 中。 随后点进你创建的隧道,在 Public Hostname Page 选项卡中添加代理的端口。举个例子,我绑定在 Cloudflare 的域名是 wiki-power.com,我需要代理的服务本地的端口是 80、HTTP 协议,那么我只需要这样填写: 即可通过 https://dashboard.wiki-power.com 访问本地的端口。并且,它会帮你自动申请 SSL 证书,直接在公网通过 https 访问。 参考与致谢 官网 / 文档 GitHub repo Docker Hub 原文地址:https://wiki-power.com/ 本篇文章受 CC BY-NC-SA 4.0 协议保护,转载请注明出处。

AI生成摘要 Cloudflared是一个免费的内网穿透方案,用于外网访问无公网IP的主机。它不需要公网IP的服务器、防火墙、反向代理、备案或自行申请SSL证书。但国内访问速度较慢,相对依赖Cloudflare平台。部署时需要创建compose.yaml文件,并填写相关配置信息。在Cloudflare Zero Trust面板创建隧道并添加代理端口,即可通过https访问本地端口。

相关推荐 去reddit讨论

Power's Wiki -

ATTiny85 调试记录

Bootloader shell P:\Arduino\hardware\tools\avr/bin/avrdude -C "P:\Arduino\hardware\tools\avr/etc/avrdude.conf" -v -pattiny85 -carduino -PCOM4 -b119200 -Uflash:w:D:\t85_default.hex:i -U lfuse:w:0xE1:m -U hfuse:w:0xDD:m -U efuse:w:0xFE:m Arduino 作为 ISP 下载器 | Attiny | Arduino | | :-----------: | :-----: | | Pin 1(PB5) | D10 | | Pin 4 (GND) | GND | | Pin 5 (PB0) | D11 | | Pin 6 (PB1) | D12 | | Pin 7 (PB2) | D13 | | Pin 8 (VCC) | 5V | 先给 Arduino 烧 ISP 程序: 打开 IDE 首选项,在附加开发板地址中填写: https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json 打开开发板管理器: 搜索并安装(可能需要代理): 烧录时注意选对芯片型号、时钟速率(Internal 16 MHz)、Arduino 所在的端口,注意编程器选择 Arduino as ISP: 总结 参考与致谢 基于 ATTiny85 的 digispark Arduino 最小系统的自制教程(一) 基于 ATTiny85 的 digispark Arduino 最小系统的自制教程(二) Digispark USB 开发板把玩笔记(一):认识这块小巧、便宜、多功能的 Arduino 兼容板 Connecting and Programming Your Digispark Attiny85 Micronucleus bootloader 燒錄 ATtiny85 制作迷你小游戏机 DigiSpark ATtiny85 8 脚 Arduino AVR ISP 编程的那点事儿 BootLoader 熔丝 Quick Reference Frequently requested info 文章作者:Power Lin 原文地址:https://wiki-power.com 版权声明:文章采用 CC BY-NC-SA 4.0 协议,转载请注明出处。

AI生成摘要 这篇文章记录了使用ATTiny85进行调试的过程。首先使用Arduino作为ISP下载器,然后通过连接不同的引脚来实现不同的功能。文章提供了一些参考和致谢,并附带了一些相关的教程和笔记。

相关推荐 去reddit讨论

Power's Wiki -

StyleTransferCam - 基于 ESP32-S3 的风格迁移相机

当艺术与技术交汇,一幅新的世界在我们面前展开,这是一场视觉上的奇妙盛宴,也是一份无限可能的探索。StyleTransferCam 是一个基于 ESP32-S3 的风格迁移相机。它使用的是一种叫「风格迁移」的机器学习技术,当你按下板载按钮时,它将拍下当前的景色,并与一张预设的风格模板照片混合(可以是梵高的「星空」),生成一张别具匠心的作品。 StyleTransferCam 大致由以下几个流程组成: 按下板载按钮 - 拍摄照片 - 上传到后端服务器上(也可以是 PC 或旧手机)。 自动启动风格迁移的 Python 程序,对照片进行处理,并输出风格化的照片。 如果 ESP32-S3 有附带 TFT 屏幕的话,也可以回传屏幕显示出来。 测试板载按钮与 LED 首先是一个简单的 Arduino 程序,用于测试板载按钮与 LED 能否正常使用。程序中设置了硬件中断,捕捉按钮按下的事件,点亮 LED 半秒后自动熄灭。 ```cpp title="Onboard-Key-ctrl-LED_interrupt.ino" define ONBOARD_KEY 47 // 板载按钮 define ONBOARD_LED 21 // 板载 LED volatile bool buttonPressed = false; // 按钮下降沿中断标志位 void setup() { pinMode(ONBOARD_LED, OUTPUT); pinMode(ONBOARD_KEY, INPUT); Serial.begin(115200); attachInterrupt(digitalPinToInterrupt(ONBOARD_KEY), buttonInterrupt, FALLING); } void loop() { if (buttonPressed) { digitalWrite(ONBOARD_LED, HIGH); delay(500); digitalWrite(ONBOARD_LED, LOW); Serial.println("buttonPressed"); buttonPressed = false; // 重置中断标志位 } } void buttonInterrupt() { buttonPressed = true; // 设置下降沿中断标志位 } ``` 使用按钮拍摄照片并上传 接下来,我们编写一个 Arduino 程序,使用板载按钮控制 ESP32-S3 拍摄一张照片,并将其上传到指定的网络位置。这个网络位置在代码中的 serverName = "http://192.168.31.2:9000/upload" 进行设置,需要修改为你后端服务器的地址。我们用的是一个后端 Python 文件上传服务(会在接下来的步骤中说明),而这里需要修改为运行这个服务的机器 IP 地址。(9000 与 /upload 在下文的 receive-photo.py 程序中设置) ```cpp title="Capture-and-Upload.ino" include "esp_camera.h" include include // 用于上传照片的服务器地址 const char *serverName = "http://192.168.31.2:9000/upload"; // // WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality // Ensure ESP32 Wrover Module or other board with PSRAM is selected // Partial images will be transmitted if image exceeds buffer size // // You must select partition scheme from the board menu that has at least 3MB APP space. // Face Recognition is DISABLED for ESP32 and ESP32-S2, because it takes up from 15 // seconds to process single frame. Face Detection is ENABLED if PSRAM is enabled as well // =================== // Select camera model // =================== define PWDN_GPIO_NUM -1 define RESET_GPIO_NUM -1 define XCLK_GPIO_NUM 45 define SIOD_GPIO_NUM 1 define SIOC_GPIO_NUM 2 define Y9_GPIO_NUM 48 define Y8_GPIO_NUM 46 define Y7_GPIO_NUM 8 define Y6_GPIO_NUM 7 define Y5_GPIO_NUM 4 define Y4_GPIO_NUM 41 define Y3_GPIO_NUM 40 define Y2_GPIO_NUM 39 define VSYNC_GPIO_NUM 6 define HREF_GPIO_NUM 42 define PCLK_GPIO_NUM 5 define ONBOARD_KEY 47 // 板载按钮 define ONBOARD_LED 21 // 板载 LED volatile bool buttonPressed = false; // 按钮下降沿中断标志位 include "DFRobot_AXP313A.h" DFRobot_AXP313A axp; // =========================== // Enter your WiFi credentials // =========================== const char ssid = "WiFi_SSID"; const char password = "**"; void startCameraServer(); void setup() { pinMode(ONBOARD_KEY, INPUT); pinMode(ONBOARD_LED, OUTPUT); attachInterrupt(digitalPinToInterrupt(ONBOARD_KEY), buttonInterrupt, FALLING); Serial.begin(115200); Serial.setDebugOutput(true); Serial.println(); while (axp.begin() != 0) { Serial.println("init error"); delay(1000); } axp.enableCameraPower(axp.eOV2640); // 设置摄像头供电 camera_config_t config; config.ledc_channel = LEDC_CHANNEL_0; config.ledc_timer = LEDC_TIMER_0; config.pin_d0 = Y2_GPIO_NUM; config.pin_d1 = Y3_GPIO_NUM; config.pin_d2 = Y4_GPIO_NUM; config.pin_d3 = Y5_GPIO_NUM; config.pin_d4 = Y6_GPIO_NUM; config.pin_d5 = Y7_GPIO_NUM; config.pin_d6 = Y8_GPIO_NUM; config.pin_d7 = Y9_GPIO_NUM; config.pin_xclk = XCLK_GPIO_NUM; config.pin_pclk = PCLK_GPIO_NUM; config.pin_vsync = VSYNC_GPIO_NUM; config.pin_href = HREF_GPIO_NUM; config.pin_sscb_sda = SIOD_GPIO_NUM; config.pin_sscb_scl = SIOC_GPIO_NUM; config.pin_pwdn = PWDN_GPIO_NUM; config.pin_reset = RESET_GPIO_NUM; config.xclk_freq_hz = 20000000; config.frame_size = FRAMESIZE_UXGA; // 照片分辨率。这里默认为 FRAMESIZE_UXGA config.pixel_format = PIXFORMAT_JPEG; // for streaming // config.pixel_format = PIXFORMAT_RGB565; // for face detection/recognition config.grab_mode = CAMERA_GRAB_WHEN_EMPTY; config.fb_location = CAMERA_FB_IN_PSRAM; config.jpeg_quality = 0; // 63; // 照片质量。这里默认为 12 config.fb_count = 1; / FRAMESIZE_QVGA (320 x 240) FRAMESIZE_CIF (352 x 288) FRAMESIZE_VGA (640 x 480) FRAMESIZE_SVGA (800 x 600) FRAMESIZE_XGA (1024 x 768) FRAMESIZE_SXGA (1280 x 1024) FRAMESIZE_UXGA (1600 x 1200) / // if PSRAM IC present, init with UXGA resolution and higher JPEG quality // for larger pre-allocated frame buffer. if (config.pixel_format == PIXFORMAT_JPEG) { if (psramFound()) { config.jpeg_quality = 0; // 63; // 照片质量。这里默认为 10 config.fb_count = 2; config.grab_mode = CAMERA_GRAB_LATEST; } else { // Limit the frame size when PSRAM is not available config.frame_size = FRAMESIZE_UXGA; // 照片分辨率。这里默认为 FRAMESIZE_SVGA config.fb_location = CAMERA_FB_IN_DRAM; } } else { // Best option for face detection/recognition config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_240X240; if CONFIG_IDF_TARGET_ESP32S3 config.fb_count = 2; endif } if defined(CAMERA_MODEL_ESP_EYE) pinMode(13, INPUT_PULLUP); pinMode(14, INPUT_PULLUP); endif // camera init esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { Serial.printf("Camera init failed with error 0x%x", err); return; } sensor_t *s = esp_camera_sensor_get(); // initial sensors are flipped vertically and colors are a bit saturated if (s->id.PID == OV3660_PID) { s->set_vflip(s, 1); // flip it back s->set_brightness(s, 1); // up the brightness just a bit s->set_saturation(s, -2); // lower the saturation } // drop down frame size for higher initial frame rate if (config.pixel_format == PIXFORMAT_JPEG) { s->set_framesize(s, FRAMESIZE_QVGA); } if defined(CAMERA_MODEL_M5STACK_WIDE) || defined(CAMERA_MODEL_M5STACK_ESP32CAM) s->set_vflip(s, 1); s->set_hmirror(s, 1); endif if defined(CAMERA_MODEL_ESP32S3_EYE) s->set_vflip(s, 1); endif WiFi.begin(ssid, password); WiFi.setSleep(false); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); startCameraServer(); Serial.print("Camera Ready! Use 'http://"); Serial.print(WiFi.localIP()); Serial.println("' to connect"); digitalWrite(ONBOARD_LED, LOW); } void loop() { // Do nothing. Everything is done in another task by the web server // delay(10000); // 按钮按下后的逻辑 if (buttonPressed) { digitalWrite(ONBOARD_LED, HIGH); delay(300); digitalWrite(ONBOARD_LED, LOW); // 拍摄照片 camera_fb_t *fb = esp_camera_fb_get(); if (!fb) { Serial.println("获取摄像头帧缓冲失败"); return; } // 建立HTTP客户端 HTTPClient http; // 将照片上传到服务器 http.begin(serverName); http.addHeader("Content-Type", "image/jpeg"); int httpResponseCode = http.POST(fb->buf, fb->len); if (httpResponseCode > 0) { Serial.printf("照片上传成功,服务器返回代码:%d\n", httpResponseCode); // 再闪一下提示上传成功 digitalWrite(ONBOARD_LED, HIGH); delay(300); digitalWrite(ONBOARD_LED, LOW); } else { Serial.printf("照片上传失败,错误代码:%s\n", http.errorToString(httpResponseCode).c_str()); } http.end(); // 释放帧缓冲 esp_camera_fb_return(fb); // delay(1000); // 等待 1 秒后才可再次拍摄和上传 buttonPressed = false; // 重置中断标志位 } } void buttonInterrupt() { buttonPressed = true; // 设置下降沿中断标志位 } ``` 接收照片上传的服务 在这里我们使用 Python 的 flask 库搭建一个接收照片上传的 HTTP 服务器。 ```python title="receive-photo.py" from flask import Flask, request import subprocess app = Flask(name) @app.route('/upload', methods=['POST']) def upload(): try: image = request.data # 保存照片到指定目录 with open('base.png', 'wb') as f: f.write(image) print("照片已保存,正在渲染中……") # 启动风格迁移的 python 脚本 subprocess.run(['python', './style_transfer.py']) return "照片上传成功", 200 except Exception as e: print("照片上传失败:", str(e)) return "照片上传失败", 500 if name == 'main': app.run(host='0.0.0.0', port=9000) ``` 先不要急着运行程序,style_transfer.py 是风格迁移的程序,将会在下一个步骤展示。这个程序的逻辑是,如果成功接收了 ESP32-S3 传回来的照片,就会使用 subprocess 自动调起运行风格迁移的脚本。 需要注意的是,如果程序出现异常,提示端口被占用,你可以试试将 port=9000 换一个值。 风格迁移的程序 在 receive-photo.py 相同的目录下,我们使用 TensorFlow 编写一个风格迁移的 Python 程序。首先安装程序所需的依赖(国内的网络环境导致 TensorFlow 很难下载,需要多一些耐心),然后在相同目录下准备一张待风格化的照片,将其命名为 base.png;还有一张风格参考的图片,命名为 style_reference.png,这副图片可以是一副艺术画,比如梵高的「星空」: 接下来,编写风格迁移的程序: ```python title="style_transfer.py" from IPython.display import Image, display import numpy as np import tensorflow as tf from tensorflow import keras from tensorflow.keras.applications import vgg19 base_image_path = "./base.png" # 待风格迁移的图片地址 style_reference_image_path = "./style_reference.png" # 风格样式图片地址 result_prefix = "img_generated" 各部分损失的权重设置 total_variation_weight = 1e-6 style_weight = 1e-6 content_weight = 2.5e-8 生成图片的尺寸 width, height = keras.preprocessing.image.load_img(base_image_path).size img_nrows = 400 img_ncols = int(width * img_nrows / height) 通过下面命令查看要进行风格迁移的基本图片和样式参考图片 display(Image(base_image_path)) display(Image(style_reference_image_path)) 图像预处理 def preprocess_image(image_path): # 利用Keras库函数的来打开图片,调整图片大小并将其格式化为适当的张量 img = keras.preprocessing.image.load_img( image_path, target_size=(img_nrows, img_ncols) ) img = keras.preprocessing.image.img_to_array(img) img = np.expand_dims(img, axis=0) img = vgg19.preprocess_input(img) return tf.convert_to_tensor(img) def deprocess_image(x): # 再利用函数将张量转换为有效图像 x = x.reshape((img_nrows, img_ncols, 3)) # 通过平均像素去除零中心 x[:, :, 0] += 103.939 x[:, :, 1] += 116.779 x[:, :, 2] += 123.68 # 'BGR'->'RGB' x = x[:, :, ::-1] x = np.clip(x, 0, 255).astype("uint8") return x 图像张量的gram矩阵(特征矩阵和特征矩阵转置的乘积) def gram_matrix(x): x = tf.transpose(x, (2, 0, 1)) features = tf.reshape(x, (tf.shape(x)[0], -1)) gram = tf.matmul(features, tf.transpose(features)) return gram “风格损失”旨在保持生成图像中参考图像的样式。 它基于的gram矩阵(样式提取)来自样式参考图像 和从它生成的图像的特征图 def style_loss(style, combination): S = gram_matrix(style) C = gram_matrix(combination) channels = 3 size = img_nrows * img_ncols return tf.reduce_sum(tf.square(S - C)) / (4.0 * (channels ** 2) * (size ** 2)) 辅助损失函数设计来是为了 维护生成的图像中的基本图像的内容 def content_loss(base, combination): return tf.reduce_sum(tf.square(combination - base)) 第三个损失函数是总变化损失, 设计此函数是为了使生成的图像保持局部连贯。 def total_variation_loss(x): a = tf.square( x[:, : img_nrows - 1, : img_ncols - 1, :] - x[:, 1:, : img_ncols - 1, :] ) b = tf.square( x[:, : img_nrows - 1, : img_ncols - 1, :] - x[:, : img_nrows - 1, 1:, :] ) return tf.reduce_sum(tf.pow(a + b, 1.25)) 接下来,让我们创建一个特征提取模型,该模型检索VGG19的中间激活(根据名字制成字典)。 替换为你本地下载的权重文件路径 weights_path = "./dependencies/vgg19_weights_tf_dim_ordering_tf_kernels_notop.h5" 建立一个加载了已经训练好的ImageNet的权重的VGG19模型 model = vgg19.VGG19(weights=weights_path, include_top=False) 获取每个“关键”层的符号输出(我们给它们指定了唯一的名称)。 outputs_dict = dict([(layer.name, layer.output) for layer in model.layers]) 建立一个模型,以返回VGG19中每层的激活值(以字典的方式)。 feature_extractor = keras.Model(inputs=model.inputs, outputs=outputs_dict) 最后,这是计算样式转移损失的代码。 用于样式丢失的图层列表。 style_layer_names = [ "block1_conv1", "block2_conv1", "block3_conv1", "block4_conv1", "block5_conv1", ] 用于内容丢失的层。 content_layer_name = "block5_conv2" def compute_loss(combination_image, base_image, style_reference_image): input_tensor = tf.concat( [base_image, style_reference_image, combination_image], axis=0 ) features = feature_extractor(input_tensor) # 初始化损失 loss = tf.zeros(shape=()) # 加入内容丢失 layer_features = features[content_layer_name] base_image_features = layer_features[0, :, :, :] combination_features = layer_features[2, :, :, :] loss = loss + content_weight * content_loss( base_image_features, combination_features ) # 加入风格损失 for layer_name in style_layer_names: layer_features = features[layer_name] style_reference_features = layer_features[1, :, :, :] combination_features = layer_features[2, :, :, :] sl = style_loss(style_reference_features, combination_features) loss += (style_weight / len(style_layer_names)) * sl # 加入总变化损失 loss += total_variation_weight * total_variation_loss(combination_image) return loss 将tf.function装饰器添加到损耗计算和梯度计算中,使在编译过程中能运行更快 @tf.function def compute_loss_and_grads(combination_image, base_image, style_reference_image): with tf.GradientTape() as tape: loss = compute_loss(combination_image, base_image, style_reference_image) grads = tape.gradient(loss, combination_image) return loss, grads 重复执行批量梯度下降步骤,以最大程度地减少损失,并每100次迭代保存生成的图像。 每100步将学习率降低0.96。 optimizer = keras.optimizers.SGD( keras.optimizers.schedules.ExponentialDecay( initial_learning_rate=100.0, decay_steps=100, decay_rate=0.96 ) ) base_image = preprocess_image(base_image_path) style_reference_image = preprocess_image(style_reference_image_path) combination_image = tf.Variable(preprocess_image(base_image_path)) iterations = 4000 for i in range(1, iterations + 1): loss, grads = compute_loss_and_grads( combination_image, base_image, style_reference_image ) optimizer.apply_gradients([(grads, combination_image)]) if i % 100 == 0: print("Iteration %d: loss=%.2f" % (i, loss)) img = deprocess_image(combination_image.numpy()) fname = result_prefix + "at_iteration%d.png" % i keras.preprocessing.image.save_img(fname, img) 经过 4000 次迭代,输出结果: display(Image(result_prefix + "_at_iteration_4000.png")) ``` 现在,你可以试试单独运行这个 Python 程序,如果程序没有报错,等上一小会儿(具体时间取决于你电脑的性能),你就可以在当前目录下找到阶梯次风格迁移迭代后的照片了。 如果这个程序能正常运行,你可以直接运行 receive-photo.py,使用自动化的方式接收来自 ESP32-S3 拍摄的照片,直接生成风格化的照片。 参考与致谢 风格迁移 TensorFlow 实现 神经风格迁移 摄像头使用 原文地址:https://wiki-power.com/ 本篇文章受 CC BY-NC-SA 4.0 协议保护,转载请注明出处。

AI生成摘要 StyleTransferCam是一款基于ESP32-S3的风格迁移相机。它使用风格迁移机器学习技术,将当前景色与预设的风格模板照片混合,生成独特的作品。相机由按下板载按钮、拍摄照片、上传到后端服务器等流程组成。另外,还介绍了测试板载按钮与LED的Arduino程序,以及使用按钮拍摄照片并上传的Arduino程序。最后,介绍了接收照片上传的Python服务和风格迁移的Python程序。

相关推荐 去reddit讨论

Power's Wiki -

HAL 库开发笔记 - 以太网通信(LwIP) 🚧

以下是基于 反客 STM32F407 主控核心板 与 DP83848 以太网 PHY 模块 的教程。 硬件 DP83848 接口为 RMII,DP83848 可支持 10M/100M 的线速,板载 50MHz 无源晶振。 | STM32 主控 | DP83848 模块 | | ----------- | ------------ | | ETH_REF_CLK | PA1 | | ETH_MDIO | PA2 | | ETH_MDC | PC1 | | ETH_CRS_DV | PA7 | | ETH_RXD0 | PC4 | | ETH_RXD1 | PC5 | | ETH_TX_EN | PB11 | | ETH_TXD0 | PB12 | | ETH_TXD1 | PB13 | 软件 CubeMX 内配置 RCC:HSE 选择外部晶振 SYS DEBUG:SW GPIO PA15:USER_BTN, Input, Pull-up PC13:LED_GREEN, Output Push Pull, level High PC14:LED_BLUE, Output Push Pull, level High PC15:LED_RED, Output Push Pull, level High ETH Mode:RMII Advanced Parameters PHY:DP83848_PHY_ADDRESS LWIP Key Options 勾选 Show Advanced Parameters 确保 LWIP_NETIF_LINK_CALLBACK 为 Enable(一般默认) xLWIP_LOOPIF_MULTICAST:Enabled xLWIP_MULTICAST_TX_OPTIONS:Enabled xLWIP_NETIF_STATUS_CALLBACK:Enabled xLWIP_NETIF_EXT_STATUS_CALLBACK:Enabled xLWIP_SO_RCVBUF:Enabled Genetal Settings xLWIP_IGMP:Enabled 时钟树配置:按照板载晶振(此板为 8M)配置。 添加功能代码 ```c title="main.c" / USER CODE BEGIN PV / extern struct netif gnetif; / USER CODE END PV / / USER CODE BEGIN 0 / void ethernetif_notify_conn_changed(struct netif netif) { / NOTE : This is function could be implemented in user file when the callback is needed, / if (netif_is_link_up(netif)) { HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(LED_RED_GPIO_Port, LED_RED_Pin, GPIO_PIN_SET); } else { HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(LED_RED_GPIO_Port, LED_RED_Pin, GPIO_PIN_RESET); } } / USER CODE END 0 */ / USER CODE BEGIN 2 / ethernetif_notify_conn_changed(&gnetif); / USER CODE END 2 / / USER CODE BEGIN 3 / MX_LWIP_Process(); } / USER CODE END 3 / ``` c title="lwip.c" /* USER CODE BEGIN 4_3 */ ethernetif_set_link(&gnetif); if (netif_is_link_up(&gnetif) && !netif_is_up(&gnetif)) { netif_set_up(&gnetif); dhcp_start(&gnetif); } /* USER CODE END 4_3 */ 调试 查看连接到此电脑的设备 IP:arp -a 通过插拔确定 STM32 的 IP 地址 ping [ip 地址] (-t) 热插拔网线会出现 传输失败,常见故障,稍等即可自动重新建立连接。 参考与致谢 STM32 HAL Ethernet initialization 原文地址:https://wiki-power.com/ 本篇文章受 CC BY-NC-SA 4.0 协议保护,转载请注明出处。 ``` 本篇基于自研 RobotCtrl 开发套件,单片机内核为 STM32F407ZET6,以太网 PHY 芯片为 LAN8720A,原理图及详细介绍请见 RobotCtrl - STM32 通用开发套件。 LwIP 是 轻型(Light Weight)IP 协议,不管有没有操作系统的支持,都可以运行。LwIP 实现的重点是在保持 TCP 协议主要功能的基础上减少对 RAM 的占用,它只需十几 KB 的 RAM 和 40K 左右的 ROM 就可以运行,这使 LwIP 协议栈适合在低端的嵌入式系统中使用。 LwIP 提供了三种编程接口,分别为 RAW/Callback API、NETCONN API、SOCKETAPI。它们的易用性从左到右依次提高,而执行效率从左到右依次降低。可以权衡利弊选择适合自己的 API 进行开发。在本文中,使用 Raw API,调用以下的函数: | API 函数 | 说明 | | -------------- | ---------------------------------------- | | udp_new | 创建新的 UDP PCB | | udp_remove | 移除 UDP PCB 并释放相关资源 | | udp_bind | UDP PCB 与本地 IP 地址和端口绑定 | | udp_connect | 建立 UDP PCB 远程 IP 地址和端口 | | udp_disconnect | 移除 UDP PCB 远程 IP 和端口 | | udp_send | 发送 UDP 数据 | | udp_recv | 注册回调函数,当收到新数据报时即对其调用 | CubeMX 内配置 在 RCC 页面内为 HSE 选择外部晶振。 在 ETH 页面内配置 PHY 模式为RMII,并配置以下参数: 在 Parameter Setting 标签页下,将 PHY Address 配置为 0(根据 PHYAD0 管脚配置决定的)。 在 Advanced Parameter 标签页下,根据 LAN8720A 的芯片手册,将 PHY special control/status register Offset 配置为 31; PHY Speed mask 配置为 0x0004; PHY Duplex mask 配置为 0x0010。 在 LWIP 页面内开启使能,并配置以下参数: 在 General Settings 标签页下,将 LWIP_DHCP (DHCP Module) 配置为 Disabled(使用静态 IP); IP_ADDRESS 配置为 192.168.001.100; NETMASK_ADDRESS 配置为 255.255.255.000;GATEWAY_ADDRESS 配置为 192.168.001.001;LWIP_UDP (UDP Module) 和 LWIP_TCP (TCP Module) 配置为 Enabled。 参考与致谢 LwIP TCP/IP stack demonstration for STM32F4x7 microcontrollers (AN3966) Developing applications on STM32Cube with LwIP TCP/IP stack (UM1713) 54zorb/stm32-lwip 文章作者:Power Lin 原文地址:https://wiki-power.com 版权声明:文章采用 CC BY-NC-SA 4.0 协议,转载请注明出处。 ```

AI生成摘要 本教程介绍了使用STM32F407主控核心板和DP83848以太网PHY模块的方法。DP83848支持RMII接口和10M/100M的线速,板载50MHz无源晶振。时钟树配置根据板载晶振(8M)进行设置。

相关推荐 去reddit讨论