伺服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 重新上电恢复出厂设置(出厂为 站号7F,波特率38400,n82 ) //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使用非轴卡,使用台达轴卡DMCNET //P3. 002 = 0x0006 DCBA:A:(6:8n2(RTU8校验2停止8人。 // //(7:8E1(RTU8位E偶校验1停止。 // //(8:8O1(RTU数据位8,奇检验odd,停止位1) //P3. 003 = 0x0000 DCBA:A:(0:警告并继续运行) // //(P5.003) //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位是开关的功能第3位是控制接常开还是常闭 //P4. 007 = 00E0 bit对应软开关DI 0x0011(表示sdi5和sdi1为ON,软开关总共0x1fff)控制输入13个开关 //P3. 007 = 0x0001 通信延迟回复 0.5ms单位 //初始化B3 public void init_B3_regs()///初始化B3伺服 //这功能需要手动配置 {//伺服P2.008=0x0010恢复出厂:从站00x7f,波特率38400,RTU模式,8数据,无校验,2停止位置 ///改变站号 //rs485.address = 0x7f; //set_reg("P3.000", 0x00寄存器,数值 P3. 000 站号01 //set_reg("P3.001", 0x0201) P3. 001 波特率9600 //set_reg("P3.002", 0x008);/数值 P3. 0 8奇1 set_reg("P3.003", 0x0001) P3. 0 警告并减速 set_reg("P3.004", 0x//寄存器,数值 P3. 004 断开通信时报警 单位:秒 set_reg("P3.006", 0x01FFF);//寄存器,值 P3. 006 DI输入端子选择,0:外部端子 1.控制内部寄存器 P4.007决定,Bit 0 ~Bit 7 对应至 DI1 ~DI8(P2.010~P2.017) set_reg("P3.007", 0x0000);/值 P3. 007 通信延迟回复 单位:0.5ms //set_reg("P3.000", 0x0001) P3. 000 站号01 //rs485.address = 0x01; //set_reg("P3.001", 0x//寄存器,数值 P3. 001 波特率9600 //set_reg("P3.002", 0x008);/数值 P3. 0 8奇1 } #region PR# 模式 ///输入开关信号 public void set_io_DI(ushort start)//0x1fff { set_reg("P4.007", start);//0x1fff bit 12~0 对应输入开关 Di 13~0 } public void PR_init_PR模型初始化() { //伺服模式 //P5.004=0x0109 原点回归模式 //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) 定义(1092:1us滤波,方向 脉冲) 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);
}
}
}