News:

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

Main Menu

Positron8 - Writing and Reading bits in a Byte Array

Started by top204, Apr 18, 2023, 06:31 PM

Previous topic - Next topic

top204

Using procedures and indirect access for the RAM, accessing individual bits within an array's element is pretty straightforward, and is very similar to writing and reading a graphic LCD that uses bytes for its display instead of individual pixels. The demo program below shows two procedures. One to write bits to a Byte array and one to read bits from a Byte array.

Note: Because it is using SFRs (Special Function Registers), it is only suitable for 18F devices, but could be changed for enhanced 14-bit core devices as well:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Write and read bits in a byte array's elements.
' Because the program listing uses the indirect SFRs, the program is only suitable for an 18F device.
'
' Written for the Positron8 compiler by Les Johnson.
'
    Device = 18F25K20                               ' Tell the compiler what device to compile for
    Declare Xtal = 16                               ' Tell the compiler what frequency the device will be operating at (in MHz)
'
' Setup USART1
'
    Declare Hserial1_Baud = 9600                    ' Set the Baud rate to 9600
    Declare HRSOut1_Pin = PORTC.6                   ' Set the TX pin
'
' Create some variables for the demo

    Dim MyByteArray[160 / 8] As Byte Heap           ' Create a byte array large enough to holds 160 bits    
    Dim MyBit As Bit                                ' Holds the bit written and read to/from the array
    Dim bBitNum As Byte                             ' Holds the bit number within the array
          
'-------------------------------------------------------------------------
' The main program starts here
' Write pseudo random bits to a byte array, then read them back and display them on a serial terminal.
'
Main:
    Seed $0345                                      ' Seed the pseudo random number generator
    Clear MyByteArray                               ' Clear the array holding the bits
'
' Write bits to the array
'   
    HRSOut "Write:"
    For bBitNum = 0 To 109                          ' Create a loop for the bit numbers
        MyBit = Random                              ' Get a pseudo random bit
        WriteBit(MyByteArray, bBitNum, MyBit)       ' Load the array's bit with the random value
        If bBitNum // 8 = 0 Then                    ' \
            HRSOut "|"                              ' | Place a boundary around each 8-bits displayed so it is easier to view
        EndIf                                       ' /
        HRSOut Bin1 MyBit                           ' Transmit the bit written to a serial terminal
    Next
'
' Read the bits from the array
'   
    HRSOut "\rRead :"
    For bBitNum = 0 To 109                          ' Create a loop for the bit numbers
        MyBit = ReadBit(MyByteArray, bBitNum)       ' Read a bit from the array
        If bBitNum // 8 = 0 Then                    ' \
            HRSOut "|"                              ' | Place a boundary around each 8-bits displayed so it is easier to view
        EndIf                                       ' /
        HRSOut Bin1 MyBit                           ' Transmit the bit read to a serial terminal
    Next
    HRSOut 13
    
'-------------------------------------------------------------------------
' Read a single bit from a byte array
' Input     : pArrAddr (FSR1L\H) holds the address of the byte array containing the bits
'           : pBitNum holds the bit number to read (0 to 255)
' Output    : Returns the state of the bit
' Notes     : None
'
Proc ReadBit(ByRef pArrAddr As wRdFSR1, pBitNum As Byte), Bit
Global Dim wRdFSR1 As FSR1L.Word                        ' Create a global 16-bit SFR of FSR1L\H. It can also be used as a parameter   
      
    pArrAddr = pArrAddr + (pBitNum / 8)                 ' Find the element of the array that holds the bit, and move up to it
    Result = GetBit(INDF1, (pBitNum // 8))              ' Read the bit from its position within the array's element
EndProc

'-------------------------------------------------------------------------
' Write a single bit to a byte array
' Input     : pArrAddr (FSR1L\H) holds the address of the byte array to write the bit to
'           : pBitNum holds the bit number to write (0 to 255)
'           : pValue holds the value to write to the bit (1 or 0)
' Output    : None
' Notes     : None
'
Proc WriteBit(ByRef pArrAddr As wWrFSR1, pBitNum As Byte, pValue As Bit)
    Dim bTemp      As PRODL                             ' Holds the element's contents because LoadBit also uses indirect access
Global Dim wWrFSR1 As FSR1L.Word                        ' Create a global 16-bit SFR of FSR1L\H. It can also be used as a parameter
      
    pArrAddr = pArrAddr + (pBitNum / 8)                 ' Find the element of the array that holds the bit, and move up to it
    bTemp = INDF1                                       ' Transfer the element's value into a temporary variable
    LoadBit(bTemp, (pBitNum // 8), pValue)              ' Write the bit
    INDF1 = bTemp                                       ' Transfer the value into the array's element
EndProc

Notice the, still beta, Global directive that will create a variable that can also be used as a parameter because it is global and created before the procedure, but only if the procedure is called in the program's listing. It is still beta, but seems to work well, and will allow parameters to use global variables that are only ever created when the procedure is called. In theory anyway. :-)

The procedures are, essentially, creating a Bit array mechanism from a Byte array, so may come in handy someday.

Below is a screenshot of the above program working with a reliable device in Proteus:
Write and Read Array Bits.jpg

top204

Below is another version of the above Bit reading and writing procedures. It uses masking to read and write the bit within the array's element instead of the GetBit and LoadBit commands in the procedures, and makes the program more efficient and easier to understand:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Write and read bits to/from a Byte array's elements, and treat it as a form of Bit array.
' Because it uses some the indirect SFRs, the program is only suitable for an 18F device.
'
' This version uses masking to read and write the bit within an array's element, instead of the GetBit and LoadBit commands within the procedures.
' The replacements make the code more efficient and easier to understand and follow.
'
' Written for the Positron8 compiler by Les Johnson.
'
    Device = 18F25K20                                   ' Tell the compiler what device to compile for
    Declare Xtal = 16                                   ' Tell the compiler what frequency the device will be operating at (in MHz)
'
' Setup USART1
'
    Declare Hserial1_Baud = 9600                        ' Set the Baud rate to 9600
    Declare HRSOut1_Pin = PORTC.6                       ' Set the TX pin
'
' Create some variables for the demo
'
    Dim MyByteArray[160 / 8] As Byte Heap               ' Create a byte array large enough to holds 160 bits
    Dim MyBit As Bit                                    ' Holds the bit written and read to/from the array
    Dim bBitNum As Byte                                 ' Holds the bit number within the array

'-------------------------------------------------------------------------
' The main program starts here
' Write bits to a byte array, then read them back and display them on a serial terminal.
'
Main:
    Seed $0345                                          ' Seed the pseudo random number generator
    Clear MyByteArray                                   ' Clear the array holding the bits
'
' Write bits to the array
'
    HRSOut "Write:"
    For bBitNum = 0 To 109                              ' Create a loop for the bit numbers
        MyBit = Random                                  ' Get a pseudo random bit
        WriteBit(MyByteArray, bBitNum, MyBit)           ' Load the array's bit with the random value
        If bBitNum // 8 = 0 Then                        ' \
            HRSOut "|"                                  ' | Place a boundary around each 8-bits displayed, to make the array's element bytes easier to view
        EndIf                                           ' /
        HRSOut Bin1 MyBit                               ' Transmit the bit written to a serial terminal
    Next
'
' Read the bits from the array
'
    HRSOut "\rRead :"
    For bBitNum = 0 To 109                              ' Create a loop for the bit numbers
        MyBit = ReadBit(MyByteArray, bBitNum)           ' Read a bit from the array
        If bBitNum // 8 = 0 Then                        ' \
            HRSOut "|"                                  ' | Place a boundary around each 8-bits displayed, to make the array's element bytes easier to view
        EndIf                                           ' /
        HRSOut Bin1 MyBit                               ' Transmit the bit read to a serial terminal
    Next
    HRSOut 13

'-------------------------------------------------------------------------
' Read a bit from a byte array
' Input     : pArrAddr holds the address of the Byte array holding the bits
'           : pBitNum holds the bit number to read (0 to 255)
' Output    : Returns the state of the bit
' Notes     : Uses masking for the bit to read
'
Proc ReadBit(ByRef pArrAddr As wRdFSR1, pBitNum As PP0), Bit
    Dim PP0H       As Byte System                       ' Create a temporary compiler system variable
    Dim bMask      As PP0H                              ' Holds the bit mask
Global Dim wRdFSR1 As FSR1L.Word                        ' Create a global 16-bit SFR of FSR1L\H so it can be used as a parameter
Global Dim PP0     As Byte System                       ' Create a global 8-bit compiler system variable so it can be used as a parameter

    pArrAddr = pArrAddr + (pBitNum / 8)                 ' Find the element of the array that holds the bit, and move up to it
    bMask = pBitNum // 8                                ' Calculate a mask for the bit's position within the byte

    WREG = INDF1                                        ' \
    WREG = WREG >> bMask                                ' | Return the bit from its position within the array's element
    Result = WREG.0                                     ' /
EndProc

'-------------------------------------------------------------------------
' Write a bit to a byte array
' Input     : pArrAddr holds the address of the byte array holding the bits
'           : pBitNum holds the bit number to write (0 to 255)
'           : pValue holds the value to write to the bit (1 or 0)
' Output    : None
' Notes     : Uses masking for the bit to write
'
Proc WriteBit(ByRef pArrAddr As wWrFSR1, pBitNum As PP0, pValue As Bit)
    Dim PP0H       As Byte System                       ' Create a temporary compiler system variable
    Dim bMask      As PP0H                              ' Holds the bit mask
Global Dim wWrFSR1 As FSR1L.Word                        ' Create a global 16-bit SFR of FSR1L\H so it can be used as a parameter
Global Dim PP0     As Byte System                       ' Create a global 8-bit compiler system variable so it can be used as a parameter

    pArrAddr = pArrAddr + (pBitNum / 8)                 ' Find the element of the array that holds the bit, and move up to it
    WREG = pBitNum // 8                                 ' \
    bMask = 1 << WREG                                   ' / Calculate a mask for the bit's position within the byte

    If pValue = 1 Then                                  ' Is the bit to be set?
        bMask = INDF1 | bMask                           ' Yes. So Or in the bit mask
    Else                                                ' Otherwise... The bit is to be cleared
        bMask = ~bMask                                  ' So... Complement the mask first
        bMask = INDF1 & bMask                           ' And in the bit mask
    EndIf
    INDF1 = bMask                                       ' Write the modified byte to the array's element
EndProc