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>
Bookmarks