oldbeginner 发表于 2013-12-11 14:34:38

开源PLC学习笔记17(开源PLC与组态软件通讯MODBUS)——2013_12_11

从freemodbus的阴影中逃了出来,现在需要把modbus加入到开源PLC中了。

首先,利用笔记13中的方法,逐步添加。但是因为STC12系列无法通过PROTEUS仿真,不过找到了内部含有EEPROM并且可以PROTEUS仿真的51,
《单片机C语言程序设计实训100例——基于8051+Proteus仿真(第2版)》25 单片机内置EEPROM读写测试仿真

这样就可以仿真了,然后把笔记15中的代码加入,过程比想象地要简单很多。



输入的命令是03040415
复习一下,
03040415 会被分解成 0403 和 1504
0403:第一个0是散转函数的下标,表示LD命令,403表示X3,是第4个开关;
1504:第一个1是散转函数的下标,表示OUT命令,504表示Y3,是第5个LED;
即 LD X3
    OUT Y4

然后,先利用组态王
设置按照http://www.chinabaike.com/z/gyzd/877961.html




这样组态王的开关就可以控制X3,从而间接控制Y4。

sbit LED0 = P0^0; // 对应线圈0
sbit LED1 = P0^1; // 对应线圈1
sbit LED2 = P0^2; // 对应线圈2
sbit LED3 = P0^3; // 对应线圈3
sbit LED4 = P0^4; // 对应线圈4
sbit LED5 = P0^5; // 对应线圈5
sbit LED6 = P0^6; // 对应线圈6
sbit LED7 = P0^7; // 对应线圈7

sbit KEY0 = P1^0;
sbit KEY1 = P1^1;
sbit KEY2 = P1^2;
sbit KEY3 = P1^3;
sbit KEY4 = P1^4;
sbit KEY5 = P1^5;
sbit KEY6 = P1^6;
sbit KEY7 = P1^7;

并且在设置线圈函数中,主要对KEY进行操作
//设定线圈状态 返回0表示成功
INT16U setCoilVal(INT16U addr, INT16U tempData)
{
        INT16U result = 0;
        INT16U tempAddr;

        tempAddr = addr & 0xfff;

        switch(tempAddr)                // & 0xff
        {
                case 0:
                                if (tempData)
                                        KEY0 = 1;
                                else
                                        KEY0 = 0;
                                break;
                case 1:
                                if (tempData)
                                        KEY1 = 1;
                                else
                                        KEY1 = 0;
                                break;
                case 2:
                                if (tempData)
                                        KEY2 = 1;
                                else
                                        KEY2 = 0;
                                break;
                case 3:
                                if (tempData)
                                        KEY3 = 1;
                                else
                                        KEY3 = 0;
                                break;
                case 4:
                                if (tempData)
                                        KEY4 = 1;
                                else
                                        KEY4 = 0;
                                break;
                case 5:
                                if (tempData)
                                        KEY5 = 1;
                                else
                                        KEY5 = 0;
                                break;
                case 6:
                                if (tempData)
                                        KEY6 = 1;
                                else
                                        KEY6 = 0;
                                break;
                case 7:
                                if (tempData)
                                        KEY7 = 1;
                                else
                                        KEY7 = 0;
                                break;
                case 10:
                                break;
                case 11:
                                break;
                case 12:
                                break;
                case 13:
                                break;
                case 14:
                                break;
                case 15:
                                break;
                case 16:
                                break;
                case 17:
                                break;

                default:
                                break;
        }

        return result;
}


进行仿真,


从中可以看出,组态王设置线圈状态是没有问题的,但是查询线圈状态,组态王发出的命令总是01 01 01 00 。。。。不是LED所对应的地址,目前还不知道如何解决。

另外,为了简洁和集中重点,命令输入通讯还没加入。



oldbeginner 发表于 2013-12-11 20:19:14



添加通讯,只添加写命令
void FX1NProcessing(void)
{

      unsigned char i;
      unsigned char WriteLen=0;
         unsigned intWriteAddr=0;

      if(UDRFlag)                              // 有数据来
      {
                UDRFlag=0;
                if(Buffer==ENQ)      // 发送请求                                        ==== 1. 3. 5. 7. 10. 12. 14.(14开始下发数据)
                {
                        UartSendByte(ACK);
                }
                else if(STXETX)      // 可识别的                        
                {
                        if(E11)
                        {
                              //      计算得到写入字节数:
                              for(i=8;i<10;i++)Buffer=ascto0F(Buffer);
                              Buffer<<=4;
                              WriteLen=(Buffer+Buffer);
                              //      计算得到写入地址:
                              for(i=4;i<8;i++)Buffer=ascto0F(Buffer);
                              WriteAddr =Buffer<<12;
                              WriteAddr+=Buffer<<8;
                              WriteAddr+=Buffer<<4;
                              WriteAddr+=Buffer;
//                                        if(WriteAddr==0x8000)ErasurePLC(ErasureCODE);      //      擦除PLC程序区
                              WriteFlash(WriteAddr,(unsigned char *)(Buffer+10),(unsigned char)WriteLen);      //      写 flash
                              step=WriteLen;
                              UartSendByte(ACK);
                              }                        
                        
                }
                UartReceiveCounter=0;
               REN=1;
      }
}
省去了和检验,
因为采用串口助手,写入命令02 45 31 31 30 30 30 30 30 34 30 32 30 34 30 32 31 35 03 33 33,最后两个随意
表示STX E 1 1 0 0 0 0 0 4 0 2 0 4 0 2 1 5 ETX 3 3
即在0000地址写入 LD X2
                           OUT Y2


主函数也更改为
#include "system.h"
unsigned char command[]={'0','3','0','4','0','4','1','5'};

void main(void)
{
          SYSTEM_DISABLE_INTERRUPT();
      UartInit();
         TimerInit();
      SYSTEM_ENABLE_INTERRUPT();

      WriteFlash(IAP_ADDRESS,(unsigned char*)(command),4);
      step=4;
   while (1)
    {
            FX1NProcessing();
         //更新IO端口,必须
                RefreshIO();            
   //PLC执行去找二当家的,当老大就是好
                main_PLC();                                                
                timerProc();                        
                checkComm0Modbus();//检测modbus帧
         }
}

fiaanull 发表于 2014-5-22 09:44:09

mark下!{:lol:}【开源PLC与组态软件通讯MODBUS)】

wkman 发表于 2014-5-22 10:10:01

{:shocked:}不是很明白组态,,,收藏先
页: [1]
查看完整版本: 开源PLC学习笔记17(开源PLC与组态软件通讯MODBUS)——2013_12_11