diff --git a/Core/Src/main.c b/Core/Src/main.c index dd9b591..058b547 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -200,9 +200,9 @@ int main(void) Error_Handler(); } - /* 上电自测:Q0 发一段测试脉冲(验证后删除)。 */ + /* 上电自测:延时 1s 待电源/外设稳定后,Q0 发一段测试脉冲(验证后删除)。 */ + HAL_Delay(1000U); (void)PlsrSelfTestQueue(); - OSStart(); /* USER CODE END 2 */ diff --git a/Document/PLSR_document/xd_1_4_extract.txt b/Document/PLSR_document/xd_1_4_extract.txt new file mode 100644 index 0000000..08de2af --- /dev/null +++ b/Document/PLSR_document/xd_1_4_extract.txt @@ -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轴” : + +在打开的参数配置表格中按如下进行配置(圈起来的参数指需要在默认参数下进行修改的参数) : + +系统参数块配置一 diff --git a/Document/PLSR_document/截图/Snipaste_2026-08-07_16-01-10.png b/Document/PLSR_document/截图/Snipaste_2026-08-07_16-01-10.png new file mode 100644 index 0000000..89b25c6 Binary files /dev/null and b/Document/PLSR_document/截图/Snipaste_2026-08-07_16-01-10.png differ diff --git a/Document/PLSR_document/波形/2026-08-07_16-43-23.bin b/Document/PLSR_document/波形/2026-08-07_16-43-23.bin new file mode 100644 index 0000000..f4d00b2 Binary files /dev/null and b/Document/PLSR_document/波形/2026-08-07_16-43-23.bin differ diff --git a/Document/PLSR_document/波形/2026-08-07_16-43-23_timefreq.png b/Document/PLSR_document/波形/2026-08-07_16-43-23_timefreq.png new file mode 100644 index 0000000..3f1f7fd Binary files /dev/null and b/Document/PLSR_document/波形/2026-08-07_16-43-23_timefreq.png differ diff --git a/Document/PLSR_document/波形/plot_waveform.py b/Document/PLSR_document/波形/plot_waveform.py new file mode 100644 index 0000000..101cd99 --- /dev/null +++ b/Document/PLSR_document/波形/plot_waveform.py @@ -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 [--fs 100e6] [--ch 8] [--out ] +""" +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() diff --git a/PLSR/Inc/plsr_hal_f407.h b/PLSR/Inc/plsr_hal_f407.h index d5581ca..9e5ed17 100644 --- a/PLSR/Inc/plsr_hal_f407.h +++ b/PLSR/Inc/plsr_hal_f407.h @@ -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); diff --git a/PLSR/Src/plsr_hal_f407.c b/PLSR/Src/plsr_hal_f407.c index 6341d05..d05116d 100644 --- a/PLSR/Src/plsr_hal_f407.c +++ b/PLSR/Src/plsr_hal_f407.c @@ -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; diff --git a/PLSR/Src/plsr_self_test.c b/PLSR/Src/plsr_self_test.c index ec2135a..dd2b313 100644 --- a/PLSR/Src/plsr_self_test.c +++ b/PLSR/Src/plsr_self_test.c @@ -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); diff --git a/PLSR/Test/test_plsr_hal.c b/PLSR/Test/test_plsr_hal.c index 93686f2..b9a5e82 100644 --- a/PLSR/Test/test_plsr_hal.c +++ b/PLSR/Test/test_plsr_hal.c @@ -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)