Discussion forum for the BasicX family of microcontroller chips.
|
Hi I'm writting a program to control an ICON H bridge with a PID controller. I basically send data to the serial port and the board moves the motor. The program looks like this: Option Explicit '------------------------------------------------------------------- ' ************* Serial Port Buffer and Pins Set Up **************** Const InputPin as Byte = 6 Const OutputPin as byte = 5 Dim SerialOutputBuffer(1 to 10) as byte Dim SerialInputBuffer(1 to 13) as byte Dim A as byte ' Data output Dim B as byte ' Data input ' ******************** Main program ***************************** Public Sub Main() Call OpenQueue(SerialOutputBuffer, 10) ' Open buffers Call OpenQueue(SerialInputBuffer, 13) Call DefineCom3(InputPin, OutputPin, bx0000_1000) ' Port settings Call OpenCom(3, 19200, SerialInputBuffer, SerialOutputBuffer) ' open port ' ******************** Servo Data Output ************************** A=&HF0 ' Command Call PutQueue (SerialOutputBuffer, A, 1) A=&H01 ' Address Call PutQueue (SerialOutputBuffer, A, 1) A=&HD0 ' Position Call PutQueue (SerialOutputBuffer, A, 1) A=&H07 ' Position Call PutQueue (SerialOutputBuffer, A, 1) A=&H00 ' Position Call PutQueue (SerialOutputBuffer, A, 1) A=&H00 ' Position Call PutQueue (SerialOutputBuffer, A, 1) A=&HC8 ' Checksum Call PutQueue (SerialOutputBuffer, A, 1) Call Delay (0.25) ' ************ Check for ACK PID controller signal ************** Call GetQueue (SerialInputBuffer, B, 1) Debug.Print Cstr(B) Call Sleep (0.0) End Sub As you can see, I'm sending byte by byte to the serial port. The PID needs to receive the Least Significant byte before [LSB]. This motor has to move thousands of time to different positions ans I don't think it would be very practical to do it this way. Is there any way to do something like this? (instead of changing the value of A everytime): Call PutQueue (SerialOutputBuffer, &HFF,1) Can you think of any way to simplify the program? Do I really need to sue the Buffers Queue? Thanks |
|
|
|
Ok, i got a way of simplify it: ------------------------------------------------------------------ Public Sub Movements() Dim N as byte For N=1 to 21 Command = &HF0 ' Command Call PutQueue (SerialOutputBuffer, Command, 1) Address = &H01 ' Address Call PutQueue (SerialOutputBuffer, Address, 1) D = 2000 Call PutQueue (SerialOutputBuffer, D, 4) Check = &HC8 ' Checksum Call PutQueue (SerialOutputBuffer, Check, 1) ----------------------------------------------------------------- The problem is that I need to generate 256 Checksum summation. I can easily add Command & Address but for D that now is a long number, i need to split it in two. That is D(1)=00 and D(2)=20 so I can add them with the rest of the variables (bytes) and generate the Checksum. What I wanted to do is to generate a loop that continuosly adds 250 to variable D (Displacement) so I don't have to write 250 variables. Any ideas? |
|
Hi Ed, I looked at a datasheet at http://www.solutions-cubed.com assuming that you are using that system, in (ref 4.5) "Direct Control Mode", I think the Protocol calls for 7 bytes to be sent to execute the (ref 5.2.18)"Write Desired Position" command. In thinking about this as a "Move To" command, you would know everything but the "checksum" prior to sending the 7 bytes. There are many different ways of proceeding, the following is just a suggestion. The "Position" is assigned to a 32 bit, 4 byte, "Long" variable. This is now in memory, stored LSB at the "address" of the variable, the next byte at "address + 1", the next byte at "address + 2" and the MSB at "address + 3". A subroutine would sequentially add the 4 bytes, add the "Command" and "DeviceADDR" bytes, do a "mod 256" to produce a checksum byte and then send all the known data. TRIAL CODE IDEAS '-------------------------------- 'Declarations ' 'Const eCMD As Byte = &HF0 'Const eADDR As Byte = &H01 ' 'Dim ePREAMBLE(1 to 2) As Byte 'is 2 bytes 'Dim ePOSITION As Long 'is 4 bytes 'Dim eCHKsumBYTE As Byte 'is 1 byte ' 'Dim eCHKsumINTEGER As Integer ' 'Dim SerialOutputBuffer(1 to 13) as byte ' must be at least 13 to send 4 bytes (+9 byte overhead) 'Dim SerialInputBuffer(1 to 13) as byte ' '-------------------------------- 'setup queues (do once) ' ' Call OpenQueue(SerialOutputBuffer, 13) ' Call OpenQueue(SerialInputBuffer, 13) ' Call DefineCom3(InputPin, OutputPin, bx0000_1000) ' Call OpenCom(3, 19200, SerialInputBuffer, SerialOutputBuffer) ' '-------------------------------- 'Build preamble (do once) ' ' ePREAMBLE(1) = eCMD ' ePREAMBLE(2) = eADDR ' '-------------------------------- 'Set the desired position (any time) ' ' ePOSITION = 2000 ' &H000007D0 ' ' uses twos complement '-------------------------------- 'Compute checksum (prior to sending) ' ' eCHKsumINTEGER = 0 'clear checksum bytes ' eCHKsumINTEGER = eCHKsumINTEGER + RAMpeek( VarPtr(ePREAMBLE(1)) ) ' eCHKsumINTEGER = eCHKsumINTEGER + RAMpeek( VarPtr(ePREAMBLE(2)) ) ' eCHKsumINTEGER = eCHKsumINTEGER + RAMpeek( VarPtr(ePOSITION(1)) ) ' eCHKsumINTEGER = eCHKsumINTEGER + RAMpeek( VarPtr(ePOSITION(1))+1 ) ' eCHKsumINTEGER = eCHKsumINTEGER + RAMpeek( VarPtr(ePOSITION(1))+2 ) ' eCHKsumINTEGER = eCHKsumINTEGER + RAMpeek( VarPtr(ePOSITION(1))+3 ) ' eCHKsumBYTE = CByte(eCHKsumINTEGER MOD 256) 'the conversion may not be necessary ' '-------------------------------- 'Send 7 bytes of data (when you're ready) ' ' Call PutQueue (SerialOutputBuffer, ePREAMBLE, 2) ' Call PutQueue (SerialOutputBuffer, ePOSITION, 4) ' Call PutQueue (SerialOutputBuffer, eCHKsumBYTE, 1) ' '-------------------------------- I hope this will be helpful Best Regards, Eric ----- Original Message ----- From: Ed To: Sent: Thursday, January 20, 2005 4:56 AM Subject: [BasicX] Re: HEX simplify program. How? Ok, i got a way of simplify it: ------------------------------------------------------------------ Public Sub Movements() Dim N as byte For N=1 to 21 Command = &HF0 ' Command Call PutQueue (SerialOutputBuffer, Command, 1) Address = &H01 ' Address Call PutQueue (SerialOutputBuffer, Address, 1) D = 2000 Call PutQueue (SerialOutputBuffer, D, 4) Check = &HC8 ' Checksum Call PutQueue (SerialOutputBuffer, Check, 1) ----------------------------------------------------------------- The problem is that I need to generate 256 Checksum summation. I can easily add Command & Address but for D that now is a long number, i need to split it in two. That is D(1)=00 and D(2)=20 so I can add them with the rest of the variables (bytes) and generate the Checksum. What I wanted to do is to generate a loop that continuosly adds 250 to variable D (Displacement) so I don't have to write 250 variables. Any ideas? [Non-text portions of this message have been removed] |
|
|
|
eserdahl@ wrote: >Hi Ed, >I looked at a datasheet at http://www.solutions-cubed.com >assuming that you are using that system, in (ref 4.5) "Direct Control Mode", I think the Protocol calls for 7 bytes to be sent to execute the (ref 5.2.18)"Write Desired Position" command. In thinking about this as a "Move To" command, you would know everything but the "checksum" prior to sending the 7 bytes. There are many different ways of proceeding, the following is just a suggestion. The "Position" is assigned to a 32 bit, 4 byte, "Long" variable. This is now in memory, stored LSB at the "address" of the variable, the next byte at "address + 1", the next byte at "address + 2" and the MSB at "address + 3". A subroutine would sequentially add the 4 bytes, add the "Command" and "DeviceADDR" bytes, do a "mod 256" to produce a checksum byte and then send all the known data. > > Let me offer some improvements to Eric's suggested code. 1. Add constants for InputPort and OutputPort and fixup a few other compile problems such as adding some CInt conversions. 2. When you add a byte to a byte in BasicX, the resultant byte is automatically modulo 256. This fact can be used to eliminate the eCHKsumINTEGER variable. 3. Adding the 6 bytes to create the checksum can be done all in one statement. This saves on pushing and popping the variable eCHKsumBYTE for each assignment. 4. Changed to output queue size to accommodate all 7 bytes of the message. These changes reduce the code size down from 196 bytes to 144 bytes, The checksum calculation is now only 52 bytes long. When I wrapped the checksum calculation in a function, the mean time to execute was 0.55 ms including the overhead of the function call, return and a for/next iteration loop for timing. This means you could execute at least 1800 checksums per second or probably more than 3000 if you inline the code. Given that the two variables (ePREAMBLE and ePOSITION) are together in memory, a For/Next loop could be used to cycle through the 6 bytes but actually that turns out to be more code and slower than the simple addition because of the loop overhead. Here is my revision to Eric's example code: Option Explicit Public Sub Main() '-------------------------------- 'Declarations ' Const eCMD As Byte = &HF0 Const eADDR As Byte = &H01 Const InputPin as Byte = 6 Const OutputPin as Byte = 5 ' Dim ePREAMBLE(1 to 2) As Byte 'is 2 bytes Dim ePOSITION As Long 'is 4 bytes Dim eCHKsumBYTE As Byte 'is 1 byte ' Dim SerialOutputBuffer(1 to 16) as byte ' must be at least 16 to send 7 bytes (+9 byte overhead) Dim SerialInputBuffer(1 to 13) as byte ' '-------------------------------- 'setup queues (do once) ' Call OpenQueue(SerialOutputBuffer, 13) Call OpenQueue(SerialInputBuffer, 13) Call DefineCom3(InputPin, OutputPin, bx0000_1000) Call OpenCom(3, 19200, SerialInputBuffer, SerialOutputBuffer) ' '-------------------------------- 'Build preamble (do once) ' ePREAMBLE(1) = eCMD ePREAMBLE(2) = eADDR ' '-------------------------------- 'Set the desired position (any time) ' ePOSITION = 2000 ' &H000007D0 ' ' uses twos complement '-------------------------------- 'Compute checksum (prior to sending) ' eCHKsumBYTE = RAMpeek(VarPtr(ePREAMBLE(1))) + RAMpeek(VarPtr(ePREAMBLE(2))) + RAMpeek(VarPtr(ePOSITION)) + RAMpeek(VarPtr(ePOSITION)+1) + RAMpeek(VarPtr(ePOSITION)+2) + RAMpeek(VarPtr(ePOSITION)+3) ' '-------------------------------- 'Send 7 bytes of data (when you're ready) ' Call PutQueue (SerialOutputBuffer, ePREAMBLE, 2) Call PutQueue (SerialOutputBuffer, ePOSITION, 4) Call PutQueue (SerialOutputBuffer, eCHKsumBYTE, 1) '-------------------------------- End Sub |
|
|
|
I wrote: : > These changes reduce the code size down from 196 bytes to 144 bytes, The > checksum calculation is now only 52 bytes long. When I wrapped the > checksum calculation in a function, the mean time to execute was 0.55 > ms including the overhead of the function call, return and a for/next > iteration loop for timing. This means you could execute at least 1800 > checksums per second or probably more than 3000 if you inline the code. I inlined the code 100 times and found the average execution for the checksum calculation to be 0.23 ms (230 microseconds) which should be fast enough for what you want :) Mike |
|
Hi Mike, Excellent improvements. Explaining that RAMpeek byte+byte=byte in the example addition results in an effective MOD 256 on the sum is SWEET! Very good example of how to optimize, reduce code and speed up. The line ... Call OpenQueue(SerialOutputBuffer, 13) should be ... Call OpenQueue(SerialOutputBuffer, 16). In my programs I use a "Const" to dimension the "size" of my buffers so that I'll have to think twice when I use OpenQueue. Hopefully this will help Ed and he'll let us know how it worked. Best Regards, Eric ----- Original Message ----- From: Mike Perks To: Sent: Thursday, January 20, 2005 7:00 PM Subject: Re: [BasicX] Re: HEX simplify program. How? eserdahl@ wrote: >Hi Ed, >I looked at a datasheet at http://www.solutions-cubed.com >assuming that you are using that system, in (ref 4.5) "Direct Control Mode", I think the Protocol calls for 7 bytes to be sent to execute the (ref 5.2.18)"Write Desired Position" command. In thinking about this as a "Move To" command, you would know everything but the "checksum" prior to sending the 7 bytes. There are many different ways of proceeding, the following is just a suggestion. The "Position" is assigned to a 32 bit, 4 byte, "Long" variable. This is now in memory, stored LSB at the "address" of the variable, the next byte at "address + 1", the next byte at "address + 2" and the MSB at "address + 3". A subroutine would sequentially add the 4 bytes, add the "Command" and "DeviceADDR" bytes, do a "mod 256" to produce a checksum byte and then send all the known data. > Let me offer some improvements to Eric's suggested code. 1. Add constants for InputPort and OutputPort and fixup a few other compile problems such as adding some CInt conversions. 2. When you add a byte to a byte in BasicX, the resultant byte is automatically modulo 256. This fact can be used to eliminate the eCHKsumINTEGER variable. 3. Adding the 6 bytes to create the checksum can be done all in one statement. This saves on pushing and popping the variable eCHKsumBYTE for each assignment. 4. Changed to output queue size to accommodate all 7 bytes of the message. These changes reduce the code size down from 196 bytes to 144 bytes, The checksum calculation is now only 52 bytes long. When I wrapped the checksum calculation in a function, the mean time to execute was 0.55 ms including the overhead of the function call, return and a for/next iteration loop for timing. This means you could execute at least 1800 checksums per second or probably more than 3000 if you inline the code. Given that the two variables (ePREAMBLE and ePOSITION) are together in memory, a For/Next loop could be used to cycle through the 6 bytes but actually that turns out to be more code and slower than the simple addition because of the loop overhead. Here is my revision to Eric's example code: Option Explicit Public Sub Main() '-------------------------------- 'Declarations ' Const eCMD As Byte = &HF0 Const eADDR As Byte = &H01 Const InputPin as Byte = 6 Const OutputPin as Byte = 5 ' Dim ePREAMBLE(1 to 2) As Byte 'is 2 bytes Dim ePOSITION As Long 'is 4 bytes Dim eCHKsumBYTE As Byte 'is 1 byte ' Dim SerialOutputBuffer(1 to 16) as byte ' must be at least 16 to send 7 bytes (+9 byte overhead) Dim SerialInputBuffer(1 to 13) as byte ' '-------------------------------- 'setup queues (do once) ' Call OpenQueue(SerialOutputBuffer, 13) Call OpenQueue(SerialInputBuffer, 13) Call DefineCom3(InputPin, OutputPin, bx0000_1000) Call OpenCom(3, 19200, SerialInputBuffer, SerialOutputBuffer) ' '-------------------------------- 'Build preamble (do once) ' ePREAMBLE(1) = eCMD ePREAMBLE(2) = eADDR ' '-------------------------------- 'Set the desired position (any time) ' ePOSITION = 2000 ' &H000007D0 ' ' uses twos complement '-------------------------------- 'Compute checksum (prior to sending) ' eCHKsumBYTE = RAMpeek(VarPtr(ePREAMBLE(1))) + RAMpeek(VarPtr(ePREAMBLE(2))) + RAMpeek(VarPtr(ePOSITION)) + RAMpeek(VarPtr(ePOSITION)+1) + RAMpeek(VarPtr(ePOSITION)+2) + RAMpeek(VarPtr(ePOSITION)+3) ' '-------------------------------- 'Send 7 bytes of data (when you're ready) ' Call PutQueue (SerialOutputBuffer, ePREAMBLE, 2) Call PutQueue (SerialOutputBuffer, ePOSITION, 4) Call PutQueue (SerialOutputBuffer, eCHKsumBYTE, 1) '-------------------------------- End Sub [Non-text portions of this message have been removed] |
|
|
|
eserdahl@ wrote: >Hi Mike, > >Excellent improvements. Explaining that RAMpeek byte+byte=byte in the example addition results in an effective MOD 256 on the sum is SWEET! > >Very good example of how to optimize, reduce code and speed up. > >The line ... Call OpenQueue(SerialOutputBuffer, 13) should be ... Call OpenQueue(SerialOutputBuffer, 16). In my programs I use a "Const" to dimension the "size" of my buffers so that I'll have to think twice when I use OpenQueue. > >Hopefully this will help Ed and he'll let us know how it worked. > >Best Regards, Eric Thanks. You are right of course - I was more focused on the problem at hand. Constants should be used for almost everything with suitable comments. In fact it could even be something like: Const MandatoryQueueSize as Byte = 9 Const HBridgeSerialOutputSize as Byte = 7 + MandatoryQueueSize See message 17545 for an explanation of what is in the 9 byte header for every queue. Mike |
|
WOW!! You're great guys!! Thanks a lot for the info!! Yesterday afternoon I got it working by using GetBit and PutBit so basically I built my own four 4 bytes variables to add them together with a few FOR NEXT loops. A quite complex and long way to do it compared to your solution. Just for reference purposes only I post the code of how I got it: ' ********* CALCULATE CHECKSUM ************************** For I = 0 to 7 C1(I) = GetBit (D,I) Call PutBit (T1, I, C1(I)) 'Debug.Print CStr(C1(I)); " ";Cstr (T1); " "; Cstr(I) Next Checksum = T1 For I = 0 to 7 C2(I+8) = GetBit (D,I+8) Call Putbit (T2, (I), C2(I+8)) 'Debug.Print CStr(C2(I)); " ";Cstr (T2); " "; Cstr(I+8) Next Checksum = Checksum + T2 + Command + Address 'Checksum = &H04 'Debug.Print Cstr(Checksum) ' ******* END CALCULATE CHECKSUM **************************** I won't be able to test your code until Monday, as the Motor has been taken to a workshop to do a few modifications to the support where it is mounted on. I will let you know as soon as I get some results. - Eric, yes the system I'm using is the one you mention and yes: Direct Mode. - Mike, how you find out how fast the calculations are? (just out of curiosity) Thanks a lot again, you're been of great help!! Ed --- In , "eserdahl@" <eserdahl@p...> wrote: > Hi Mike, > > Excellent improvements. Explaining that RAMpeek byte+byte=byte in the example addition results in an effective MOD 256 on the sum is SWEET! > > Very good example of how to optimize, reduce code and speed up. > > The line ... Call OpenQueue(SerialOutputBuffer, 13) should be ... Call OpenQueue(SerialOutputBuffer, 16). In my programs I use a "Const" to dimension the "size" of my buffers so that I'll have to think twice when I use OpenQueue. > > Hopefully this will help Ed and he'll let us know how it worked. > > Best Regards, Eric > ----- Original Message ----- > From: Mike Perks > To: > Sent: Thursday, January 20, 2005 7:00 PM > Subject: Re: [BasicX] Re: HEX simplify program. How? > eserdahl@ wrote: > > >Hi Ed, > >I looked at a datasheet at http://www.solutions-cubed.com > >assuming that you are using that system, in (ref 4.5) "Direct Control Mode", I think the Protocol calls for 7 bytes to be sent to execute the (ref 5.2.18)"Write Desired Position" command. In thinking about this as a "Move To" command, you would know everything but the "checksum" prior to sending the 7 bytes. There are many different ways of proceeding, the following is just a suggestion. The "Position" is assigned to a 32 bit, 4 byte, "Long" variable. This is now in memory, stored LSB at the "address" of the variable, the next byte at "address + 1", the next byte at "address + 2" and the MSB at "address + 3". A subroutine would sequentially add the 4 bytes, add the "Command" and "DeviceADDR" bytes, do a "mod 256" to produce a checksum byte and then send all the known data. > > > Let me offer some improvements to Eric's suggested code. > > 1. Add constants for InputPort and OutputPort and fixup a few other > compile problems such as adding some CInt conversions. > 2. When you add a byte to a byte in BasicX, the resultant byte is > automatically modulo 256. This fact can be used to eliminate the > eCHKsumINTEGER variable. > 3. Adding the 6 bytes to create the checksum can be done all in one > statement. This saves on pushing and popping the variable eCHKsumBYTE > for each assignment. > 4. Changed to output queue size to accommodate all 7 bytes of the message. > > These changes reduce the code size down from 196 bytes to 144 bytes, The > checksum calculation is now only 52 bytes long. When I wrapped the > checksum calculation in a function, the mean time to execute was 0.55 > ms including the overhead of the function call, return and a for/next > iteration loop for timing. This means you could execute at least 1800 > checksums per second or probably more than 3000 if you inline the code. > > Given that the two variables (ePREAMBLE and ePOSITION) are together in > memory, a For/Next loop could be used to cycle through the 6 bytes but > actually that turns out to be more code and slower than the simple > addition because of the loop overhead. Here is my revision to Eric's > example code: > > Option Explicit > > Public Sub Main() > > '-------------------------------- > 'Declarations > ' > Const eCMD As Byte = &HF0 > Const eADDR As Byte = &H01 > > Const InputPin as Byte = 6 > Const OutputPin as Byte = 5 > ' > Dim ePREAMBLE(1 to 2) As Byte 'is 2 bytes > Dim ePOSITION As Long 'is 4 bytes > Dim eCHKsumBYTE As Byte 'is 1 byte > ' > Dim SerialOutputBuffer(1 to 16) as byte > ' must be at least 16 to send 7 bytes (+9 byte overhead) > Dim SerialInputBuffer(1 to 13) as byte > ' > '-------------------------------- > 'setup queues (do once) > ' > Call OpenQueue(SerialOutputBuffer, 13) > Call OpenQueue(SerialInputBuffer, 13) > Call DefineCom3(InputPin, OutputPin, bx0000_1000) > Call OpenCom(3, 19200, SerialInputBuffer, SerialOutputBuffer) > ' > '-------------------------------- > 'Build preamble (do once) > ' > ePREAMBLE(1) = eCMD > ePREAMBLE(2) = eADDR > ' > '-------------------------------- > 'Set the desired position (any time) > ' > ePOSITION = 2000 ' &H000007D0 > ' ' uses twos complement > '-------------------------------- > 'Compute checksum (prior to sending) > ' > eCHKsumBYTE = RAMpeek(VarPtr(ePREAMBLE(1))) + > RAMpeek(VarPtr(ePREAMBLE(2))) + RAMpeek(VarPtr(ePOSITION)) + > RAMpeek(VarPtr(ePOSITION)+1) + RAMpeek(VarPtr(ePOSITION)+2) + > RAMpeek(VarPtr(ePOSITION)+3) > > ' > '-------------------------------- > 'Send 7 bytes of data (when you're ready) > ' > Call PutQueue (SerialOutputBuffer, ePREAMBLE, 2) > Call PutQueue (SerialOutputBuffer, ePOSITION, 4) > Call PutQueue (SerialOutputBuffer, eCHKsumBYTE, 1) > > '-------------------------------- > > End Sub > [Non-text portions of this message have been removed] |
|
|