News:

Let's find out together what makes a PIC Tick!

Main Menu

Shifting data in arrays Left & Right

Started by chris_cb_uk, May 06, 2022, 01:52 PM

Previous topic - Next topic

chris_cb_uk

I have decoded the data from a cable meterage display.  I've processed the data into a neater format which generates examples below giving (+)/- Meter,cm:

-0,11
-10000,99
0,11
10000,99

I've created a little loop to look for the "," and replace with "." so I can always find the decimal point in the array number, I've extracted the cm using the +1 and +2 from the decimal. I've also extracted array
  • to look for the "-" and flag up as a negative.

This now gives 0.11 1000.99 etc

My next task I am struggling to get my head around is to remove the - from array[0] and shift the data to the left so it just reads as a positive figure.

I also want to be able to shuffle the unit, 10 100 1000 10,000 into a designated array of fixed size. For example instead of being 0.11 it is presented as 00000.11 or 100.12 is 00100.11

I have the reference of the decimal and that's how I imagine best to tackle it as the rest to the left is variable number of digits.

I have not really played with arrays properly and it's been quite an interesting experience, but just looking for a bit of input of how to achieve the above?

Would it be best to lift the parts using left$ and right$ from the decimal and lay it into a new array? or can I shift the array?

RGV250

Hi,
Can you do something like
Array[0] = Array[1]
Array[1] = Array[2]
Array[2] = Array[3]
Array[3] = Array[4]
and so on in a proceedure.

Bob]

chris_cb_uk

Hi Bob, yes for the - (negative) element I can shift over that way, I didn't know if there was a more efficient way to carry this out.

For the setting of unit, ten, hundred, thousand I was thinking about looking for the number of leading 0's or empty arrays lower than the highest figure to work out the right unit to put into the right array segment.

RGV250

Is it always 2 dec places, could it work to create a string without the comma and then use VAL to convert to an integer than divide by 100 to get back to the floating point value?

Bob

trastikata

Quote from: chris_cb_uk on May 06, 2022, 02:28 PMHi Bob, yes for the - (negative) element I can shift over that way, I didn't know if there was a more efficient way to carry this out.

Variations of this code, according the need and direction of the shift.

  For i = 5 To 1 Step -1
       My_Buffer[i] = My_Buffer[i - 1] 
  Next




top204

Below is a more refined method that parses the byte array that contains ASCII characters and returns a String variable.

It looks more complex, but it is actually more efficient because the same procedure can be used multiple times and with different byte arrays or Strings sent to it. The byte array must be a null terminated type containing ASCII characters only, and it may be better to use a String variable instead of the byte array in your program, if it only ever contains ASCII characters.

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' A demo to show how to parse an ASCII filled byte array and remove/replace any unwanted characters.
' Uses indirect reading of the array so that any byte array can be sent to the procedure.
' The program is suitable for any 18F device or enhanced 14-bit core device.
'
' Written for the Positron8 compiler by Les Johnson.
'
    Device = 18F25K20
    Declare Xtal = 16
'
' Setup USART1
'   
    Declare Hserial_Baud = 9600
    Declare HRSOut1_Pin = PORTC.6
'
' Create some variables
'
    Dim MyString As String * 30                     ' Holds the returned, parsed, array's characters
    Dim MyByteArray[20] As Byte                     ' Holds the characters to parse
 
'--------------------------------------------------------------------
' The main program starts here
'
Main:
    Clear MyByteArray                               ' Clear the array, so it is filled with zeroes (nulls)
    MyByteArray = "-100000,14"                      ' Load ASCII characters into the array

    HRSOutLn "Orig: ", Str MyByteArray              ' Serially transmit the original ASCII filled array
    MyString = AbsArray(MyByteArray)                ' Remove and replace characters from the array
    HRSOutLn "Abs: ", MyString                      ' Serially transmit the modified String

'--------------------------------------------------------------------
' Remove a minus or plus character from a null terminated byte array holding ASCII characters
' It also replaces a comma with a decimal point
' Input     : pArrayAddr holds the address of the byte array to extract from 
' Output    : Returns a String holding the byte array's ASCII values without the minus or plus characters
'           : And the replaced comma
' Notes     : If the array sent does not contain the minus or plus characters, nothing will be removed
'  
Proc AbsArray(ByRef pArrayAddr As Word), String * 20
    Dim bChar As Byte
    Dim bCharCount As Byte
    Clear Result                                    ' Clear the returning String
   
    For bCharCount = Bound(Result) DownTo 0         ' Create a loop to examine the byte array
        bChar = Ptr8(pArrayAddr++)                  ' Extract a character from the array and increment its address
        If bChar = 0 Then                           ' Is the character a Null (0)?
            Break                                   ' Yes. So exit the loop
       
        ElseIf bChar = "," Then                     ' Is the character a comma? 
            Result = Result + "."                   ' Yes. So replace it with a decimal point
       
        ElseIf bChar <> "-" And bChar <> "+" Then   ' Is the character "-" or "+"?
            Result = Result + bChar                 ' No. So add it to the Result String
        EndIf
    Next
EndProc

chris_cb_uk

Quote from: RGV250 on May 06, 2022, 02:41 PMIs it always 2 dec places, could it work to create a string without the comma and then use VAL to convert to an integer than divide by 100 to get back to the floating point value?

Bob

Yes always 2 decimals, regardless of the unit, ten, hundred, thousand, that's why I am thinking to use the decimal (,) as reference.

chris_cb_uk

Quote from: top204 on May 06, 2022, 04:22 PMBelow is a more refined method that parses the byte array that contains ASCII characters and returns a String variable.

It looks more complex, but it is actually more efficient because the same procedure can be used multiple times and with different byte arrays or Strings sent to it. The byte array must be a null terminated type containing ASCII characters only, and it may be better to use a String variable instead of the byte array in your program, if it only ever contains ASCII characters.

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' A demo to show how to parse an ASCII filled byte array and remove/replace any unwanted characters.
' Uses indirect reading of the array so that any byte array can be sent to the procedure.
' The program is suitable for any 18F device or enhanced 14-bit core device.
'
' Written for the Positron8 compiler by Les Johnson.
'
    Device = 18F25K20
    Declare Xtal = 16
'
' Setup USART1
'   
    Declare Hserial_Baud = 9600
    Declare HRSOut1_Pin = PORTC.6
'
' Create some variables
'
    Dim MyString As String * 30                     ' Holds the returned, parsed, array's characters
    Dim MyByteArray[20] As Byte                     ' Holds the characters to parse
 
'--------------------------------------------------------------------
' The main program starts here
'
Main:
    Clear MyByteArray                               ' Clear the array, so it is filled with zeroes (nulls)
    MyByteArray = "-100000,14"                      ' Load ASCII characters into the array

    HRSOutLn "Orig: ", Str MyByteArray              ' Serially transmit the original ASCII filled array
    MyString = AbsArray(MyByteArray)                ' Remove and replace characters from the array
    HRSOutLn "Abs: ", MyString                      ' Serially transmit the modified String

'--------------------------------------------------------------------
' Remove a minus or plus character from a null terminated byte array holding ASCII characters
' It also replaces a comma with a decimal point
' Input     : pArrayAddr holds the address of the byte array to extract from 
' Output    : Returns a String holding the byte array's ASCII values without the minus or plus characters
'           : And the replaced comma
' Notes     : If the array sent does not contain the minus or plus characters, nothing will be removed
'   
Proc AbsArray(ByRef pArrayAddr As Word), String * 20
    Dim bChar As Byte
    Dim bCharCount As Byte
    Clear Result                                    ' Clear the returning String
   
    For bCharCount = Bound(Result) DownTo 0         ' Create a loop to examine the byte array
        bChar = Ptr8(pArrayAddr++)                  ' Extract a character from the array and increment its address
        If bChar = 0 Then                           ' Is the character a Null (0)?
            Break                                   ' Yes. So exit the loop
       
        ElseIf bChar = "," Then                     ' Is the character a comma? 
            Result = Result + "."                   ' Yes. So replace it with a decimal point
       
        ElseIf bChar <> "-" And bChar <> "+" Then   ' Is the character "-" or "+"?
            Result = Result + bChar                 ' No. So add it to the Result String
        EndIf
    Next
EndProc


Thanks Les, I've made a similar outcome occur but less pretty coding as you which replaces the , and identifies the - and shifts everything left using Bob's suggestion of shifting the updated array numbers to the -1 of the last.   

I'm now working to try and make the unit, ten, hundred, thousand, ten thousand appear in their respective "slots" so to speak. Currently it's 1.11m 11.11m, 111.11m, 1111.11m Imagine it's a 5 digit lcd set layout screen where the digits are set. So 1.50m = 00001.50 | 100.99m = 00100.99 post decimal. I can only see checking for filled digits to the left of the decimal and reassigning them to the new array number?

Yasin

I may not understand correctly because my English is poor. So I apologize in advance. Your goal is a number; Is it to print the whole part in 5 digits and the decimal part in 2 digits? If so, I would like to suggest another method.

Declare Xtal = 4
Dim String1 As String * 8
Dim Float1 As Float = 1.91
Dim W1 As Word
Dim B1 As Byte

MAIN:
    Float1 = Float1 + 0.01
    W1 = Float1
    B1 = (Float1 - W1) * 100
    String1 = Str$(Dec5 W1) + "," + Str$(Dec2 B1)
    HSerOut [String1,13,10]
    DelayMS 100
GoTo MAIN
End


top204

#9
To remove the possibility of the 32-bit floating point not converting the ASCII to Float correctly, which will always happen with some values in the IEEE floating point format. You can separate the Pre and Post decimal point values into two Strings. Then do simple padding of the Strings and use them to place on the LCD.

Then, as Yasin showed, convert both pre and post integer Strings into integers for display, with the decimal point in the same place on the LCD.

To get them in the same place on the display, a set of Select-EndSelect or If-Thens can look at the size of the integer values and determine where on the LCD they should be placed based upon how many digits the value will contain.



top204

Below is a demo of a procedure that will split the Byte array or String holding a floating point value into two seperate pre and post, decimal point, integer variables:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' A demo to show how to parse a Floating Point ASCII filled Byte array and convert the pre and post, decimal point, values into integers.
' Uses indirect reading of the array so that any Byte array or String can be sent to the procedure.
' Also uses indirect writing to fill the variables passed to the procedure.
' The program is suitable for any 18F device or enhanced 14-bit core device.
'
' Written for the Positron8 compiler by Les Johnson.
'
    Device = 18F25K20
    Declare Xtal = 16
'
' Setup USART1
'   
    Declare Hserial_Baud = 9600
    Declare HRSOut1_Pin = PORTC.6
'
' Create some variables

    Dim MyByteArray[20] As Byte Heap                ' Holds the digit characters to parse   
    Dim Global_dPreValue As Dword                   ' Holds the pre-decimal point integer value
    Dim Global_wPostValue As Word                   ' Holds the post-decimal point integer value
   
'--------------------------------------------------------------------
' The main program starts here
'
Main:    
    Clear MyByteArray                               ' Clear the array, so it is filled with zeroes (nulls)
    MyByteArray = "-12345678,140"                   ' Load ASCII characters into the array

    HRSOutLn "Orig: ", Str MyByteArray                          ' Serially transmit the original ASCII filled array
    ConvArray(MyByteArray, Global_dPreValue, Global_wPostValue) ' Convert the array into pre and post, decimal point, integer values
    HRSOutLn Dec Global_dPreValue, ".", Dec Global_wPostValue  ' Serially transmit the pre and post, decimal point, integer values
 
'--------------------------------------------------------------------
' Extracts the Pre and Post, decimal point, values from a null terminated byte array holding ASCII floating point digits
' Input     : pArrayAddr holds the address of the byte array to extract from 
'           : pPreAddr holds the address of the 32-bit variable to load the pre-decimal point value into
'           : pPostAddr holds the address of the 16-bit variable to load the post-decimal point value into
' Output    : The variables passed to the procedure will be loaded with pre and post integer values
' Notes     : None
'  
Proc ConvArray(ByRef pArrayAddr As Word, ByRef pPreAddr As Word, ByRef pPostAddr As Word)
    Dim dTemp As Dword                              ' A temporary Dword
    Dim wTemp As dTemp.Word0                        ' A temporary Word aliased to the low word of dTemp
    Dim TmpString As String * 20 Heap               ' Holds the parsed array's characters 
    Dim bChar As dTemp.Byte3                        ' Holds the character extracted from the passed array. Aliased to the High Byte of dTemp
    Dim bCharCount As Byte                          ' Holds a count of the characters
    Dim wStrAddr As dTemp.Word0                     ' Holds the address of "TmpString". Aliased to the low word of dTemp
   
    wStrAddr = AddressOf(TmpString)                 ' Load wStrAddr with the address of "TmpString"
    Clear TmpString                                 ' Clear TmpString
    For bCharCount = Bound(TmpString) DownTo 0      ' Create a loop to examine the byte array
        bChar = Ptr8(pArrayAddr++)                  ' Extract a character from the array and increment the address
        If bChar = 0 Then                           ' Is the character a Null (0)?
            wTemp = Val(TmpString, Dec)             ' Yes. So convert the string into a 16-bit integer value
            Ptr16(pPostAddr) = wTemp                ' Load the address pPostAddr with the 16-bit integer value
            Break                                   ' Exit the loop
       
        ElseIf bChar = "," Or bChar = "." Then      ' Is the character a decimal point or comma? 
            dTemp = Val(TmpString, Dec)             ' Yes. So convert the string into a 32-bit integer value
            Ptr32(pPreAddr) = dTemp                 ' Load the address pPreAddr with the 32-bit integer value
            wStrAddr = AddressOf(TmpString)         ' Set the address to the beginning of "TmpString"
            Clear TmpString                         ' Clear TmpString, because it will be filled again
           
        ElseIf bChar <> "-" Then                    ' Is the character "-"?
            Ptr8(wStrAddr++) = bChar                ' No. So add it to the String held in "wStrAddr"           
        EndIf
    Next   
EndProc

It shows the use of the indirect PtrX commands for reading and writing, and using the parameters as return variables as well.

chris_cb_uk

Thanks Les, I'll have. Play with your code to understand it in the real application.

Thanks all for input!