找回密码
 立即注册
查看: 1196|回复: 52

PLC 实战, 让你的STC32变成FX3U-PLC, 教程(一)建立连接

[复制链接]
  • TA的每日心情
    开心
    5 天前
  • 签到天数: 90 天

    [LV.6]常住居民II

    38

    主题

    986

    回帖

    6773

    积分

    荣誉版主

    冲哥视频教程和各种开源资料QQ交流群884047237,可群

    积分
    6773
    QQ
    发表于 2024-4-7 09:41:19 | 显示全部楼层 |阅读模式
    PLC 实战, STC32 变成 FX3U-PLC
    PLC, 教程(一), 建立连接
    前言   首先在开始之前我们得先知道什么是FX3U。
    截图202403192131427390.jpg

        百度百科里对他是这么定义的,说白了他就是一个集成了一些常用的外设(例如adc,dac,串口等)的带驱动程序的一个控制器,我们只需要用梯形图或相对应的语言就可以快速的开发(下图是一个端口闪烁的程序,只需要一行即可轻松完成一个闪烁,换成单片机的话,我们抛开新建工程那些步骤,还需要初始化端口,还需要通过延时或者实际做端口取反,但是PLC里这些常见的底层代码都已经做好了,只需要用图形进行调用即可,该软件为GX Developer 8.86,因为这个软件的特殊性,就不在论坛放安装包了,直接在Q群文件下载即可)
    截图202403192143055858.jpg


    对于一些复杂的功能来说他可以快速的帮助我们开发,但是他也会存在一些缺点。
    区别对比
    单片机
    PLC
    硬件
    裸芯片(外围电路全部需要自己搭建,可以自由扩展)
    常用的外围电路全部集成,只需要接线即可(功能单一)
    成本
    价格低,可以按照需求自由搭建
    成本高,甚至很多都是进口
    开发难度
    绝大多数都是C语言开发,需要一定语言基础
    可以用梯形图开发,掌握了逻辑和方法一天就能快速上手
    可靠性
    对软件和硬件的设计要求极高,一般人设计的并不稳定
    大品牌的都已经在无数场合应用且相对可靠


        其实说了这么多不难看出,其实对于有能力的人来说,单片机加上外围电路,在设计好底层的驱动,就可以作为一个PLC了,这就诞生了我们这一个系列章节的主题,用STC32去仿一个PLC,这里我们也叫工控板(后文均用工控板一词代替PLC)。
        当然,其实市面上PLC非常的多,有很多的系列,这里着重以FX系列的这一款来分析。

    一、原理分析
        截图202403192159335325.jpg
        首先,用过FX系列的的小伙伴可能都知道,这个型号基本都可以通过这个RS232下载程序,而232的本质就是就是串口,所以很明显我们只需要通过单片机的一个串口就可以轻松的实现我们的工控板教程了。

        其次我们还需要知道这个软件和工控板之间是怎么连接的。点击上图的按钮,在点开一个串口监控软件,在进行如下配置,去监控一下串口连接的过程,我们很轻易就可以实现连接。
    截图202404070828358063.jpg
    经过监控,可以发现数据的内容如下图所示:
    截图202404070830101432.jpg

    应答过程分为如下几步:
    1.上位机发送05
    2.下位机回应06
    3.上位机发送02 30 30 45 30 32 30 32 03 36 43
    4.下位机回应02 41 38 35 45 03 46 36

    5.上位机发送02 30 30 45 43 41 30 32 03 38 45
    6.下位机回应02 36 38 33 46 03 45 41


    7.上位机发送02 30 30 45 30 32 30 32 03 36 43
    8.下位机回应02 41 38 35 45 03 46 36

    9.上位机发送02 30 30 45 43 41 30 32 03 38 45
    10.下位机回应02 36 38 33 46 03 45 41


    上面的上位机就是gx的软件,下位机就是代指工控板,经过如上的几步即可实现让GX将工控板识别为FX3U
    截图202404070833596376.jpg


    二、代码实现
    1.因为代码工作量非常庞大,所以这里第一步需要STC的芯片设置为仿真芯片(注意这里主频设置为22.1184Mhz),然后这里用LINK的第二组串口作为下载的串口,硬件连接如下图所示,设置为仿真芯片的过程见如下帖子:https://www.stcaimcu.com/forum.php?mod=viewthread&tid=324
    截图202404070846285434.jpg

    LINK1D的下载口直接插板子的下载口,link上的S-TXD接STC的P1.1,S-RXD接板子上的P1.0。

    2.编写串口代码,由于stc32g有串口的发送/接收DMA,这里直接用DMA实现收发,虽然这一版没有串口超时中断,但是我们还是可以用软件模拟的方式来实现超时检测,具体代码实现参考试验箱的这个代码即可,这里简单带过
    截图202404070851301690.jpg

    这里的DMA的代码主要分为如下几步:
    (1)串口初始化
    1. void InitHardUart(void)
    2. {
    3.     T2R = 0;                //Timer stop
    4.     T2_CT = 0;        //Timer2 set As Timer
    5.     T2x12 = 1;        //Timer2 set as 1T mode
    6.     T2H = (u8)((65536 - MAIN_Fosc / Baudrate2 / 4) / 256);
    7.     T2L = (u8)((65536 - MAIN_Fosc / Baudrate2 / 4) % 256);
    8.     ET2 = 0;    //禁止中断
    9.     T2R = 1;                //Timer run enable
    10.    
    11.     S2CFG |= 0x01;     //使用串口2时,W1位必需设置为1,否则可能会产生不可预期的错误
    12.     S2CON = (S2CON & 0x3f) | 0xc0;    //UART2模式, 0x00: 同步移位输出, 0x40: 8位数据,可变波特率, 0x80: 9位数据,固定波特率, 0xc0: 9位数据,可变波特率
    13.     ES2   = 1;         //允许中断
    14.     S2REN = 1;         //允许接收
    15.     S2_S  = 0;         //UART2 switch to: 0: P1.0 P1.1,  1: P4.6 P4.7
    16.     DMA_UR2T_CFG = 0x80;                //bit7 1:Enable Interrupt
    17.     DMA_UR2T_STA = 0x00;
    18.     DMA_UR2T_AMT = 0x10;                //设置传输总字节数(低8位):n+1
    19.     DMA_UR2T_AMTH = 0x00;                //设置传输总字节数(高8位):n+1
    20.     DMA_UR2T_TXAH = (u8)((u16)&g_tUart2.g_TxBuf >> 8);
    21.     DMA_UR2T_TXAL = (u8)((u16)&g_tUart2.g_TxBuf);
    22. //                DMA_UR2T_CR = 0xc0;                        //bit7 1:使能 UART1_DMA, bit6 1:开始 UART1_DMA 自动发送
    23.     DMA_UR2R_CFG = 0x80;                //bit7 1:Enable Interrupt
    24.     DMA_UR2R_STA = 0x00;
    25.     DMA_UR2R_AMT = 0xFF;                //设置传输总字节数(低8位):n+1
    26.     DMA_UR2R_AMTH = 0xFF;                //设置传输总字节数(高8位):n+1
    27.     DMA_UR2R_RXAH = (u8)((u16)&g_tUart2.g_RxBuf >> 8);
    28.     DMA_UR2R_RXAL = (u8)((u16)&g_tUart2.g_RxBuf);
    29.     DMA_UR2R_CR = 0xa1;                        //bit7 1:使能 UART1_DMA, bit5 1:开始 UART1_DMA 自动接收, bit0 1:清除 FIFO
    30.     g_tUart2.com  = COM2;             // 端口号
    31.     g_tUart2.baud = Baudrate2;       // 波特率
    32.    
    33.     g_tUart2.txBufSize = TX_length;        // 发送缓冲区大小
    34.     g_tUart2.rxBufSize = RX_length;        // 接收缓冲区大小
    35.     g_tUart2.rxCnt = 0;                                                // 接收到的新数据个数
    36.     g_tUart2.txCnt = 0;                                                  // 待发送的数据个数
    37. //                g_tUart2.SendBefor = 0;                                                // 发送数据前的回调函数
    38. //                g_tUart2.SendOver = 0;                                                // 发送完毕后的回调函数
    39.     g_tUart2.ReciveNew = 0;                                                // 接收到新数据后的回调函数
    40.    
    41.     g_tUart2.txflag = 1;
    42.     g_tUart2.rxflag = 0;
    43.     g_tUart2.timeout =0;        
    44. }
    复制代码
    先配置串口的波特率和定时器,在配置接收DMA和发送的DMA,最后清空串口数组的数据,这里需要注意的是串口的发送和接收缓冲区必须设置为XDATA区域,否则会出现不可预知的错误。

    (2)系统时钟配置
    1. void Timer0_Init(void)                //1毫秒@22.1184MHz
    2. {
    3.         AUXR |= 0x80;                        //定时器时钟1T模式
    4.         TMOD &= 0xF0;                        //设置定时器模式
    5.         TL0 = 0x9A;                                //设置定时初始值
    6.         TH0 = 0xA9;                                //设置定时初始值
    7.         TF0 = 0;                                //清除TF0标志
    8.         TR0 = 1;                                //定时器0开始计时
    9.         ET0 = 1;                                //使能定时器0中断
    10. }
    复制代码
    这里配置了一个1ms的定时器,用来做串口超时的判断

    (3)串口收发代码配置(注意串口需要设置为7-E-1,波特率9600)
    1.     if( Time_Run_Last!=Time_Run  )
    2.     {
    3.         if(Usart_RecCheck(&g_tUart2,Time_Run-Time_Run_Last)==2)
    4.         {
    5.             length = Usart_RecLength(&g_tUart2);
    6.             
    7.             Usart_Send(&g_tUart2,&g_tUart2.g_RxBuf[0],length);
    8.             Usart_RecSet(&g_tUart2,200);
    9.         }
    10.         
    11.         if( Time_Run>5000 )                                                                                                //时间点间隔处理
    12.             Time_Run -=5000;        
    13.         Time_Run_Last = Time_Run;
    14.     }
    复制代码
    这里判断串口接收成功,就获取串口接收到的数据长度(因为串口接收DMA只有到达设定长度的数据才会触发DMA中断,所以这里要手动获取长度),接收到的数据都保存在了串口数组comm_port.g_RxBuf里,这几切记读取一次之后需要清除数据才能接收下一次的数据,不然数据会一直叠加上去。

    (4)通信数据判断
    从上面的代码不难看出,上位机发送的第一个指令05就是通信的指令,这个指令明显和别的不太一样,别的都是02开头,03结尾,这个只有个孤零零的05,所以这个指令单独处理,上位机发送05过来,就直接给他回个06
    1.             //--------------------------检测CPU指令--------------------------
    2.             if(( length==1 )&&( comm_port.g_RxBuf[0] == 0x05 ))
    3.             {
    4.                 comm_port.g_TxBuf[0] = 0x06;
    5.                 comm_port.txCnt =1;
    6.             }
    复制代码

    其次,下面的两个型号识别指令,
    1.             //--------------------------检测通信指令--------------------------
    2.             if(( length>2 )&&( comm_port.g_RxBuf[length-3]==0x03 )) //判断传送结束
    3.             {
    4.                 sum = CheckSum( comm_port.g_RxBuf,length );
    5.                                 if((comm_port.g_RxBuf[length -2] == Ascll[sum/0x10])&&(comm_port.g_RxBuf[length-1] == Ascll[sum%0x10]))// 计算数据和状态 数据是否正常
    6.                                 {                 
    7.                                         Process_switch2();
    8.                                 }
    9.                                 else            //错误应答
    10.                                 {
    11.                                         comm_port.g_TxBuf[0] =0x15;
    12.                                         comm_port.txCnt =1;
    13.                                 }               
    14.             }
    复制代码
    先判断这个接收到的数据包是否是02开头,03结尾,其次校验数据包,校验正确在执行,错误的话直接发送一个15返回。
    校验正确的话,在吧数据转化下格式,
    1. void switch_read_data2(void)
    2. {
    3.         u16 temp;
    4.         for(temp=2; temp<(length -4); temp++)
    5.         {
    6.                 comm_port.g_TxBuf[temp/2]=hex[comm_port.g_RxBuf[temp]]*0x10;
    7.                 comm_port.g_TxBuf[temp/2]+=hex[comm_port.g_RxBuf[temp+1]];
    8.                 temp++;
    9.         }
    10. }
    复制代码
    接收到的数据转为程序数据,即ascll转为hex数据,例如02 30 30 45 30 32 30 32 03 36 43这个命令执行完就是comm_port.g_TxBuf[1]=0X0E, comm_port.g_TxBuf[2]=0X02


    然后再来判断这个命令的功能,
    1. void PC_READ_byte2(void)           //读字
    2. {
    3.         u16 prog_address =comm_port.g_TxBuf[1]*0x100 +comm_port.g_TxBuf[2];     //计算数据操作起始地址
    4.         switch(prog_address)
    5.         {
    6.         case 0x0ECA:
    7.             read_plc_tyte2(101);
    8.             break;,
    9.             
    10.         case 0x0E02:
    11.             read_plc_tyte2(1);
    12.             break;
    13.             
    14.         default:
    15. //            read_other_data2();
    16.             break;
    17.         }
    18. }
    复制代码
    还是以02 30 30 45 30 32 30 32 03 36 43为例,执行完数据格式转换之后comm_port.g_TxBuf[1]=0X0E, comm_port.g_TxBuf[2]=0X02,这里prog_address 就是0x0e02,直接读取内部存储的一个数据返回即可,这数据就是类似于识别码的一个指令,直接手动填入即可

    至此这个识别的过程就完成了。需要源代码的小伙伴群文件下载即可,有问题的小伙伴欢迎帖子下面留言~
    开源不易,禁止商用!



    1 喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香!
    回复 送花

    使用道具 举报

  • TA的每日心情
    擦汗
    19 小时前
  • 签到天数: 69 天

    [LV.6]常住居民II

    11

    主题

    389

    回帖

    1135

    积分

    金牌会员

    积分
    1135
    发表于 2024-4-7 09:47:34 | 显示全部楼层
    我是第一个来的??
    开贴大吉,开始学习!
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    5 天前
  • 签到天数: 51 天

    [LV.5]常住居民I

    2

    主题

    148

    回帖

    191

    积分

    注册会员

    积分
    191
    发表于 2024-4-7 10:04:10 | 显示全部楼层
    学习了
    回复 送花

    使用道具 举报

  • TA的每日心情
    开心
    11 小时前
  • 签到天数: 158 天

    [LV.7]常住居民III

    0

    主题

    46

    回帖

    259

    积分

    中级会员

    积分
    259
    发表于 2024-4-7 10:27:08 | 显示全部楼层
    厉害了,是不是我下载上你的工控板建立连接的程序,就可以直接用三菱的那个梯形图来编程了啊,牛

    点评

    三菱的t型图下载马上更新,最后可以当三菱的plc来用这个板子  详情 回复 发表于 2024-4-7 10:37
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    5 天前
  • 签到天数: 90 天

    [LV.6]常住居民II

    38

    主题

    986

    回帖

    6773

    积分

    荣誉版主

    冲哥视频教程和各种开源资料QQ交流群884047237,可群

    积分
    6773
    QQ
     楼主| 发表于 2024-4-7 10:37:54 | 显示全部楼层
    yinds 发表于 2024-4-7 10:27
    厉害了,是不是我下载上你的工控板建立连接的程序,就可以直接用三菱的那个梯形图来编程了啊,牛 ...

    三菱的t型图下载马上更新,最后可以当三菱的plc来用这个板子
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    5 天前
  • 签到天数: 70 天

    [LV.6]常住居民II

    2

    主题

    90

    回帖

    544

    积分

    高级会员

    积分
    544
    发表于 2024-4-7 11:22:49 | 显示全部楼层
    坐等大神最终作品
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    11 小时前
  • 签到天数: 112 天

    [LV.6]常住居民II

    1

    主题

    76

    回帖

    319

    积分

    中级会员

    积分
    319
    发表于 2024-4-7 12:08:45 | 显示全部楼层
    学习学习,谢谢!
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    3 天前
  • 签到天数: 137 天

    [LV.7]常住居民III

    4

    主题

    32

    回帖

    620

    积分

    高级会员

    积分
    620
    发表于 2024-4-7 12:13:15 | 显示全部楼层
    有没有原文件分享的

    点评

    软件什么的群文件下载  详情 回复 发表于 2024-4-7 12:50
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    慵懒
    19 小时前
  • 签到天数: 59 天

    [LV.5]常住居民I

    0

    主题

    184

    回帖

    366

    积分

    中级会员

    积分
    366
    发表于 2024-4-7 12:26:06 | 显示全部楼层
    坐等开源
    回复 送花

    使用道具 举报

  • TA的每日心情
    开心
    5 天前
  • 签到天数: 90 天

    [LV.6]常住居民II

    38

    主题

    986

    回帖

    6773

    积分

    荣誉版主

    冲哥视频教程和各种开源资料QQ交流群884047237,可群

    积分
    6773
    QQ
     楼主| 发表于 2024-4-7 12:50:13 | 显示全部楼层
    hu3507 发表于 2024-4-7 12:13
    有没有原文件分享的

    软件什么的群文件下载
    回复 支持 反对 送花

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

    GMT+8, 2024-5-4 19:16 , Processed in 0.142818 second(s), 70 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

    快速回复 返回顶部 返回列表