pATAq 发表于 2022-9-8 22:57:04

跟着思兼学习Klipper(17) 基于Klipper的Manta M4P牌夏日降温电风扇

## 前言

原创文章,转载引用务必注明链接,水平有限,如有疏漏,欢迎指正交流。

前几日还是穿着短袖都出汗,突然间冻得直哆嗦,我就知道这是催更了,再不整理出来黄花菜都凉了。

今年夏天尤其热,不过国外也不提全球气候变暖了,缺少化石燃料的欧洲,环保少女也可以通俄。今天给大家介绍如何使用 Klipper 固件做一个家用桌上式电风扇。有朋友要问你说啥,Klipper 不是 3D 打印机固件吗,还能做电风扇?其实私以为 Mainsail 翻译为 Machine 十分准确,Klipper 功能强大,拓展能力强,除了本职之外,还能作为很多其他机械控制系统,比如写字机、打印平台模型清理装置(连续打印),还比如今天我们做的风扇。

这里对必趣(BigTreeTech)公司提供的硬件表示感谢。

<img src="https://www.klipper3d.org/img/sponsors/BTT_BTT.png" style="zoom: 25%;" />

硬件组成:

* 12V 4线 PWM 调速 12025 台式机散热风扇,从我的九州风神大霜塔散热器上拆的
* 角度传感器、非自锁式按钮
* BigTreeTech Manta M4P 二合一主板(原型板)
* MKS Mini12864 LCD 屏幕 / BTT TFT35 V3.0.1 彩色触摸屏

!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/202209080027033.png)

!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/202209080028658.png)

!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/20220908184040.png)

测试设备:

*MINIWARE DS213 四通道袖珍示波器
*利利普 OWON VDS1022 双通道虚拟示波器
*日置 HIOKI 卡片型万用表3244-60
*智位 DFRobot 便携式多路可调电源
*!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/20220908191737.png)

!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/202209080024104.png)

---

本文介绍的知识:

- 如何创建最小测试配置文件 printer.cfg
- **<u>如何控制 PWM 调速风扇(重点)</u>**
- 如何读取 ADC 引脚值
- **<u>如何通过角度传感器(电位器)控制风扇转速(重点与难点)</u>**
- 创建 LCD 菜单控制风扇转速/控制启停
- 使用示波器观察 PWM 风扇

---

文章如有更新请访问 (https://mc.dfrobot.com.cn/thread-314060-1-1.html?fromuid=725344) 或者 (https://www.cnblogs.com/sjqlwy/p/klipper_fan.html)。

欢迎对 Klipper 固件、KlipperBoxOS 感兴趣,以及对改版 CNC 加工的 Voron 三叉戟、v0、v2.4 感兴趣的朋友加群交流(QQ Group:490111638)

## 1、桌上式风扇控制系统架构

我们设计的电风扇由三部分组成:**输入控制系统** ——> **处理系统**(Klipper + BTT Manta M4P)——> **输出效应器**(风扇)。

这里的输入控制方式包括:

1. 启停控制

   * 温控自动启停

   * 按钮手动启停

2. 调速控制

   * 模拟角度传感器(电位器)调速
   * LCD屏幕菜单控制调速

!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/20220908160004.png)

## 2、处理系统:知己知彼——Manta M4P

开始之前我们需要对手中的物什有个了解。最主要是 Manta M4P,我手里的是早期原型板,与最终零售版有所不同,这里先准备好主板说明书三件套:

* [用户手册](https://raw.fastgit.org/bigtreetech/Manta-M4P/master/BIGTREETECH_M4P%26CB1%20%E7%94%A8%E6%88%B7%E6%89%8B%E5%86%8C.pdf)      | 使用方法与注意事项
* [硬件引脚图](https://raw.fastgit.org/bigtreetech/Manta-M4P/master/Hardware/BIGTREETECH_Manta_M4P_V2.1_220608%20PINOUT.pdf)| 引脚布局
* [硬件原理图 ](https://raw.fastgit.org/bigtreetech/Manta-M4P/master/Hardware/bigtreetech_manta_m4p_v2.1_220608_SCH.pdf) | 原理与细节

这块板主要的亮点是采用 “核心板 + 功能底板” 的方式,且核心板可以用在 Pi 底板上,也可以用在 3D 打印底板上,这在 3D 打印机主板上还是挺有意思的。

### 2.1 引脚说明

由于我们需要用模拟输入、PWM 输出、MOS 输出、数字输入输出引脚,所以要先了解个大概。

**上位机主板引脚:**

> 上位机的信号电平为 3.3V,包括 UART 通讯引脚。而 STM32 芯片的信号电平虽然也是 3.3v,但是部分引脚可用耐受 5v,这部分引脚可用查看其数据手册,加 * 的为 5V 耐受。

!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/20220908162326.png)

* RGB1/2 信号经电平转换,其电平为 5V
* FAN 引脚为 5V/VCC 可选
* SoC_FAN 电压 VCC
* 原型板上位机 GPIO 似乎不可用
> VCC 为输入电压,这里为12/24V

**下位机主板引脚:**

| 类别                           | 描述                                                         |
| ------------------------------ | ------------------------------------------------------------ |
| ADC/Analog 引脚                | 模拟引脚,用于连接温敏电阻或模拟传感器,连接到非 ADC 引脚会报错:`Not a valid ADC pin`,此类引脚一般连接 4k7 欧姆上拉电阻 |
| PWM/Timer 引脚               | PWM引脚,Klipper 默认使用 GPIO 引脚进行模拟,而不使用硬件 PWM 输出引脚,如果配置了 `hardware_pwm: True`,则需要连接到对应的引脚,否则报错 `Not a valid PWM pin`。详见下文 |
| IRQ/Interrupt 引脚             | 中断引脚,Klipper 不使用此类引脚                           |
| SPI 通讯引脚                   | Klipper 支持使用 GPIO 引脚实现软件模拟SPI,不过硬件 SPI 性能更好 |
| I2C 通讯引脚                   | 用于 I2C 通讯                                                |
| GPIO (General Purpose IO) 引脚 | 通用输入输出引脚                                             |
| Pins With MOSFET               | 由于主板 GPIO 数字引脚不支持带大电流负载,所以需要借助 MOS 管,此类引脚包括挤出头、热床加热器以及可控风扇,一般不做信号输入 |

> * MCU 引脚介绍:(https://www.klipper3d.org/FAQ.html#do-i-have-to-wire-my-device-to-a-specific-type-of-micro-controller-pin)
>
> * 通过源码查找功能引脚:[跟着思兼学习Klipper(03-1)加速度计与输入整形器](https://mc.dfrobot.com.cn/thread-311525-1-1.html?fromuid=725344)
> * Fluidd/Mainsail 网页查看:可以看到基本的 SPI、I2C 引脚,但是其他的需要看源码或者 MCU 数据手册

!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/20220907143034.png)

### 2.2 创建最小机器配置文件

我们使用加法而非减法来定义一个桌面电风扇的配置文件 `printer.cfg`,不包括电机驱动、挤出头/热床、热敏等配置

```yaml
# printer.cfg
######################################################################
##以下为必填项,否则会报红色错误,无法使用 Klipper
## 主板 MCU, 根据实际情况修改

serial: /dev/serial/by-id/usb-Klipper_stm32g0b1xx_190036000D50415833323520-if00

# 上位机作为 MCU 时启用
#
# serial: /tmp/klipper_host_mcu


kinematics: none
max_velocity: 1000
max_accel: 1000
######################################################################
##以下在 Fluidd/Mainsail 中需要,否则会报黄色警告



path: ~/gcode_files


description: 无实际作用,避免出现黄字报错
rename_existing: CANCEL_PRINT_BASE
gcode:
######################################################################
# 用于调试

```

## 3、输出效应器:创建不同 DC 风扇配置

直流风扇主要有三种:

1. 两线风扇:VCC + GND,可以实现开和关两种状态,也可以通过调节输出电压来进行线性调速控制
2. 三线风扇:VCC + GND + TACHO 测速引脚
3. 四线风扇:VCC + GND + TACHO + PWM 调速引脚,可以通过 PWM 调节占空比控制速度

![](http://bbs.gemwon.com/attachment.aspx?attachmentid=7729)

### 3.1 两线风扇

两线风扇只有正负极,一般作为常开风扇。也可以通过 DC 调压实现变速,缺点是调速不够准确但是一般够用。

启停风扇只有开关两种状态,我们既可以和灯带一样定义一个 [`output_pin`](https://www.klipper3d.org/Config_Reference.html#output_pin),只输出 0 或者 1 进行控制;也可以定义一个 [`fan_generic`](https://www.klipper3d.org/Config_Reference.html#fan_generic) ,可以调节(0-1)范围输出值,然后手动指定输出 0 或者 1。由于风扇有一些特殊参数,单纯的 output_pin 无法满足进阶要求,故此本文使用后者。

同时由于 MCU、MPU 引脚不能输出大电流带负载,所以我们选择可控风扇引脚或者加热器输出引脚连接风扇。

!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/20220908165255.png)

!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/202209031701056.png)

查看原理图,找到 `热床加热器`、`挤出头加热器`、`风扇控制` 引脚使用的 MOS 信号:

* RGB 灯带、挤出头加热:(https://www.semiee.com/11fc3fed-84af-4971-b74b-2fdb492779fc.html) MOS (富鼎先进-APEC) VDS 20V,持续电流5.3A(25摄氏度),峰值电流10A
* 热床加热:(https://www.semiee.com/0655c43b-03d1-4aba-9c1a-8250eec04e88.html) (英飞凌-Infineon) VDS 40V,持续电流 90A(25摄氏度),峰值电流 400A

我们选择 HE0的 `PC8` MOS 输出引脚,主要原因是它也是硬件 PWM 引脚,可以测试软硬 PWM 的效果区别。

此外注意风扇引脚和加热输出引脚的电压,其中 `可控风扇引脚` 在 M4P 上可选 `5v/VIN` (12/24V,由端子 `POWER` 输入电压决定),有的主板可选 `5/12/VIN` ,加热输出引脚固定为 VIN。注意电压选择和 +/- 极,不要接错烧坏了。

**Method 1 :output_pin 输出引脚**

```yaml
# printer.cfg 最简单的启停风扇,连接 HE0 输出引脚

pin: PC8

# 启停控制
SET_PIN PIN=simple_fan VALUE=0|1
```

**Method 2 :fan_generic 通用风扇**

```yaml

pin: PC8
max_power: 1 # 24v
# max_power: 0.5 # 等效~12v,调整 PWM 占空比从而影响输出电压,和 Fan_speed 相乘后是最终速度
shutdown_speed: 0 # 系统进入错误状态时风扇转速,默认为零避免继续输出
cycle_time: 0.010 # 每秒钟 PWM 供电循环次数,对应 100Hz
hardware_pwm: False # 是否使用硬件 PWM,需要引脚支持。同时大多数风扇难以很好地工作在硬件PWM模式下,所以除非有高速切换的需求,否则不建议开启。此外实际结果可能和预想的有出入。
kick_start_time: 0.100 # 风扇加速到全速的时间,用于风扇启动或者提速超过一半时
off_below: 0.0 # 风扇一般有个启动电压,当低于此电压时风扇不转但是确实上电了。当 max_power 改变时,需要重新校准此值。一般用于防止风扇堵转或者高效启动提速。校准方法:首先将此值设置为0.0,然后开启风扇,逐渐降低风速(占空比),直到风扇停转。建议最终设置的值比测试值稍高一些。编者注:不过由于惯性我习惯逐渐提高到启动电压。
```

**Caution:** 这里我建议要设置合适的 `max_power`、 `kick_start_time` 和 `off_below`,尤其是 `off_below` 经测试后填写适当的值。

### 3.2 三线测速风扇

三线风扇增加了一个测速引脚 TACHO,电机工作时输出测速信号,提供转速反馈。和我最初设想的不同,优先增加测速引脚而不是调速引脚的原因是:

1. 两线就可以调速,虽然不是那么精准平滑
2. 相比于转速快慢,很多场合更怕风扇坏了不转,比如服务器应用场景。在 3D 打印机上,主要是要监控挤出头喉管风扇,防止坏了堵头,甚至更危险的情况。

### 3.3 四线调速风扇

四线是在三线的基础上增加了 PWM 调速引脚,有几点需要注意:

* 电机工作时控制器输入 PWM 控制信号来控制风扇转速 (通常为占空比可变的方波,占空比越高电机转速越高)。
* 不同四线风扇引脚顺序不尽相同,判断方法包括
* 一般 PWM 信号引脚悬空时,风扇全速转动。接收到信号时正常转动
* 使用万用表测量,有输出的是 TACHO 测速引脚
* PWM 和 TACHO 引脚信号电压为 5V,与风扇额定电压无关。实际测试 3.3V 信号也可以,转速无明显区别(由占空比控制)。其实联想到单片机的信号电平一般为 3.3/5V 就好理解了。

**定义四线 PWM 调速风扇**

```yaml

pin: PD0 # PWM 信号输出,可使用 5V 电平的 RGB1/2
max_power: 1
kick_start_time: 0.10
off_below: 0 # 测试后填入

# 请注意不同风扇支持的 PWM 信号频率不同,可以先尝试 100Hz。信号频率控制风扇启停
## 25KHZ PWM 方波信号
# cycle_time: 0.00004
## 100HZ PWM 方波信号
cycle_time: 0.01

## 测速引脚,选择直连 mcu 数字引脚作为输入,需要上拉,不能使用接 MOS 管引脚
tachometer_pin: ^PA14 # SWD

## 可以根据风扇参数及最大转速调整以下参数
# tachometer_poll_interval: 0.0005
#tachometer_ppr: 2
#tachometer_poll_interval: 0.0015

## 启用硬件 PWM 引脚,需要引脚支持,不建议风扇开启
# hardware_pwm: True
```

更多信息请移步:
* (https://www.klipper3d.org/G-Codes.html#fan_generic)
* (https://blog.csdn.net/sinat_29315697/article/details/106880355)

## 4、输入控制系统
包括启停控制和调速控制。

### 4.1 启停控制
风扇只有两种状态开和关。一种是通过温度阈值,一种通过按钮手动控制

#### 4.1.1 温控自动启停

!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/20220908165622.png)

可以以 SoC_FAN 为例,使用 CB1 核心板时,对应控制引脚为 `PC15`,参考之前的文章 [跟着思兼学习Klipper(09)Klipper 温控风扇以及电源管理(部分)](https://mc.dfrobot.com.cn/thread-312100-1-1.html?fromuid=725344)以及 [跟着思兼学习Klipper(06) 学用 Fly-Gemini 3D打印机控制板](https://mc.dfrobot.com.cn/thread-311661-1-1.html?fromuid=725344 "您的朋友访问此链接后,您将获得相应的积分奖励"),轻车熟路。
!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/202112140438072.png)
!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/202112150853772.png)
* 默认的 Armbian 系统仍然没有 GPIO 读写权限,解决方法见上文
* `PC15` 对应 `gpio-79` 转换为 `gpiochip0/gpio79`
* 不要用 Klipper 来测试,即使没有权限也不会报错,

```shell
sudo apt-get install gpiod
# 识别 gpiochip 芯片
gpiodetect
# 查看 gpio 引脚信息,如是可知 gpiochip0/gpio79
gpioinfo
# 1. 根据 PC15-79 判断为 gpiochip0 还是 1。
sudo cat /sys/kernel/debug/gpio
```
创建温控风扇:
```yaml

serial: /tmp/klipper_host_mcu

# Temperature-triggered cooling fan | 温控风扇
pin: host:gpiochip0/gpio79 # 设置正确的引脚
kick_start_time: 0.500
sensor_type: temperature_host
control: watermark
# 高于以下温度启用风扇
target_temp: 50.0
# 允许的温度范围
min_temp: 0
max_temp: 90
# 调节最大风速以降低噪音
#max_speed: 1.0
#min_speed: 0.3
```
也可以使用其他温度来源,例如:
* (https://www.klipper3d.org/Config_Reference.html#htu21d-sensor) | I2C 通讯
* LM75 温度传感器
* DS18B20 温度传感器 | 1-wire 通讯,目前仅支持连接到上位机
* NTC 100K 3950 温敏电阻 | 由于温敏-阻值曲线以及上拉电阻,普通 3D 打印机用的在低于 100℃ 情况可能不准确

#### 4.1.2 手动按钮控制

分为两种:自锁和非自锁开关。

* 自锁开关很简单,按下和松开分别执行启动和停止命令即可
* 非自锁开关则是每次切换状态,根据状态判断打开或者关闭风扇。
* 需要做 [按键消抖(debounce)](https://www.digikey.cn/zh/articles/how-to-implement-hardware-debounce-for-switches-and-relays),Moonraker 有相关代码,缺点仅支持上位机 GPIO,优点不需要启动 Klipper
* Klipper 有相关防抖动代码,但是不支持自定义,所以我设置为松开按钮时才生效,起到一定防抖作用

```yaml
# btn.cfg
## 自锁按钮

pin: PA2 # UART2
press_gcode:
SET_FAN_SPEED FAN=two_wire_fan SPEED=1.0
release_gcode:
SET_FAN_SPEED FAN=two_wire_fan SPEED=0.0

## 非自锁按钮
# 如果是 output_pin 可以直接获取引脚状态每次取反,这里定义一个用于存储状态值以取反的宏,变量名不含大写字符

description: 用于储存当前风扇状态,便于非自锁按钮切换开关
variable_state: 1
# variable_last_temp: 0 | 后面给电位器用的
gcode:
   

pin: ~PA2 # UART2,注意有的按钮模块默认拉高或者拉低
press_gcode:
release_gcode:
      # 触发状态改变
    SET_GCODE_VARIABLE MACRO=_fan_state VARIABLE=state value={not printer["gcode_macro _fan_state"].state|int}
    {% if printer["gcode_macro _fan_state"].state == 1 %}
      M118 TURN_ON_FAN!
      SET_FAN_SPEED FAN=two_wire_fan SPEED=1.0
    {% else %}
      M118 TURN_OFF_FAN!
      SET_FAN_SPEED FAN=two_wire_fan SPEED=0.0
    {% endif %}
   
## 读取按钮状态,测试用
QUERY_BUTTON button=fan_none_lock_switch
```
> 我这个按钮兼容 3.3/5v 电压,默认拉低,并且注意手不要触摸按钮引脚,防止误触发

!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/20220908170418.png)

### 4.2 调速控制
以上我们实现了风扇的启停控制,这时候又有朋友要说,教练,风太大吹得头疼、噪音太大,每次手动改配置文件调整 fan_speed 比较麻烦,我想搞个可以调速的风扇。

#### 4.2.1 屏幕控制转速
这里要先定义一个屏幕以供使用,使用 MKS mini12864 LCD 屏幕,注意需要换排线,见文章 [跟着思兼学习Klipper(11)3D 打印机主板拓展更多轴和可控风扇](https://mc.dfrobot.com.cn/thread-312209-1-1.html?fromuid=725344),也可以使用 BTT TFT35 彩色触摸屏的兼容模式(长按按钮切换)。M4P 的引脚见 [这里](https://github.com/bigtreetech/Manta-M4P/blob/master/Firmware/Klipper/generic-bigtreetech-manta-m4p-voron0.cfg)。
```yaml
# display.cfg
## 主板 EXP 插座引脚定义

aliases:
    # EXP1 header
    EXP1_1=PD6,EXP1_3=PB9,EXP1_5=PA15, EXP1_7=PA9,   EXP1_9=<GND>,
    EXP1_2=PB8,EXP1_4=PC3,EXP1_6=PA10, EXP1_8=PB5,   EXP1_10=<5V>,
    # EXP2 header
    EXP2_1=PB14, EXP2_3=PC11, EXP2_5=PC12, EXP2_7=PC13,EXP2_9=<GND>,
    EXP2_2=PB13, EXP2_4=PA8,EXP2_6=PB15, EXP2_8=<RST>, EXP2_10=<NC>

## MKS mini12864 LCD 屏幕定义
# lcd_type: uc1701
# cs_pin: EXP1_6
# a0_pin: EXP1_7
# contrast: 40
# encoder_pins: ^EXP2_3, ^EXP2_5
# click_pin: ^!EXP1_2
# encoder_steps_per_detent: 4
# menu_reverse_navigation: True
# spi_bus: spi2

## BTT TFT34 彩色触摸屏幕定义

lcd_type: emulated_st7920
en_pin: EXP1_4
spi_software_sclk_pin: EXP1_5
spi_software_mosi_pin: EXP1_3
spi_software_miso_pin: PA6
encoder_pins: ^EXP2_3, ^EXP2_5
click_pin: ^!EXP1_2
encoder_steps_per_detent: 4
menu_reverse_navigation: True
# 模拟 st7920 显示屏引脚:
# en-cs
# spi_software_sclk_pin-sclk_pin
# spi_software_mosi_pin-sid_pin
# spi_software_miso_pin-任意一个空闲引脚,用不到但是需要设置。

######################################################################
# 蜂鸣器 | Beeper
######################################################################
# TFT35 的 蜂鸣器 0|1 声调不对
#    M300 S440 P200
#    M300 S660 P250
#    M300 S880 P300

# M300 : Play tone. Beeper support, as commonly found on usual LCD
# displays (i.e. RepRapDiscount 2004 Smart Controller, RepRapDiscount
# 12864 Full Graphic). This defines a custom I/O pin and a custom
# GCODE macro.Usage:
#   M300
#   P is the tone duration, S the tone frequency.
# The frequency won't be pitch perfect.


pin: EXP1_1
pwm: True
value: 0
shutdown_value: 0
cycle_time: 0.001
#   Default PWM frequency : 0.001 = 1ms will give a tone of 1kHz


description: Add a tone to the tone queue.
gcode:
    # Use a default 1kHz tone if S is omitted.
    {% set S = params.S|default(1000)|int %}
    # Use a 10ms duration is P is omitted.
    {% set P = params.P|default(100)|int %}
    SET_PIN PIN=BEEPER_pin VALUE=0.5 CYCLE_TIME={ 1.0/S if S > 0 else 1 }
    G4 P{P}
    SET_PIN PIN=BEEPER_pin VALUE=0
   

type: disabled
```

以上重启固件屏幕就可以看到了

!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/20220908170145.png)

TFT35 触摸和兼容模式,[相关信息](https://hub.0z.gs/Klipper3d/klipper/pull/3979):

!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/20220909123323.png)

添加相关菜单:

```yaml
# menu.cfg
### 此处控制的为 fan_generic,名称为two_wire_fan
## 风扇启停控制

type: input
enable: {"fan_generic two_wire_fan" in printer} # True|False,Jinja2 表达式用 {}
index: 1 # 显示位置顺序
name: Fan: {'ON ' if menu.input else 'OFF'} # menu.input 为输入值
input: {printer["fan_generic two_wire_fan"].speed|int} # menu.input 默认值
input_min: 0
input_max: 1
input_step: 1
gcode:
    SET_FAN_SPEED FAN=two_wire_fan SPEED={menu.input}

## 风扇调速控制

type: input
enable: {"fan_generic two_wire_fan" in printer} # 注意对象名称
index: 2
name: Fan speed: {'%3d' % (menu.input*100)}% # jinja2 格式化
input: {printer["fan_generic two_wire_fan"].speed} # 和上面不同,不是 int 而是 float
input_min: 0
input_max: 1
input_step: 0.01
gcode:
    SET_FAN_SPEED FAN=two_wire_fan SPEED={menu.input}
```

!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/20220908170217.png)

* 本来想着清空 (https://hub.0z.gs/Klipper3d/klipper/blob/master/klippy/extras/display/menu.cfg),只保留风扇控制功能,但是这东西启动 Klipper 会自动生成,后续再研究研究
* [首页显示转速和风速](https://www.klipper3d.org/Config_Reference.html#display_data)
* [屏幕菜单创建](https://www.klipper3d.org/Command_Templates.html#menu-templates)

#### 4.2.2 电位器控制转速【难点】

我们设想通过调节电位器的值来控制风扇转速,我们查看文档,读取引脚模拟输入量有一个函数:[`QUERY_ADC`](https://www.klipper3d.org/G-Codes.html?h=query_a#query_adc),找了下 Klipper 发现有两个对象会用到 adc 值:按钮 (gcode_button) 和 温度传感器,其中最简单的方法就是使用温敏引脚。

**`QUERY_ADC` 命令用法及返回值:**
```yaml
QUERY_ADC : Report the last analog value received for a configured analog pin. If NAME is not provided, the list of available adc names are reported. If PULLUP is provided (as a value in Ohms), the raw analog value along with the equivalent resistance given that pullup is reported.
# 返回值,可见 ADC 值约 0-1
QUERY_ADC NAME="temperature_sensor rotation_sensor"
// ADC object "temperature_sensor rotation_sensor" has value 0.213919 (timestamp 310.750)
// ADC object "temperature_sensor rotation_sensor" has value 0.002991 (timestamp 346.750)
// ADC object "temperature_sensor rotation_sensor" has value 1.000000 (timestamp 372.250)
```

**模拟值按钮示例:**
```yaml
#
# pin: PC2
# analog_range: 0, 8700
# analog_pullup_resistor: 4700
# press_gcode:
```
模拟按钮的问题是无法获取调用对象属性值,`QUERY_ADC` 作为一个 gcode 命令,通过 (https://www.klipper3d.org/API_Server.html#gcodescript) 只有返回值,有可能使用,有空研究。

**温度传感器方式示例:**
温敏电阻也是一个可变电阻,所以我们把可调电位器接上去用。一般 TH 和 TB 都是可用模拟输入引脚(上拉 4700 欧姆电阻),其他模拟输入引脚见后文。

!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/202209031656472.png)

接线方式:GND 接地,Signal 信号脚接温敏信号脚,VCC 空置。

```yaml
## 定义一个“温度传感器”,连接电位器

sensor_pin: PA0 # TH0,4k7上拉电阻
# sensor_type: potentiometer
sensor_type:Generic 3950 # 随便选,不行,不是线性曲线
pullup_resistor: 4700 # 查看原理图,默认4700欧姆
# min_temp: -270
# max_temp: 999999999


initial_duration: 5. # Klipper Ready 后 5s 自动启动脚本
gcode:
    {% set CURRENT = printer["temperature_sensor rotation_sensor"].temperature|float %}
    {% set LAST = printer["gcode_macro _fan_state"].last_temp|float %} # 需要先在之前的宏里初始化
    {% set DIFF = (CURRENT-OLD)|abs %} # 取差值的绝对值
    {% if DIFF > 5 %} # 选择合适的差值
      {% set SPEED = (CURRENT-90)/460 %} # 最小值和最大值
      M118 TRIGGERED!
      SET_FAN_SPEED FAN=two_wire_fan SPEED={SPEED}
    {% endif %}
   
    {% if printer["temperature_sensor rotation_sensor"].temperature %} # 随便选个真值
      {% set LAST = CURRENT %}
      SET_GCODE_VARIABLE MACRO=_fan_state VARIABLE=last_temp value={LAST}
      UPDATE_DELAYED_GCODE ID=set_fan_speed DURATION=4 # 延时 4s
    {% endif %}

## 手动启动脚本
#
#gcode:
#    UPDATE_DELAYED_GCODE ID=set_fan DURATION=1
```
**说明:**
* jinja2 表达式默认的 `for` 循环一般用于遍历,这里使用 `if` 自调用实现循环定时任务
* jinja2 {} 内部不需要再 {}
* 由于存在读值漂移且不想让电位器没有调整阻值也重复或者微小调速,使用之前的宏变量来对比当前温度和上次查询温度,如果超出预设值才设置新转速。
* 需要手动拧电位器至最大、最小阻值,记下对应值,算出量程。
* 由于有正向和反向拧动,前后温度差值需要取绝对值,用到 (https://jinja.palletsprojects.com/en/2.10.x/templates/#abs)

**获取温度传感器对象的属性值:**
```yaml
# 查看打印机对象列表
http://c3pbox.local/printer/objects/list

# 查看某一对象属性
http://c3pbox.local/printer/objects/query?temperature_sensor%20rotation_sensor

# 查看某一对象某属性值
http://c3pbox.local/printer/objects/query?temperature_sensor%20rotation_sensor=temperature
```

返回对象属性值如下:

```json
// 20220907154217
// http://c3pbox.local/printer/objects/query?temperature_sensor%20rotation_sensor

{
"result": {
    "eventtime": 20231.241420938,
    "status": {
      "temperature_sensor rotation_sensor": {
      "temperature": -109.28,
      "measured_min_temp": -109.28,
      "measured_max_temp": 498.31
      }
    }
}
}
```

#### 4.2.3 进阶电位器设置
上述方案有几个问题:
* 显示的温度和 0-100 转速范围不是完全对应
* 温敏电阻曲线不是线性的,导致如果电位器随便使用一个温敏型号,其调速也不是线性的

!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/20220908192409.png)

Source:(http://www.thermistors.cn/news/287.html)
所以我们可以自己定义一个 `adc_temperature`,建立阻值与温度之间的线性关系。此电位器实测最大电阻 8500Ω,测试时有问题,会报错 (https://github.com/Klipper3d/klipper/blob/0b918b357cb0c282d53cbdf59e1931a2054cd60a/src/adccmds.c)。
```yaml
#
# # 要先定义再用
# temperature1: 0
# resistance1: 8k5
# temperature2: 100
# resistance2: 0
```



## 5、使用示波器探究 PWM 风扇

| 信号电压 | 占空比 | 转速 rpm | 占空比 | 转速rpm |
| -------- | ------ | -------- | ------ | ------- |
| 3.3v   | 50%    | ~4900    | 100%   | 8817    |
| 5v       | 50%    | ~4900    | 100%   | 8817    |



* PWM 信号为 5V,与 VCC 无关

* 3.3v 和 5v pwm 信号调节转速效果相同
* 风扇调速通过调节占空比,实现
* pwm 方波频率不合适时,风扇不转
* 无 pwm 信号输入时,风扇设置为全速
* 不同风扇引脚顺序不一定相同

!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/20220908190730.png)
【不同频率不同占空比】我的调速风扇采用 25kHz 方波时无法启动,100Hz 时正常(调节 cycle_time 参数)。Klipper 调节转速其实是改变 pwm 的占空比

!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/20220908190831.png)
【tacho 测速引脚】此引脚有电压输出,波形为方波,通过频率来代表不同的转速,信号电压 ~3.3v,即使 PWM 信号为 5V时。


## 6、STM32G081 可用引脚一览
* 最近的更新增加了对 STM32G0 芯片的硬件 PWM 引脚支持
(https://github.com/Klipper3d/klipper/commit/b220b8bfaf9f54989286f6be373064a768ae28ae)
* 测试过程中不适用步进电机和限位开关引脚,剩余引脚如下:
!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/202209031647845.png)

我做了一个表格方便快速选择各个引脚。

!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/20220909123509.png)


Reference:

* (https://www.amobbs.com/thread-5528381-1-1.html) | 3.3v 可以用来驱动 PWM 引脚。调整峰峰值验证。
* [四线直流风扇PWM调速探研](https://blog.csdn.net/u012388993/article/details/78691510)
* [电脑CPU散热器4线风扇转速控制的探讨](http://www.crystalradio.cn/thread-974992-1-1.html)
* (https://www.elecfans.com/analog/20171028571721.html)
* [自制PWM风扇控制器 & 自制电脑4PIN风扇调速器](https://www.cnblogs.com/DLHC-TECH/p/PWM_FAN_CONTROLLER_T-D-P15.html)

## 7、关于等效电压的思考与探讨

测试过程中,PWM 调速风扇电压为 12V,而 Manta 主板采用 24V 供电时,风扇无12V 输出。
那么有没有一种可能,使用 `max_power` 参数,设置最大输出为 24*0.5 也就是 12V?
!(https://raw.fastgit.org/sjqlwy/blog_imgs/default/images/20220908191430.png)

**使用示波器测试发现:**
* 平均电压降到 12V,使用万用表测试也是如此
* 但是峰值电压仍然为24V,通过调节占空比实现的

**思考:**

1. 方波信号输出的并不是恒压电,能否用最大电压来判断是否会导致电子元件损坏?就比如 220V 交流电峰值电压约 311V
2. 电子元件损坏的原因是什么?电流过大,发热过高烧坏击穿?焦耳定律
3. 风扇、加热器等电阻器件应该不怕峰值电压,只看有效电压,本质是热传导?
4. 集成电路怕峰值电压,高压击穿,类似高压静电那种?
5. 由于专业知识缺乏,欢迎赐教

## 8、番外
最小配置文件添加测试电机:
```yaml
# 如果使用 TMC 驱动,务必先定义

uart_pin: MOT0_UART
interpolate: False
run_current: 0.7
# hold_current: 0.5
# stealthchop_threshold: 999999


step_pin:   MOT0_STEP
dir_pin:    !MOT0_DIR   # X轴电机方向引脚设置,可以通过添或删除引脚前面的!来改变电机方向
enable_pin: !MOT0_EN
microsteps: 16
rotation_distance: 40
velocity: 5
accel: 0
# endstop_pin: tmc2209_test_stepper:virtual_endstop

## 调用方式
# MANUAL_STEPPER STEPPER=test_stepper SET_POSITION=0 SPEED=20 ACCEL=0 MOVE=80 STOP_ON_ENDSTOP=1
# https://www.klipper3d.org/G-Codes.html#manual_stepper
# https://github.com/Klipper3d/klipper/issues/3677
```

* 使用 MQTT 协议实现手机控制电风扇
* 使用 `直流控交流固态继电器` 实现大型立式电风扇
页: [1]
查看完整版本: 跟着思兼学习Klipper(17) 基于Klipper的Manta M4P牌夏日降温电风扇