- PlsrHwStartPwmTimer 补配 CCMR1.OC1M=PWM模式1:裸定时器复位为冻结模式, 通道输出恒定电平(上板实测 PF6 无方波,仅一段 672ms 恒高) - ARR/CCR 使能预装载(ARPE/OC1PE)+ 启动时 EGR.UG 加载影子寄存器: 运行中调频不再因 CNT 超调提前回绕,加速段多余脉冲消除(7517→7500) - 方向延时仅在方向变化时生效(首次/换向/换方向点), 段间同向衔接由 14.9ms 缩短至 ~2ms - 上电自测扩展为 3 段(2000Hz/1000 脉冲、5000Hz/6000、1000Hz/500), 上电延时 1s 后启动,顺带验证段间跳转 - 新增波形分析脚本(破译 16bit/CH0/100MS/s 导出格式 + 时频曲线拟合), 实测三段总脉冲 7500,与理论完全一致 已知遗留(不影响脉冲计数与位置精度,留待 P4 上板调试): - 段尾 profile DONE 后冻结频率收尾(段3 尾部 150Hz 平台 38 脉冲) - 段首第一周期被压缩(首脉冲占空比异常)deepseek
| @@ -200,9 +200,9 @@ int main(void) | |||
| Error_Handler(); | |||
| } | |||
| /* 上电自测:Q0 发一段测试脉冲(验证后删除)。 */ | |||
| /* 上电自测:延时 1s 待电源/外设稳定后,Q0 发一段测试脉冲(验证后删除)。 */ | |||
| HAL_Delay(1000U); | |||
| (void)PlsrSelfTestQueue(); | |||
| OSStart(); | |||
| /* USER CODE END 2 */ | |||
| @@ -0,0 +1,826 @@ | |||
| ===== PDF page 162 ===== | |||
| 1.脉冲输出 XD/XL系列可编程控制器用户手册[定位控制篇] | |||
| 152 | |||
| 1-4.输出端子接线及注意事项 | |||
| Y0 | |||
| COM0 | |||
| Y1 | |||
| COM1 | |||
| Y2 | |||
| COM2 | |||
| 下面是 T 型输出端子与步进电机驱动器的接线示意图: | |||
| PLC侧 步进电机驱动侧 | |||
| Y0 | |||
| PU | |||
| PU | |||
| Y1 | |||
| 【注】:如果步进电机脉冲和方向端子是 DC5V驱动,请在脉冲输出端子和方向输出端子后接2.2K电阻。 | |||
| 下面是 T 型输出端子与信捷伺服电机驱动器的接线示意图: | |||
| 【注】 :请将 P+5V和 D+5V悬空。 | |||
| 下面是差分型输出端子与伺服驱动器的接线示意图: | |||
| 详细的硬件接线图请参考《XD/XL系列可编程控制器用户手册【硬件篇】 》 。 | |||
| COM0 | |||
| Y0 | |||
| +24V | |||
| P- | |||
| R=3.3K | |||
| COM1 | |||
| Y1 D- | |||
| R=3.3K | |||
| P+5V | |||
| D+5V | |||
| 屏蔽层0V | |||
| D+24V | |||
| P+24V | |||
| Y0+ | |||
| 双绞线 | |||
| Y0- | |||
| COM | |||
| Y1+ | |||
| Y1- | |||
| A+ | |||
| A- | |||
| FG | |||
| B+ | |||
| B- | |||
| Y0 | |||
| Y1 | |||
| PLC侧-差分输出端 负载端 | |||
| X0+ | |||
| X0- | |||
| COM | |||
| X1+ | |||
| X1- | |||
| 双绞线 | |||
| A+ | |||
| A- | |||
| FG | |||
| B+ | |||
| B- | |||
| 编码器端 | |||
| A | |||
| B | |||
| PLC侧-差分输入端 | |||
| X0+ | |||
| X0- | |||
| X1+ | |||
| X1- | |||
| PLC侧-差分输入端 | |||
| + | |||
| -5VDC | |||
| NPN型 | |||
| PNP型 | |||
| X0+ | |||
| X0- | |||
| X1+ | |||
| X1- | |||
| PLC侧-差分输入端 | |||
| NPN型 | |||
| PNP型 | |||
| 3KΩ/0.5W | |||
| 3KΩ/0.5W | |||
| NPN传感器 | |||
| PNP传感器 | |||
| + | |||
| -24VDC | |||
| NPN传感器 | |||
| PNP传感器 | |||
| 输出端口 Y0:脉冲输出口 1(单相) | |||
| 输出端口 Y1:脉冲输出口 2(单相) | |||
| ===== PDF page 163 ===== | |||
| XD/XL系列可编程控制器用户手册[定位控制篇] 1.脉冲输出 | |||
| 153 | |||
| 1-4-1.连接设备的构成 | |||
| 1)XD系列T型输出PLC | |||
| 晶体管输出 | |||
| ※:可控制 2~10 轴伺服电机或者步进电机。 | |||
| 2)XL系列T型输出PLC | |||
| 晶体管输出 | |||
| ※:可控制 2~10 轴伺服电机或者步进电机。 | |||
| 伺服电机或者 | |||
| 步进电机 | |||
| 伺服电机或者 | |||
| 步进电机 | |||
| ===== PDF page 164 ===== | |||
| 1.脉冲输出 XD/XL系列可编程控制器用户手册[定位控制篇] | |||
| 154 | |||
| 1-4-2.脉冲输出性能规格 | |||
| 脉冲输出性能规格如下表所示: | |||
| 机型 T、RT | |||
| 型 T4 型 T6型 T10 型 D4T4型 D2T2型 XDH XLH | |||
| 控制轴数 独立 | |||
| 2 轴 | |||
| 独立 | |||
| 4轴 | |||
| 独立 | |||
| 6 轴 | |||
| 独立 | |||
| 10轴 | |||
| 独立 | |||
| 8 轴 | |||
| 独立 | |||
| 4 轴 | |||
| 独立 | |||
| 4 轴 | |||
| 独立 | |||
| 4 轴 | |||
| 插补功能 不支持 | |||
| 仅 | |||
| XDM/XDME | |||
| /XLME 支持 | |||
| 不支持 | |||
| 仅 | |||
| XDM/XDME | |||
| /XLME 支持 | |||
| 不支持 支持 | |||
| 输出方式 OC OC、差分 OC | |||
| 输出形式 脉冲+方向 | |||
| 最大频率 100KHz OC:100KHz | |||
| 差分:920KHz 100KHz | |||
| 加减速处理 直线加减速+S型曲线加减速+正弦曲线加减速 | |||
| 控制单位 脉冲、1mm、0.1mm、0.01mm、1um | |||
| 定位范围 -2147483648~2147483647(脉冲) | |||
| 编程语言 梯形图 | |||
| 手脉连接 不支持 | |||
| 仅 | |||
| XDM/XDME | |||
| /XLME 支持 | |||
| 不支持 | |||
| 仅 | |||
| XDM/XDME | |||
| /XLME 支持 | |||
| 不支持 支持 | |||
| 【注】 : | |||
| (1)所有 XD/XL系列 PLC的脉冲输出必须为晶体管或差分输出类型,否则无法发送脉冲! | |||
| (2)PLC 可以输出 100KHz~200KHz的高速脉冲(XD3-24T4/32T4 的 Y2、Y3 为 10KHz),但不能保证 | |||
| 所有伺服都正常运行,请在输出端和 24V电源之间接入约 500Ω电阻,电阻功率需>2W。 | |||
| 1-4-3.定位控制接线以及布线注意事项 | |||
| >>>>> 设计注意事项 <<<<< | |||
| 危险! | |||
| 请在可编程控制器的外部设置安全回路,以便在出现外部电源异常、可编程控制器故障等情况 | |||
| 时,也能确保整个系统在安全状态下运行。误动作、误输出有可能会导致事故发生。 | |||
| 1. 请务必在可编程控制器的外部设置紧急停止回路、保护回路、防止正反转等相反动作同时进行的互 | |||
| 锁回路、定位上下限等防止机械破损的互锁回路等。 | |||
| 2. 当可编程控制器 CPU 通过看门狗定时器出错等的自诊断功能检测出异常时,所有的输出变为OFF。 | |||
| 此外,当发生了可编程控制器 CPU 不能检测出的输入输出控制部分等的异常时,输出控制有时候会 | |||
| 失效。 | |||
| 此时,请设计外部回路以及结构,以确保机械在安全状态下运行。 | |||
| 3. 由于输出单元的继电器、晶体管、晶闸管等的故障,有时候会导致输出一直接通,或是一直断开。 | |||
| 为了确保机械在安全状态下运行,请为可能导致重大事故的输出信号设计外部回路以及结构。 | |||
| 注意! | |||
| 1. 控制线请勿与主回路或动力线等捆在一起接线,或是靠近接线。 | |||
| ===== PDF page 165 ===== | |||
| XD/XL系列可编程控制器用户手册[定位控制篇] 1.脉冲输出 | |||
| 155 | |||
| 原则上请离开100mm以上或者远离主回路。否则会因噪音引起误动作。 | |||
| 2. 使用时,请确保内置编程接口、电源连接器、输入输出连接器不受外力。 | |||
| 否则会导致断线以及故障。 | |||
| >>>>> 接线注意事项 <<<<< | |||
| 危险! | |||
| 1. 进行安装、接线等作业时, 请务必在外部将所有电源均断开后方可进行操作。 | |||
| 否则有触电、产品损坏的危险。 | |||
| 2. 在安装、接线等作业后执行上电运行时,请务必在产品上安装附带的接线端子盖板。 | |||
| 否则有触电的危险性。 | |||
| 注意! | |||
| 1. AC 电源的配线请与基本单元手册记载的专用端子连接。 | |||
| 如果将AC电源连接到直流的输出输入端子及DC电源端子,可编程控制器将被烧毁。 | |||
| 2. DC 电源的配线请与基本单元手册记载的专用端子连接。 | |||
| 如果将AC电源连接到直流的输出输入端子及DC电源端子,可编程控制器将被烧毁。 | |||
| 3. 请不要在外部对空端子进行配线。 | |||
| 有可能会损坏产品。 | |||
| 4. XD/XL 系列基本单元的接地端子请使用2mm | |||
| 2 | |||
| 以上的电线进行D种接地(接地电阻:100Ω以下)。 | |||
| 但是,请勿与强电流共同接地(参照XD/XL系列可编程控制器用户手册【硬件篇】)。 | |||
| 5. 在进行螺栓孔加工及配线作业时, 请不要将切屑及电线屑落入可编程控制器的通风孔内。 | |||
| 否则有可能导致火灾、故障及误动作。 | |||
| 6. 使用时,请确保输入输出连接器不受外力。 | |||
| 否则会导致断线以及故障。 | |||
| 7. 输入输出电缆请牢固地安装在所规定的连接器上。 | |||
| 接触不良会导致误动作。 | |||
| 8. 对 XD/XL 系列基本单元以及XD/XL 系列扩展设备的端子排型产品进行接线时,请遵照以下的注意事 | |||
| 项操作。 | |||
| 否则有可能导致触电、故障、短路、断线、误动作、损坏产品。 | |||
| --请依据手册中记载的尺寸对电线的末端进行处理。 | |||
| --紧固扭矩请依照手册中记载的扭矩。 | |||
| >>>>> 启动维护保养时的注意事项 <<<<< | |||
| 危险! | |||
| 1. 在通电时请勿触碰到端子。 | |||
| 否则有触电的危险性,并且有可能引起误动作。 | |||
| 2. 进行清扫以及拧紧接线端子时,请务必在断开所有外部电源后方可操作。 | |||
| 如果在通电的状态下进行操作,则有触电的危险。 | |||
| 3. 要在运行过程中更改程序、执行强制输出、RUN、STOP等操作前,请务必先熟读手册,在充分确认安 | |||
| 全的情况下方可进行操作。 | |||
| 操作错误有可能导致机械破损及事故发生。 | |||
| ===== PDF page 166 ===== | |||
| 1.脉冲输出 XD/XL系列可编程控制器用户手册[定位控制篇] | |||
| 156 | |||
| 注意! | |||
| 1. 请勿擅自拆解、改动产品。 | |||
| 否则有可能引起故障、误动作、火灾。 | |||
| 2. 对扩展电缆等连接电缆进行拆装时请在断开电源之后再进行操作。 | |||
| 否则有可能引起故障、误动作。 | |||
| 3. 在对以下的设备进行拆装时请务必将电源切断。 | |||
| 否则有可能引起故障、误动作。 | |||
| --外围设备、扩展功能板、特殊适配器、 | |||
| --输入输出扩展模块、网络模块等。 | |||
| 1-4-4.伺服放大器(驱动单元)侧的设定 | |||
| 1)可编程控制器侧的脉冲输出形式 | |||
| XD/XL系列 PLC的脉冲输出类型全部为集电极开路信号(脉冲+方向) ,如下图所示: | |||
| 脉冲输出端口Y0 | |||
| 任意的输出Y□ | |||
| (指定旋转方向) | |||
| 脉冲输出端口Y1 | |||
| 任意的输出Y□ | |||
| (指定旋转方向) | |||
| H | |||
| L | |||
| H | |||
| L | |||
| H | |||
| L | |||
| H | |||
| L | |||
| 正转 反转 | |||
| ON | |||
| ON | |||
| OFF | |||
| OFF | |||
| 脉冲输出端口Y2 | |||
| 任意的输出Y□ | |||
| (指定旋转方向) | |||
| 脉冲输出端口Y11 | |||
| 任意的输出Y□ | |||
| (指定旋转方向) | |||
| H | |||
| L | |||
| H | |||
| L | |||
| H | |||
| L | |||
| H | |||
| L | |||
| 正转 反转 | |||
| ON | |||
| ON | |||
| OFF | |||
| OFF | |||
| 正转 反转 | |||
| 【注】 :ON、OFF表示可编程控制器的输出状态;H、L表示波形的 HIGH、LOW。 | |||
| 2)伺服放大器(驱动单元)的指令脉冲输入形式的设定 | |||
| 如下表所示,请使伺服放大器(驱动单元)参数中的脉冲串输入形式与可编程控制器的脉冲输出形式相 | |||
| 符合。 | |||
| 伺服放大器 | |||
| (驱动单元) | |||
| 基本单元的脉冲输出形式 集电极转差分板DC-Diff | |||
| 晶体管输出(漏型输出) 差动驱动 | |||
| 脉冲+方向 正转脉冲、反转脉冲 | |||
| 指令脉冲输入形式 脉冲+符号 正转脉冲、反转脉冲 | |||
| 指令脉冲逻辑 负逻辑 负逻辑 | |||
| 【注】 :XD/XL系列 PLC本体脉冲输出形式为集电极开路信号输出(脉冲+方向) ,可以通过集电极转差分 | |||
| 扩展板 OC-Diff将集电极开路信号输出(脉冲+方向)转化为差动信号输出。 | |||
| 集电极开路信号(脉冲+方向)通过 OC-Diff转化为差分信号接线图(以 DS2-21P5-A为例): | |||
| ===== PDF page 167 ===== | |||
| XD/XL系列可编程控制器用户手册[定位控制篇] 1.脉冲输出 | |||
| 157 | |||
| 1 | |||
| 5 | |||
| 6 | |||
| 10 | |||
| 11 | |||
| 15 | |||
| +24V 2P- +5V +24V 1P- +5V | |||
| 24V+ 24V- PUL2- PUL2+ PUL1- PUL1+ | |||
| 开关电源 | |||
| 集电极转差分OC-Diff | |||
| Z0 | |||
| GN | |||
| 24V | |||
| 0V | |||
| 差分输出 | |||
| CN1口 | |||
| DS系列伺服放大器的各系列的参数设定: | |||
| 系列名称 参数号 设定值 | |||
| 脉冲+方向(负逻辑) 差动信号(负逻辑) | |||
| DS2系列 AS — √ — | |||
| DS2系列 AS2 — √ — | |||
| DS2系列 AS6 P2-00 2 1 | |||
| DS2系列 BS — √ — | |||
| DS2系列 BS6 P2-00 2 1 | |||
| DS2系列 BSW — √ — | |||
| DS2系列 BSW6 P2-00 2 1 | |||
| DS3系列 PQA P2-00 2 1 | |||
| DS3E系列 PFA P2-00 2 1 | |||
| DS3系列 P0-10 2 1 | |||
| DS3E系列 P0-10 2 1 | |||
| 3)伺服放大器(驱动单元)电子齿轮比的设定(以DS2系列为例) | |||
| 通过使用伺服电机的电子齿轮,可以设定每个脉冲的移动量。 | |||
| 关于电子齿轮的设定,请参考使用的伺服电机以及伺服放大器的手册,设定与用途相符合的数值。 | |||
| (1)例 1 | |||
| 将每个脉冲的移动量设定为 10μm时(使用丝杆的机械时)。 | |||
| 机械规格 | |||
| 伺服放大器 DS2系列 | |||
| 伺服电机的额定转速 3000r/min | |||
| 滚珠丝杆导程螺距(Pb) 10mm | |||
| 减速机减速比(n) 1:5 | |||
| 伺服电机分辨率(Pt) 10000PLS/REV | |||
| 伺服电机 减速 | |||
| 机构 | |||
| 工作台 | |||
| f0:指令脉冲频率 | |||
| CMX:电子齿轮/分子 | |||
| CDV:电子齿轮/分母 | |||
| NR:伺服电机转速r/min | |||
| X:每个脉冲的移动量mm | |||
| ===== PDF page 168 ===== | |||
| 1.脉冲输出 XD/XL系列可编程控制器用户手册[定位控制篇] | |||
| 158 | |||
| 电子齿轮比计算公式如下: | |||
| = X ×CMX | |||
| CDV | |||
| Pt | |||
| n×Pb | |||
| =10×10 ×-3 10000 | |||
| 1/5×10 | |||
| 50 | |||
| 1 | |||
| = | |||
| 由上图可知,伺服驱动器电子齿轮比应该设定为 50:1 | |||
| 此时,基本单元最大输出脉冲频率(200,000Hz)时的伺服电机的旋转速度如下计算所示: | |||
| ×CMX | |||
| CDV | |||
| = | |||
| NR = 60 | |||
| Pt | |||
| × f0 | |||
| 50 | |||
| 1 | |||
| × 60 | |||
| 10000 | |||
| × 200000 | |||
| = 60000r/min > 3000r/min(额定转速) | |||
| 注意:请设定可编程控制器侧的最高速度,以使伺服电机的旋转速度控制在额定转速以下。 | |||
| (2)例 2 | |||
| 将每个脉冲的移动量设定为 0.01°时(旋转台时)。 | |||
| 机械规格 | |||
| 伺服放大器 DS2系列 | |||
| 伺服电机的额定转速 3000r/min | |||
| 旋转台角度 360°/ REV | |||
| 减速比(n) 1:5 | |||
| 伺服电机分辨率(Pt) 10000PLS/REV | |||
| 伺服电机 | |||
| Pt=10000[PLS/REV] | |||
| 旋转台 | |||
| 同步皮带:1:5 | |||
| F0 :指令脉冲频率[Hz](集电极开路方式) | |||
| CMX:电子齿轮(指令脉冲倍率分子) | |||
| CDV:电子齿轮(指令脉冲倍率分母) | |||
| NR :伺服电机旋转速度[r/min] | |||
| X :每个脉冲的移动量[°] | |||
| 电子齿轮比计算公式如下: | |||
| = X ×CMX | |||
| CDV | |||
| Pt | |||
| n×360 | |||
| = 1×10 ×-2 10000 | |||
| 1/5×360 | |||
| 25 | |||
| 18 | |||
| = | |||
| 由上图可知,伺服驱动器电子齿轮比应该设定为 25:18 | |||
| 此时,基本单元最大输出脉冲频率(200,000Hz)时的伺服电机的旋转速度如下计算所示: | |||
| CMX | |||
| CDV | |||
| × 60 | |||
| Pt | |||
| × f0 | |||
| 25 | |||
| 18 | |||
| × 60 | |||
| 10000 | |||
| × 100000= | |||
| = 833.33r/min < 3000r/min(额定转速) | |||
| NR= | |||
| 因为伺服电机的旋转速度在额定转速以下,所以可编程控制器侧的最高速度不需要有限制。 | |||
| ===== PDF page 169 ===== | |||
| XD/XL系列可编程控制器用户手册[定位控制篇] 1.脉冲输出 | |||
| 159 | |||
| 4)伺服放大器(驱动单元)准备好信号设定(以DS2系列为例) | |||
| DS2系列伺服使能信号有效代表伺服电机通电工作,当伺服使能信号无效时,电机不运行。 | |||
| 系列名 参数号 设定值 | |||
| DS2系列 P5-10 0010 | |||
| 1-4-5.定位指令脉冲发送完成标志位的使用及注意事项 | |||
| 正在发脉冲标志位SM1000、SM1020、SM1040……等标志位由ON变为OFF时,意味着指令的动作 | |||
| (脉冲输出动作等)结束了。但是,并不意味着伺服电机的动作也结束(停止)了。为了确切掌握伺服电机 | |||
| 的动作结束情况,请正确使用正在发脉冲标志位。 | |||
| 正在发脉冲标志位如下表所示: | |||
| 序号 线圈 轴数 说明 | |||
| 1 SM1000 Y0 当脉冲发送时线圈置 ON, 脉冲发送结束后立即置OFF, | |||
| 利用线圈的下降沿判断脉冲发送是否结束。 | |||
| t0 | |||
| 频率 | |||
| SM1000 | |||
| 脉冲段 | |||
| 2 SM1020 Y1 | |||
| 3 SM1040 Y2 | |||
| 4 SM1060 Y3 | |||
| 5 SM1080 Y4 | |||
| 6 SM1100 Y5 | |||
| 7 SM1120 Y6 | |||
| 8 SM1140 Y7 | |||
| 9 SM1160 Y10 | |||
| 10 SM1180 Y11 | |||
| 如果编写多个同一脉冲输出端口的定位指令, 那么指令执行时, 正在发送脉冲标志位SM1000、SM1020、 | |||
| SM1040……等随着各个指令而ON/0FF变化。因此,如果将多个指令执行正在发送脉冲标志位 SM1000、 | |||
| SM1020、SM1040……等同时用在同一段程序内,则无法判断是因为执行哪条指令而ON/OFF,同时也不能 | |||
| 正常获取与各个指令相支持的标志位。 | |||
| 错误的写法如下: | |||
| ===== PDF page 170 ===== | |||
| 1.脉冲输出 XD/XL系列可编程控制器用户手册[定位控制篇] | |||
| 160 | |||
| 正确的写法如下: | |||
| 1-4-6.定位指令触发条件注意事项 | |||
| XD/XL 系列 PLC 定位指令主要有 PLSR(边沿触发) 、PLSF(常开/常闭触发) 、DRVI(边沿触发) 、 | |||
| DRV A(边沿触发) 、ZRN(边沿触发) ;除了PLSF指令外,其余的脉冲指令全部是边沿触发,同一脉冲输 | |||
| 出端口(例如Y0)在执行一条定位指令的过程中,正在发送脉冲标志位(SM1000)会一直处于导通状态, | |||
| 此时再触发其它同一脉冲输出端口的脉冲指令,则PLC将不会予以响应,直到正在执行的脉冲输出指令脉 | |||
| 冲发送结束,正在发送脉冲标志位复位以后才会响应。 | |||
| 由于 PLSF脉冲指令的导通条件为常开/常闭,所以在使用 PLSF指令时,当脉冲发送结束不需要执行 | |||
| 时,请立即对 PLSF 指令的导通条件进行复位(不要只将脉冲输出频率设定为 0Hz,而不对脉冲导通条件 | |||
| 进行复位) 。 | |||
| 1-4-7.定位指令与系统参数块相关参数 | |||
| 下表整理了脉冲输出指令与系统参数块有关参数设定: | |||
| 系统参数块内容 PLSR PLSF DRVI DRVA ZRN | |||
| 公共参数—脉冲方向逻辑 必须设定 必须设定 必须设定 必须设定 必须设定 | |||
| 公共参数—启用软限位功能 可不设 可不设 可不设 可不设 可不设 | |||
| 公共参数—机械回原点默认方向 × × × × 必须设定 | |||
| 公共参数—脉冲单位 必须设定 必须设定 必须设定 必须设定 必须设定 | |||
| 公共参数—插补坐标模式 × × × × × | |||
| 公共参数—脉冲发送模式 必须设定 必须设定 必须设定 必须设定 必须设定 | |||
| 公共参数—脉冲数(1转) 可不设 可不设 可不设 可不设 可不设 | |||
| 公共参数—移动量(1转) 可不设 可不设 可不设 可不设 可不设 | |||
| 公共参数—脉冲方向端子 可不设 可不设 可不设 可不设 必须设定 | |||
| 公共参数—脉冲方向延时时间 可不设 可不设 可不设 可不设 可不设 | |||
| 公共参数—齿轮间隙正向补偿 可不设 可不设 可不设 可不设 可不设 | |||
| 公共参数—齿轮间隙负向补偿 可不设 可不设 可不设 可不设 可不设 | |||
| 公共参数—电气原点位置 × × × × × | |||
| ===== PDF page 171 ===== | |||
| XD/XL系列可编程控制器用户手册[定位控制篇] 1.脉冲输出 | |||
| 161 | |||
| 系统参数块内容 PLSR PLSF DRVI DRVA ZRN | |||
| 公共参数—原点开关状态设置 × × × × 必须设定 | |||
| 公共参数—原点信号端子设定 × × × × 必须设定 | |||
| 公共参数—Z 相开关状态设置 × × × × 可不设 | |||
| 公共参数—Z 相端子设定 × × × × 可不设 | |||
| 公共参数—正极限开关状态设置 可不设 可不设 可不设 可不设 可不设 | |||
| 公共参数—正极限端子设定 可不设 可不设 可不设 可不设 可不设 | |||
| 公共参数—负极限开关状态设置 可不设 可不设 可不设 可不设 可不设 | |||
| 公共参数—负极限端子设定 可不设 可不设 可不设 可不设 可不设 | |||
| 公共参数—归零清零 CLR 信号输出端子 | |||
| 设定 × × × × 可不设 | |||
| 公共参数—回归速度 VH × × × × 必须设定 | |||
| 公共参数—爬行速度 VC × × × × 必须设定 | |||
| 公共参数—机械原点位置 × × × × 必须设定 | |||
| 公共参数—Z 相个数 × × × × 可不设 | |||
| 公共参数—CLR信号延时时间 × × × × 可不设 | |||
| 公共参数—软限位正极限值 可不设 可不设 可不设 可不设 × | |||
| 公共参数—软限位负极限值 可不设 可不设 可不设 可不设 × | |||
| 公共参数—快速定位指令默认参数块 × × 可不设 可不设 × | |||
| 公共参数—插补指令默认参数块 × × × × × | |||
| 第 1 套参数—脉冲默认速度 必须设定 必须设定 × × 必须设定 | |||
| 第 1 套参数—脉冲默认速度加速时间 必须设定 必须设定 × × 必须设定 | |||
| 第 1 套参数—脉冲默认速度减速时间 必须设定 必须设定 × × 必须设定 | |||
| 第 1 套参数—补间加减速时间 可不设 可不设 可不设 可不设 可不设 | |||
| 第 1 套参数—脉冲加减速模式 必须设定 必须设定 必须设定 必须设定 必须设定 | |||
| 第 1 套参数—最高速度 必须设定 必须设定 必须设定 必须设定 必须设定 | |||
| 第 1 套参数—起始速度 必须设定 必须设定 必须设定 必须设定 必须设定 | |||
| 第 1 套参数—终止速度 必须设定 必须设定 必须设定 必须设定 必须设定 | |||
| 第 1 套参数—脉冲频率刷新时间 可不设 可不设 可不设 可不设 可不设 | |||
| 第 1 套参数—回归速度 VH × × × × 必须设定 | |||
| 第 1 套参数—爬行速度 VC × × × × 必须设定 | |||
| 【注】 : | |||
| ※1:第 0、2、3、4套参数设定请参照第 1套参数设定。 | |||
| ※2:设定了“第 1套参数—回归速度 VH” 、 “第1套参数—爬行速度 VC”的情况下,公共参数的 VH、 | |||
| VC可不设定。 | |||
| 1-4-8.伺服电机、步进电机不动作故障排查 | |||
| 伺服电机、步进电机不转时,请确认以下项目: | |||
| 1)请确认接线。 | |||
| 2)请执行定位指令,确认以下的 LED的状态。 | |||
| -设定为脉冲输出端软元件的输出信号的LED; | |||
| -设定为旋转方向输出的输出信号的 LED。 | |||
| 3)请确认可编程控制器执行定位指令时,各轴累计脉冲寄存器的数值是否在变化。 | |||
| 各脉冲输出累积寄存器如下表所示: | |||
| ===== PDF page 172 ===== | |||
| 1.脉冲输出 XD/XL系列可编程控制器用户手册[定位控制篇] | |||
| 162 | |||
| 编号 功能 说明 轴数 | |||
| HSD0 累计脉冲量低 16位 脉冲个数为单位 | |||
| Y0 HSD1 累计脉冲量高 16位 | |||
| HSD2 累计脉冲量低 16位 脉冲当量为单位 | |||
| HSD3 累计脉冲量高 16位 | |||
| HSD4 累计脉冲量低 16位 脉冲个数为单位 | |||
| Y1 HSD5 累计脉冲量高 16位 | |||
| HSD6 累计脉冲量低 16位 脉冲当量为单位 | |||
| HSD7 累计脉冲量高 16位 | |||
| HSD8 累计脉冲量低 16位 脉冲个数为单位 | |||
| Y2 | |||
| HSD9 累计脉冲量高 16位 | |||
| HSD10 累计脉冲量低 16位 脉冲当量为单位 | |||
| HSD11 累计脉冲量高 16位 | |||
| HSD12 累计脉冲量低 16位 脉冲个数为单位 | |||
| Y3 HSD13 累计脉冲量高 16位 | |||
| HSD14 累计脉冲量低 16位 脉冲当量为单位 | |||
| HSD15 累计脉冲量高 16位 | |||
| HSD16 累计脉冲量低 16位 脉冲个数为单位 | |||
| Y4 HSD17 累计脉冲量高 16位 | |||
| HSD18 累计脉冲量低 16位 脉冲当量为单位 | |||
| HSD19 累计脉冲量高 16位 | |||
| HSD20 累计脉冲量低 16位 脉冲个数为单位 | |||
| Y5 | |||
| HSD21 累计脉冲量高 16位 | |||
| HSD22 累计脉冲量低 16位 脉冲当量为单位 | |||
| HSD23 累计脉冲量高 16位 | |||
| HSD24 累计脉冲量低 16位 脉冲个数为单位 | |||
| Y6 HSD25 累计脉冲量高 16位 | |||
| HSD26 累计脉冲量低 16位 脉冲当量为单位 | |||
| HSD27 累计脉冲量高 16位 | |||
| HSD28 累计脉冲量低 16位 脉冲个数为单位 | |||
| Y7 HSD29 累计脉冲量高 16位 | |||
| HSD30 累计脉冲量低 16位 脉冲当量为单位 | |||
| HSD31 累计脉冲量高 16位 | |||
| HSD32 累计脉冲量低 16位 脉冲个数为单位 | |||
| Y10 | |||
| HSD33 累计脉冲量高 16位 | |||
| HSD34 累计脉冲量低 16位 脉冲当量为单位 | |||
| HSD35 累计脉冲量高 16位 | |||
| HSD36 累计脉冲量低 16位 脉冲个数为单位 | |||
| Y11 HSD37 累计脉冲量高 16位 | |||
| HSD38 累计脉冲量低 16位 脉冲当量为单位 | |||
| HSD39 累计脉冲量高 16位 | |||
| 4)请确认可编程控制器侧和伺服放大器(驱动单元)的脉冲输出形式是否相符。 | |||
| ===== PDF page 173 ===== | |||
| XD/XL系列可编程控制器用户手册[定位控制篇] 1.脉冲输出 | |||
| 163 | |||
| 5)请确认脉冲输出停止标志位是否动作。 | |||
| 各脉冲输出端软元件的脉冲输出标志位如下表所示: | |||
| 序号 线圈 轴数 说明 | |||
| 1 SM1001 Y0 当脉冲数值为正值正向发送脉冲时,线圈置 ON; | |||
| 当脉冲数值为负值反向发送脉冲时,线圈置 OFF。 | |||
| t0 | |||
| 频率 | |||
| SM1001 | |||
| 脉冲段 | |||
| 2 SM1021 Y1 | |||
| 3 SM1041 Y2 | |||
| 4 SM1061 Y3 | |||
| 5 SM1081 Y4 | |||
| 6 SM1101 Y5 | |||
| 7 SM1121 Y6 | |||
| 8 SM1141 Y7 | |||
| 9 SM1161 Y10 | |||
| 10 SM1181 Y11 | |||
| 6)请确认极限(正转限位、反转限位)是否动作。 | |||
| 7)请确认定位指令的动作时序。 | |||
| 正在发送脉冲标志位为ON时,使用同一脉冲输出端软元件的定位指令或者脉冲输出指令不能被执 | |||
| 行。 | |||
| 1-4-9.伺服电机、步进电机停止位置不正确故障排查 | |||
| 停止位置不正确时,请确认以下项目: | |||
| 1)请确认伺服放大器(驱动单元)的电子齿轮的设定是否正确。 | |||
| 2)请确认原点位置是否偏移。 | |||
| A、设计原点信号时,请考虑有足够为ON的时间能充分减速到爬行速度。 | |||
| ZRN指令在原点前端开始减速到停止,延时反向加速到爬行速度,在脱离原点时停止, 清除当前值 | |||
| 寄存器。 | |||
| 在原点后端前,没有能够减速到爬行速度时,会导致停止位置偏移。 | |||
| B、请使爬行速度足够的慢。 | |||
| 原点回归指令的停止是不进行减速停止的, 所以如果爬行速度过快, 会由于惯性导致停止位置偏 | |||
| 移。 | |||
| C、关于原点信号的软元件。 | |||
| 原点信号端子可以选择 PLC本体上所有的输入点; 但是如果选择的输入点为PLC上的外部中断端子, | |||
| 则回机械原点的过程中都会按照中断进行处理,从而可以进一步的提高回机械原点的精度(如果使用Z 相 | |||
| 回原点则无影响) ;而选择的输入点为非PLC本体上的外部中断端子,会机械原点的过程中则会受到PLC | |||
| 扫描周期的影响(如果使用 Z相回原点则无影响) 。 | |||
| 3)进行正反转动作(往返动作)后,停止位置有偏离。 | |||
| 由于移动工作台与滚珠丝杠之间存在接触间隙,工作台由正向移动结束切到反向移动时,从而导致反 | |||
| 向实际移动距离小于设定距离;工作台由反向移动结束切到正向移动时,从而导致正向实际移动距离小于 | |||
| 设定距。 | |||
| 可以通过正向齿轮间隙补偿和反向齿轮间隙补偿进行修正。 | |||
| ===== PDF page 174 ===== | |||
| 1.脉冲输出 XD/XL系列可编程控制器用户手册[定位控制篇] | |||
| 164 | |||
| 1-5.定位指令案例程序 | |||
| 本节主要通过几个样例程序来介绍 PLSR、PLSF、DRV A、DRVI、ZRN指令的使用方式。 | |||
| 动作 指令 程序举例 | |||
| 顺控梯形图 流程梯形图 | |||
| 多段脉冲定位 PLSR 1-5-4、1-5-6 1-5-5、1-5-7 | |||
| 可变频脉冲输出 PLSF 1-5-2、1-5-4 1-5-3、1-5-5 | |||
| 相对单段定位 DRVI 1-5-2、1-5-6 1-5-3、1-5-7 | |||
| 绝对单段定位 DRV A 1-5-2、1-5-6 1-5-3、1-5-7 | |||
| 机械原点回归 ZRN 1-5-2、1-5-4、1-5-6 1-5-3、1-5-5、1-5-7 | |||
| 1-5-1.I/O点分配 | |||
| 程序举例中使用脉冲输出端 Y0(1 轴)。使用其它脉冲输出端的时候,请修改对应的脉冲轴软元件。 | |||
| 信号名称 输入输出编号 备注 | |||
| 脉冲输出端口 Y0 | |||
| 脉冲方向端口 Y2 | |||
| CLR清零信号 Y3 | |||
| 伺服准备好 X0 | |||
| 停止控制 X1 | |||
| 脉冲继续 X13 | |||
| 原点回归控制 X4 | |||
| 点动前进控制 X5 | |||
| 点动后退控制 X6 | |||
| 正转定位控制 X7 | |||
| 反转定位控制 X10 | |||
| 原点输入端子 X3 使用外部中断端子 | |||
| 正向限位开关 X11 | |||
| 反向限位开关 X12 | |||
| 1-5-2.正反转顺控样例程序【PLSF、DRVI、DRVA、ZRN】 | |||
| 例1:根据下图运行,采用绝对单段定位方式进行定位。 | |||
| 10000Hz | |||
| 原点 | |||
| 加减速时间 | |||
| 200ms | |||
| (50000,0) | |||
| 10000Hz加减速时间 | |||
| 200ms | |||
| (100,0) | |||
| (0,0) | |||
| 加减速时间 | |||
| 200ms | |||
| ===== PDF page 175 ===== | |||
| XD/XL系列可编程控制器用户手册[定位控制篇] 1.脉冲输出 | |||
| 165 | |||
| 首先,编写梯形图程序,如下: | |||
| X4 | |||
| X6 X5 | |||
| M100 | |||
| X5 X6 | |||
| M101 | |||
| X7 X10 | |||
| 原点回 | |||
| 归控制 | |||
| 点动后 | |||
| 退控制 | |||
| 点动前 | |||
| 进控制 | |||
| 点动前进 | |||
| 运行中 | |||
| 点动前 | |||
| 进控制 | |||
| 点动后 | |||
| 退控制 | |||
| 点动后退 | |||
| 运行中 | |||
| 正转定位 | |||
| 控制 | |||
| 反转定位 | |||
| 控制 | |||
| ZRN K1 Y0 | |||
| PLSF K10000 K1 Y0 | |||
| ( ) | |||
| M100 | |||
| PLSF K-10000 K1 Y0 | |||
| ( ) | |||
| M101 | |||
| 点动前进运行中 | |||
| 点动后退运行中 | |||
| DRVA K50000 K10000 K200 Y0 Y2 | |||
| X10 X7 | |||
| 正转定位 | |||
| 控制 | |||
| 反转定位 | |||
| 控制 | |||
| DRVA K100 K10000 K200 Y0 Y2 | |||
| X0 X5 X6 | |||
| STOP Y0 K0 | |||
| X1 | |||
| 停止控制 | |||
| 伺服准备 | |||
| 好 | |||
| 点动前 | |||
| 进控制 | |||
| 点动后 | |||
| 退控制 | |||
| X13 | |||
| GOON Y0 | |||
| 脉冲继续 | |||
| 由于样例程序中除 DRVI和 DRV A,其余所有的脉冲指令使用的系统参数块都为第一套参数,所以, | |||
| 我们点击 PLC编程软件左边的工程栏中的“脉冲配置参数” ,如下图: | |||
| //机械回原点指令(选用第一套系统参数块参数) | |||
| //点动前进控制, 速度为10000Hz(选用第一套系统参 | |||
| 数块参数) | |||
| //点动后退控制, 速度为-10000Hz(选用第一套系统参 | |||
| 数块参数) | |||
| //正转定位控制 | |||
| //反转定位控制 | |||
| //脉冲停止发送控制(缓停) | |||
| //脉冲没有发送完执行脉冲继续将剩余的脉冲发送完 | |||
| ===== PDF page 176 ===== | |||
| 1.脉冲输出 XD/XL系列可编程控制器用户手册[定位控制篇] | |||
| 166 | |||
| 将会打开如下窗口: | |||
| 点击打开窗口中的“配置”选项,在下拉菜单中选择“Y0轴” : | |||
| 在打开的参数配置表格中按如下进行配置(圈起来的参数指需要在默认参数下进行修改的参数) : | |||
| 系统参数块配置一 | |||
| @@ -0,0 +1,162 @@ | |||
| # -*- coding: utf-8 -*- | |||
| """逻辑分析仪波形 .bin → 时频曲线拟合。 | |||
| 文件格式(自动探测): | |||
| 16 通道逻辑分析仪导出:每采样 2 字节(小端 uint16),bit0..15 = CH0..CH15。 | |||
| 信号通道 = 值 0x0100 的位(bit8),即字节流的奇数索引字节承载 CH8。 | |||
| 采样率默认 100MS/s(可用 --fs 覆盖;也可自动验证 2000/5000Hz 命中)。 | |||
| 用法: | |||
| python plot_waveform.py <xxx.bin> [--fs 100e6] [--ch 8] [--out <png>] | |||
| """ | |||
| import argparse | |||
| import sys | |||
| import numpy as np | |||
| import matplotlib | |||
| matplotlib.use("Agg") | |||
| import matplotlib.pyplot as plt | |||
| def extract_channel(m, ch): | |||
| """从 2 字节/采样(小端 uint16)格式中提取通道 ch 的数字序列。""" | |||
| # 目标位在 16bit 值中的字节位置:bit<8 → 低字节(偶索引);>=8 → 高字节(奇索引) | |||
| if ch < 8: | |||
| lo = m[0::2] | |||
| return (lo >> ch) & 1 | |||
| hi = m[1::2] | |||
| return (hi >> (ch - 8)) & 1 | |||
| def rising_edges(sig): | |||
| """上升沿索引(数字序列)。""" | |||
| return np.nonzero((sig[1:] == 1) & (sig[:-1] == 0))[0] + 1 | |||
| def main(): | |||
| ap = argparse.ArgumentParser() | |||
| ap.add_argument("bin_path") | |||
| ap.add_argument("--fs", type=float, default=None, help="采样率 Hz") | |||
| ap.add_argument("--ch", type=int, default=0, help="信号通道号") | |||
| ap.add_argument("--out", default=None, help="输出png路径") | |||
| args = ap.parse_args() | |||
| m = np.memmap(args.bin_path, dtype=np.uint8, mode="r") | |||
| if len(m) % 2 != 0: | |||
| sys.exit("odd file size, not 2-byte/sample format?") | |||
| nsamp = len(m) // 2 | |||
| print("samples:", nsamp) | |||
| ch = args.ch | |||
| sig = extract_channel(m, ch) | |||
| ones = int(sig.sum()) | |||
| print("CH%d: %d ones / %d samples (%.2f%%)" | |||
| % (ch, ones, nsamp, 100.0 * ones / nsamp)) | |||
| nz = np.nonzero(sig)[0] | |||
| if len(nz) == 0: | |||
| sys.exit("channel has no signal") | |||
| lo, hi = int(nz[0] * 0.97), int(nz[-1] * 1.03) | |||
| print("signal range: sample %d .. %d" % (lo, hi)) | |||
| # ---- 采样率:自动验证(检查匀速段 2000/5000Hz 命中) ---- | |||
| if args.fs is None: | |||
| candidates = [100e6, 50e6, 200e6, 25e6] | |||
| best = [] | |||
| for fs in candidates: | |||
| down = max(1, int(fs // 5000000)) | |||
| s = sig[lo:hi:down] | |||
| r = rising_edges(s) | |||
| if len(r) < 20: | |||
| continue | |||
| per = np.diff(r) * down / fs | |||
| f = 1.0 / np.maximum(per, 1e-9) | |||
| f = f[(f > 100) & (f < 20000)] | |||
| if len(f) < 10: | |||
| continue | |||
| h, e = np.histogram(f, bins=400, range=(0, 20000)) | |||
| e2 = h[(e[:-1] >= 1940) & (e[:-1] <= 2060)].sum() | |||
| e5 = h[(e[:-1] >= 4850) & (e[:-1] <= 5150)].sum() | |||
| best.append(((e2 + e5) / max(h.sum(), 1), fs)) | |||
| best.sort(reverse=True) | |||
| fs = best[0][1] | |||
| print("sample-rate ranking:", ["%g:%.3f" % (f, s) for s, f in best]) | |||
| print("using fs = %g Hz" % fs) | |||
| else: | |||
| fs = float(args.fs) | |||
| # ---- 上升沿 → 时频 ---- | |||
| r = rising_edges(sig[lo:hi]) | |||
| r = r + lo | |||
| t_rise = r / fs | |||
| per = np.diff(t_rise) | |||
| freq = 1.0 / np.maximum(per, 1e-9) | |||
| t_mid = (t_rise[:-1] + t_rise[1:]) / 2.0 | |||
| print("rising edges: %d" % len(r)) | |||
| print("first pulse @ %.3fs, last @ %.3fs" % (t_rise[0], t_rise[-1])) | |||
| print("total pulses: %d" % len(r)) | |||
| print("average freq: %.1f Hz" | |||
| % (len(r) / max(t_rise[-1] - t_rise[0], 1e-9))) | |||
| # ---- 三段结构(按 10ms 桶取中位频率) ---- | |||
| buckets = np.arange(t_rise[0] - 0.05, t_rise[-1] + 0.05, 0.01) | |||
| med = [] | |||
| bt = [] | |||
| for i in range(len(buckets) - 1): | |||
| sel = (t_mid >= buckets[i]) & (t_mid < buckets[i + 1]) | |||
| if sel.sum() > 0: | |||
| med.append(np.median(freq[sel])) | |||
| bt.append((buckets[i] + buckets[i + 1]) / 2) | |||
| med = np.array(med) | |||
| bt = np.array(bt) | |||
| active = med > 100 | |||
| edges = np.diff(active.astype(int)) | |||
| starts = bt[1:][edges == 1] | |||
| stops = bt[1:][edges == -1] | |||
| if len(bt) > 0 and active[0]: | |||
| starts = np.concatenate(([bt[0]], starts)) | |||
| if len(bt) > 0 and active[-1]: | |||
| stops = np.concatenate((stops, [bt[-1]])) | |||
| print("segments:") | |||
| for s, e in zip(starts, stops): | |||
| sel = (t_rise >= s) & (t_rise <= e) | |||
| n = sel.sum() | |||
| print(" %.3f ~ %.3fs dur=%.3fs pulses=%d avg=%.0fHz" | |||
| % (s, e, e - s, n, n / max(e - s, 1e-9))) | |||
| for i in range(len(stops) - 1): | |||
| print(" gap seg%d->%d: %.3fms" % (i + 1, i + 2, | |||
| (starts[i + 1] - stops[i]) * 1e3)) | |||
| # ---- 画图 ---- | |||
| out = args.out or (args.bin_path.rsplit(".", 1)[0] + "_timefreq.png") | |||
| fig, axes = plt.subplots(2, 1, figsize=(14, 9), sharex=True, | |||
| gridspec_kw={"height_ratios": [1, 3]}) | |||
| ax = axes[0] | |||
| step = max(1, int(fs // 200000)) | |||
| xs = np.arange(lo, hi, step) / fs | |||
| ax.plot(xs, sig[lo:hi:step], lw=0.4, color="steelblue") | |||
| ax.set_ylabel("CH%d raw" % ch) | |||
| ax.set_yticks([0, 1]) | |||
| ax.grid(alpha=0.3) | |||
| ax = axes[1] | |||
| ax.plot(t_mid, freq, lw=0.8, color="crimson") | |||
| ax.axhline(2000, color="gray", ls="--", lw=0.8) | |||
| ax.axhline(5000, color="gray", ls="--", lw=0.8) | |||
| ax.set_ylabel("instantaneous freq (Hz)") | |||
| ax.set_xlabel("time (s)") | |||
| ax.set_ylim(0, 6000) | |||
| ax.grid(alpha=0.3) | |||
| ax.legend(["freq", "2000Hz", "5000Hz"], loc="upper right", fontsize=8) | |||
| fig.suptitle("CH%d time-frequency: %d pulses, fs=%g Hz, ch=%d" | |||
| % (ch, len(r), fs, ch)) | |||
| fig.tight_layout() | |||
| fig.savefig(out, dpi=130) | |||
| print("saved:", out) | |||
| if __name__ == "__main__": | |||
| main() | |||
| @@ -51,6 +51,8 @@ uint8_t PlsrHwResolveDirectionPoint(uint8_t pointNumber); | |||
| /* 模拟寄存器访问与中断触发(测试用)。 */ | |||
| uint32_t PlsrHwTestGetArr(uint8_t axis); | |||
| uint32_t PlsrHwTestGetCcr(uint8_t axis); | |||
| uint32_t PlsrHwTestGetCcmr1(uint8_t axis); | |||
| uint32_t PlsrHwTestGetCr1(uint8_t axis); | |||
| uint32_t PlsrHwTestGetPsc(uint8_t axis); | |||
| uint8_t PlsrHwTestGetPwmEnabled(uint8_t axis); | |||
| uint8_t PlsrHwTestGetDirLevel(uint8_t axis); | |||
| @@ -89,6 +89,7 @@ typedef struct | |||
| uint32_t psc; | |||
| uint32_t arr; | |||
| uint32_t ccr1; | |||
| uint32_t ccmr1; | |||
| uint32_t ccer; | |||
| uint8_t dirLevel; | |||
| } PLSR_HW_TIMER_REGS; | |||
| @@ -170,6 +171,18 @@ static void PlsrHwTimerSetCc1e(uint8_t axis, uint32_t value) | |||
| #endif | |||
| } | |||
| /* 通道 1 输出模式 = PWM 模式 1(OC1M=110)+ CCR 预装载(OC1PE)。 | |||
| * 上电复位后 CCMR1=0(冻结),通道输出恒定电平、无方波,必须显式配置。 */ | |||
| static void PlsrHwTimerSetPwmMode1(uint8_t axis) | |||
| { | |||
| #ifdef PLSR_HOST_TEST | |||
| PlsrHwTimers[axis].ccmr1 = 0x0068UL; | |||
| #else | |||
| PlsrHwAxisMap[axis].timer->CCMR1 = (TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2) | |||
| | TIM_CCMR1_OC1PE; | |||
| #endif | |||
| } | |||
| static void PlsrHwTimerSetUie(uint8_t axis, uint32_t value) | |||
| { | |||
| #ifdef PLSR_HOST_TEST | |||
| @@ -195,7 +208,9 @@ static void PlsrHwTimerClearUif(uint8_t axis) | |||
| #endif | |||
| } | |||
| /* ---- DIR 输出 ---- */ | |||
| /* ---- DIR 输出 ---- | |||
| * XDM 为晶体管(NPN 漏型)输出:ON(导通)= 引脚低电平。 | |||
| * 信捷正逻辑:正向发脉冲时方向端子置 ON(低)。 */ | |||
| static void PlsrHwSetDirLevel(uint8_t axis, uint8_t positive) | |||
| { | |||
| @@ -213,19 +228,60 @@ static void PlsrHwSetDirLevel(uint8_t axis, uint8_t positive) | |||
| { | |||
| const PLSR_HW_OUTPUT_PIN *pin = | |||
| &PlsrHwOutputPins[state->directionPoint]; | |||
| GPIO_InitTypeDef gpio; | |||
| if (pin->port != NULL) | |||
| { | |||
| HAL_GPIO_WritePin(pin->port, pin->pin, | |||
| (positive != 0U) ? GPIO_PIN_SET : GPIO_PIN_RESET); | |||
| /* DIR 点按需配置为推挽输出(上电默认高阻=截止,安全)。 */ | |||
| gpio.Pin = pin->pin; | |||
| gpio.Mode = GPIO_MODE_OUTPUT_PP; | |||
| gpio.Pull = GPIO_NOPULL; | |||
| gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH; | |||
| HAL_GPIO_Init(pin->port, &gpio); | |||
| /* 漏型输出:ON(导通)= 低电平。 */ | |||
| HAL_GPIO_WritePin(pin->port, | |||
| pin->pin, | |||
| (positive != 0U) ? GPIO_PIN_RESET | |||
| : GPIO_PIN_SET); | |||
| } | |||
| } | |||
| #endif | |||
| } | |||
| /* ---- PWM 启停 ---- */ | |||
| /* ---- PWM 启停 ---- | |||
| * ARR/CCR 使用预装载(ARPE/OC1PE):运行中调频写入延迟到更新事件生效, | |||
| * 避免 ARR 变小瞬间 CNT 超调提前回绕(每段加速会多出 ~ln(f1/f0) 个假脉冲)。 | |||
| * 首次启动用 EGR.UG 把预装载值加载到影子寄存器,杜绝首个周期用复位值。 */ | |||
| static void PlsrHwTimerSetArpe(uint8_t axis, uint32_t value) | |||
| { | |||
| #ifdef PLSR_HOST_TEST | |||
| PlsrHwTimers[axis].cr1 = (PlsrHwTimers[axis].cr1 & ~0x0080UL) | |||
| | ((value != 0UL) ? 0x0080UL : 0UL); | |||
| #else | |||
| if (value != 0UL) | |||
| { | |||
| PlsrHwAxisMap[axis].timer->CR1 |= TIM_CR1_ARPE; | |||
| } | |||
| else | |||
| { | |||
| PlsrHwAxisMap[axis].timer->CR1 &= ~TIM_CR1_ARPE; | |||
| } | |||
| #endif | |||
| } | |||
| /* 生成更新事件:立即加载 ARR/CCR/PSC 影子寄存器(启动时用)。 */ | |||
| static void PlsrHwTimerSetUg(uint8_t axis) | |||
| { | |||
| #ifdef PLSR_HOST_TEST | |||
| PlsrHwTimers[axis].sr &= ~PLSR_HW_TIMER_UPDATE_BIT; | |||
| #else | |||
| PlsrHwAxisMap[axis].timer->EGR = TIM_EGR_UG; | |||
| #endif | |||
| } | |||
| static void PlsrHwStartPwmTimer(uint8_t axis, uint32_t frequencyHz) | |||
| /* 配置 PWM 定时器(预装载写入;启动/调频共用,不触碰使能位)。 */ | |||
| static void PlsrHwConfigurePwm(uint8_t axis, uint32_t frequencyHz) | |||
| { | |||
| uint16_t psc; | |||
| uint16_t arr; | |||
| @@ -240,6 +296,14 @@ static void PlsrHwStartPwmTimer(uint8_t axis, uint32_t frequencyHz) | |||
| PlsrHwTimerSetPsc(axis, psc); | |||
| PlsrHwTimerSetArr(axis, arr); | |||
| PlsrHwTimerSetCcr(axis, (uint32_t)arr / 2UL); /* 50% 占空比 */ | |||
| PlsrHwTimerSetPwmMode1(axis); | |||
| PlsrHwTimerSetArpe(axis, 1UL); | |||
| } | |||
| /* 首次启动输出:加载影子寄存器后使能更新中断、通道与计数。 */ | |||
| static void PlsrHwPwmBegin(uint8_t axis) | |||
| { | |||
| PlsrHwTimerSetUg(axis); | |||
| PlsrHwTimerSetUie(axis, 1UL); | |||
| PlsrHwTimerSetCc1e(axis, 1UL); | |||
| PlsrHwTimerSetCen(axis, 1UL); | |||
| @@ -295,9 +359,8 @@ PLSR_RESULT PlsrHwInit(void) | |||
| #ifndef PLSR_HOST_TEST | |||
| { | |||
| GPIO_InitTypeDef gpio; | |||
| uint8_t point; | |||
| /* 1. 输出点 GPIO 时钟。 */ | |||
| /* 1. 输出点 GPIO 时钟(DIR 点按需配置时使用)。 */ | |||
| __HAL_RCC_GPIOF_CLK_ENABLE(); | |||
| __HAL_RCC_GPIOI_CLK_ENABLE(); | |||
| __HAL_RCC_GPIOE_CLK_ENABLE(); | |||
| @@ -305,22 +368,8 @@ PLSR_RESULT PlsrHwInit(void) | |||
| __HAL_RCC_GPIOH_CLK_ENABLE(); | |||
| __HAL_RCC_GPIOB_CLK_ENABLE(); | |||
| /* 2. 全部输出点上电安全电平(推挽输出、低)。 */ | |||
| gpio.Mode = GPIO_MODE_OUTPUT_PP; | |||
| gpio.Pull = GPIO_NOPULL; | |||
| gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH; | |||
| for (point = 0U; point < PLSR_HW_OUTPUT_POINT_COUNT; point++) | |||
| { | |||
| if (PlsrHwOutputPins[point].port != NULL) | |||
| { | |||
| gpio.Pin = PlsrHwOutputPins[point].pin; | |||
| HAL_GPIO_WritePin(PlsrHwOutputPins[point].port, | |||
| PlsrHwOutputPins[point].pin, | |||
| GPIO_PIN_RESET); | |||
| HAL_GPIO_Init(PlsrHwOutputPins[point].port, | |||
| &gpio); | |||
| } | |||
| } | |||
| /* 2. 上电安全:输出点保持复位默认高阻(漏型输出 = 截止 = OFF)。 | |||
| * 不驱动任何 Y 点,DIR 点仅在 PlsrHwSetDirLevel 时按需配置。 */ | |||
| /* 3. 定时器时钟。 */ | |||
| __HAL_RCC_TIM10_CLK_ENABLE(); | |||
| @@ -329,8 +378,10 @@ PLSR_RESULT PlsrHwInit(void) | |||
| __HAL_RCC_TIM14_CLK_ENABLE(); | |||
| /* 4. 脉冲点切定时器复用(PF6/7=AF3、PF8/9=AF9)。 | |||
| * 定时器通道尚未使能(CC1E=0),输出为无效电平(低),无毛刺。 */ | |||
| * 定时器通道尚未使能(CC1E=0),输出级断开,无毛刺。 */ | |||
| gpio.Mode = GPIO_MODE_AF_PP; | |||
| gpio.Pull = GPIO_NOPULL; | |||
| gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH; | |||
| gpio.Pin = GPIO_PIN_6 | GPIO_PIN_7; | |||
| gpio.Alternate = 3U; | |||
| HAL_GPIO_Init(GPIOF, &gpio); | |||
| @@ -355,6 +406,7 @@ PLSR_RESULT PlsrHwInit(void) | |||
| PLSR_RESULT PlsrHwStartPulse(uint8_t axis, const PLSR_HW_START_PARAMS *params) | |||
| { | |||
| PLSR_HW_AXIS_STATE *state; | |||
| uint8_t directionChanged; | |||
| if ((axis >= PLSR_HW_AXIS_COUNT) || (params == NULL)) | |||
| { | |||
| @@ -370,13 +422,20 @@ PLSR_RESULT PlsrHwStartPulse(uint8_t axis, const PLSR_HW_START_PARAMS *params) | |||
| return PLSR_RESULT_BUSY; | |||
| } | |||
| /* 方向延时只在方向发生变化时生效(首次启动/换向/换方向点): | |||
| * 段间同向衔接不再等待 10ms,直接进入 PWM 待启动。 */ | |||
| directionChanged = (state->directionPoint == PLSR_HW_DIR_POINT_NONE) | |||
| || (state->directionPoint != params->directionPoint) | |||
| || (state->directionPositive != params->directionPositive); | |||
| state->targetPulses = params->targetPulses; | |||
| state->emittedPulses = 0; | |||
| state->currentFrequencyHz = params->frequencyHz; | |||
| state->directionPoint = params->directionPoint; | |||
| state->directionDelayRemainingMs = params->directionDelayMs; | |||
| state->directionDelayRemainingMs = | |||
| (directionChanged != 0U) ? params->directionDelayMs : 0U; | |||
| PlsrHwSetDirLevel(axis, params->directionPositive); | |||
| state->state = (params->directionDelayMs > 0U) | |||
| state->state = (state->directionDelayRemainingMs > 0U) | |||
| ? PLSR_HW_STATE_DIR_SETTLING | |||
| : PLSR_HW_STATE_PWM_PENDING; | |||
| return PLSR_RESULT_OK; | |||
| @@ -396,7 +455,8 @@ PLSR_RESULT PlsrHwSetFrequency(uint8_t axis, uint32_t frequencyHz) | |||
| { | |||
| if (frequencyHz > 0UL) | |||
| { | |||
| PlsrHwStartPwmTimer(axis, frequencyHz); | |||
| /* 运行中调频:预装载写入,更新事件时生效,不触碰使能位。 */ | |||
| PlsrHwConfigurePwm(axis, frequencyHz); | |||
| } | |||
| else | |||
| { | |||
| @@ -406,7 +466,8 @@ PLSR_RESULT PlsrHwSetFrequency(uint8_t axis, uint32_t frequencyHz) | |||
| else if ((state->state == PLSR_HW_STATE_PWM_PENDING) | |||
| && (frequencyHz > 0UL)) | |||
| { | |||
| PlsrHwStartPwmTimer(axis, frequencyHz); | |||
| PlsrHwConfigurePwm(axis, frequencyHz); | |||
| PlsrHwPwmBegin(axis); | |||
| state->state = PLSR_HW_STATE_RUNNING; | |||
| } | |||
| return PLSR_RESULT_OK; | |||
| @@ -481,7 +542,8 @@ void PlsrHwTick(uint8_t axis) | |||
| case PLSR_HW_STATE_PWM_PENDING: | |||
| if (state->currentFrequencyHz > 0UL) | |||
| { | |||
| PlsrHwStartPwmTimer(axis, state->currentFrequencyHz); | |||
| PlsrHwConfigurePwm(axis, state->currentFrequencyHz); | |||
| PlsrHwPwmBegin(axis); | |||
| state->state = PLSR_HW_STATE_RUNNING; | |||
| } | |||
| break; | |||
| @@ -528,6 +590,16 @@ uint32_t PlsrHwTestGetCcr(uint8_t axis) | |||
| return PlsrHwTimers[axis].ccr1; | |||
| } | |||
| uint32_t PlsrHwTestGetCcmr1(uint8_t axis) | |||
| { | |||
| return PlsrHwTimers[axis].ccmr1; | |||
| } | |||
| uint32_t PlsrHwTestGetCr1(uint8_t axis) | |||
| { | |||
| return PlsrHwTimers[axis].cr1; | |||
| } | |||
| uint32_t PlsrHwTestGetPsc(uint8_t axis) | |||
| { | |||
| return PlsrHwTimers[axis].psc; | |||
| @@ -6,12 +6,15 @@ | |||
| /* 上电自测(验证后可删除): | |||
| * - 方向端子设为 Y4(SFD906=4),其余用出厂默认参数(K1) | |||
| * - 任务:Q0 发 1 段 2000Hz / 1000 脉冲,H00 完成,梯形曲线 | |||
| * - 任务:Q0 发 3 段脉冲(H00 完成,顺序衔接),同时验证段间跳转: | |||
| * 段1:2000Hz / 1000 脉冲(已单段验证) | |||
| * 段2:5000Hz / 6000 脉冲(加速 500ms + 匀速 200ms + 减速 500ms) | |||
| * 段3:1000Hz / 500 脉冲 | |||
| * 数据源为静态数组,仅自测使用(正式 D 设备适配器见 Modbus 阶段)。 */ | |||
| #define SELF_TEST_WORD_CAPACITY (64U) | |||
| #define SELF_TEST_S0_BASE (10U) | |||
| #define SELF_TEST_S1_BASE (30U) | |||
| #define SELF_TEST_S1_BASE (60U) | |||
| #define SELF_TEST_DIR_POINT (4U) | |||
| static uint16_t SelfTestWords[3][SELF_TEST_WORD_CAPACITY]; | |||
| @@ -76,10 +79,14 @@ PLSR_RESULT PlsrSelfTestQueue(void) | |||
| /* 方向端子 Y4(PULSE/DIR 模式必需,接线参数)。 */ | |||
| (void)PlcDeviceWriteSfd(906U, SELF_TEST_DIR_POINT); | |||
| /* S0:1 段,2000Hz / 1000 脉冲,H00 完成,顺序跳转。 */ | |||
| SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE, 1U); | |||
| /* S0:3 段,H00 完成,顺序跳转。 */ | |||
| SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE, 3U); | |||
| SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE + 10U, 2000UL); | |||
| SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE + 12U, 1000UL); | |||
| SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE + 20U, 5000UL); | |||
| SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE + 22U, 6000UL); | |||
| SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE + 30U, 1000UL); | |||
| SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE + 32U, 500UL); | |||
| /* S1:相对模式,起始段 0(=段1)。 */ | |||
| SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S1_BASE, 0U); | |||
| @@ -189,6 +189,25 @@ static void TestDirDelaySequence(void) | |||
| CHECK(PlsrHwTestGetArr(0U) == arr); | |||
| CHECK(PlsrHwTestGetPsc(0U) == psc); | |||
| CHECK(PlsrHwTestGetCcr(0U) == arr / 2UL); | |||
| /* PWM 模式 1(OC1M=110):复位后 CCMR1=0 冻结,无此配置输出恒定电平。 */ | |||
| CHECK((PlsrHwTestGetCcmr1(0U) & 0x70UL) == 0x60UL); | |||
| /* ARR/CCR 预装载(ARPE=CR1 bit7,OC1PE=CCMR1 bit3): | |||
| * 运行中调频不产生提前回绕,否则加速段多出 ~ln(f1/f0) 个假脉冲。 */ | |||
| CHECK((PlsrHwTestGetCr1(0U) & 0x80UL) == 0x80UL); | |||
| CHECK((PlsrHwTestGetCcmr1(0U) & 0x08UL) == 0x08UL); | |||
| /* 段间同向衔接:方向不变时跳过方向延时,直接进入 PWM 待启动。 */ | |||
| CHECK(PlsrHwStopPulse(0U) == PLSR_RESULT_OK); | |||
| params.targetPulses = 50; | |||
| CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_OK); | |||
| CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_PWM_PENDING); | |||
| CHECK(PlsrHwTestGetDirLevel(0U) == 1U); | |||
| /* 反向时方向延时仍生效。 */ | |||
| params.directionPositive = 0U; | |||
| CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_OK); | |||
| CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_DIR_SETTLING); | |||
| CHECK(PlsrHwTestGetDirLevel(0U) == 0U); | |||
| } | |||
| static void TestZeroFrequencyWaits(void) | |||