News:

;) This forum is the property of Proton software developers

Main Menu

Best way to read an 8-DIP switch on non-sequential pins

Started by rick.curl, Jan 07, 2023, 09:48 PM

Previous topic - Next topic

rick.curl

What is the simplest way to read an 8-position DIP switch if it is not connected to sequential pins on one port? I need to read a number between 0 and 255 from the switch.  I can think of a number of sloppy, convoluted ways to do this, but I keep thinking there is a better way.  Any suggestions?

Thanks!

-Rick

Ivano

if I understand correctly you want to use only one pin of the pic for reading.
You can use a shiftregister and put the 8 reads into the 8 bits of a variable.
if you use 8 pin you just read the port
I don't know if I understood the question correctly.

tumbleweed

If the connections are all jumbled then probably the easiest way is just brute force...
Dim dipsw As Byte

dipsw = 0
If porta.0=1 Then dipsw.7 = 1
If portb.0=1 Then dipsw.6 = 1
If portc.0=1 Then dipsw.5 = 1
If porta.1=1 Then dipsw.4 = 1
If portb.1=1 Then dipsw.3 = 1
If portc.1=1 Then dipsw.2 = 1
If porta.2=1 Then dipsw.1 = 1
If portb.2=1 Then dipsw.0 = 1

You can turn it into a procedure, adjust for correct logic levels, etc, but that's about the simplest, fastest way.

rick.curl

Quote from: tumbleweed on Jan 07, 2023, 10:46 PMIf the connections are all jumbled then probably the easiest way is just brute force...
Dim dipsw As Byte

dipsw = 0
If porta.0=1 Then dipsw.7 = 1
If portb.0=1 Then dipsw.6 = 1
If portc.0=1 Then dipsw.5 = 1
If porta.1=1 Then dipsw.4 = 1
If portb.1=1 Then dipsw.3 = 1
If portc.1=1 Then dipsw.2 = 1
If porta.2=1 Then dipsw.1 = 1
If portb.2=1 Then dipsw.0 = 1

You can turn it into a procedure, adjust for correct logic levels, etc, but that's about the simplest, fastest way.
Hi Tumbleweed-
That's almost identical to the way I was doing it. It does work perfectly, but I keep thinking there is a more streamlined way to do it. At least you verified that I'm not way out in left field on this!

Thanks.

-Rick

shantanu@india

For a pin starved application you can use a 4021 shift register as Ivano suggested... 3 pins strobe/data/clock.
Or if you connect 8 no.1K resistors in series and connect the dip switch points to the 8 junction points would that create an exclusive analog voltage for every swich combination? Then you just need one analog pin with a look up table. I may be wrong... the thought just floated into my mind.
Regards
Shantanu

keytapper

On top of my mind it's possible to get a part of a port and ORing with another. If this is only involving two ports.
Dim dipswitches As byte
' Every zero on the mask will be ignored
Symbol BITMASKD 0b00001111          'Mask out the unnecessary bit for PORTD
Symbol BITMASKC 0b11110001          'Mask out the unnecessary bit for PORTC

dipswitches = (PORTD & BITMASKD) | (PORTC & BITMASKC)
Ignorance comes with a cost

John Drew

Shantanu, You're on the right track. Somewhere (?) on the forum or in the manual there is a program that does just that with a string of resistors and a A/D.
On my phone and can't look it up.
John

Frizie

With 5 to 6 dipswitches I find the analog way reliable, but with 8 dipswitches on a 10-bit converter it is no longer guaranteed that you read all 8 dip switches 100% correctly.
Ohm sweet Ohm | www.picbasic.nl

John Lawton


tumbleweed

If you have the IO pins to spare then why add all the extra hardware and code?

Even though it seems ugly, the code in post 2 translates to 17 asm instructions, so it's small and fast.
Some newer pics even have programmable pullups on all the IO pins, so you don't need anything but the DIP sw.

If you don't have the pins then that's a different story...
 

rick.curl

Thanks guys, but to clarify, I have plenty pins available, but to keep the layout simple they will be connected to the dip switch out of order and spread across two ports.
Tumbleweed had the right idea- I was just thinking there was a more streamlined way to do it. I'll stick with his "brute force" approach for now.

-Rick

HAL

Hello everyone

This solution is really elegant when it comes down to it.  There is no shortage of available pins and the dip switch itself is the only additional hardware needed.  Saves PC board space, no additional components, ease of routing, etc. Wow!

I've been retired for a few years now and the forum does help to keep a few gray cells (no pun) firing.  At work we had a monthly award called the "Ockham's Razor".  The winner got a free beer after work that day.  This design would have easily won (probably for two months).

I believe it also shows the genius behind the flexibility of the compiler...

Best to everyone
Hal
 

Oskar-svr

#12
Hello friend, in my case I do this I configure the port where
there is the DIPSW and select the work option, I use the negative logic or positive logic
I always use negative logic because it is less susceptible to electrical noise, in the micro I use port B regularly and I enable the PULL UP resistors to always have a 1 and with the dipsw at one end I connect it to GND and when I close any switch I pass a logical 0 to it, I also put names to each bit of the port to know which bit I am working on, I hope it helps you friend, greetings

EXAMPLE

            Symbol D1=PORTB.0
            Symbol D2=PORTB.1
            Symbol D3=PORTC.0
            Symbol D4=PORTC.1
'.................................................. ...................
            If D1=0 Then
            GoTo TEST1
            endIf
'.................................................. ...................
  If D1=1 And D3=1 And D2=0 And D4=0 Then
            GoTo TEST1
            endIf
'.................................................. ...................
            If D1=1 And D3=1 And D2=1 And D4=1 Then
            hrs=0 'HOUR
            Mins=0 'MINUTES
            secs=0 'SECONDS
            Call MODFECH
            endIf

top204

Here's another way using aliasing of the individual pins of each port used:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Read a DIP switch using different pins of different ports using aliases
' Written for the Positron BASIC compiler by Les Johnson
'
    Device = 18F25K22                   ' Tell the compiler what device to compile for
    Declare Xtal = 16                   ' Tell the compiler what frequency the device is operating at (in MHz)
'
' Setup USART1
'
    Declare Hserial1_Baud = 9600        ' Setup the Baud rate of USART1
    Declare HRSOut1_Pin   = PORTB.6     ' Tell the compiler what pin is used for USART1 TX
'
' Create some aliases and variables
'  
    Dim tDIP0 As PORTA.0                ' \
    Dim tDIP1 As PORTA.1                ' |
    Dim tDIP2 As PORTA.2                ' |
    Dim tDIP3 As PORTA.3                ' | Alias pins of ports that represent the DIP switch pins
    Dim tDIP4 As PORTB.1                ' |
    Dim tDIP5 As PORTB.0                ' |
    Dim tDIP6 As PORTB.2                ' |
    Dim tDIP7 As PORTB.3                ' /  

    Dim bDIP As Byte                    ' Holds the final DIP switch value
   
'--------------------------------------------------------------------------
' The main program starts here
'
Main:
    Setup()                             ' Setup the program
   
    Do                                  ' Create a loop
        bDIP = DIP_Read()               ' Read the DIP switch
        HRSOutLn Bin8 bDIP              ' Serially display the value of the DIP switch
        DelayMS 300                     ' Delay between reads so they can be seen
    Loop   
   
'--------------------------------------------------------------------------
' Read various port pins and transfer them to a single byte
' Input     : None
' Output    : Returns the bits sequentially
' Notes     : tDIP0 to tDIP7 are aliases to port pins
'
Proc DIP_Read(), Byte
    Result.0 = tDIP0                    ' \
    Result.1 = tDIP1                    ' |
    Result.2 = tDIP2                    ' |
    Result.3 = tDIP3                    ' | Transfer the pins of the ports into the bits of Result
    Result.4 = tDIP4                    ' |
    Result.5 = tDIP5                    ' |
    Result.6 = tDIP6                    ' |
    Result.7 = tDIP7                    ' /
EndProc

'--------------------------------------------------------------------------
' Setup the program
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
    PinInput tDIP0                      ' \
    PinInput tDIP1                      ' |
    PinInput tDIP2                      ' |
    PinInput tDIP3                      ' | Make the pins inputs
    PinInput tDIP4                      ' |
    PinInput tDIP5                      ' |
    PinInput tDIP6                      ' |
    PinInput tDIP7                      ' /
EndProc 

tumbleweed

QuoteHere's another way using aliasing of the individual pins of each port used:
Ignoring the proc overhead, that method uses 3 instructions to read each position, for a total of 24 instructions.

Here's a version of DIP_Read() with the aliases using the method in post 2 for a total of 17 instructions:
Proc DIP_Read(), Byte
    Result = 0
    If tDIP0=1 Then Result.0 = 1
    If tDIP1=1 Then Result.1 = 1
    If tDIP2=1 Then Result.2 = 1
    If tDIP3=1 Then Result.3 = 1
    If tDIP4=1 Then Result.4 = 1
    If tDIP5=1 Then Result.5 = 1
    If tDIP6=1 Then Result.6 = 1
    If tDIP7=1 Then Result.7 = 1
EndProc


rick.curl

Quote from: tumbleweed on Jan 09, 2023, 11:51 AM
QuoteHere's another way using aliasing of the individual pins of each port used:
Ignoring the proc overhead, that method uses 3 instructions to read each position, for a total of 24 instructions.

Here's a version of DIP_Read() with the aliases using the method in post 2 for a total of 17 instructions:
Proc DIP_Read(), Byte
    Result = 0
    If tDIP0=1 Then Result.0 = 1
    If tDIP1=1 Then Result.1 = 1
    If tDIP2=1 Then Result.2 = 1
    If tDIP3=1 Then Result.3 = 1
    If tDIP4=1 Then Result.4 = 1
    If tDIP5=1 Then Result.5 = 1
    If tDIP6=1 Then Result.6 = 1
    If tDIP7=1 Then Result.7 = 1
EndProc


I don't think it gets any better than that. Thanks very much for all the responses.  This turned into an interesting and helpful thread!

-Rick

HAL

Hi everyone,

I don't want to state the obvious, but at that risk, here is what the implementation of the original example might look like:

 
    Dim dipsw As Byte
    dipsw = 0

    ' note:
    ' the dipswitch actually grounds the port pin and
    ' each port pin has a bussed pull-up resistor (say 33k)
    ' port pins are chosen based upon ease of pcb routing
   
    If PORTA.0=0 Then dipsw.7 = 1
    If PORTB.0=0 Then dipsw.6 = 1
    If PORTC.0=0 Then dipsw.5 = 1
    If PORTA.1=0 Then dipsw.4 = 1
    If PORTB.0=0 Then dipsw.3 = 1
    If PORTC.1=0 Then dipsw.2 = 1
    If PORTA.2=0 Then dipsw.1 = 1
    If PORTB.2=0 Then dipsw.0 = 1





SeanG_65

Use a parallel to serial converter and NOT tie up 8 pins ;-)

I have a routine for this somewhere, found it. See below.

'****************************************************************
'*  Name    : Main Micro Code DEVICE 16F628A.bas                *
'*  Author  : Sean Goddard                                      *
'*  Notice  : Copyright (c) 2020 [select VIEW...EDITOR OPTIONS] *
'*          : All Rights Reserved                              *
'*  Date    : 28/03/2020                                        *
'*  Version : 1.0                                              *
'*  Notes  :                                                  *
'*          :                                                  *
'****************************************************************

;-------------------------------------------------------------------------------
;**** Added by Fuse Configurator ****
; Use the Fuse Configurator plug-in to change these settings

DEVICE = 16F628A

CONFIG FOSC_INTOSCCLK, WDTE_OFF, PWRTE_OFF, MCLRE_OFF, BOREN_OFF, LVP_ON, CPD_OFF, CP_OFF

;**** End of Fuse Configurator Settings ****
;-------------------------------------------------------------------------------

XTAL = 20


ON_HARDWARE_INTERRUPT Process_Interrupt 

SYMBOL T0IE INTCON.5
SYMBOL T0IF INTCON.2
SYMBOL GIE INTCON.7
SYMBOL PS0 OPTION_REG.0
SYMBOL PS1 OPTION_REG.1
SYMBOL PS2 OPTION_REG.2
SYMBOL PSA OPTION_REG.3
SYMBOL T0CS OPTION_REG.5

SYMBOL K_CLK PORTA.1
SYMBOL K_RST PORTA.2
SYMBOL PING PORTA.3
SYMBOL RADAR_CP PORTA.4
SYMBOL SDR_RST PORTA.6
SYMBOL INT1 PORTA.7


TRISA = %10110000
TRISB = %00000000

DIM K_Pos AS BYTE
DIM CTR_Val AS BYTE

CTR_Val = 0

DELAYMS 250          ' Wait for things to stabilise


K_CLK = 0            ' Ensure switch scanner clock is logic zero
SDR_RST = 0          ' Set sounder PIC RESET Low
K_RST = 1            ' Activate RESET for switch scanner 4022
DELAYMS 100          ' Wait 100ms for 4022 to RESET
K_RST = 0            ' RESET switch scanner 4022 to LOW
SDR_RST = 1          ' Take Sounder RESET HIGH


GOTO Over_Interrupt

Process_Interrupt:
CONTEXT SAVE
T0IF = 0
TMR0 = CTR_Val
HIGH PING
DELAYMS 10
LOW PING
'delayms 10000

CONTEXT RESTORE


Over_Interrupt:

PORTB = 0
GIE = 0
PSA = 1              ' Assign Prescaler to WDT
PS0 = 0
PS1 = 0
PS2 = 0
T0CS = 1
TMR0 =  0
T0IE = 1
GIE = 1

Main:
' **** Form a RESET pulse for the switch scanner ****

K_RST = 1
DELAYMS 25
K_RST = 0
DELAYMS 25
'****************************************************

IF INT1 = 1 THEN CTR_Val = 222


GOSUB ScanSwitch
IF INT1 = 1 THEN CTR_Val = 199


GOSUB ScanSwitch
IF INT1 = 1 THEN CTR_Val = 188


GOSUB ScanSwitch
IF INT1 = 1 THEN CTR_Val = 176


GOSUB ScanSwitch
IF INT1 = 1 THEN CTR_Val = 165


GOSUB ScanSwitch
IF INT1 = 1 THEN CTR_Val = 154


GOSUB ScanSwitch
IF INT1 = 1 THEN CTR_Val = 142


GOSUB ScanSwitch
IF INT1 = 1 THEN CTR_Val = 131


'GOSUB ScanSwitch
'IF INT1 = 1 THEN CTR_Val = 155


'GOSUB ScanSwitch
'IF INT1 = 1 THEN CTR_Val = 146


GOTO Main


END

ScanSwitch:
K_CLK = 1
DELAYMS 25
K_CLK = 0
DELAYMS 25
RETURN

   

SeanG_65

Schematic 3 pins used and TEN pins monitored ;-)