搜索
bottom↓
回复: 15

开源PLC学习笔记09(再从51开始 主函数)——2013_11_18

[复制链接]

出0入0汤圆

发表于 2013-11-18 21:09:24 | 显示全部楼层 |阅读模式
本帖最后由 oldbeginner 于 2013-11-18 21:27 编辑

理解的主函数框架如下,

void main(void)
{
    I0口复位;

    RAM复位;

    中断复位;

    串口初始化;

    PLC版本核查;

   while(下载模式条件)
         {
               FX1NProcessing();
              
               if(下载模式条件不满足)
                    {
                       软件复位并从用户程序空间启动;
                    }
           }
   
     PLC 代码初次扫描;

     while(1)
          {
                 输入输出刷新;
                 
                 main_PLC();
            }
}

****************************************

按照顺序来理解,

一、首先I0口复位,为简单和简洁去除了显示器。

void reset_IO(void)             // I,O口初始化
{
    P0M0  = 0x00;
    P0M1  = 0xff;
    P0    = 0x00;
    P1    = 0xff;
    P2    = 0xff;
    P3    = 0xff;
}

P0M0和P1M1是MPC82G56芯片自己的寄存器,

P0M0:端口0模式寄存器0;
P0M1:端口0模式寄存器1;

P0口采用上拉输出,可以想到,P0对应的输出就是Y。

**************************************

二、 RAM复位,只看X和Y

void reset_RAM(void)
{
   for (i=0; i<_Y_BYTE; i++)  
            {
               rY.BYTE = 0;
              rY1.BYTE = 0;
            }

  Timer_5ms     = 0;           // 5ms时基计数器,5ms Timer0中断计数
  Timer_10ms    = 0;           // 10ms时基计数器,5ms Timer0中断计数
  Timer_100ms   = 0;           // 100ms时基计数器,5ms Timer0中断计数
  Pulse_val_Sec = 0;           // 1s时基计数器
  Pulse_val_Min = 0;           // 1min时基计数器
  CODE_ERROR    = 0;

  input_IO();

  for (i=0; i<_X_BYTE; i++)
             rX1.BYTE = rX.BYTE;
}

因为对rX和rY的结构比较熟悉了,所以容易理解。但是为什么把rX1的赋值放在后面,它前面还有一个input_IO函数,可以想到,input_IO会影响到rX。为了简单,去掉了键盘输入和显示器。

//  初始化,输入输出,内存处理 子函数                                                  //
//-------------------------------------------------------------------------------------//
void input_IO(void)           // X输入,Y输出刷新
{
  unsigned char i;
  i = P2;
  i = ((i << 1) & 0xaa) | ((i >> 1) & 0x55);
  i = ((i << 2) & 0xcc) | ((i >> 2) & 0x33);

  rX[0].BYTE = ~((P1 & 0x0f) | (i & 0xf0));
  rX[1].BYTE = ~(i & 0x0f) & 0x0f;

  P0 = rY[0].BYTE;
}

看了前4行, i 到底是什么?



真巧,4年前的今天。

搜了一下啊,http://wenku.baidu.com/view/fea1e985b9d528ea81c779ee.html,很不幸,目前没有精力顾及。

暂时理解其功能,变换未按照次序输入输出的IO口。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

 楼主| 发表于 2013-11-18 21:49:30 | 显示全部楼层
这个PLC加了好多外设,键盘和显示器,如果作为学习那负担承受不起,在学习中,只要不影响核心功能的外设都会被和谐。

继续中断复位,

void reset_interrupt(void)
{
  IP   = 0x00;
  IE   = 0x00;
  TCON = 0x00;                 // 定时器控制寄存器, 注意:TCON只需操作一次
  TMOD = 0x01;
  T0  = Value_T0_cons;       // 装入5ms Timer0中断常数
  PT0 = 1;
  ET0 = 1;
  TR0 = 1;
}


中断是很常规的那种。

然后是串口复位,串口复位在笔记05中理解过,串口使用了定时器1,而中断复位采用定时器0
void UartInit(void)
{
      //停止定时器
    TR1=0;  
           
/******电源管理PCON寄存器************
位        7            6            5        4        3        2        1        0
寄存器    SMOD    X             X        X        X        X        X        X
        ————————————————————   
取值        1        0              0        0        0        0        0        0
说明    波特率加倍
************************************/
    PCON=0x80;
   
/*****定时器TMOD寄存器**********
位            7         6            5            4                3        2            1        0
寄存器    GATE    C/T          M1        M0        GATE         C/T        M1        M0
        ——————————————----         |———————————   
                定时器1的设置                    定时器0的设置
取值    0                0            1           0               0         0        0            0
说明        使用定时器1,工作方式2            |            没用使用            
**********************************/
   TMOD=TMOD | 0x20;

//定时器1工作方式2
//在下面的PCON设置上增加了倍频,所以晶振位22.1184Mhz
/**********波特率设置表(22.1184Mhz)************
波特率    2400    4800    9600    19200
TH1        E8        F4        FA        FD
TL1        E8        F4        FA        FD
说明,因为选取波特率9600,所以TH1和TL1都取FA
*************************************************/
    TH1=0xFA;
    TL1=0xFA;


//串口工作方式1
/*******串口SCON寄存器***************
位        7              6                5                    4                3             2                    1                          0
寄存器    SM0        SM1          SM2                REN            TB8            RB8                TI                        RI
        ——————————————————————————————————————
             工作方式控制|         多机通信|       接受标志位|  发第9位|     收第9位|          发送中断标志位  接受中断标志位
取值     0            1                 0                     1                0                0                     0                            0
说明        工作方式1            开始接受
**************************************/
SCON=0x50;   


//启动定时器1   
   TR1=1;               

    UartReceiveCounter=0;
    UartRxTimerStartFlag=0;
}

也好理解。

这样,几个复位函数先理解。后面的函数就感觉复杂了。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2013-11-18 22:22:21 | 显示全部楼层

出0入0汤圆

发表于 2013-11-18 22:28:50 | 显示全部楼层
不得不顶楼主,你的精研劲头值得大家学习。

出0入0汤圆

 楼主| 发表于 2013-11-18 22:42:40 | 显示全部楼层
kinsno 发表于 2013-11-18 22:28
不得不顶楼主,你的精研劲头值得大家学习。


谢谢鼓励,具有精研劲头应该是开源PLC的人,我只不过是来学习一下的,另外写成笔记感觉效率更好些。

出0入0汤圆

发表于 2013-11-18 22:49:43 | 显示全部楼层
oldbeginner 发表于 2013-11-18 22:42
谢谢鼓励,具有精研劲头应该是开源PLC的人,我只不过是来学习一下的,另外写成笔记感觉效率更好些。 ...

哈哈,其实你这样也蛮不错,至少能给后面搞PLC的人一个启示或少走一些弯路啊。
其实,PLC现在这些远远不够,只能说先仿仿,最终还是要取其精华,用在我们自己的产品上,或形成我们自己的东西吧;PLC这个行业越来越难啊,西门子最近在成都搞了一个大工厂,S200系列将全部在这里生产,听说现在200已经有大降价了,比以前。

出75入0汤圆

发表于 2013-11-18 23:48:41 | 显示全部楼层
睡不着,上来就碰到楼主的笔记,这段时间虽然还来不及学习,但是先说声感谢!

出0入0汤圆

发表于 2013-11-19 19:20:58 | 显示全部楼层
好东西学习了

出0入0汤圆

发表于 2013-11-21 13:46:41 | 显示全部楼层
建议楼主把笔记做PDF文档,这样文便阅读和学习。。。

出0入0汤圆

 楼主| 发表于 2013-11-26 09:28:41 | 显示全部楼层
继续PLC版本检测,
PLCType=IAPFlashReadMode(PLCTypeAddr);        //    上电,核实 PLC 硬件版本号

复习一下地址和函数,
#define PLCTypeAddr            (MCUFLASHSIZE-MCUISPFLASHSIZE-512)    //    即IAP倒数第一页.

unsigned char IAPFlashReadMode(unsigned int codeaddr)    // 读模式

读取地址为  PLCTypeAddr的内容,这个内容就是PLC版本号。

因为写PLC初始化内容时,第一个字符是0,如果不是,表示没有初始化,

  if(PLCType!=0)                                //    第一次使用. IAP -- "FX1N PLC\r\n".
    {
      写入PLC初始化代码(第一个字符为0);
      UartSendString(ArrFirstused);
    }
  else UartSendString(ArrPass);

上面发送的字符串笔记简单,
  unsigned char code ArrFirstused[]="First used!\0";
  unsigned char code ArrPass[]="PASS!\0";

初始化内容有,
      ErasurePLC(ErasureALL);                    //    全部擦除    初始PLC程序为空
      IAPFlashProgremMode(PLCTypeAddr,0);        //    更新硬件版本号标识符标志
      for(i=0;i<PLCTypeArrayLen;i++)            //    更新硬件版本号
        { IAPFlashProgremMode(PLCTypeAddr+1+i,PLCTypeArray);
   
    }
      for(i=0;i<46;i++)                        //    写入PLC初始化代码            查询地址0x8000. 0x802e.
        { IAPFlashProgremMode(0x8000+i,OrderSend3);
          IAPFlashProgremMode(0x802e+i,OrderSend4);
        }
1、全部擦除    初始PLC程序为空
2、更新硬件版本号标识符标志(即第一个字符为0)
3、更新硬件版本号
4、写入PLC初始化代码            查询地址0x8000. 0x802e.

上面的代码都是比较好理解的。
******************************************
然后,
  for(i=0;i<PLCTypeArrayLen;i++)
    { PLCTypeArray=IAPFlashReadMode(PLCTypeAddr+1+i);
    }
把版本信息再读出来

  UartSendByte(PLCTypeArray,PLCTypeArrayLen);
  UartSendString("\r\n");
再发送出去。

*******************************************

  while (((P1 & 0x03) == 0) && (RUN == 0))
    { FX1NProcessing();                        //    PLC下载通信处理
        if ((P1 & 0x03) != 0)     
          { delay_ms(20);
              if ((P1 & 0x03) != 0)
              { RUN = 1;
                IFMT  = 0;          //
                ISPCR = 0x20;      // SWBS  = 0; 选择AP空间, SWRST = 1; 软复位
                while (1) { ; }
              }
          }
    }

这就是通讯判断函数,是不是接收上位机指令。
(P1 & 0x03) == 0) && (RUN == 0)
P1的第三个端口为低电平,同时设置的位变量RUN也是0时,就开始进入通讯核心函数FX1NProcessing。
        if ((P1 & 0x03) != 0)     
          {
             延时消抖;
             从AP空间复位;
             }
P1的第三个端口应该是一个按键,可以用来复位。复位函数是参考该芯片手册上的,不同芯片有区别。

******************************************
然后,
CODE_scan();
这是一个比较复杂的函数,
//   PLC 代码 初次扫描,求出标号 Pn 地址函数  main_PLC();                                                        //
//-------------------------------------------------------------------------------------//

void CODE_scan (void)
理解这个函数,需要复习笔记07里的内容。

CODE_p = (unsigned char code *)CODE_START;
其中,
#define   CODE_START   0x8000         // PLC执行代码缓冲区首地址
然后,
      orderL = *CODE_p;
      CODE_p++;
      orderH = *CODE_p;
      CODE_p++;
      ppp = order & 0xfff;
可以看出,求出了偏移地址ppp。
具体如图所示,



从中可看出,利用 order & 0xfff求出偏移地址,
再利用orderH>>=4求出映射表(散转函数表)对应的位置。

然后很多if else if语句,这些语句暂时忽略。

最后,
CSP_Pn[CSP_Pn_MAX] = (unsigned char code *)CODE_START;
这个语句需要结合PLC_main()一起理解,暂时略过。

*********************************************


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2013-11-26 10:11:59 | 显示全部楼层
oldbeginner 发表于 2013-11-26 09:28
继续PLC版本检测,
PLCType=IAPFlashReadMode(PLCTypeAddr);        //    上电,核实 PLC 硬件版本号

最后就是 ,省掉非核心代码和非相关变量。
  while (1)
    {
        input_IO();
         
        main_PLC();

      mov_to_old();

    }

这段代码就是PLC正常执行时的循环。

首先,
*******************************************
void input_IO(void)           // X输入,Y输出刷新
这个功能是必要的

因为只考虑x和y,其余不考虑,包括外设
void input_IO(void)           // X输入,Y输出刷新
{
unsigned char i;
  i = P2;
  i = ((i << 1) & 0xaa) | ((i >> 1) & 0x55);
  i = ((i << 2) & 0xcc) | ((i >> 2) & 0x33);
  rX[0].BYTE = ~((P1 & 0x0f) | (i & 0xf0));
  rX[1].BYTE = ~(i & 0x0f) & 0x0f;

  P0 = rY[0].BYTE;
   }
这种碟形算法还不会,因为不理解对应关系,暂时略过,打算把该算法换成容易理解的语句。

********************************************************


然后进入main_PLC函数,
void main_PLC (void)
{
  CODE_p = (unsigned char code *)CODE_START;
  Pi = 0x01;
  do{
      orderL = *CODE_p;
          CODE_p++;
      orderH = *CODE_p;
          CODE_p++;

      ppp = order & 0xfff;

      (*key_list[orderH >> 4])();

    } while((CODE_p < CODE_END) && (CODE_p != CODE_START));
}
因为在笔记07中理解过,在功能上基本都能理解。
需要增加的一个知识点就是函数指针,

http://www.amobbs.com/forum.php? ... 2715&extra=page%3D1上说过函数指针重要性,但是作为入门材料并不好,我推荐的文章是
http://wenku.baidu.com/view/28d11678a26925c52cc5bf71.html
有图有例子,非常好懂。

程序中定义如下,
code (*key_list[16])();

按照我的理解,改成
code void (*key_list[16])(void); 更好些

main_PLC 把 CODE_START和 CODE_END 之间的代码执行了一遍。因为CODE_p++会等于CODE_END,不是死循环,只是执行一遍。

*******************************************

void mov_to_old(void)
{
  unsigned char i;
  for (i=0; i<_X_BYTE; i++)
             { rX1.BYTE = rX.BYTE; }
  for (i=0; i<_Y_BYTE; i++)
              { rY1.BYTE = rY.BYTE; }
}

根据定义
volatile TYPE_BIT_BYTE   data  rX[_X_BYTE] , rY[_Y_BYTE];       //  位元件 X,Y 存储位
volatile TYPE_BIT_BYTE   data  rX1[_X_BYTE], rY1[_Y_BYTE];      //  位元件 X,Y 存储位上一步备份

从代码和功能上可以理解,备份作用。
不过rX1和rX和容易混淆,把rX1改成 rXbk或许好些。

***************************************

因为只理解x y LD SET OUT RST等几个变量和命令,并且不考虑外设,所以代码量小了很多,这样就完成了整个程序的第一遍理解。从理论上说,已经具备把理解的程序移植到STC12C516系列芯片上,因为该芯片已经有相应的PLC程序,所以下一步进行移植,可以完成:

1、对开源PLC程序的第二遍理解;
2、更新通讯协议;
3、和已有STC12C516程序的对比(现有的STC12C516程序没有详细的注解,文件安排也比较乱);
4、利用三菱梯形图软件完成LD X02
                                      OUT Y5
                                      END
能够把命令传递给STC12C516上,并且该单片机可以正常工作。

出0入0汤圆

 楼主| 发表于 2013-12-13 16:41:04 | 显示全部楼层
oldbeginner 发表于 2013-11-26 09:28
继续PLC版本检测,
PLCType=IAPFlashReadMode(PLCTypeAddr);        //    上电,核实 PLC 硬件版本号

因为之前只理解LD和OUT,所以省去了很多相关代码,现在需要把PLC指令逐步添加,就有必要重新理解Code_scan函数了。

先把散转列表复习一下,
code (*key_list[16])()={
          CMDFNC ,   // 0 (FNC应用指令)   
          CMDP   ,   // 1 (P 应用指令)  
          LD     ,   // 2 (LD指令, 2000+ppp, 扩展 Mp除外)  
          LDI    ,   // 3 (LDI指令, 3000+ppp, 扩展 Mp除外)   
          AND    ,   // 4 (AND指令, 4000+ppp, 扩展 Mp除外)   
          ANI    ,   // 5 (ANI指令, 5000+ppp, 扩展 Mp除外)   
          OR     ,   // 6 (OR指令, 6000+ppp, 扩展 Mp除外)   
          ORI    ,   // 7 (ORI指令, 7000+ppp, 扩展 Mp除外)   
          CMDER  ,   // 8 (多字指令,第二字及以后有效)
          CMDER  ,   // 9  
          CMDER  ,   // A (多字指令,第二字及以后有效, 仅对M1536-M3071有效,需加偏移量200)  
          CMDER  ,   // B (Pn指令, 仅对CJ,CALL有效)
          OUTYM  ,   // C (OUT指令, 仅对Y,M有效)
          SETYM  ,   // D (SET指令, 仅对Y,M有效)
          RSTYM  ,   // E (RST指令, 仅对Y,M有效)
          CMDCH };   // F (纯单字指令)

************************************************************

void CODE_scan (void)
{
unsigned char pa, pb;

  CODE_p = (unsigned char code *)CODE_START;

  do{
      orderL = *CODE_p;
          CODE_p++;

      orderH = *CODE_p;
          CODE_p++;

      ppp = order & 0xfff;

分别取出偏移地址和命令码(散转表数组下标)
继续,
          if ((orderH>>4) <= 0x1)
                {
                        if (ppp == 0x00f)      //   (END指令, 000F )
                            {
                                 END();  
                        }
(orderH>>4) <= 0x1,即命令码是0或者1,CMDFNC或CMDP命令,或者是END命令。因为END指令 00 0f,这时再通过验证偏移地址来确认是否是END指令。
继续,

          else if (ppp <= 0x00e)
            {
                pa = (unsigned char)ppp;

              if ((pa <= 0x001) || (pa == 0x00e)) ;

                  else if ((pa == 0x00a) || (pa == 0x00d))
                         {
                                 CODE_p += 4;
                        }
                      else
                        {
                                CODE_p++;
                                  CODE_p++;
                        }
            }
原因不知道(还需要确认一下),肯定没有相对应的指令,跳过4个字节或2个字节,应该类似空行。

          else if ((ppp  >= 0x1c0) && (ppp <= 0x1cf))  
            {
                 pa = (unsigned char)(ppp - 0x1c0);
            
                 if ((pa <= 0x001) || (pa == 0x008) || (pa == 0x009)) ;
            
                 else
                {
                 CODE_p++;
                  CODE_p++;
                }
            }
类似上面,继续执行或跳过2个字节

          else if ((ppp >= 0x600) && (ppp < 0x800))        // 三字指令
            {
                 CODE_p += 4;
            }
判断出是三字指令,则指针+4。为什么?

看来要打断一下,找到原因再继续这里的理解。
http://www.amobbs.com/thread-3303497-1-1.html

出0入0汤圆

 楼主| 发表于 2013-12-14 15:45:39 | 显示全部楼层
oldbeginner 发表于 2013-12-13 16:41
因为之前只理解LD和OUT,所以省去了很多相关代码,现在需要把PLC指令逐步添加,就有必要重新理解Code_sca ...

借鉴数学常用的反证法,如果(orderH>>4) > 0x1,是哪些指令?

单字指令
                    LD     2000+ppp           ;(扩展 Mp除外)
                    LDI    3000+ppp           ;(扩展 Mp除外)
                    AND    4000+ppp           ;(扩展 Mp除外)
                    ANI    5000+ppp           ;(扩展 Mp除外)
                    OR     6000+ppp           ;(扩展 Mp除外)
                    ORI    7000+ppp           ;(扩展 Mp除外)
                    Pn     B000+(N)           ; N=0-127
                    OUT    C000+ppp           ;(仅对Y,M有效)
                    SET    D000+ppp           ;(仅对Y,M有效)
                    RST    E000+ppp           ;(仅对Y,M有效)

纯单字指令
                    ANB    FFF8
                    ORB    FFF9
                    MPS    FFFA
                    MRD    FFFB
                    MPP    FFFC
                    INV    FFFD
                    NOP    FFFF

************************************************
其余的都是(orderH>>4) <= 0x1),有哪些?

纯单字指令
                    END    000F

单字指令
          CMDFNC ,   // 0 (FNC应用指令)   
          CMDP   ,   // 1 (P 应用指令)
基本应用指令  =  (FNC.No.n+8)*2   
D 应用指令   =  (FNC.No.n+8)*2 +1
P 应用指令   =  (FNC.No.n+8)*2 +1000

双字指令
                    OUT    0002 8000+ppp      ;(仅对M8xxx有效)
                    OUT    0002 A000+ppp      ;(仅对Mp有效)
                    SET    0003 8000+ppp      ;(仅对M8xxx有效)
                    SET    0003 A000+ppp      ;(仅对Mp有效)
                    RST    0004 8000+ppp      ;(仅对M8xxx有效)
                    RST    0004 A000+ppp      ;(仅对Mp有效)
                    OUT    0005 8000+ppp      ;(仅对S有效)
                    SET    0006 8000+ppp      ;(仅对S有效)
                    RST    0007 8000+ppp      ;(仅对S有效)
                    PLS    0008 8000+ppp      ;(仅对Y,M有效)
                    PLF    0009 8000+ppp      ;(仅对Y,M有效)
                    MC     000A 8000+(N) 8000+ppp ;(仅对Y,M有效)
                    MCR    000B 8000+(N)          ; N=0-7
                    RST    000C 8000+ppp          ;(仅对T,C,Cp有效)
                    RST    000D 8m00+xx  8n00+yy  ;(仅对 D 有效,包含Z,V)

                    LD     01C2 A000+ppp      ;(仅对Mp有效)
                    LDI    01C3 A000+ppp      ;(仅对Mp有效)
                    AND    01C4 A000+ppp      ;(仅对Mp有效)
                    ANI    01C5 A000+ppp      ;(仅对Mp有效)
                    OR     01C6 A000+ppp      ;(仅对Mp有效)  
                    ORI    01C7 A000+ppp      ;(仅对Mp有效)  

                    LDP    01CA 8000+ppp      ;(扩展 Mp除外)  
                    LDP    01CA A000+ppp      ;(仅对 Mp有效)  
                    LDF    01CB 8000+ppp      ;(扩展 Mp除外)   
                    LDF    01CB A000+ppp      ;(仅对 Mp有效)   
                    ANDP   01CC 8000+ppp      ;(扩展 Mp除外)   
                    ANDP   01CC A000+ppp      ;(仅对 Mp有效)   
                    ANDF   01CD 8000+ppp      ;(扩展 Mp除外)     
                    ANDF   01CD A000+ppp      ;(仅对 Mp有效)     
                    ORP    01CE 8000+ppp      ;(扩展 Mp除外)   
                    ORP    01CE A000+ppp      ;(仅对 Mp有效)   
                    ORF    01CF 8000+ppp      ;(扩展 Mp除外)   
                    ORF    01CF A000+ppp      ;(仅对 Mp有效)  


三字及五字指令
                    OUT  T  K      0600+(T)  8000+xx 8000+yy
                    OUT  C  K      0E00+(C)  8000+xx 8000+yy
                    OUT  Cp K      0000+(Cp) 8000+xx 8000+yy 8000+zz 8000+ww  //忽略
**************************************************************

所以现在可以理解为何当 if ((orderH>>4) <= 0x1) 时,会有很多if。。。else if。。。else if。。。语句,是因为不同类型指令字节长度不一样。


研究一个例子看看,
例如 OUT T1 K5
指令码应该是 0601 8000 8005





再回到Code_scan函数,
          else if ((ppp >= 0x600) && (ppp < 0x800))        // 三字指令
            {
                CODE_p += 4;
            }
因为ppp=0x601,所以执行这句;这样指针就跳过8000 和8005指令,指向下一条指令。

这样证明Code_scan只是检验命令格式是否正确。

用类似的方法可以把其它命令都确认一下。但是没有返回信息,感觉这样子确认有些多余。

如果指令格式不对(很简单只考虑指针是否超出,并不全面),会有
  if (CODE_p >= CODE_END)
    {
        CODE_ERROR =1;
        }
这样在主函数中,
          if (CODE_ERROR == 0)
        {
                main_PLC();
        }

Code_scan作用有限。

但是从上面OUT T1 K5例子中引出了一个类似的但更复杂函数,

code (*key_list[16])()={
          CMDFNC ,   // 0 (FNC应用指令)
        。。。。
        }

void CMDFNC(void)     // 0 (应用指令)   
{
        很多代码
        。。。
}

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2013-12-14 16:17:02 | 显示全部楼层
oldbeginner 发表于 2013-12-14 15:45
借鉴数学常用的反证法,如果(orderH>>4) > 0x1,是哪些指令?

单字指令

/********************CMDFNC指令散转  *******************************************/

void CMDFNC(void)     // 0 (应用指令)   
{
        END指令();

         (ppp <= 0x00e)();

        ((ppp  >= 0x1c0) && (ppp <= 0x1cf))();

        三字指令T();

        三字指令C();

        基本应用指令();

        D应用指令();

}

还是按照例子OUT T1 K5来理解,
这里会选择

三字指令T()

  else if ((ppp >= 0x600) && (ppp < 0x800))        // 三字指令
    {
        WR_TK(ppp - 0x600);       // OUT  T,K      0000+(T)  8000+xx 8000+yy  
    }
因为ppp=0x601,则调用 WR_TK(1);

其中
void WR_TK(unsigned int a)       // ,(K值写入T)
{
  代码();
}

至此,OUT T1 K5才得到执行。

********************************************

如果是基本应用指令,则还要复杂一些,

在CMDFNC中,还要散转一下,调用
          (*key_list_3[pa])();            //  应用指令散转

code (*key_list_3[256])() ={
       FNC_CJ    ,    // 0
       FNC_CALL  ,    // 1
       FNC_SRET  ,    // 2   
       FNC_IRET  ,    // 3
       。。。。
}
根据下标,再调用相应函数。

还有其它情况的散转函数,这里暂时不展开,目的只是先把大脉络理解,然后把PLC指令逐步加入到笔记19中,笔记19将是51下的PROTEUS仿真,并且能接收三菱梯形图指令。

出0入0汤圆

发表于 2015-4-7 14:05:23 | 显示全部楼层
mark,楼主很牛哦!

出0入0汤圆

发表于 2015-7-24 10:52:11 | 显示全部楼层
mark,楼主很牛!顶一个.好资料
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-27 03:31

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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