News:

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

Main Menu

3 actions and two inputs

Started by Marcel_741, Feb 22, 2024, 08:01 PM

Previous topic - Next topic

Marcel_741

Hello,

As I am working on a project (CMOS tester), I choose for the 16F628A. The circuit involves a HD1602 so, for me that is perfect because I did more projects with this combination and it works fine.

The rest of the I/O is used for generating outputs "8" which controls logics like CD4011/4081/4043/4044 etc. I have 2 port left and one of them is the PORTA.5 which can only be used as input and PORTA.7 which is free. The use of a menu is by scrolling through the Menu and enter the choice. This needs three actions. (up/down/enter) and there 2 to use.

My question in this story is what is possible to create 3 actions with only two port left?

I used a potmeter of 25K and a condensator (in series)of 100nF on RA.7 and let charging/uncharging create a time that could be used, but some how I couldn't get values that makes it something to work with. (I must have done something incorrect)

Anybody an idea?

Regards,

Marcel

Pepe

Use each input to raise or lower and when you activate both at the same time it is OK

trastikata

As @Pepe said check for both inputs as OK action.

Because the PIC is much faster than your fingers, you will have to give it some thought. For example as soon as one of the inputs is detected, wait some arbitrary time and check the other input to see if both buttons have been depressed.   

top204

A simple method for reading multiple buttons with only a single pin, is to use an analogue method. Where each button will give a different value to an ADC input when it is pressed, and whatever value is read can be translated to a certain button pressed. I've used this method many times, and on a PIC device that does not contain an ADC, the RCIn command can be used instead.

I've just written a simple demonstration that shows exactly how this works, and it is listed below for a PIC16F628A device. I guessed at the resistor values, but made them approx double resistance to each other so the values returned from the RCIn command would have large differences for each button.

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Wait for button presses and transmit what button was pressed to a serial terminal
' The three buttons are attached to a single pin via series resistors of different values,
' so each button will give a different reding to the RCin command.
'
' Written for the Positron8 compiler by Les Johnson.
'
    Device       = 16F628A                                      ' Tell the compiler what device to compile for
    Declare Xtal = 20                                           ' 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   = PORTB.2                             ' Set the TX pin

    Symbol Buttons_Pin = PORTA.0                                ' The pin to use for the Buttons
'
' Create any global variables fro the demo here
'
    Dim bButtonPressed As Byte                                  ' Holds the button pressed value

'-------------------------------------------------------------------------
' The main program starts here
' Wait for button presses and transmit what button was pressed to a serial terminal
'
Main:
    HRsoutLn "Press a Button"
    Do                                                          ' Create a loop
        bButtonPressed = Button_Get()                           ' Read the buttons
        If bButtonPressed = cUp_Button Then                     ' Was the Up Button pressed?
            HRsoutLn "Up Button Pressed"                        ' Yes. So transmit to a serial terminal what button was pressed
        ElseIf bButtonPressed = cMenu_Button Then               ' Was the Menu Button pressed?
            HRsoutLn "Menu Button Pressed"                      ' Yes. So transmit to a serial terminal what button was pressed
        ElseIf bButtonPressed = cDown_Button Then               ' Was the Down Button pressed?
            HRsoutLn "Down Button Pressed"                      ' Yes. So transmit to a serial terminal what button was pressed
        EndIf
        DelayMs 50
    Loop                                                        ' Do it forever

'-------------------------------------------------------------------------
' Read a button press from an analogue sequence of buttons connected to a single pin
' Input     : Buttons_Pin holds the Port.Pin used for the buttons
' Output    : Returns a value that represents what button is pressed (0 to 3)
' Notes     : Only allows a single button press, until it is released.
'           : This stops multiple repeats if the button is pressed for too long, and acts as a form of debounce.
'
Proc Button_Get(), Byte
Global Symbol cNo_Button   = 0                                  ' The return value for No Button pressed
Global Symbol cUp_Button   = 1                                  ' The return value for the Up Button pressed
Global Symbol cMenu_Button = 2                                  ' The return value for the Menu Button pressed
Global Symbol cDown_Button = 3                                  ' The return value for the Down Button pressed

Static Dim bPrevButton As Byte = $FF                            ' Holds the previous button value
    Dim wRCTime As Word                                         ' Holds the value returned from the RCin command
    Dim bButton As wRCTime.Byte0                                ' Holds the button value (aliased)
'
' Read the buttons
'
    PinHigh Buttons_Pin
    DelayMs 1                                                   ' Wait for 1 ms
    wRCTime = RCin Buttons_Pin, High                            ' Measure the RC charge time
    'HRsoutLn Dec wRCTime                                   ' Uncomment to see the RC Time value for each button pressed
'
' Choose what button was pressed by the value returned from RCin
'
    Result = cNo_Button                                         ' Default to no button pressed
    Select wRCTime                                              ' Do comparisons on the value held in wRCTime
        Case 550 To 700                                         ' Does wRCTime holds the values between 500 To 700?
            bButton = cUp_Button                                ' Yes. So that is the Up Button pressed
        Case 280 To 400                                         ' Does wRCTime holds the values between 280 To 400?
            bButton = cMenu_Button                              ' Yes. So that is the Menu Button pressed
        Case 100 To 220                                         ' Does wRCTime holds the values between 100 To 220?
            bButton = cDown_Button                              ' Yes. So that is the Down Button pressed
        Case Else                                               ' Otherwise...
            bButton = cNo_Button                                ' No Button pressed
    EndSelect
    If bButton <> bPrevButton Then                              ' Is the button the same as the previous button pressed?
        Result = bButton                                        ' No. So place the button pressed value in the result
        bPrevButton = bButton                                   ' Update the previous button press variable
    EndIf
EndProc

Running it in the Proteus simulator gives good results, and a screenshot of it operating inside Proteus is shown below. To get the values returned from the RCin command for particular resistors used, uncomment a line in the code and it will transmit the values received for a button press to a serial terminal, then use that value for a particular button choice within the Button_Get() procedure, then re-comment the line when they are chosen. The Button_Get() procedure also has a simple mechanism for a one-shot button press to stop repeats if the button is left pressed down. It also acts as a simple form of debounce. :-)

The Positron8 source code and the proteus project files are also attached below. It is named "Analogue_Buttons.zip".

Analogue_Buttons_PIC16F268A.jpg

trastikata

Great article Les, thank you.

Unfortunately the OP says only the MCLR and OSC1 pins are available.

ken_k

maybe

BUTTONS.png

ken_k

I guess we have all done this kind of thing 3 inputs 7 buttons no strobing.BUTTONS 7 png.png

okmn

#7
you can use  74hc595 by spi serial com.


Stephen Moss

Another possible method would be that once a menu button press is detected you enter a loop that scrolls the menu in the desired direction until the button is released.
Whereupon the current menu item indicates the selected device to test for, so the button release is effectively your OK input.
So something like...
If Menu_Button_Scroll_Up = true then
   Scroll_Menu_Up()
ElseIf Menu_Button_Down = true then
   Scroll_Menu_Down()
End If



Sub Scroll_Menu_Up()
  Do
      move up one item in the menu
      delayMs 1000   'Allow time to read current item
  Loop Until Menu_Button_Scroll_up = False   'Equals OK

  Menu selection = Current menu item
End Sub
And either create a similar sub for scroll down or use a single Procedure instead of a two Subs and pass it a parameter indicating which direction to scroll, although separate up/down Subroutines may initially make debugging easier.

top204

#9
That is a good idea Ken. It looks like a form of DTL?

I was thinking of a similar type of mechanism last night, but my brain just would not come up with the diode formation for it. :-)

top204

Based upon Ken's circuit for the three buttons connected to two pins using diodes, the code listing below will demonstrate the button reads using any two pins on the microcontroller only ever being set as inputs:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Wait for button presses and transmit what button was pressed to a serial terminal
' The three buttons are attached to two pins via diodes, so each button will give a different pattern to the pins.
'
' Based upon Ken's circuit, posted on the forum.
' Written for the Positron8 compiler by Les Johnson.
'
    Device       = 16F628A                                      ' Tell the compiler what device to compile for
    Declare Xtal = 20                                           ' 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   = PORTB.2                             ' Set the TX pin

    Symbol Button1_Pin = PORTA.0                                ' One of the pins to use for the buttons
    Symbol Button2_Pin = PORTA.1                                ' The other pin to use for the buttons
'
' Create any global variables for the demo here
'
    Dim bButtonPressed As Byte                                  ' Holds the button pressed value

'-------------------------------------------------------------------------
' The main program starts here
' Read the buttons and transmit what button was pressed to a serial terminal
'
Main:
    HRsoutLn "Press a Button"
    Do                                                          ' Create a loop
        bButtonPressed = Button_Get()                           ' Read the buttons
        Select bButtonPressed                                   ' Compare what value is held in bButtonPressed
            Case cUp_Button                                     ' Was the Up Button pressed?
                HRsoutLn "Up Button Pressed"                    ' Yes. So transmit to a serial terminal what button was pressed
            Case cMenu_Button                                   ' Was the Menu Button pressed?
                HRsoutLn "Menu Button Pressed"                  ' Yes. So transmit to a serial terminal what button was pressed
            Case cDown_Button                                   ' Was the Down Button pressed?
                HRsoutLn "Down Button Pressed"                  ' Yes. So transmit to a serial terminal what button was pressed
        EndSelect
        DelayMs 50                                              ' A small delay
    Loop                                                        ' Do it forever

'-------------------------------------------------------------------------
' Read a button press from three buttons connected to two pins using diode logic
' Input     : Button1_Pin holds the Port.Pin used for one of the buttons input
'           : Button2_Pin holds the Port.Pin used for the other button input
' Output    : Returns a value that represents what button is pressed (0 to 3)
' Notes     : Only allows a single button press, until it is released.
'           : This stops multiple repeats if the button is pressed for too long, and acts as a form of debounce.
'
Proc Button_Get(), Byte
Global Symbol cNo_Button   = 0                                  ' The return value for No Button pressed
Global Symbol cUp_Button   = 1                                  ' The return value for the Up Button pressed
Global Symbol cMenu_Button = 2                                  ' The return value for the Menu Button pressed
Global Symbol cDown_Button = 3                                  ' The return value for the Down Button pressed
Static Dim bPrevButton As Byte = $FF                            ' Holds the previous button value
    Dim bButton As Byte                                         ' Holds the button value
 
    PinInput Button1_Pin                                        ' \
    PinInput Button2_Pin                                        ' / Set the pins used for the buttons to input (just in case)
    DelayUs 100                                                 ' Give a little time for the pins to settle (just in case)
    Result = cNo_Button                                         ' Default to no button pressed
    If Button1_Pin = 1 And Button2_Pin = 1 Then                 ' Are both button pins high?
        bButton = cMenu_Button                                  ' Yes. So that is the Menu Button pressed
    ElseIf Button1_Pin = 1 Then                                 ' Is pin1 high?
        bButton = cUp_Button                                    ' Yes. So that is the Up Button pressed
    ElseIf Button2_Pin = 1 Then                                 ' Is pin2 high?
        bButton = cDown_Button                                  ' Yes. So that is the Down Button pressed
    Else                                                        ' Otherwise...
        bButton = cNo_Button                                    ' No Button pressed
    EndIf
    If bButton <> bPrevButton Then                              ' Is the button the same as the previous button pressed?
        Result = bButton                                        ' No. So place the button pressed value in the result
        bPrevButton = bButton                                   ' Update the previous button press variable
    EndIf
EndProc

Below is a screenshot of the program running in the proteus simulator, and the Positron8 source code and proteus project files are attached below. It is named "Diode_Logic_Buttons.zip"

Diode_Logic_Buttons.jpg

Marcel_741

All,

Lot of thanks for the reactions and a lot of options came out of it. I am very pleased with that. The option in post#3 is the first to try out and then with only the up and down button because I have the Enter (Select) on RA5. Which brings me to the point that what I have treid up till now is that RA5 is not usable for a "RCin" command. The change in resistor value in combination with charge/uncharge time gave only a "0" on the LCD screen. Offcourse I could something wrong, but still didn't figure that out ou yet. As I have two possible inputs (RA5 for a hard "1 or 0" and one for RCin "RA7") I will use them in a challenge to solve it.



I will come back with the result.

Regards,

Marcel


Marcel_741

Hello,

I lined up a 3K9 and a 8K2 resistor to A7 and switch to ground via a 100nF (to +5V) and a resistor of 100K to ground. Just like the setup in post#3 but then with 2 resistors. The outcome was 87 and 173 on the LCD and without switch value was "0".

The programm uses the value of RCin (Weerstand=Pot PORTA.7) and I attempt to count up/down using this value in a TEL_PLUS/TEL AF routine, but it won't count. It seemed so easy to do, but it wasn't.

Anybody any idea.

What it does is show the Menu select = 1 and with the "Select" button OUTPUT 1 will go "High". So, that works.

Regards,

Marcel
'****************************************************************
'*  Name    : CMOS_tester.bas                                   *
'*  Author  : Marcel Alkema                                     *
'*  Notice  : Copyright (c) 2024 Marcel Alkema                  *
'*          : All Rights Reserved                               *
'*  Date    : 23-02-2024                                        *
'*  Version : 1 .0                                              *
'*  Notes   : OUTPUTS GENERATOR to test CMOS : 4001/4011        *
'*          : /4071/4081/4093/4069/4043/4044                    *
'****************************************************************
Device 16F628A                     ;Gebruik een 16F628A type
 
Config INTRC_OSC_NOCLKOUT,_
       WDT_OFF,_
       PWRTE_ON,_
       LVP_OFF,_
       MCLRE_OFF

      All_Digital TRUE             ;All input digital
      Xtal =4

 Symbol sw1 = PORTA.5              ; PORTA.5 is called SW1 (Enter/Select)
 
 Symbol OUTP1=PORTB.0
 Symbol OUTP2=PORTB.1
 Symbol OUTP3=PORTB.0
 Symbol OUTP4=PORTA.1
 Symbol OUTP5=PORTA.2
 Symbol OUTP6=PORTA.3
 Symbol OUTP7=PORTA.4
 Symbol OUTP8=PORTA.6
 
 Dim TELLER As Byte
 Dim tel_BIT As Bit
 Dim Weerstand As Byte              ;Choice up or down

 PORTA = %00000000             ;All PORTA low
 PORTB = %00000000                 ;All PORTB low
 
 TRISA = %10100000                  ;Alle port as output except A.5 & A7

 Clear
 
 DelayMS 500
 Cls
 While 1 = 1
 
 TELLER = 1
 Weerstand = Pot PORTA.7,255
 
 Print At 1,1,"MENU select = ", Dec2 TELLER   
             
 
 RUN:
 If TELLER = 1 Then Print At 2,1, "OUTPUT 1     ON "
 If TELLER = 2 Then Print At 2,1, "Output 1     OFF"
 If TELLER = 3 Then Print At 2,1, "Output 2     On "
 If TELLER = 4 Then Print At 2,1, "Output 2     OFF"
 If TELLER = 5 Then Print At 2,1, "Output 3     On "
 If TELLER = 6 Then Print At 2,1, "Output 3     OFF"
 If TELLER = 7 Then Print At 2,1, "Output 4     On "
 If TELLER = 8 Then Print At 2,1, "Output 4     OFF"
 If TELLER = 9 Then Print At 2,1, "Output 5     On "
 If TELLER = 10 Then Print At 2,1, "Output 5     OFF"
 If TELLER = 11 Then Print At 2,1, "Output 6     On "
 If TELLER = 12 Then Print At 2,1, "Output 6     OFF"
 If TELLER = 13 Then Print At 2,1, "Output 7     On "
 If TELLER = 14 Then Print At 2,1, "Output 7     OFF"
 If TELLER = 15 Then Print At 2,1, "Output 8     On "
 If TELLER = 16 Then Print At 2,1, "Output 8     OFF"
   
 If TELLER = 1 And sw1= 1 Then
 High OUTP1
 End If
 
 If TELLER = 2 And sw1= 1 Then
 Low OUTP1
 End If
 
 If TELLER = 3 And sw1= 1 Then
 High OUTP2
 End If
 
 If TELLER = 4 And sw1= 1 Then
 Low OUTP2
 End If
 
 If TELLER = 5 And sw1= 1 Then
 High OUTP3
 End If
 
 If TELLER = 6 And sw1= 1 Then
 Low OUTP3
 End If
 
 If TELLER = 7 And sw1= 1 Then
 High OUTP4
 End If
 
 If TELLER = 8 And sw1= 1 Then
 Low OUTP4
 End If
 
 If TELLER = 9 And sw1= 1 Then
 High OUTP5
 End If
 
 If TELLER = 10 And sw1= 1 Then
 Low OUTP5
 End If
 
 If TELLER = 11 And sw1= 1 Then
 High OUTP6
 End If

 If TELLER = 12 And sw1= 1 Then
 Low OUTP6
 End If
 
  If TELLER = 13 And sw1= 1 Then
 High OUTP7
 End If

 If TELLER = 14 And sw1= 1 Then
 Low OUTP7
 End If
 
  If TELLER = 15 And sw1= 1 Then
 High OUTP8
 End If

 If TELLER = 16 And sw1= 1 Then
 Low OUTP8
 End If
 
    If Weerstand > 100 Then
     tel_BIT = 1
      GoSub TEL_PLUS_1
    EndIf
   
    If Weerstand < 100 And Weerstand <> 0 Then
     tel_BIT = 1
      GoSub TEL_AF
    EndIf 
   
GoTo RUN

TEL_PLUS_1:
    If tel_BIT = 1 Then
     TELLER = TELLER + 1
    EndIf
   
     Print At 1,1,"MENU select = ",Dec2 TELLER
           
    tel_BIT = 0
   
    If TELLER > 16 Then
     TELLER = TELLER - 1
    EndIf
   
    If Weerstand = 0 Then
     If tel_BIT = 0 Then
      Return
     EndIf
    EndIf
 
GoTo TEL_PLUS_1

TEL_AF:
    If tel_BIT = 1 Then
     TELLER = TELLER - 1
    EndIf
   
     Print At 1,1,"MENU select = ",Dec2 TELLER
         
    tel_BIT = 0
   
    If TELLER = 0 Then
     TELLER = TELLER + 1
    EndIf
   
    If Weerstand = 0 Then
     If tel_BIT = 0 Then
    Return
     EndIf
    EndIf
 
GoTo TEL_AF
 
Wend 
End

   
 


Pepe

Put this

TEL_PLUS_1:
    If tel_BIT = 1 Then
     TELLER = TELLER + 1
    EndIf
   
     Print At 1,1,"MENU select = ",Dec2 TELLER
           
    tel_BIT = 0
   
    If TELLER > 16 Then
     TELLER = TELLER - 1
    EndIf
   
    Weerstand = Pot PORTA.7,255

    If Weerstand = 0 Then
     If tel_BIT = 0 Then
      Return
     EndIf
    EndIf
 
GoTo TEL_PLUS_1

TEL_AF:
    If tel_BIT = 1 Then
     TELLER = TELLER - 1
    EndIf
   
     Print At 1,1,"MENU select = ",Dec2 TELLER
         
    tel_BIT = 0
   
    If TELLER = 0 Then
     TELLER = TELLER + 1
    EndIf

    Weerstand = Pot PORTA.7,255

    If Weerstand = 0 Then
     If tel_BIT = 0 Then
    Return
     EndIf
    EndIf
 
GoTo TEL_AF


top204

Your program is using the Pot command not the RCin command? The Pot command is a throwback from the very early BASIC Stamp module from around 1998. The RCIn command has a better resolution, so its returned values are much more reliable.

When the PIC16F628A device is set to use one of its internal 4MHz oscillator configurations, the OSC pins (RA6 and RA7), become standard I/O lines, so either one of them can be used for the RCin command.

Below is a code listing for the Analogue Buttons circuit above, using the device's internal 4MHz oscillator, and the buttons connected to PORTA.7, and not PORTA.0 as the original is. Because it is operating at 4MHz and not the original 20MHz, the values returned from RCin are not the same, but they are still different enough to identify what button is pressed using the original button resistors. However, the discharge resistor should now be 220K instead of the 100K as used in the above circuit, to make the values returned from RCin larger:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Wait for button presses and transmit what button was pressed to a serial terminal
' The three buttons are attached to a single pin via series resistors of different values,
' so each button will give a different reding to the RCin command.
'
' This version of the program operates with the internal 4MHz oscillator.
' The buttons connect to pin RA7 (PORTA.7)
'
' Written for the Positron8 compiler by Les Johnson.
'
    Device       = 16F628A                                      ' Tell the compiler what device to compile for
    Declare Xtal = 4                                           ' 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   = PORTB.2                             ' Set the TX pin

    Symbol Buttons_Pin = PORTA.7                                ' The pin to use for the Buttons
'
' Create any global variables fro the demo here
'
    Dim bButtonPressed As Byte                                  ' Holds the button pressed value

'-------------------------------------------------------------------------------------------------------------------------------
' The main program starts here
' Wait for button presses and transmit what button was pressed to a serial terminal
'
Main:
    HRsoutLn "Press a Button"
    Do                                                          ' Create a loop
        bButtonPressed = Button_Get()                           ' Read the buttons
        If bButtonPressed = cUp_Button Then                     ' Was the Up Button pressed?
            HRsoutLn "Up Button Pressed"                        ' Yes. So transmit to a serial terminal what button was pressed
        ElseIf bButtonPressed = cMenu_Button Then               ' Was the Menu Button pressed?
            HRsoutLn "Menu Button Pressed"                      ' Yes. So transmit to a serial terminal what button was pressed
        ElseIf bButtonPressed = cDown_Button Then               ' Was the Down Button pressed?
            HRsoutLn "Down Button Pressed"                      ' Yes. So transmit to a serial terminal what button was pressed
        EndIf
        DelayMs 50
    Loop                                                        ' Do it forever

'-------------------------------------------------------------------------------------------------------------------------------
' Read a button press from an analogue sequence of buttons connected to a single pin
' Input     : Buttons_Pin holds the Port.Pin used for the buttons
' Output    : Returns a value that represents what button is pressed (0 to 3)
' Notes     : Only allows a single button press, until it is released.
'           : This stops multiple repeats if the button is pressed for too long, and acts as a form of debounce.
'
Proc Button_Get(), Byte
Global Symbol cNo_Button   = 0                                  ' The return value for No Button pressed
Global Symbol cUp_Button   = 1                                  ' The return value for the Up Button pressed
Global Symbol cMenu_Button = 2                                  ' The return value for the Menu Button pressed
Global Symbol cDown_Button = 3                                  ' The return value for the Down Button pressed

Static Dim bPrevButton As Byte = $FF                            ' Holds the previous button value
    Dim wRCTime As Word                                         ' Holds the value returned from the RCin command
    Dim bButton As wRCTime.Byte0                                ' Holds the button value (aliased)
'
' Read the buttons
'
    PinHigh Buttons_Pin                                         ' Pre-Charge the capacitor
    DelayMs 1                                                   ' Wait for 1 ms
    wRCTime = RCin Buttons_Pin, High                            ' Measure the RC charge time
    'HRsoutLn "wRCTime=", Dec wRCTime                       ' Uncomment to see the RC Time value for each button pressed
'
' Choose what button was pressed by the value returned from RCin
'
    Result = cNo_Button                                         ' Default to no button pressed
    Select wRCTime                                              ' Do comparisons on the value held in wRCTime
        Case 120 To 160                                         ' Does wRCTime holds the values between 120 To 160?
            bButton = cUp_Button                                ' Yes. So that is the Up Button pressed
        Case 50 To 80                                           ' Does wRCTime holds the values between 50 To 80?
            bButton = cMenu_Button                              ' Yes. So that is the Menu Button pressed
        Case 25 To 40                                           ' Does wRCTime holds the values between 25 To 40?
            bButton = cDown_Button                              ' Yes. So that is the Down Button pressed
        Case Else                                               ' Otherwise...
            bButton = cNo_Button                                ' No Button pressed
    EndSelect
    If bButton <> bPrevButton Then                              ' Is the button the same as the previous button pressed?
        Result = bButton                                        ' No. So place the button pressed value in the result
        bPrevButton = bButton                                   ' Update the previous button press variable
    EndIf
EndProc

'-------------------------------------------------------------------------------------------------------------------------------
' Setup the configuration fuses for internal 4MHz operation and the OSC pins as I/O pins, and the MCLR pin disabled
'
    Config FOSC_INTOSCIO, WDT_OFF, PWRTE_ON, BODEN_ON, LVP_OFF, CP_OFF, MCLRE_OFF

Marcel_741

Hello,

I managed to make it work and it became an mixure of given solution. As soon as I finalized the test, I will place it here. I must say that the outcome looks easy, allthough I wasn't for me. Even some of the given options/advise/ideas were above my current knowlegde, allthough I could see the meaning of it.

Thanks for now, very greatfull

Regards,

Marcel

Marcel_741

#16
Hello,

As I allready mentioned, I would place the program and I did. It is not fully operational, because I bumped into port RA.4. It is a open drain port so, the use of a pull up resistor was required. And then I thought I was there, but not yet. I did several attempts to make a I/O switch with RA.4 and no succes yet. I placed a drawing of how I thought it would work.

As a NOR port has no HIGH inputs, the output will be zero. As soon as one of the inputs becomes HIGH1, the output will go LOW. Also with two HIGH inputs the output is LOW. I treid to do this with the attached drawing.

What is the trick to create a HIGH and LOW input on the NOR port.

Thanks in front,

Regards,

Marcel

'****************************************************************
'*  Name    : CMOS_tester.BAS                                  *
'*  Author  : Marcel Alkema                                    *
'*  Notice  : Copyright (c) 2024 [select VIEW...EDITOR OPTIONS] *
'*          : All Rights Reserved                              *
'*  Date    : 25-2-2024                                        *
'*  Version : 1.0                                              *
'*  Notes  : Test procedure for CMOS:4001/4011/4071/4081      *
'*          : 4093/4069/4043/4044                              *
'****************************************************************
 Device      = 16F628A            ;Device to compile
 
 Config INTRC_OSC_NOCLKOUT,_
      WDT_OFF,_
      PWRTE_ON,_
      LVP_OFF,_
      MCLRE_OFF

      All_Digital TRUE            ;All input digital
 
  Declare Xtal = 4                ;Frequency off device (in MHz)
 
  Dim Waarde As Word              ;Waarde for up/down defenition
  Dim sw2 As Byte                ;SW2 to count down (software)
  Dim sw3 As Byte                ;SW3 to count down (software)
  Dim teller As Byte              ;Count up in Menu
  Dim tel_BIT As Bit              ;Bit to count up/down
 
  Symbol Potmeter = PORTA.7      ;Uncharge time condensator is PORTA.4
  Symbol sw1 = PORTA.5            ;PORTA.5 is now SW3 (Select)
  Symbol OUT1 = PORTB.0          ;PORTB.0 is now OUTPUT 1
  Symbol OUT2 = PORTB.1          ;PORTB.1 is now OUTPUT 2
  Symbol OUT3 = PORTA.0          ;PORTA.0 is now OUTPUT 3
  Symbol OUT4 = PORTA.1          ;PORTA.1 is now OUTPUT 4
  Symbol OUT5 = PORTA.2          ;PORTA.2 is now OUTPUT 5
  Symbol OUT6 = PORTA.3          ;PORTA.3 is now OUTPUT 6
  Symbol OUT7 = PORTA.4          ;PORTA.4 is now OUTPUT 7
  Symbol OUT8 = PORTA.6          ;PORTA.6 is now OUTPUT 8
 
  PORTA = %00000000                ;All PORTA low
  PORTB = %00000000                ;All PORTB low
 
  TRISA = %10100000              ;Alle port as output except A.5 & A7
 
     
  Cls                              ;LCD clean screen
 
While 1 = 1                        ;continue measurment
 
 teller = 1
 
 Print At 1,1,"MENU KEUS = ", Dec2 teller                 
 
 RUN:
 If teller = 1 Then Print At 2,1, "CD4001 4 x NOR  "
 If teller = 2 Then Print At 2,1, "CD4011 4 x NAND "
 If teller = 3 Then Print At 2,1, "CD4071 4 x OR  "
 If teller = 4 Then Print At 2,1, "CD4081 4 x AND  "
 If teller = 5 Then Print At 2,1, "CD4093 4 x NAND "
 If teller = 6 Then Print At 2,1, "CD4069 6 x HEX  "
 If teller = 7 Then Print At 2,1, "CD4043 R/S LATCH"
 If teller = 8 Then Print At 2,1, "CD4044 R/S LATCH"
 
 ;CD4001 CD4011 CD4071 CD4081 CD4093 
 If teller <6 And sw1= 1 Then
 ; Port 1
 High OUT1
 DelayMS 2000
 Low OUT1
 DelayMS 2000
 High OUT2
 DelayMS 2000
 Low OUT2
 DelayMS 2000
 High OUT1
 DelayMS 1000
 High OUT2
 DelayMS 2000
 Low OUT1
 DelayMS 500
 Low OUT2
 DelayMS 2000
 ; Port 2
 High OUT3
 DelayMS 2000
 Low OUT3
 DelayMS 2000
 High OUT4
 DelayMS 2000
 Low OUT4
 DelayMS 2000
 High OUT3
 DelayMS 1000
 High OUT4
 DelayMS 2000
 Low OUT3
 DelayMS 500
 Low OUT4
 DelayMS 5000
 ; Port 3
 High OUT5
 DelayMS 2000
 Low OUT5
 DelayMS 2000
 High OUT6
 DelayMS 2000
 Low OUT6
 DelayMS 2000
 High OUT5
 DelayMS 2000
 High OUT6
 DelayMS 2000
 Low OUT5
 DelayMS 500
 Low OUT6
 DelayMS 2000
 ; Port 4
 High OUT7
 DelayMS 5000
 Low OUT7
 DelayMS 5000
 High OUT8
 DelayMS 5000
 Low OUT8
 DelayMS 5000
 High OUT7
 DelayMS 5000
 High OUT8
 DelayMS 5000
 Low OUT7
 DelayMS 5000
 Low OUT8
 DelayMS 5000
 End If
 
 ;  CD4069
 If teller = 6 And sw1= 1 Then
 ; Port 1
 High OUT1
 DelayMS 2000
 Low OUT1
 DelayMS 2000
 ; Port 2
 High OUT2
 DelayMS 2000
 Low OUT2
 DelayMS 2000
 ; Port 3
 High OUT3
 DelayMS 2000
 Low OUT3
 DelayMS 2000
 ; Port 4
 High OUT4
 DelayMS 2000
 Low OUT4
 DelayMS 2000
 ; Port 5
 High OUT5
 DelayMS 2000
 Low OUT5
 DelayMS 2000
 ; Port 6
 High OUT6
 DelayMS 2000
 Low OUT6
 DelayMS 2000
 End If
 
 If teller = 7 And sw1= 1 Then
 'High LED1
 'High LED2
 'High LED3
 End If
 
 If teller = 8 And sw1= 1 Then
 'Low LED1
 'Low LED2
 'Low LED3
 End If
 
      High Potmeter                ;Load Condensator
  DelayMS 1                        ;Wait for unload condensator
  Waarde =  RCIn Potmeter, High
     
  If Waarde <60 Then
  sw2 = 1
  ElseIf Waarde <100 Then
  sw3 = 1
  ElseIf Waarde <200 Then
  sw2 = 0
  sw3 = 0
  EndIf
 
    If sw3 = 1 Then
    tel_BIT = 1
      GoSub TEL_PLUS_1
    EndIf
   
    If sw2 = 1 Then
    tel_BIT = 1
      GoSub TEL_AF
    EndIf 
   
GoTo RUN

TEL_PLUS_1:

    If tel_BIT = 1 Then
    teller = teller + 1
    EndIf
   
    Print At 1,1,"MENU KEUS = ",Dec2 teller
           
    tel_BIT = 0
   
    If teller > 8 Then
    teller = teller - 1
    EndIf
 
  High Potmeter                    ;Load Condensator
  DelayMS 1                        ;Wait for unload condensator
  Waarde =  RCIn Potmeter, High
  'Print At 1, 1, Dec Waarde, " " ;Zet RC oplaadtijd op het display
   
  If Waarde <60 Then
  sw2 = 1
  ElseIf Waarde <100 Then
  sw3 = 1
  ElseIf Waarde <200 Then
  sw2 = 0
  sw3 = 0
  EndIf 
     
    If sw3 = 0 Then
    If tel_BIT = 0 Then
      Return
    EndIf
    EndIf
 
GoTo TEL_PLUS_1

TEL_AF:
   
    If tel_BIT = 1 Then
    teller = teller - 1
    EndIf
   
    Print At 1,1,"MENU KEUS = ",Dec2 teller
         
    tel_BIT = 0
   
    If teller = 0 Then
    teller = teller + 1
    EndIf
 
  High Potmeter                    ;Load Condensator
  DelayMS 1                        ;Wait for unload condensator
  Waarde =  RCIn Potmeter, High
     
  If Waarde <60 Then
  sw2 = 1
  ElseIf Waarde <100 Then
  sw3 = 1
  ElseIf Waarde <200 Then
  sw2 = 0
  sw3 = 0
  EndIf 
    If sw2 = 0 Then
    If tel_BIT = 0 Then
    Return
    EndIf
    EndIf
 
GoTo TEL_AF
 
Wend 
End

xvovanx

Hello!

Why is this so difficult? I perform three functions with one pin. High - one LED is light, low - the second LED is light, I make a pin as an analog input - I measure the battery charge of the device, but the LEDs do not light (sequentially low voltage on each).

Frizie

@Marcel_741:

Divide your program into pieces and test each piece.
Then slowly build up your main program and test it every time until it no longer works.
After that it is easier to find faults.

It is also better to post a small program code here that contains the problem (a large program takes me (or us) too much time to dig through it completely to find the error).
You often find the mistake yourself when you divide your program into small pieces. ;)
Ohm sweet Ohm | www.picbasic.nl

Stephen Moss

#19
Quote from: Marcel_741 on Feb 27, 2024, 01:47 PMAs a NOR port has no HIGH inputs, the output will be zero. As soon as one of the inputs becomes HIGH1, the output will go LOW. Also with two HIGH inputs the output is LOW. I tried to do this with the attached drawing.
Not sure what the purpose of the transistor is as you could connect both LED's to the output of the NOR gate but your logic is wrong, for a NOR gate, no high inputs will be a high output not a low output...
00 = 1
01 = 0
10 = 0
11 = 0

I am not sure about anything else as I found you code a little difficult to read, however...
    If sw3 = 0 Then
    If tel_BIT = 0 Then
      Return
    EndIf
    EndIf
I think should work as
If sw3 | tel_BIT = 0 Then
      Return
    EndIf
which is a bit neater.

Also using a Goto to jump to a Subroutine label is not a good idea. If you are trying to prevent the code running the following instruction (i.e. entering the following subroutine) it should not be necessary as when the compiler sees the Return command it will know that defines the end of the sub routine.

If it makes things clearer for you then instead of using GoSub Tel_AF and a return command use Tel_AF() to jump to the subroutine and

Sub Tel_AF()
Subroutine code here
End Sub

to more clearly define the start and end of your subroutines for you (End Sub = Return).

However if you are trying to run a loop inside your subroutine and exit the subroutine when sw3 = 0 and tel_bit = 0 then I would suggest changing...
TEL_AF:
   
    If tel_BIT = 1 Then
    teller = teller - 1
    EndIf
   
    Print At 1,1,"MENU KEUS = ",Dec2 teller
         
    tel_BIT = 0
   
    If teller = 0 Then
    teller = teller + 1
    EndIf
 
  High Potmeter                    ;Load Condensator
  DelayMS 1                        ;Wait for unload condensator
  Waarde =  RCIn Potmeter, High
     
  If Waarde <60 Then
  sw2 = 1
  ElseIf Waarde <100 Then
  sw3 = 1
  ElseIf Waarde <200 Then
  sw2 = 0
  sw3 = 0
  EndIf
    If sw2 = 0 Then
    If tel_BIT = 0 Then
    Return
    EndIf
    EndIf
 
GoTo TEL_AF

to include a Do loop, when the loop exits the Return command is executed and takes you back to your main program code (see below)

TEL_AF:
   Do

    If tel_BIT = 1 Then
    teller = teller - 1
    EndIf
   
    Print At 1,1,"MENU KEUS = ",Dec2 teller
         
    tel_BIT = 0
   
    If teller = 0 Then
    teller = teller + 1
    EndIf
 
  High Potmeter                    ;Load Condensator
  DelayMS 1                        ;Wait for unload condensator
  Waarde =  RCIn Potmeter, High
     
  If Waarde <60 Then
  sw2 = 1
  ElseIf Waarde <100 Then
  sw3 = 1
  ElseIf Waarde <200 Then
  sw2 = 0
  sw3 = 0
  EndIf

Loop Until sw2 | tel_BIt = 0

    Return
   
QuoteHello!

Why is this so difficult? I perform three functions with one pin. High - one LED is light, low - the second LED is light, I make a pin as an analog input - I measure the battery charge of the device, but the LEDs do not light (sequentially low voltage on each).
What pin have you set as analogue, I would presume from the circuit RA0, are you sure you are reading that input, have you measured the voltage on that pin with a meter to see what range of voltage you are getting and if so what are the value(s) are you referencing it to determine which LED should be on?
It is difficult to help with minimal information or source code to check for errors.