伺服PR模式:通过通信控制伺服进行定位旋转。 在一个寄存器中输入坐标,在另一个寄存器中输入使能值。伺服电机将旋转到坐标。 坐标寄存器为32bit是的,有符号。因此,可以正反转定位控制。
using System;using System.Threading;namespace help{ // <summary> B3 //</summary> public delegate void WT_TX_CMD(byte[] cmd); public class Help_Delta_B3 B3系列 RS485 通讯 public static byte delay_下位机数据帧 { get; set; } = 30;//下位机数据帧时间 public WT_TX_CMD wt_tx_cmd { get; set; Help_ModBus rs485 = new Help_ModBus();;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;public void set_address_站号(byte add) rs485.address = add; //====通信参数:287页======================================== P2.008=0010 重新上电,恢复出厂设置(出厂 站号7)F,波特率38400,n P3. 000 = 0x007F 站号01 P3. 001 = 0x0203 DCBA:A:(RS485波特率(0:4800,1:9600,2:19200,3:38400,4:57600,5:115200) C: can(0:125Kbps,1:250Kbps,2:500kps,3:750Kbps,4:1Mbps) D:0使用非轴卡,3使用台达轴卡DMCNET P3. 002 = 0x0006 DCBA:A:(6:8n2(RTU8位无校验2停止) (7:8E1(RTU8位E偶校验1停止) (8:8O1(RTU数据位8,奇检验odd, P3. 003 = 0x0000 DCBA:A:(0:警告并继续运行) //(1:通信故障处理:警告和减速(P5. P3. 004 = 0x0000 DCBA:A:(通讯逾期报警sec秒:1秒(调试0) P3. 006 = 0x0000 DI开关来源(0:外端 1:内端P4.007控制),Bit 0 ~Bit 7 对应 DI1 ~DI8(P2.010~P2.017) DI9 ~DI3(P2.036~P2.040) P2.010后2位是开关的功能。第三位是控制常开还是常闭 P4. 007 = 00E0 bit对应软开关DI 0x0011(表示sdi5和sdi1为ON,软开关总共0x1fff)控制输入13个开关 P3. 007 = 0x0001 通信延迟回复 .5ms 单位B3 public void init_B3_regs()///初始化B手动配置3伺服 //这个功能 P2.008=0x0010恢复出厂:从站0x7f,波特率38400,RTU模式,8数据,无校验,2停车位 //改变站号 rs485.address = 0x7f; set_reg("P3.000",0x0001);//寄存器,数值 P3. 000 站号01 set_reg("P3.001",0x0201)P3. 001 波特率9600 set_reg("P3.002",0x008);//寄存器,数值 P3. set_reg("P3.003",0x0001);//寄存器,数值 P3. set_reg("P3.004",0x0000);/值 P3. 004 通信断开时报警 单位:秒 set_reg("P3.006",0x01FFF);///寄存器,数值 P3. 006 DI0:外部端子 1:内部寄存器控制 P4.007决定,Bit 0 ~Bit 7 对应 DI1 ~DI8(P2.010~P2.017) set_reg("P3.007",0x0000);/值 P3. 007 通信延迟回复 单位.5ms set_reg("P3.000",0x0001);//寄存器,数值 P3. 0000 rs485.address = 0x01; set_reg("P3.001",0x0201)P3. set_reg("P3.002",0x008);//寄存器,数值 P3. #region PR# 模式 //输入开关信号public void set_io_DI(ushort start)//0x1fff set_reg("P4.007",start);//0x1fff bit 12~ Di 13~ public void PR_init_PR模式初始化() { //伺服模式 //P5.004=0x P5.005 第一段高速原点回归速度设定 P5.007■ PR 命令触发缓存器写入 0 ,表示开始原点回归; //写入 1 ~ 99 表示开始执行指定 PR 程序,相当于 DI.CTRG POSn。 //P5.008 软件极限:正向 //P5.009 软件极限:反向 //P5.015=0x0011 ■ PATH#1 ~ PATH#2 数据断电不记忆设定 //P5.016■ 轴位置-电机编码器 //P5.018 轴位置-脉冲命令 // //P6.000=0x 1000 0000 原点复归定义 //P6.001 原点坐标 // //P6.002=0x0000 0011, #1 //P6.003=坐标 //P6.004=0x0000 0011, #2 //P6.005=坐标 // set_reg("P1.000",0x1092)us过滤,方向 脉冲) set_reg("P1.001",0x0001);//PR模式,io不切换,电机方向正 set_reg("P1.001",0x1009);//PR T模式,io切换,电机方向正,停机扭矩为0 set_reg("P1.002",0x000开扭矩限制(必须关闭)///扭矩值P1.012,13,14 set_reg("P1.003",0x0000);//CH1和2个方向 set_reg("P1.004",100);//ch1模拟量监控 set_reg("P1.005",100);//ch2模拟量监测 set_reg("P1.022",0);//pr模式 命令过滤器 set_reg("P1.032",0x//电机制动方式:Y=0动态刹车 set_reg("P1.038",10);//零速信号条件的参数定义 默认10转 set_reg("P1.039",500)DO输出 //set_reg("P1.041",50);//CH模拟量输入的扭矩比例 默认为100 set_reg("P1.042",0)//伺服使能后电磁制动器释放延迟ms set_reg("P1.043",0x0)////脱机后刹车开关延迟ms =============================================== //set_reg("P1.044", 1);//分子16.7 77216 //set_reg("P1.045", 1);//分母 //=============================================== //set_reg("P1.054", 0x1092);//位置确认范围 0.1 67772 //set_reg("P1.055", 1000);//最大速度限制 //set_reg("P1.056", 100);//预过载百分比0~120 /* 这参数很重要,低于导轨最大受力值 */ set_reg("P1.057", 30);//防撞百分比 0~300 P0.002=54电机实时扭力 set_reg("P1.058", 10);// 防撞时间过滤1~1000ms 2个值都超过时AL30 //set_reg("P1.064", 0);//模拟量输入控制电机旋转角度 PT 0关 //set_reg("P1.066", 0);//模拟位置+10v圈数DEC 0~2000(200圈) //set_reg("P1.074", 0);//编码器ABZ位置输出源 /* 这参数很重要,低于导轨最大受力值 */ set_reg("P1.087", 12);//扭力回零准位 1~300% set_reg("P1.088", 1000);//扭力计时 2~2000ms set_reg("P5.004", 0x0109);//原点复归模式:超程反转, //set_reg("P1.112", 500);//单边扭力限制 -500~500 P1.012~P1.014 //set_reg("P1.012", 100);//单边扭力限制 -500~500 P1.012~P1.014 //set_reg("P1.014", 100);//单边扭力限制 -500~500 P1.012~P1.014 set_reg("P1.098", 100);//断线侦测保护(UVW)反应时间 ms 0~800ms //set_reg("P2.050", 1);//脉冲清除 //set_reg("P2.052", 1073.741824);//分度总行程 set_reg("P0.002", 39);//伺服显示屏:39 DI //#1(P5.007 呼叫) //P6.002=0x0000 0011, #1 //set_reg("P6.002", 0x0011);//参数定义 //set_reg("P6.003", 0x1000);//#1坐标 #2 //set_reg("P6.004", 0x0011);//参数定义 //set_reg("P6.005", 0x2000);//#2坐标 set_io_DI_init(); } public void set_motor_防撞保护(ushort data, ushort time)//力矩报警阀值 { set_reg("P1.057", data);//防撞百分比 0~300 P0.002=54电机实时扭力 set_reg("P1.058", time);// 防撞时间过滤1~1000ms 2个值都超过时AL30 } public void set_motor_回零力矩(ushort data)//力矩报警阀值 { /* 这参数很重要,低于导轨最大受力值 */ if (data > 30) { data = 30; } set_reg("P1.087", data);//扭力回零准位 1~300% set_reg("P1.088", 1000);//扭力计时 2~2000ms set_reg("P5.004", 0x0109);//原点复归模式:超程反转, } //设置#编号和坐标 // 32bit //public void set_PR_坐标(ushort reg,UInt32 mode,UInt32 where) public void set_PR_坐标A(ushort reg, UInt32 where) { set_reg32bit("P6.002", 0x0032);//PATH# 1 定义 set_reg32bit ("P6.003", where);//32bit10进制 坐标 } public void set_PR_坐标B(ushort reg, UInt32 where) { set_reg32bit("P6.004", 0x00000032); set_reg32bit("P6.005", where); } //设置呼叫码段 PR# 0~99 public void set_io_POS_6_0(ushort data) { set_reg("P4.007", data);//0x1fff bit 12~0 对应输入开关 Di 13~0 } //设置呼叫执行 public void set_io_CTRG_run() {//上升沿触发 //set_reg("P4.007", data);//0x1fff bit 12~0 对应输入开关 Di 13~0 } //直接呼叫执行 PR# 1~99 public void set_PR_go(ushort num) { set_reg("P5.007", num); } //呼叫执行 PR# 0 回原点 public void set_PR_ZERO_go() {//机械回零操作 /* 这参数很重要,低于导轨最大受力值 */ set_reg("P1.087", 7);//16bit扭力回零准位 1~300% set_reg("P1.088", 1000);//16bit扭力计时 2~2000ms set_reg("P5.004", 0x0109);//16bit原点复归模式:超程反转, set_reg32bit("P5.005", 1000);//32bit第一段高速原点复归速度设定 set_reg32bit("P5.006", 200);//第二段低速原点复归速度设定 set_reg("P6.000", 0);//32bit原点复归定义 set_reg("P6.001", 0);//32bit原点定义值 set_reg("P5.007", 0);//bit16直接呼叫 #0 机械回零 } #endregion #region 监视 //AL.013 急停报警 // P0.001当前伺服报警 //P0.002=0~26 //0电机坐标PUU(理论坐标) P5.016 // //1位置命令的目前坐标PUU // //2位置命令与回授位置的差异值PUU // //3电机编码器目前回授的位置坐标Pulse(实际实时坐标) // //4位置命令的目前坐标Pulse // //5位置命令与回授位置的差异值,单位为编码器单位pulse // //6驱动器接收到脉冲命令的频率,单位为 kpps适用于 PT / PR 模式。 // //7电机目前转速 // //8由模拟信道输入的速度命令,单位为 0.01 伏特 // //9整合的速度命令,单位为 0.1 rpm。 // //10由模拟信道输入的扭力命令,单位为 0.01 伏特 // //11整合的扭力命令,单位为百分比(%)。 // //12平均负载率 // //13峰值负载率 // //14 DC Bus 电压 // //15负载惯量比 // //16 IGBT 温度 // //17 共振频率 // //18 与 Z 相偏移量范围为-4999 ~ +5000。 // //19映像参数内容# 1 // //20映像参数内容# 2 // //35分度坐标命令 // //38电池电压 // //39 DI 状态(整合) // //40 DO 状态(硬件) // //49脉冲命令(CN1)输入的脉冲计数值。 // //51电机目前实际速度 // // 54电机目前实际扭力 // //55电机目前实际电流 // //56整流后的电容器电压 // //67PR 目标速度 // //111驱动器伺服错误码 // //-124编码器温度 0.0.124 //============================================= public void read_报警故障码() {//故障码 read_reg("P0.001");//伺服当前故障码 } //编码器位置 public void read_codeing() {//编码器位置 read_reg32bit("P5.016");//轴位置-电机编码器 } public void look_电机位置() {//32bit //P5.016 //编码器位置 read_reg32bit("P5.016"); } //查看模拟量1输出 public void look_CH1() {//P0.003控制最大0x77 bit0是CH2功能设置 //p1.003 //p1.004 //p1.005 //P1.101 //P4.020偏移CH1校正mV //模拟速度输入P4.022 } //查看模拟量2输出 public void look_CH2() {//P0.003控制最大0x77 bit0是CH2功能设置 //P1.102 //P4.021偏移CH2校正mV //模拟扭矩输入P4.023 } #endregion #region 一般参数 public void init_一般参数() { //P1.001● 控制模式及控制命令输入源设定 //P1.002▲ 速度及扭矩限制设定 //P1.003 检出器脉冲输出极性设定 //P1.012 ~ //P1.014 内部扭矩指令 / 内部扭矩限制 1 ~3 // //P1.044▲ 电子齿轮比分子 (N1) //P1.045▲ 电子齿轮比分母 (M) //P1.046▲ 检出器输出脉冲数设定 //P1.055 最大速度限制 //P1.097▲ 检出器输出(OA, OB)分母 //P5.003 自动保护的减速时间 // //P5.020 ~ //P5.035 加 / 减速时间(编号#0 ~ 15) // //P5.016■ 轴位置-电机编码器 //P5.018 轴位置-脉冲命令 // //P1.000▲ 外部脉冲列输入型式设定 //P2.060 电子齿轮比分子(N2) //P2.061 电子齿轮比分子(N3) //P2.062 电子齿轮比分子(N4) //P5.008 软件极限:正向 //P5.009 软件极限:反向 //P6.002 ~ //P7.099 内部位置指令#1 ~ 99 //P5.060 ~ //P5.075 //内部位置指令控制#0 ~ 15 的移动速 //度设定 //P5.004 原点复归模式 //P5.005 第一段高速原点复归速度设定 //P5.006 第二段低速原点复归速度设定 //P5.007■ PR 命令触发缓存器 //P5.040 ~ // P5.055 //位置到达之后的 Delay 时间(编号 //#0 ~ 15) //P5.098 事件上缘触发 PR 程序编号 //P5.099 事件下缘触发 PR 程序编号 //P5.015■PATH#1 ~ PATH#2 数据断电不记忆设定 //P1.001● 控制模式及控制命令输入源设定 //P1.002▲ 速度及扭矩限制设定 //P1.003 检出器脉冲输出极性设定 //P1.046▲ 检出器输出脉冲数设定 } #endregion #region 外部 操作 //设置D0初始化 端子输出 public void set_io_DO_init() { // + 0x100是常开 // DO 1 端子定义101 电源 // DO 2 端子定义103 零速 // DO 3 端子定义109 原点复归完成, 坐标有效 // DO 4 4端子定义105 坐标到位信号(参数 P1.054 设定值) // DO 5 5端子定义007 伺服故障 // DO 6 端子定义100 关 set_reg("P2.018", 0);//DO 1端子定义101 电源 set_reg("P2.019", 0);//DO 2端子定义103 零速 set_reg("P2.020", 0);//DO 3端子定义109 原点复归完成, 坐标有效 set_reg("P2.021", 0);//DO 4端子定义105 坐标到位信号(参数 P1.054 设定值) set_reg("P2.022", 0);//DO 5端子定义007 伺服故障 set_reg("P2.041", 0);//DO 6端子定义100 关 0x100是常开 } public void jogu_正点动(UInt16 speed) { set_reg("P4.005", speed); //点动速度 set_reg("P4.007", 0x02 | 0x01); // DI2 DI1 } public void jogu_负点动(UInt16 speed) { set_reg("P4.005", speed); //点动速度 set_reg("P4.007", 0x04 | 0x01); // DI3 DI1 } #endregion #region 内部 操作 public void set_电子齿轮比(ushort a_分子, ushort b_分母) { set_reg("P1.044", a_分子);//16.777216 set_reg("P1.045", b_分母);// 0.1 } //设置DI初始化 开关量 端子输入 public void set_io_DI_init() { //极性和功能// | 0x100是常开 //DI1 ~ DI8: P2.010 ~ P2.017 //DI9 ~DI13: P2.036 ~ P2.040 //来源 //P3.006 输入接点(DI)来源控制开关 Bit 12 ~ Bit 0 对应至 DI13 ~ DI1; //0:输入接点状态由外部硬件端子控制。 //1:输入接点状态由系统参数 P4.007 控制。 //P4.007 bit对应开关状态 // // DI 1 P2.010 101 使能 常开 // DI 2 P2.011 137 正点动 // DI 3 P2.012 138 反点动 // DI 4 P2.013 117 力矩 // DI 5 P2.014 102 复位 // DI 6 P2.015 022 负限位 // DI 7 P2.016 023 正限位 // DI 8 P2.017 021 急停开关 常闭 // DI 9 P2.036 100 关 常开 // DI 10 P2.037 100 关 常开 // DI 11 P2.038 100 关 常开 // DI 12 P2.039 100 关 常开 // DI 13 P2.040 100 关 常开 //输入开关信号滤波 0~20ms set_reg("P2.009", 0);//开关过滤杂波 0~20 单位:ms 毫秒 //================================== set_reg("P3.006", 0x1FFF);//开关量来源0x1FFF(bit12~0) 0端子 1内部 P4.007 //===断电丢失============================= set_reg("P2.010", (ushort)io_in_功能.SON_伺服使能 | 0x100);//DI 1端子定义 01 DCBA:C(0:接常闭,1接常开)BA功能码 set_reg("P2.011", (ushort)io_in_功能.JOGU_正点动 | 0x100);//DI 2端子定义 set_reg("P2.012", (ushort)io_in_功能.JOGU_负点动 | 0x100);//DI 3端子定义 //set_reg("P2.013", 0);//DI 4端子定义 //set_reg("P2.014", 0);//DI 5端子定义 //set_reg("P2.015", 0);//DI 6端子定义 //set_reg("P2.016", 0);//DI 7端子定义 //set_reg("P2.017", 0);//DI 8端子定义 //set_reg("P2.036", 0);//DI 9端子定义 //set_reg("P2.037", 0);//DI 10端子定义 //set_reg("P2.038", 0);//DI 11端子定义 //set_reg("P2.039", 0);//DI 12端子定义 set_reg("P2.040", (ushort)io_in_功能.ARST_复位 | 0x100);//DI 13端子定义 } #endregion //设置使能 public void set_SON(bool start) { //set_reg(); } //读取外部输入 public void read_io_DI() { } #region 寄存器操作 // 1 获取参数寄存器编号 P3.002 =》 寄存器 0x0304 private ushort get_reg_获取寄存器地址(string reg) { //if (reg<0x07C8)//最大寄存器 if (reg.IndexOf(".") > 0) // "P5.016" 伺服电机坐标 { string hi = reg.Substring(reg.IndexOf(".") - 1, 1); // 5 string li = reg.Substring(reg.IndexOf(".") + 1); // 16 int hv = int.Parse(hi) * 0x0100; // 0x500 int lv = int.Parse(li) * 2; //32 0x20 ushort reg_NO = (ushort)(hv + lv); // 0x0520 return reg_NO; } return 0; } //====read========================================== //读单个寄存器 16bit public void read_reg(string reg) { rs485.Read_Reg(get_reg_获取寄存器地址(reg), 1); // 在寄存器地址,读1个寄存器 delay(delay_下位机数据帧);//等待命令执行,和数据上传 } //读32位寄存器 32bit public void read_reg32bit(string reg) { rs485.Read_Reg(get_reg_获取寄存器地址(reg), 2);//在寄存器地址,读2个寄存器 delay(delay_下位机数据帧);//等待命令执行,和数据上传 } //写单个寄存器(16bit) public void set_reg(string reg, ushort data) {// 16bit寄存器 rs485.Write_Reg(get_reg_获取寄存器地址(reg), data);//发送命令 delay(delay_下位机数据帧);//等待命令执行,和数据上传 } //写32位寄存器 public void set_reg32bit(string reg, uint data) { rs485.Write_Reg32bit(get_reg_获取寄存器地址(reg),data); delay(delay_下位机数据帧);//等待命令执行,和数据上传 } #endregion //io定义:端子定义 public enum io_in_功能 : ushort //1字节 { OFF = 0, SON_伺服使能 = 0x01, ARST_复位 = 0x02, GAINUP_增益倍率 = 0x03, CCLR_清除脉冲值 = 0x04, ZCLAMP_电机零速时停转 = 0x05, CMDINV_速度扭矩模式切换 = 0x06, //========================================================== CTRG_PR模式节拍_上升沿 = 0x08, // PR模式专用:与 POS 配合使用 //P5.007直接呼叫 TRQLM_限制扭矩 = 0x09, VPL_电机自闭模式 = 0x0C, VPRS_模拟位置指令清除 = 0x0D, SPDLM_限速 = 0x10, //============================= POS0_PR模式码段 = 0x11, POS1_PR模式码段 = 0x12, POS2_PR模式码段 = 0x13, POS3_PR模式码段 = 0x1A, POS4_PR模式码段 = 0x1B, POS5_PR模式码段 = 0x1C, POS6_PR模式码段 = 0x1E, ABSE_绝对位置模式 = 0x1D, ABSC_绝对位置置0 = 0x1F, SPD0_多段速切换 = 0x14, SPD1_多段速切换 = 0x15, TCM0_多段力矩切换 = 0x16, TCM1_多段力矩切换 = 0x17, S_P_速度位置模式 = 0x18, S_T_速度力矩模式 = 0x19, T_P_力矩位置模式 = 0x20, EMGS_急停开关 = 0x21, NL_负限位 = 0x22, PL_正限位 = 0x23, ORGP伺服原点 = 0x24, SHOM_执行回原点 = 0x27, //P5.004 PT_PR_模式切换 = 0x2B, JOGU_正点动 = 0x37, JOGU_负点动 = 0x38, EV1_事件1 = 0x39, EV2_事件2 = 0x3A, EV3_事件3 = 0x3B, EV4_事件4 = 0x3C, GNUM0_多段齿轮比 = 0x43, GNUM1_多段齿轮比 = 0x44, INHP_禁止脉冲 = 0x45,//必须DI4脚才能实时性 STP_电机停止 = 0x46, PFQS_急停速度 = 0x47 } //io定义:端子定义 public enum io_out_功能 : ushort //1字节 { SRDY_伺服上电 = 0x01, SON_伺服使能 = 0x02, ZSPD_零速 = 0x03, TSPD_超速 = 0x04, TPOS_到位 = 0x05, TQL_限扭 = 0x06, ALRM_故障 = 0x07, BRKR_刹车线 = 0x08, HOME_已回零 = 0x09, ABSW_绝对光栅故障 = 0x0D, IDXD_分度完成 = 0x0E, OLW_过负载 = 0x10, WARN_警告 = 0x11,//(正反极限、通讯异常、低电压、风扇异常) OVF_位置溢出 = 0x12, SNL_负限位 = 0x13, SPL_正限位 = 0x14, Cmd_ok_指令完成 = 0x15, CAP_OK_程序完成 = 0x16, MC_OK_指令和定位都完成 = 0x17, SP_OK_速度到达 = 0x19, Zon1 = 0x2C, Zon2 = 0x2D, Zon3 = 0x2E, Zon4 = 0x2F, SPO_0 = 0x30, //P4.006 bit0 输出 SPO_1 = 0x31, //P4.006 bit1 输出 SPO_2 = 0x32, //P4.006 bit2 输出 SPO_3 = 0x33, //P4.006 bit3 输出 SPO_4 = 0x34, //P4.006 bit4 输出 SPO_5 = 0x35, //P4.006 bit5 输出 SPO_6 = 0x36, //P4.006 bit6 输出 SPO_7 = 0x37, //P4.006 bit7 输出 SPO_8 = 0x38, //P4.006 bit8 输出 SPO_9 = 0x39, //P4.006 bit9 输出 SPO_A = 0x3A, //P4.006 bit10 输出 SPO_B = 0x3B, //P4.006 bit11 输出 SPO_C = 0x3C, //P4.006 bit12 输出 SPO_D = 0x3D, //P4.006 bit13 输出 SPO_E = 0x3E, //P4.006 bit14 输出 SPO_F = 0x3F, //P4.006 bit15 输出 ABSR, ABSD } //延时 private void delay(int i) { Thread.Sleep(i); } }}
using System;using System.Collections.Generic;using System.IO.Ports;using System.Linq;using System.Text;using System.Threading.Tasks;namespace help{ //1申明委托》委托命令 delegate void WT_UI_Show_String_CMD(string cmd);//ui显示发送命令 delegate void WT_TX_CMD(byte[] cmd);//其他能实现发送功能的对象 internal class Help_ModBus { public bool WT_是否使用委托 = false;//有硬件串口就不需要委托 Help_SerialPort RS485 = new Help_SerialPort();//硬件串口RS485 public Help_ModBus()//默认构造 { } //2定义委托对象(3绑定方法) public WT_UI_Show_String_CMD wt_ui_show_cmd { get; set; }//委托=》呼叫上ui层 让上层显示:发送命令 public WT_TX_CMD wt_tx_cmd { get; set; }//委托=》呼叫上ui层 让上层:发送命令 #region 设置站号 //设置站号 public byte address { get; set; } = 0x01;//默认01从站 #endregion //==read====================================== #region 读取 0x01 0x02 0x03 0x04 //功能码:01读输出的单线圈数量 //01 01 0000 0018 3C00 //表示01站 ,01功能码,第0000点开始 ,0018表示读24个线圈,3C00表示CRC校验 可以用串口助手16进制发送看效果 public void Read_io_out(UInt16 head, UInt16 num)//第n个线圈开始,线圈数量 { string addr = address.ToString("X2");//从站 01 string cmd = addr + "01"//功能码 01 //读输出线圈 + head.ToString("X4")//偏移量 0000 + num.ToString("X4");//线圈数量 0018 string stringcmd = StringCMD(cmd);//带CRC的完整命令 if (WT_是否使用委托) { wt_ui_show_cmd(stringcmd);//显示发送命令 wt_tx_cmd(TxCMD(stringcmd));//发送命令 } else { RS485.TX_发送命令(TxCMD(stringcmd)); } } //功能码:02 读输入开关量 //01 02 00 00 00 14 78 05 //表示01站 ,02功能码,第0000点开始 ,0014表示读20个开关,7805表示CRC校验 可以用串口助手16进制发送看效果 public void Read_io_in(UInt16 head, UInt16 num)//第n个开关开始,开关数量 { string addr = address.ToString("X2");//从站 01 string cmd = addr + "02"//功能码 02 //读输入开关 + head.ToString("X4")//偏移量 0000 + num.ToString("X4");//开关数量 0014 string stringcmd = StringCMD(cmd);//带CRC的完整命令 if (WT_是否使用委托) { wt_ui_show_cmd(stringcmd);//显示发送命令 wt_tx_cmd(TxCMD(stringcmd));//发送命令 } else { RS485.TX_发送命令(TxCMD(stringcmd)); } } //功能码:03 读寄存器 //01 03 00 00 00 1D 85 C3 //表示01站 ,03功能码,第0000个寄存器开始 ,001D表示读29个寄存器,85C3表示CRC校验 public void Read_Reg(UInt16 head, UInt16 num)//第n个保持寄存器开始,寄存器数量(n*16bit) {//num=2;会返回32bit,因为1个寄存器是16bit string addr = address.ToString("X2");//从站 01 string cmd = addr + "03"//功能码 03 // 读寄存器 + head.ToString("X4")//偏移量 0000 + num.ToString("X4");//寄存器数量 001D string stringcmd = StringCMD(cmd);//带CRC的完整命令 if (WT_是否使用委托) { wt_ui_show_cmd(stringcmd);//显示发送命令 wt_tx_cmd(TxCMD(stringcmd));//发送命令 } else { RS485.TX_发送命令(TxCMD(stringcmd)); } } //功能码:04 读采集寄存器 AD模块 //01 04 00 13 00 01 C0 0F // 0013表示第19个寄存器开始,0001表示读取1个寄存器值 public void Read_Reg_ADC(UInt16 head, UInt16 num) { string addr = address.ToString("X2");//从站 01 string cmd = addr + "04"//功能码 04 //模拟量采集值 + head.ToString("X4")//偏移量 0013 + num.ToString("X4");//寄存器数量 0001 string stringcmd = StringCMD(cmd);//带CRC的完整命令 if (WT_是否使用委托) { wt_ui_show_cmd(stringcmd);//显示发送命令 wt_tx_cmd(TxCMD(stringcmd));//发送命令 } else { RS485.TX_发送命令(TxCMD(stringcmd)); } } #endregion //==writer====================================== #region 写入 0x05 0x06 0x0F 0x10 //01 05 00 01 FF 00 DD FA //0001表示D1线圈,FF00表示打开(0000表示关闭) //打开单个io //功能码:05 public void Set_io(UInt16 io) { string addr = address.ToString("X2");//从站地址:1字节 string cmd = addr //从站编号 + "05" // 05 设置输出线圈 + io.ToString("X4") // 0001 线圈编号 + "FF00";//打开 //开关设置 : FF00 开 0000 关 string stringcmd = StringCMD(cmd);//带CRC的完整命令 //4呼叫委托 if (WT_是否使用委托) { wt_ui_show_cmd(stringcmd);//显示发送命令 wt_tx_cmd(TxCMD(stringcmd));//发送命令 } else { RS485.TX_发送命令(TxCMD(stringcmd)); } } //01 05 00 01 00 00 9C 0A //关闭D1线圈 //关闭单个io //功能码:05 public void Rest_io(UInt16 io) { string addr = address.ToString("X2"); string cmd = addr //从站编号 + "05" // 05 设置输出线圈 + io.ToString("X4") // 0001 线圈编号 + "0000";//关闭 //开关设置 : FF00 开 0000 关 string stringcmd = StringCMD(cmd);//带CRC的完整命令 if (WT_是否使用委托) { wt_ui_show_cmd(stringcmd);//显示发送命令 wt_tx_cmd(TxCMD(stringcmd));//发送命令 } else { RS485.TX_发送命令(TxCMD(stringcmd)); } } //01 06 00 01 AB CD 66 AF //设置0001寄存器值是0xABCD //功能码:06 写单个寄存器 public void Write_Reg(UInt16 reg, UInt16 data)//默认16bit//写寄存器(寄存器号,数值) {//06码只能设置16bit值 string addr = address.ToString("X2");//限制字符串宽度 string cmd = addr //从站编号 "01" + "06" // 06 设置单个寄存器 + reg.ToString("X4") // 0001 寄存器编号 + data.ToString("X4"); // ABCD 数据 string stringcmd = StringCMD(cmd);//带CRC的完整命令 if (WT_是否使用委托) { wt_ui_show_cmd(stringcmd);//显示发送命令 wt_tx_cmd(TxCMD(stringcmd));//发送命令 } else { RS485.TX_发送命令(TxCMD(stringcmd)); } } public void Write_Reg32bit(UInt16 reg, uint data) {//06功能码只能写16bit, 所以用10功能码写32bit //Convert. byte[] buffer = new byte[4]; buffer[0] = (byte)(data >> 8); // 0H 第1个寄存器的高字节 buffer[1] = (byte)(data & 0xff); // 0L 第1个寄存器的低字节 buffer[2] = (byte)(data >> 24); // 1H 第2个寄存器的高字节 buffer[3] = (byte)(data >> 16); // 1L 第2个寄存器的低字节 //=====//写32bit寄存器============================== Write_Regs(reg, 2, buffer);//ok } //功能码:0F 写多个线圈 //写io(起始位,线圈数量,状态值) public void Write_io(UInt16 head, UInt16 num, byte[] data) {//01 0F 0000 0004 01 F0 3E D2 // 第0000个线圈开始,0004表示只修改4个线圈,01表示发送1个字节 F0表示字节值 3ED2表示CRC校验码。 string addr = address.ToString("X2"); string cmd = addr + "0F" + head.ToString("X4")//偏移量 + num.ToString("X4")//线圈数量 + data.Length.ToString("X2")//数据长度 + BytesToHexStrings(data);//数据值 string stringcmd = StringCMD(cmd);//带CRC的完整命令 if (WT_是否使用委托) { wt_ui_show_cmd(stringcmd);//显示发送命令 wt_tx_cmd(TxCMD(stringcmd));//发送命令 } else { RS485.TX_发送命令(TxCMD(stringcmd)); } } //功能码:10 写多个寄存器 //写io(寄存器号,值) public void Write_Regs(UInt16 head, UInt16 num, byte[] data)// 寄存器号,寄存器数量,数值 { //01 10 0005 0001 02 00 03 E6 04 // 从 0005寄存器开始(断网保护寄存器)0001表示只修改一个寄存器,02表示要发送2字节 0003表示2字节的值,这样断网超过3秒线圈就复位。 //01 10 0005 0001 02 07 08 A5 F3 //0005寄存器断网保护超过1800秒就失效。0708表示1800秒。 string addr = address.ToString("X2");//从站 01 string cmd = addr + "10"//功能码 10 // 写多个寄存器 + head.ToString("X4")//偏移量 0005 //寄存器地址 + num.ToString("X4")//寄存器数量 0001 // 寄存器数量 + data.Length.ToString("X2")//数据字节 02 //字节数量 + BytesToHexStrings(data);//数据值 // 0H 0L 1H 1L 2H 2L 3H 3L。。。。 string stringcmd = StringCMD(cmd);//带CRC的完整命令 if (WT_是否使用委托) { wt_ui_show_cmd(stringcmd);//显示发送命令 wt_tx_cmd(TxCMD(stringcmd));//发送命令 } else { RS485.TX_发送命令(TxCMD(stringcmd)); } } #endregion #region 文本处理 #region 字符串转等效数组 public byte[] StringsToHexBytes(string data)//change转换,string等效的byte[] { //清除所有空格 string str = data.Replace(" ", ""); //若字符个数为奇数,补一个0 str += str.Length % 2 != 0 ? "0" : ""; byte[] bytes = new byte[str.Length / 2];//用于返回结果 for (int i = 0, c = bytes.Length; i < c; i++)//获取bytes值 { bytes[i] = Convert.ToByte(str.Substring(i * 2, 2), 16); } return bytes; } #endregion #region 数组转等效字符串 public string BytesToHexStrings(byte[] data)//change转换 , byte[ ]等效的string { string str = string.Empty; for (int i = 0; i < data.Length; i++) { str += data[i].ToString("X2"); } return str; } #endregion #region 数组计算CRC public byte[] getCRC16(byte[] bytes, bool b)//数组,端向,默认flase小端 { int len = bytes.Length; if (len > 0) { ushort crc = 0xFFFF; for (int i = 0; i < len; i++) { crc = (ushort)(crc ^ (bytes[i])); for (int j = 0; j < 8; j++) { crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ 0xA001) : (ushort)(crc >> 1); } } byte hi = (byte)((crc & 0xFF00) >> 8); //高位置 byte lo = (byte)(crc & 0x00FF); //低位置 if (b)//端向 { return new byte[] { hi, lo };//大端 } else {//默认小端 return new byte[] { lo, hi, };//小端 } } return new byte[] { 0, 0 }; } #endregion #region StringCMD public string StringCMD(string data)//转换 带CRC的命令(用于ui查看) { return data + BytesToHexStrings(getCRC16(StringsToHexBytes(data), false));//命令+CRC } #endregion #region TxCMD public byte[] TxCMD(string data)//change转换 串口发送命令 { data.Replace(" ", "");//去除空白 byte[] buffer = StringsToHexBytes(data); return buffer;//TX的 } #endregion #endregion }}
using help;using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;namespace cnc._2ui{ public partial class B3_伺服调试 : Form { Help_Delta_B3 b3 = new Help_Delta_B3(); Help_SerialPort help_SerialPort = new Help_SerialPort(); Help_String help_string = new Help_String(); public B3_伺服调试() { InitializeComponent(); //Help_SerialPort.serialPort1.DataReceived += SerialPort1_DataReceived; //Help_SerialPort.wt_串口接收事件 += show; } //private void SerialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) //private void show(string data) //{ // this.Invoke(new Action(() => // { // this.Text = data;//显示出接收的消息 // } // )); //} //初始化 private void button1_Click(object sender, EventArgs e) { b3.init_B3_regs();//站号7f } private void button2_Click(object sender, EventArgs e) { b3.set_io_DI_init(); } private void button3_Click(object sender, EventArgs e) {//使能 //接常闭 (断线为有效)SON_伺服使能 //b3.set_reg("P2.010", (ushort)(io_in_功能.SON_伺服使能 ));//DI 1端子定义 01 DCBA:C(0:接常闭,1接常开)BA功能码 //b3.set_reg("P2.010", 0x01);//bit0 使能 b3.set_reg("P4.007", 0x01); } private void button4_Click(object sender, EventArgs e) {//脱机 //接常开 通电为有效 SON_伺服使能 //b3.set_reg("P2.010", (ushort)io_in_功能.SON_伺服使能 + 0x100);//DI 1端子定义 01 DCBA:C(0:接常闭,1接常开)BA功能码 //b3.set_reg("P2.010", 0x00);//bit0 使能 b3.set_reg("P4.007", 0x00); } private void button5_Click(object sender, EventArgs e) {//正转 b3.set_reg("P4.007", 0x02 | 0x01); } private void button7_Click(object sender, EventArgs e) {//停 b3.set_reg("P4.007", 0x01); } private void button6_Click(object sender, EventArgs e) {//反转 b3.set_reg("P4.007", 0x04 | 0x01); } private void button8_Click(object sender, EventArgs e) {//PR模式初始化 b3.PR_init_PR模式初始化(); } private void B3_伺服调试_Load(object sender, EventArgs e) { b3.set_address_站号(0x7f); c_串口1.s_波特率 = "38400"; //c_串口1.s_校验位 = 1; c_串口1.s_停止位 = 2; } private void button9_Click(object sender, EventArgs e) {//复位 b3.set_reg("P4.007", 1<<12); } private void button10_Click(object sender, EventArgs e) {//报警:故障码 b3.read_reg("P0.001"); } private void button11_Click(object sender, EventArgs e) {//恢复出厂 b3.set_reg("P2.008",10); } private void button12_Click(object sender, EventArgs e) { b3.look_电机位置(); } private void button13_Click(object sender, EventArgs e) {//寻零 //b3.set_PR_go(0); b3.set_PR_ZERO_go(); } private void button14_Click(object sender, EventArgs e) {//# 1坐标 b3.set_PR_坐标A(1, uint.Parse(textBox1.Text)); } private void button15_Click(object sender, EventArgs e) {//# 1坐标 b3.set_PR_坐标B(1, uint.Parse(textBox2.Text)); } private void button16_Click(object sender, EventArgs e) { b3.set_PR_go(1); } private void button17_Click(object sender, EventArgs e) { b3.set_PR_go(2); } }}
using System;using System.Collections.Generic;using System.IO.Ports;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;namespace help{ //====1定义委托============================================ public delegate void WT_串口接收事件(string data); public delegate void WT_发送命令事件(string data); public class Help_SerialPort { //====2生成属性========================================= public static WT_串口接收事件 wt_串口接收事件;//静态委托 public static WT_发送命令事件 wt_串口发送事件; public static SerialPort serialPort1 = new SerialPort();// 串口控件 public string read_下位机数据; public Help_String help_string = new Help_String(); public Help_SerialPort() { serialPort1.DataReceived += SerialPort1_DataReceived;//绑定一个委托 }//串口接收事件 private void SerialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) { //throw new NotImplementedException(); int length = Help_SerialPort.serialPort1.BytesToRead; byte[] buffer = new byte[length]; Help_SerialPort.serialPort1.Read(buffer, 0, length);//加载数据 //wt_rx(help_string.BytesToHexStrings(buffer));//显示接收数据 //string data= Encoding.UTF8.GetString(buffer);//显示接收数据 string data = help_string.BytesToHexStrings(buffer); if (data.Length>0) { read_下位机数据 = data;//保存下位机接收的数据 wt(data);//接收的数据呼叫上层ui } } public void TX_发送数据(byte[] data)//发送 { try { serialPort1.Write(data, 0, data.Length); } catch (Exception ex) { MessageBox.Show(ex.ToString());//显示错误 throw; } } public void TX_发送数据(string data)//发送 { try { byte[] buffer = Encoding.Default.GetBytes(data); Help_SerialPort.serialPort1.Write(buffer, 0, buffer.Length); } catch (Exception ex) { MessageBox.Show(ex.ToString());//显示错误 throw; } } public void TX_发送命令(byte[] buffer)//发送 {//RS485专用 try {//显示发送的命令 wt_串口发送事件(help_string.BytesToHexStrings(buffer)); Help_SerialPort.serialPort1.Write(buffer, 0, buffer.Length); } catch (Exception ex) { MessageBox.Show(ex.ToString());//显示错误 throw; } } //呼叫委托 public void wt(string data) { //====3呼叫委托=========================== wt_串口接收事件(data); } }}