Beijer Electronics (formerly QSI Corporation)

Manufacturer of Mobile Data and Human Machine Interface Terminals.
It is currently Sat Nov 18, 2017 11:54 pm

All times are UTC - 7 hours




Post new topic Reply to topic  [ 10 posts ] 
Author Message
PostPosted: Wed Jul 07, 2010 10:42 am 
Offline

Joined: Wed Jul 07, 2010 7:45 am
Posts: 5
I was curious if anyone has any examples or suggestions on how to both get and set single bits within a Modbus Holding register.

Currently I'm just attempting to get the value of each bit within a 16-bit unsigned modbus register. I've found a few examples on this forum but I have not had much luck getting the code to work properly. I have a basic workspace setup that increments a register's "intvalue" by 1 each time I click a button. At the same time a timer checks the intvalue of the register and outputs each bit to a separate indicator on the screen. However, my counter doesn't count in the correct order. I've attached my workspace, any suggestions or help would be greatly appreciated.

Thanks!

- Bryan

I'm currently using Qlarity version 2.60 and a G75 terminal


Attachments:
File comment: Modbus 16-bit Register to Bits Test Workspace
modbus_registertobit_test.qly [10.35 KiB]
Downloaded 164 times
Top
 Profile  
 
PostPosted: Thu Jul 08, 2010 7:38 am 
Offline
User avatar

Joined: Thu Mar 02, 2006 2:12 pm
Posts: 487
Location: Salt Lake City, Utah
Bryan,

I'm not seeing anything wrong with the code you have in the GetStatus_Timer_1, timeout() event, except that I would move that code to the Status_Reg_126, ValueChanged() event. You may want to create an additional MBRegister object with the same settings as Status_Reg_126 so that you can view the data as an integer and see if it's really changing like you're expecting.

Unfortunately with Modbus protocol registers, you cannot write a single bit in a register without writing all 16 bits. The code might look something like this.
Code:
'set a bit high
status_reg_126.intValue = (unibyte(0x0001) or unibyte(status_reg_126.intValue))

This problem with this however is that if is that if the value has changed since your last read, you will overwrite that new value for the other bits also. Coils might be the better choice in this case with modbus for individual bit values because you can write one bit (coil) at a time.

_________________
Ron L.

http://www.beijerelectronicsinc.com/


Top
 Profile  
 
PostPosted: Thu Jul 08, 2010 8:22 am 
Offline

Joined: Wed Jul 07, 2010 7:45 am
Posts: 5
Ron,

Thank you for the prompt response. I'll try out your suggestions. Is there a way is the simulation to force the Value Change function to execute, or will I need to pass actual modbus data to the simulated QSI?

- Bryan


Top
 Profile  
 
PostPosted: Thu Jul 08, 2010 8:37 am 
Offline
User avatar

Joined: Thu Mar 02, 2006 2:12 pm
Posts: 487
Location: Salt Lake City, Utah
I would recommend communicating with the modbus slave in "Simulation View" and passing actual data if possible.

If you want to force a ValueChanged() without communication you could do something like this in a Button.

Code:
func click()
    status_reg_126.value = 333
    status_reg_126.ValueChanged()
endfunc

_________________
Ron L.

http://www.beijerelectronicsinc.com/


Top
 Profile  
 
PostPosted: Thu Jul 08, 2010 9:22 am 
Offline

Joined: Wed Jul 07, 2010 7:45 am
Posts: 5
I ended up just hooking up the simulation to the modbus plc I'm communicating with. I slightly changed the code so that it's a function that writes each bit to a boolean array so I can read each single bit in the the array and/or combine data when necessary. It's not as streamlined as it could be but it works for now. Thanks for your help!

Code:
func parsebits(u as unibyte) returns boolean[]

    dim boolreg[16] as boolean

    if (u and unibyte(0x0001)) <> 0 then
        boolreg[15] = true
    else
        boolreg[15] = false
    endif

    if (u and unibyte(0x0002)) <> 0 then
        boolreg[14] = true
    else
        boolreg[14] = false
    endif

    if (u and unibyte(0x0004)) <> 0 then
        boolreg[13] = true
    else
        boolreg[13] = false
    endif

    if (u and unibyte(0x0008)) <> 0 then
        boolreg[12] = true
    else
        boolreg[12] = false
    endif

    if (u and unibyte(0x0010)) <> 0 then
        boolreg[11] = true
    else
        boolreg[11] = false
    endif

    if (u and unibyte(0x0020)) <> 0 then
        boolreg[10] = true
    else
        boolreg[10] = false
    endif

    if (u and unibyte(0x0040)) <> 0 then
        boolreg[9] = true
    else
        boolreg[9] = false
    endif

    if (u and unibyte(0x0080)) <> 0 then
        boolreg[8] = true
    else
        boolreg[8] = false
    endif

    if (u and unibyte(0x0100)) <> 0 then
        boolreg[7] = true
    else
        boolreg[7] = false
    endif

    if (u and unibyte(0x0200)) <> 0 then
        boolreg[6] = true
    else
        boolreg[6] = false
    endif

    if (u and unibyte(0x0400)) <> 0 then
        boolreg[5] = true
    else
        boolreg[5] = false
    endif

    if (u and unibyte(0x0800)) <> 0 then
        boolreg[4] = true
    else
        boolreg[4] = false
    endif

    if (u and unibyte(0x1000)) <> 0 then
        boolreg[3] = true
    else
        boolreg[3] = false
    endif

    if (u and unibyte(0x2000)) <> 0 then
        boolreg[2] = true
    else
        boolreg[2] = false
    endif

    if (u and unibyte(0x4000)) <> 0 then
        boolreg[1] = true
    else
        boolreg[1] = false
    endif

    if (u and unibyte(0x8000)) <> 0 then
        boolreg[0] = true
    else
        boolreg[0] = false
    endif

    return boolreg
endfunc


Top
 Profile  
 
PostPosted: Thu Jul 08, 2010 9:30 am 
Offline
User avatar

Joined: Thu Mar 02, 2006 2:12 pm
Posts: 487
Location: Salt Lake City, Utah
Since your using a boolean array, the code could be shortened a bit.


Code:
func parsebits(u as unibyte) returns boolean[]
    dim boolreg[16] as boolean

    boolreg[15] := (u and unibyte(0x0001)) <> 0
    boolreg[14] := (u and unibyte(0x0002)) <> 0

    '...

endfunc

_________________
Ron L.

http://www.beijerelectronicsinc.com/


Top
 Profile  
 
PostPosted: Thu Jul 08, 2010 9:56 am 
Offline

Joined: Wed Jul 07, 2010 7:45 am
Posts: 5
Thanks again Ron.

I do have one more question: How would I write a boolean to single bit in a unint16 register? So, how would I do this in reverse?


Top
 Profile  
 
PostPosted: Thu Jul 08, 2010 10:03 am 
Offline
User avatar

Joined: Thu Mar 02, 2006 2:12 pm
Posts: 487
Location: Salt Lake City, Utah
I think I answered that in this post.

Ron L. wrote:
Bryan,
Unfortunately with Modbus protocol registers, you cannot write a single bit in a register without writing all 16 bits. The code might look something like this.
Code:
'set a bit high
status_reg_126.intValue = (unibyte(0x0001) or unibyte(status_reg_126.intValue))

This problem with this however is that if is that if the value has changed since your last read, you will overwrite that new value for the other bits also. Coils might be the better choice in this case with modbus for individual bit values because you can write one bit (coil) at a time.

_________________
Ron L.

http://www.beijerelectronicsinc.com/


Top
 Profile  
 
PostPosted: Thu Jul 08, 2010 11:08 am 
Offline

Joined: Wed Jul 07, 2010 7:45 am
Posts: 5
Sorry if I wasn't clear. I realize I cannot write one bit at a time, but I can write a whole array of booleans to a integer or unibyte value and then write that value to a register. I think the following code should do the trick, do you see any way to stream-line this?
Code:
func combinebits (bitarray[] as boolean) returns integer
    dim k as integer
    dim output as integer
    for k = 0 to 15
        if bitarray[15-k] == true then
            output = output + 1*Power(2,k)
        else
            output = output + 0*Power(2,k)
        endif
    next
    return output
endfunc


Top
 Profile  
 
PostPosted: Thu Jul 08, 2010 12:22 pm 
Offline
User avatar

Joined: Thu Mar 02, 2006 2:12 pm
Posts: 487
Location: Salt Lake City, Utah
The only way I can think of to streamline that is that when you change the value of the boolean array also change the value of a redundant unibyte variable. Then there is no need to convert the boolean array because you also have the data stored in a unibyte.

_________________
Ron L.

http://www.beijerelectronicsinc.com/


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 10 posts ] 

All times are UTC - 7 hours


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group