Custom array of ports using array?


Closed Thread
Results 1 to 23 of 23

Hybrid View

  1. #1
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Thanks Bruce, Paul and Steve,

    And yes I did cheat, by using a module that I had already written.

    I started writing VirtualPort in response to this post from Osiris
    http://www.picbasic.co.uk/forum/showthread.php?t=3554

    He was looking for a way to have a 16-bit port that was scattered across random pins. By the time I got it working, Melanie had already given him what he needed, so I didn't bother posting it.

    But, I soon realized that it was going to be more usefull than originally intended so continued to add more macro's and features, and have managed to do some pretty cool stuff with it.

    Here's how the 16-bit port for Osiris looked...
    Code:
    MyPort   VAR Word  SYSTEM
    ASM  
    MyPortPins  macro        ; these define which bits go with which pins
        Vpin   0, PORTB,0
        Vpin   1, PORTC,4
        Vpin   2, PORTA,0
        Vpin   3, PORTC,1
        Vpin   4, PORTC,3
        Vpin   5, PORTC,0
        Vpin   6, PORTA,1
        Vpin   7, PORTC,5
        Vpin   8, PORTB,2
        Vpin   9, PORTB,3
        Vpin  10, PORTC,2
        Vpin  11, PORTC,0
        Vpin  12, PORTB,4
        Vpin  13, PORTB,6
        Vpin  14, PORTB,5
        Vpin  15, PORTC,7
      endm
    ENDASM
    
    @  OutputPort  MyPortPins
    @  WritePort   MyPort, MyPortPins
    
    @  InputPort   MyPortPins
    @  ReadPort    MyPort, MyPortPins
    This creates a full 16-bit bi-directional port that can be placed on ANY pins in ANY order.<HR>
    Additional macros can also allow control of Direction, Enable, Latch pulses etc. in the same structure. Here's an 8-bit port with flow control
    Code:
    Direction  VAR PORTB.5
    Enable     VAR PORTB.1
    
    ASM
    Port8_Read  macro
        PinLow _Direction   ; Set direction pin for Read
        Vpin   0, PORTB,0
        Vpin   1, PORTC,4
        Vpin   2, PORTA,0
        Vpin   3, PORTC,1
        Vpin   4, PORTC,3
        Vpin   5, PORTC,0
        Vpin   6, PORTA,1
        Vpin   7, PORTC,5
        PulseLow  Enable, 2 ; Low pulse for 2uS
      endm
    
    Port8_Write  macro
        PinHigh _Direction   ; Set direction pin for Write
        Vpin   0, PORTB,0
        Vpin   1, PORTC,4
        Vpin   2, PORTA,0
        Vpin   3, PORTC,1
        Vpin   4, PORTC,3
        Vpin   5, PORTC,0
        Vpin   6, PORTA,1
        Vpin   7, PORTC,5
        PulseLow  Enable, 2 ; Low pulse for 2uS
      endm
    ENDASM
    
    @  OutputPort  Port8_Write
    @  WritePort   MyPort, Port8_Write
    
    @  InputPort   Port8_Read
    @  ReadPort    MyPort, Port8_Read
    Or that can be simplified like this...
    Code:
    ASM
    Port8_Pins  macro
        Vpin   0, PORTB,0
        Vpin   1, PORTC,4
        Vpin   2, PORTA,0
        Vpin   3, PORTC,1
        Vpin   4, PORTC,3
        Vpin   5, PORTC,0
        Vpin   6, PORTA,1
        Vpin   7, PORTC,5
        PulseLow  Enable, 2 ; Low pulse for 2uS
      endm
    
    Port8_Read  macro
        PinLow _Direction   ; Set direction pin for Read
        Port8_Pins
      endm
    
    Port8_Write  macro
        PinHigh _Direction   ; Set direction pin for Write
        Port8_Pins
      endm
    ENDASM
    <hr>

    Another similar question that keeps popping up every now and then, is how to use an LCD that's not connected to a contiguous nibble of a port.

    This program allows you to do that, and also ties it in with LCDOUT for a "transparent" interface.
    Code:
    INCLUDE "HighJack.bas"
    @  HighJack  LCDOUT,  _LCDsend
    
    Clear
    INCLUDE "VirtualPort.bas"
    
    ;----[ Change these to match your LCD ]---------------------------------------
    LCD_DB4   VAR PORTB.0
    LCD_DB5   VAR PORTB.4
    LCD_DB6   VAR PORTC.6
    LCD_DB7   VAR PORTC.3
    LCD_RS    VAR PORTD.1
    LCD_E     VAR PORTD.0
    LCD_Lines     CON 2    ' # of Lines on LCD,  1 or 2+
    LCD_DATAUS    CON 50   ' Data delay time in us 
    LCD_COMMANDUS CON 2000 ' Command delay time in us 
     
    
    ;----[Virtual LCD Port --- 4bit mode]----------------(Don't Change)-----------
    ASM
    LCD_Port_HNIB  macro           ; Port definition for LCD High Nibble
        Vbit   LCDCDFLAG, _LCD_RS  ; Select Command/Data register
        Vpin   4, _LCD_DB4         ; Put the High Nibble on the bus
        Vpin   5, _LCD_DB5
        Vpin   6, _LCD_DB6
        Vpin   7, _LCD_DB7
        PulseLow  _LCD_E, 2        ; pulse the Enable Pin for 2 us
      endm
    ;-----------------------    
    LCD_Port_LNIB  macro           ; Port definition for LCD Low Nibble 
        Vpin   0, _LCD_DB4         ; Put the Low Nibble on the bus
        Vpin   1, _LCD_DB5
        Vpin   2, _LCD_DB6
        Vpin   3, _LCD_DB7
        PulseLow  _LCD_E, 2        ; pulse the Enable Pin for 2 us
      endm
      
      OutputPort  LCD_Port_HNIB    ; Set LCD bus to OUTPUT
    ENDASM
    
    
    ;----[Main program starts here]-----------------------------------------------
    LoopCount  VAR WORD
      
    
    Main:
      lcdout $FE,$80, dec LoopCount
      LoopCount = LoopCount + 1
    goto Main
    
    ;----[Send a byte to the Virtual LCD PORT]--------called by LCDOUT------------
    TempChar        var  byte
    Char            VAR  Byte
    LCD_Initialized VAR  FLAGS.1
    RSS             VAR  FLAGS.0                ; LCD RS State
    
    ;-------
    LCDsend:
          @  MOVE?AB  _TempChar                 ; Get char sent by LCDOUT, in WREG
          if !LCD_Initialized then LCD_Init     ; Make sure LCD was Initialized 
      LCDAfterInit:
          if TempChar = $FE then RSS=0 : goto LCDsendDone ; next char is Command 
          Char = TempChar
      LCDsendCOM:
          @  WritePort   _Char, LCD_Port_HNIB   ; send the High Nibble
      LCDsendShortCOM:
          @  WritePort   _Char, LCD_Port_LNIB   ; send the Low Nibble
    
          if LCD_RS OR (Char > 2) then
              PAUSEUS LCD_DATAUS                ; Data delay time in us 
          else
              PAUSEUS LCD_COMMANDUS             ; Command delay
          endif
          if LCD_Initialized then RSS = 1       ; Set RS to Data next time
      LCDsendDone:
    return
    
    ;----[Initialize the LCD]-----------------------------------------------------
    LCD_Init:
        LOW LCD_RS : HIGH LCD_E   ; Start with RS LOW and Enable High
        Char = 3   : gosub  LCDsendShortCOM : pause 6
                     gosub  LCDsendShortCOM : PAUSE 1
                     gosub  LCDsendShortCOM : PAUSE 1
        Char = 2   : gosub  LCDsendShortCOM : PAUSE 1  ; Start 4-bit mode
        Char = $28 : gosub  LCDsendCOM  ; Function Set, 4-bit, 2-line, 5x7
        Char = $0C : gosub  LCDsendCOM  ; Display ON
        Char = $01 : gosub  LCDsendCOM  ; Clear Screen
        Char = $06 : gosub  LCDsendCOM  ; Entry Mode
        LCD_Initialized = 1             ; LCD has been Initialized
    goto LCDAfterInit
    Of course this relies on another program I wrote, "HighJack", to actually link in to LCDOUT. But nobody bothered to respond to this thread
    http://www.picbasic.co.uk/forum/showthread.php?t=3290

    so I never bothered posting it.
    <br>
    DT

  2. #2
    Join Date
    May 2006
    Location
    Del Rio, TX, USA
    Posts
    343


    Did you find this post helpful? Yes | No

    Default

    Darrel,
    I am slowly worming my way through your code and I noticed in VituralPort the local variable "Vaddr" in the the Vpin macro. What's it for? I did a search for it and I only see it being assigned a value (in two places), but otherwise never used.

    Also, you mentioned "HighJack", but did not post it.

    BTW, I have been following your "Wish List" thread. Congrats. Get a good chair! And did you set a new avatar?

    Wish you all success,
    Steve

  3. #3
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Excellent!

    <table><tr><td valign=top></td><td>Thanks Steve. That's a bug. Thanks for finding it. The Vaddr allows it to work with WORD variables for the 16-bit ports. Then, these lines...
    Code:
              if (PortAction == 0)                   ; read
                  MOVE?TT  P, Pbit, PortVar, VarBit      
              else
                  if (PortAction == 1)               ; write
                      MOVE?TT  PortVar, VarBit, P, Pbit
    Should have used Vaddr instead of PortVar. I got the VarBit, but missed the Vaddr.

    I will make the changes. &nbsp;http://www.pbpgroup.com/Vport/VirtualPort.bas.txt

    Yeah, that new chair idea is sounding pretty good
    and, yup spruced up the avatar a bit. Hopefully it's not too annoying.

    Read the part about HighJack again.</td></tr></table>

    Thanks again,
    &nbsp; &nbsp; DT

  4. #4
    Join Date
    May 2006
    Location
    Del Rio, TX, USA
    Posts
    343


    Did you find this post helpful? Yes | No

    Question

    Alright. I've gotten though the code but still have one question. Why use seperate delay code? It's commented as "Similar to PAUSEUS, but ASM interrupt compatible".
    Yet I'm missing something here. Why is this more compatible with ASM interrupts then the PBP PAUSEUS routine? I've been using the PAUSEUS in my current project, with both high and low priority ASM interrupts (18F4620), without any problems. The delays are slightly longer than requested, due to the interrupt occuring in the delay loop (trival for most apps), but no other ill effects I've noticed. This 'error' in delay time would occur with any delay based on code exectuing timing and a loop, unless interrupts were disabled prior to entering the loop. So this can't be the reason.

    Also, I think the PBP routine could be easily called by inserting the following where the delay is required ("_us" is a predefined word variable/literal containing the delay in us):

    Code:
            movlw   (_us) >> 8
            movwf   R0 + 1
            movlw   low (_us)
            call    PAUSEUSL        ; Delay for us
    PAUSEUS_USED = 1
    One thought that just occured to me. Becuase you use a macro, your not pushing anything onto the stack. So you are avoiding any possible overflow due to interrupts occuring during the delay. Is this it?

    Steve

  5. #5
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    It's not that it's OK to "Be interrupted", but it's OK to be in the routine that does the interrupting.

    PAUSEUS has a couple shortcomings. One, is that it uses PBP's system variables (R0-R8). So it corrupts PBP's flow if it's used in an ASM interrupt without "Instant Interrupts".

    The second is that PAUSEUS has a minimum delay of around 24us @ 4mhz since it figures out the delay Count at run time.

    The DelayUS macro can pause for a little as 1us by calculating the delay at Compile Time, and adding a single NOP if that's all that's needed. Or a 3cycle loop and 2 NOP's if running at 20mhz. And it doesn't use any PBP system vars.

    It can be useful in other programs as well, so I'll show it here again for those that aren't as diligent as you Steve.
    Code:
    VP_DelayCount  VAR WORD BANK0  ; Used for DelayUS only
    
    ASM
    ;----[Similar to PAUSEUS, but ASM interrupt compatible]---(accurate to 1uS)--
    DelayUS  macro T
      local InstCount, LoopCount, DelayLoop, LoopsDone, LeftOver, Offset
    ; -- Calculate number of 3 cycle loops plus leftover nop's to execute --
    InstCount = ((OSC*10/4)*T+5)/10 ; Inst cycles required for delay (Rounded UP)
    LoopCount = InstCount / 3
        if (LoopCount > 255)
    Offset = (LoopCount >> 8) * 7 + 4
        else
    Offset = 0
        endif
    ; -- Adjust for HighByte --
    InstCount = InstCount - Offset
        if (Offset > (LoopCount & 0FFh))
    InstCount = InstCount - 4
        endif
    LoopCount = InstCount / 3
        if (LoopCount > 255)
    Offset = (LoopCount >> 8) * 7
        else
    Offset = 0
        endif
    LeftOver  = InstCount % 3
    ;-------------------------------------------
        if (LoopCount > 0)
            MOVE?CW  LoopCount, _VP_DelayCount
    DelayLoop
            decfsz   _VP_DelayCount, F               ;  1
            goto     DelayLoop                       ;  2   3 per loop, under 256
        
            if (LoopCount > 255)
                movf     _VP_DelayCount + 1, W       ;  1    
                btfsc    STATUS, Z                   ;  1    
                goto     LoopsDone                   ;  2   4 on last loop
                
                decf     _VP_DelayCount + 1, F       ;  1    
                goto     DelayLoop                   ;  2   7 per highbyte count 
    LoopsDone
            endif
        endif
        if (LeftOver > 0)
            nop
        endif
        if (LeftOver > 1)
            nop
        endif
      endm
    ENDASM
    DT

  6. #6
    Join Date
    May 2006
    Location
    Del Rio, TX, USA
    Posts
    343


    Did you find this post helpful? Yes | No

    Exclamation

    Ok,
    Quote Originally Posted by Darrel Taylor
    It's not that it's OK to "Be interrupted", but it's OK to be in the routine that does the interrupting.
    This makes much more sense than what I was thinking.

    On thing that should be mentioned. It is generally best to keep interrupt service routines (ISR) as short as possible, so that additional interrupts are not "missed" while handling the current interrupt. So putting a pause into an ISR must be used with caution, and with a good understanding of how it will effect other timing related items. One exception to this would be the 16-bit PICs with High and Low priority interrupts (which are supported by PBP), where a pause in a low prority interrupt would not prevent a high priority interrupt from executing. So all the time critical inturrupts could be High Priority.

    Steve

Similar Threads

  1. Bits, Bytes Words and Arrays
    By Melanie in forum FAQ - Frequently Asked Questions
    Replies: 24
    Last Post: - 14th June 2016, 08:55
  2. Simple Array Demo
    By Archangel in forum Code Examples
    Replies: 5
    Last Post: - 15th February 2010, 05:46
  3. Custom array of pins
    By bmagistro in forum mel PIC BASIC Pro
    Replies: 9
    Last Post: - 29th March 2009, 00:15
  4. Crystalfontz LCD
    By jman12 in forum mel PIC BASIC Pro
    Replies: 9
    Last Post: - 9th February 2007, 16:04
  5. Making Array of two ports
    By John7 in forum General
    Replies: 3
    Last Post: - 5th March 2005, 03:20

Members who have read this thread : 2

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts