台达伺服PR模式

伺服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使用非轴卡,3使用台达轴卡DMCNET
        //P3. 002   =    0x0006    DCBA:A:(6:8n2(RTU8位无校验2停止)
        //                                //(7:8E1(RTU8位E偶校验1停止)
        //                                //(8:8O1(RTU数据位8,奇检验odd,停止位1)
        //P3. 003   =    0x0000    DCBA:A:(0:警告并继续运转)
        //                                //(1:通信故障处理:警告并减速(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恢复出厂:从站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", 0x0008);//寄存器,数值   P3. 0      8奇1
            set_reg("P3.003", 0x0001);//寄存器,数值   P3. 0      警告并减速
            set_reg("P3.004", 0x0000);//寄存器,数值   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", 0x0201);//寄存器,数值   P3. 001    波特率9600
            //set_reg("P3.002", 0x0008);//寄存器,数值   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);//默认1042  定义(1092:1us滤波,方向+脉冲)
            set_reg("P1.001", 0x0001);//PR模式,io不切换,电机方向正
            //set_reg("P1.001", 0x1009);//PR+T模式,io切换,电机方向正,停机扭矩是0
            set_reg("P1.002", 0x0000);//开启扭矩限制(必须关闭)//力矩值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", 0x0000);//电机刹车方式: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);
        }

    }
}

  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值