嵌入式硬件开发物联网工业制造【免费下载链接】Grbl_Esp32A port of Grbl CNC Firmware for ESP32项目地址https://gitcode.com/gh_mirrors/gr/Grbl_Esp32点击查看免费下载本文以 Grbl_Esp32 仓库中的 User I/O 说明文档 为主线系统讲解如何通过 M62–M65数字输出开关与 M67–M68PWM 模拟输出在 G 代码中控制冷却风扇、夹具、电磁阀等外设并结合 UserOutput.cpp、GCode.cpp 等源码说明“同步/立即”语义、PWM 分辨率计算与引脚配置的底层实现帮助你在 ESP32 CNC 系统中直接用 G 代码完成通用 I/O 控制。一、User I/O 是什么用 G 代码替代专用代码Grbl_Esp32 提供了一套通用 I/O 控制机制User I/O目标是让外设控制直接写进 G 代码而不是依赖特殊编码或外部程序。典型应用包括冷却风扇的启停数字量 on/off工件夹持clamp开关电磁阀valve控制需要模拟量PWM调压/调位的器件如 RC 舵机、可变比例阀等原文档将其分为两种类型Digital I/O数字 I/O只有开/关两个状态由 M62–M65 控制Analog (PWM)模拟 I/O输出 PWM 占空比由 M67/M68 控制。二、命令速查M62–M65 数字输出、M67–M68 模拟输出2.1 数字输出控制M62–M65命令含义M62Synchronized Digital Output On同步置位数字输出为开M63Synchronized Digital Output Off同步置位数字输出为关M64Immediate Digital Output On立即置位为开M65Immediate Digital Output Off立即置位为关使用P 字指定数字输出编号0–3例如M62 P0 ; 同步打开数字输出 0 M63 P0 ; 同步关闭数字输出 0在源码中P 字是数字类命令的必需词GCode.cpp 在参数校验阶段对 M62–M65 检查 P 字是否存在缺失则报GcodeValueWordMissing错误执行阶段要求p MaxUserDigitalPin常量定义为 4见 GCode.h 中static const int MaxUserDigitalPin 4;否则报PParamMaxExceeded。因此P 取值范围是 0、1、2、3写成 P4 及以后会报错。2.2 模拟输出控制M67–M68命令含义M67Synchronized Set Analog Value同步设置模拟量值M68Immediate Set Analog Value立即设置模拟量值使用E 字指定模拟输出编号0–3使用Q 字指定占空比百分数percent duty浮点数。原文档示例M67 E1 Q23.87 ; 将模拟输出 1 设置为 23.87% 占空比 M67 E1 Q0 ; 将占空比设为 0%等效于关闭该引脚与数字命令类似源码要求 E、Q 两个字必须同时出现见 GCode.cpp 中对SetAnalogSync/SetAnalogImmediate的校验分支且执行前 Q 值会被强制钳制到 0–100 范围constrain(gc_block.values.q, 0.0, 100.0)——这与原文档“超过 100% 按 100% 处理负数按 0% 处理”的说明完全一致。E 值超出 0–3 同样报PParamMaxExceeded。2.3 模态组归属从源码结构看M62–M68 被划入独立的模态组MM10 15GCode.h 中注释[M62, M63, M64, M65, M67, M68] User Defined解析时映射到IoControl枚举DigitalOnSync/DigitalOffSync/DigitalOnImmediate/DigitalOffImmediate/SetAnalogSync/SetAnalogImmediate。这意味着同一条 G 代码块中不能出现两个 I/O 命令会触发GcodeModalGroupViolation。三、引脚编号规则原文档Pin Numbering一节规定每个引脚都被赋予一个从 0 开始的编号数字与模拟的编号相互独立。如果各用一路它们都应该是 0。对应源码System.cpp 中维护两个独立数组myDigitalOutputs[4]与myAnalogOutputs[4]sys_set_digital(io_num, ...)与sys_set_analog(io_num, ...)分别按各自编号寻址。因此M62 P0与M67 E0指向的是两块不同的物理引脚。四、Synchronized同步与 Immediate立即的语义这是原文档中最重要的使用原则Synchronized表示缓冲区中所有步骤必须完成后才改变 I/O 状态Immediate不等待。流式发送 G 代码时应使用同步命令。立即版本没有任何时序保证。源码中的实现印证了这一点在执行 I/O 动作前同步版本会先调用protocol_buffer_synchronize()排空接收缓冲与运动缓冲立即版本直接置位GCode.cpp 中 M62/M67 分支。可以推断如果你在高速加工、流式下发 G 代码的途中使用 M64/M68 立即命令引脚翻转的时刻与你预想的坐标位置之间没有任何保证而 M62/M67 会等前面排队的运动块走完再动作从而保证“在某个精确加工位置之后切换夹具”这类时序需求。五、特殊状态下的引脚行为原文档Special Behaviors一节列出Power On上电——所有引脚置为 off 状态Reset复位——所有引脚置为 off 状态Alarm Mode报警模式——引脚状态不变Error错误——引脚状态不变End of File文件结束——引脚状态不变源码层面可以逐项验证上电UserOutput.cpp 中DigitalOutput::init()执行digitalWrite(_pin, LOW)AnalogOutput::init()执行ledcWrite(_pwm_channel, 0)即两类输出上电后均为关闭态。复位MotionControl.cpp 的mc_reset()中依次调用sys_digital_all_off()与sys_analog_all_off()System.cpp 中遍历 4 路输出全部置低/清零与原文档一致。报警/错误/文件结束从源码结构看这些状态切换路径均不会调用上述置位函数引脚保持最后状态与文档描述吻合。另外每个已定义的输出在初始化时会通过串口打印一条配置信息例如User Digital Output:0 on Pin:GPIO_NUM_25、User Analog Output:1 on Pin:GPIO_NUM_15 Freq:50Hz方便调试时确认引脚映射是否正确。六、Setup在机器头文件中定义引脚原文档给出的配置模板如下在机器定义头文件中添加#define USER_DIGITAL_PIN_0 GPIO_NUM_xx #define USER_DIGITAL_PIN_1 GPIO_NUM_xx #define USER_DIGITAL_PIN_2 GPIO_NUM_xx #define USER_DIGITAL_PIN_3 GPIO_NUM_xx #define USER_ANALOG_PIN_0 GPIO_NUM_xx #define USER_ANALOG_PIN_1 GPIO_NUM_xx #define USER_ANALOG_PIN_2 GPIO_NUM_xx #define USER_ANALOG_PIN_3 GPIO_NUM_xx #define USER_ANALOG_PIN_1_FREQ 50 // Hz实际仓库中有多个现成示例tapster_pro_6P_trinamic.h定义 4 路数字输出GPIO 26/4/16/27与 4 路模拟输出GPIO 14/13/15/12全部*_FREQ 50注释明确标注for use with RC servos正好是原文档“舵机应用”一节的落地配置tapster_3.h数字输出 GPIO 25/26/27模拟输出 GPIO 2/15/16频率 50Hz注释为duty range 5% to 10%Root_Controller_Root_4_Lite_RS485.h展示数字输出也可以接到 I2S 输出引脚如I2SO(17)。几点关键细节全部 8 路引脚都是可选的。Defaults.h 中若未定义USER_DIGITAL_PIN_x/USER_ANALOG_PIN_x会回退为UNDEFINED_PIN。从源码结构看未定义的引脚不会占用 GPIO对未定义的引脚执行置位命令时set_level()会返回失败并触发错误路径因此只应使用自己定义过的引脚编号。系统初始化时机System.cpp 在系统 setup 阶段注释// Setup M62,M63,M64,M65 pins/// Setup M67 Pins逐个构造DigitalOutput与AnalogOutput对象此时即完成 GPIO 模式设置、LEDC 通道配置与上电默认关闭。PWM 通道分配限制ESP32 的 LEDC 为 8 个通道共享 4 组定时器。System.cpp 中sys_get_next_PWM_chan_num()的注释说明通道对0/1、2/3 等必须同频率主轴始终占用通道 0因此用户 PWM 从通道 2 开始分配若通道耗尽会打印Error: out of PWM channels。这意味着模拟输出并非可以无限多路混用不同频率同一定时器对内的频率需保持一致使用时应注意这一点。七、Frequency 与 ResolutionPWM 分辨率是怎么算的原文档说明频率是可选的某个引脚不定义*_FREQ时默认使用 5000HzDefaults.h 中USER_ANALOG_PIN_x_FREQ的#ifndef回退值均为 5000。分辨率取决于频率PWM 基于 80MHz 定时器。以 10kHz 为例80,000,000 / 10,000 8000 计数按 2 的幂向下取整得到 12 bit即 4096 级分辨率原文档给出的最高位宽为 13 bits。UserOutput.cpp 的构造函数正是这套逻辑的实现读取 APB 频率getApbFrequency()从 0 bit 开始递增_resolution_bits直到1 _resolution_bits超过APB 频率 / PWM 频率再减 1最终得到“不超过频率预算的最大位宽”。以默认 5000Hz 为例80MHz/5000Hz 160002^13 8192 满足而 2^14 16384 超出故得到 13 bit 分辨率——与原文档“最高 13 bits”的常见场景一致源码中循环上限放宽到 16 bit更低频率时可得到更高位宽。原文档强调这一切都在幕后完成你只需要提供频率和占空比。设置值最终通过denominator()即1 _resolution_bits把百分数换算成 LEDC 计数值见 System.cpp 中sys_set_analog()的percent / 100.0 * analog-denominator()再经ledcWrite()写入硬件。八、Duty占空比与脉冲宽度的换算原文档Duty一节的要点占空比是周期period的百分比周期 1/freqQ 是浮点数写成XX.XX形式可获得最高分辨率超过 100% 的值按 100% 处理负数按 0% 处理。原文档给出的换算示例若频率 100Hz周期即 10ms想得到 1ms 的脉冲占空比应为 0.10ms/10ms 0.1%注意1ms/10ms 实际为 10%原文示例写作 0.10%此处按原文档原文保留。九、配合 RC 舵机使用RC Servos原文档Use With RC Servos一节给出了完整的工程经验RC 舵机依靠 PWM 脉冲长度定位。标准频率是 50Hz部分数字舵机可承受更高采样率但对该应用不会提升性能反而可能让部分舵机过热。标准脉冲范围是 1ms 到 2ms部分舵机范围更宽。50Hz 时周期为 20ms因此1ms 脉冲 5% 占空比行程一端2ms 脉冲 10% 占空比行程另一端中间值对应中间位置若舵机行程更宽可尝试略小于 5% 或略大于 10% 的值。占空比设为 0% 通常会让舵机断电自由转动几乎不耗电。把这套知识写进 G 代码例如 50Hz 下让输出 0 的舵机从行程一端扫到另一端M68 E0 Q5.0 ; 1ms 脉冲行程一端 M68 E0 Q7.5 ; 1.5ms 脉冲中位 M68 E0 Q10.0 ; 2ms 脉冲行程另一端 M68 E0 Q0.0 ; 断电自由状态仓库中的 tapster_pro_6P_trinamic.h 即为该用法的真实配置4 路 50Hz 模拟输出注释指向 RC 舵机模块。十、测试脚本tests/user_io.nc仓库自带一个可直接流式发送的 I/O 测试文件 tests/user_io.nc完整演示了两类命令的用法值得参考(MSG, Starting User I/O tests) M62 P0 ; 依次打开数字输出 0..3每个间隔 0.5s 便于观察 G4 P0.5 M62 P1 G4 P0.5 M62 P2 G4 P0.5 M62 P3 G4 P2 M63 P0 ; 再依次关闭 M63 P1 M63 P2 M63 P3 G4P1 M67 E0 Q10 ; 两路模拟输出以 10% 步进做对向渐变直到 90% M67 E1 Q100 G4 P0.25 M67 E0 Q20 M67 E1 Q90 ; ...中间省略按原文档测试脚本逐步变化... M67 E0 Q0 ; 最后归零关闭 M67 E1 Q0 G4 P0.25该脚本的特点是数字部分配合G4驻留便于肉眼确认开关时序模拟部分用 E0/E1 两路以互补的占空比序列10→90 与 100→10做渐变测试最后统一Q0关闭。如果你的机器头文件已经定义了输出引脚可以直接用它冒烟测试整套 M62–M68 功能链。十一、使用要点小结事项说明依据数字输出编号P 字0–3缺失或越界报错原文档 GCode.cpp模拟输出编号E 字0–3E、Q 必须同时提供原文档 GCode.cpp占空比范围Q 为百分数浮点自动钳制到 0–100原文档 源码constrain流式加工中优先使用 M62/M63/M67 同步命令原文档 Synchronized 一节上电/复位全部输出强制关闭原文档 mc_reset()、init()报警/错误输出状态保持不变原文档 Special Behaviors频率默认值未定义*_FREQ时为 5000HzDefaults.h舵机配置50Hz5%–10% 对应 1–2ms 脉冲0% 断电原文档 RC Servos 一节掌握以上内容后你就可以在 Grbl_Esp32 中仅凭 G 代码与机器头文件中的引脚宏定义完成从继电器开关到舵机调位的完整通用 I/O 控制无需任何额外编程。赞分享嵌入式硬件开发物联网工业制造【免费下载链接】Grbl_Esp32A port of Grbl CNC Firmware for ESP32项目地址https://gitcode.com/gh_mirrors/gr/Grbl_Esp32点击查看免费下载相关推荐FluidNC 用户 I/O 输出控制全指南M62–M65/M67–M68 数字与 PWM 命令、配置与源码实现FluidNC 用户 I/O 输出控制全指南M62–M65/M67–M68 数字与 PWM 命令、配置与源码实现 本文是 FluidNC 运动控制固件中用户嵌入式固件硬件开发智能硬件ESP-IDF 标准输入输出Standard I/O与 Console 输出配置完全指南ESP IDF 标准输入输出Standard I/O与 Console 输出配置完全指南 导读 本文基于 ESP IDF 官方文档 docs/en/api物联网嵌入式ESP-IDF 标准 I/O 与控制台输出stdin/stdout/stderr 的 VFS 实现、配置与阻塞 I/O 控制ESP IDF 标准 I/O 与控制台输出stdin/stdout/stderr 的 VFS 实现、配置与阻塞 I/O 控制 本文以 ESP IDF 的《标准物联网嵌入式创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考