Question concerning pointers and BITADR()

magil
2014-04-18
2014-04-22
  • magil - 2014-04-18

    Hello, I am wondering about the following code:

    Output : POINTER TO WORD;
    Toggle : POINTER TO BOOL;


    Output := ADR(%QW6);
    Output^.1 := TRUE; - works

    Toggle:= BITADR(%QX6.1);
    Toggle^ := TRUE; - crash

    If the ADR function is used on a pointer to a word, the value of the used address can be set using that pointer.
    However, when a pointer to a bool is uses, the BITADR function should be used instead of the ADR() function. This results in an Illigal instruction.

    Can anyone explain what the difference is between ADR() and BITADR()?
    Is there another way to achieve the desired result? (The goal is to make an abstraction layer by refence to the physical IO of a plc, so that if different hardware is used, only the addresses need to be changed)

     
  • Vuli - 2014-04-20

    Hey

    Anybody figured out this one by any chance ?

    V

     
  • Vuli - 2014-04-21

    I guess I will answer my own question in case someone runs into this issue:

    BITADR and ADR operators are very different

    ADR returns pointer
    BITADR returns bit offset

    Example:

    VAR
         var1 AT %IX2.3:BOOL;
         bitoffset: DWORD;
    END_VAR
    bitoffset:=BITADR(var1);
    

    The value returned would be bitoffset = 19 (decimal)
    If you consider that %IX2.3 just represents 2nd byte and 3rd bit
    converting it to bits you get 2*8+3=19

    Now...at the moment I am not aware of the way to get the actual bit state (true/false) of bit 19 directly.

    I did figure out a decent workaround tho (needs cleaning up but it should work as is):

    VAR
       byteOffset    : POINTER TO BYTE;
       address    : UDINT;
       dInputBase      AT %IB0 : BYTE;       (* FIRST INPUT BYTE *)
       dInputs     : ARRAY[0..100] OF BYTE;           (* ARRAY of HUNDRED BYTES to COVER IB0 to IB100 *)
       i      : INT;
       bitStatus   : BOOL;
       bitCount   : UDINT;
       byteCount    : UDINT;
    END_VAR
       byteOffset := ADR(dInputBase);    (* GET A STARTING BYTE POINTER *)
       dInputs[0] := dInputBase;           (* ASSIGN A STARTING BYTE TO FIRST ARRAY ELEMENT *)
       
       (* LOOP AND INCREMENT THE POINTER, SKIP INDEX ZERO, ASSIGNED IN PREVIOUS LINE *)
       FOR i := 1 TO 100 DO
          address := byteOffset;
          address := address + SIZEOF(byteOffset^);  (* INCREMENT TO NEXT POINTER *)
          byteOffset := address;
          dInputs[i] := byteOffset^;                      (* ASSIGN INPUT BYTE TO ARRAY VIA POINTER TO THAT BYTE *)
       END_FOR
       
       (* GET BITADR FROM SOME ARBITRARY INPUT VARIABLE *)
       (* ON MY SYSTEM diAirPressure WAS MAPPED to IX76.4 BY TWINCAT *)
       (* BITADR RETURNED 612 WHICH IS 76*8+4 BASED ON TWINCAT MAPPING *)      
       (* DIVIDE 612 by 8 TO GET INTEGER BYTE COUNT *)
       (* DIVIDE 612 by 8 USING MOD to GET BIT COUNT *)
       byteCount := BITADR( diAirPressure ) / 8;
       bitCount := BITADR( diAirPressure ) MOD 8;
       bitStatus := GETBIT32( dInputs[ byteCount ], UDINT_TO_SINT( bitCount ) );
    
     
  • magil - 2014-04-22

    Hi Vuli,

    Thank you for your reply. It seems that BITADR is indeed very different from ADR.

     
  • shooter - 2014-04-22

    Inside a word you can look for a bit if it is one by:
    out:= WORD_TO_BOOL(inword and (SHL(one,bit)));
    VAR
    out : BOOL;
    inword :WORD:=0; ( word to be tested)
    bit:WORD:=0; (bit position in word)
    one:WORD:=1; ( 1 to shift left)
    END_VAR
    this is nice 61131 and bitadr is not in the code
    other ways are possible look at w www.oscat.de w for a nice library.

     

Log in to post a comment.