Interrupt Menu System Example and Help Needed


Closed Thread
Results 1 to 9 of 9
  1. #1
    Join Date
    Feb 2005
    Location
    Bellevue
    Posts
    125

    Question Interrupt Menu System Example and Help Needed

    I have a working Interrupt Menu on an 18F2525, but need some help improving it. My program is constantly listening for data coming in on serial line via RB2, converting the binary data to usable information, and then either displaying that data, or writing the raw data to EEPROM. Since the data could come in as fast as every 100ms, I want to use an interrupt to manage the menu selection vs just polling for a button push. (but am open to simpler ways, certainly!)

    The menu/interrupt needs to allow the user to change what is happening with as little disruption to the data read - store routine as possible. I don't need to get too fancy, because a few lost packets is OK, but I do want to allow user to select:

    1. View 1 of data - eg long/lat
    2. View 2 of data - eg speed/hdg
    3. View 3 of data - eg volt/temp

    AND,

    4. Start recording data to EEPROM
    5. Stop recording data to EEPROM
    6. Play recorded data from EEPROM out the Serial port (Dump)
    7. Erase EEPROM

    Ideally, I'd use 2-3 buttons - 1/2 would scroll(up/down) throgh menus displayed on the LCD, the other would 'Select' the current view so the user can skip past those not wanted, and would then display that menu info on the LCD.

    The routine I use now is a simple Interrupt with T1CON. I don't think this will do it for the more complex menu that I need. Here is what I have setup for the 18F2525:

    @ __CONFIG _CONFIG1H, _OSC_INTIO67_1H
    @ __CONFIG _CONFIG2H, _WDT_ON_2H & _WDTPS_128_2H
    @ __CONFIG _CONFIG3H, _PBADEN_OFF_3H & _MCLRE_OFF_3H
    @ __CONFIG _CONFIG4L, _LVP_OFF_4L & 0bfh ;_XINST_OFF_4L
    '
    ' -----[ Includes/Defines ]---------------------------------------------------------
    OSCCON=%01111000
    DEFINE OSC 8
    While OSCCON.2=0:Wend

    include "modedefs.bas" 'include serout defines
    'define loader_used 1 Used for bootloader only

    ADCON0 = %00110000 ' turn off - select port AN12 (nothing)
    ADCON1 = %00001111 ' turn portA to digital I/O (same as dec 15)

    CMCON = $07 ' turn off
    HLVDCON = %00000000 ' turn off
    CVRCON = $00000000 ' turn off

    SSPCON1 = %11011100 ' supposed to be turning on I2C
    SSPCON2 = %01111000 ' supposed to be turning on I2C

    INTCON = %11110000 ' TG guess at 2525 interrups for all INT pins
    INTCON2= %01110101 ' rising edge of INT0,1,2 RB0,1,2
    RCON = %10000000 ' no priority interrups

    T1CON = %11000000 'Timer1 1:1 prescale.

    ...
    variables, etc,
    ...

    ' ----- starting here ---------------------------------------------------
    On Interrupt Goto ProcedureSwitcher

    Bmenu = 1

    ReStart:
    TMR1H = 0 ' Clear time counts before Timer1 re-start
    TMR1L = 0 ' Clear time counts before Timer1 re-start
    PIR1.0 = 0 ' CLear over-flow flag before enable
    T1CON.0 = 1 ' Turn Timer1 back on before entry into MainProcedure

    Main:' ****** [Main Program Loop] ************************************************** ***************
    wp=wp+1
    gosub getdata ' go get data from radio
    if stflag = 1 then
    gosub storedata ' store ss data to EEROM if flag is on
    endif
    gosub calcvalue ' calculate values
    if wp > 15 then
    gosub waypoint ' ALWAYS put out a waypoint signal on the line (4800b)
    endif

    Select Case Bmenu ' display and act accordingly - driven from interrupts
    case 1
    gosub dis1 ' display information
    Case 2
    gosub dis2 ' display lat/long
    Case 3
    gosub dis3 ' display speed volts
    Case 4
    gosub dis4 ' Display Alt
    Case 5
    gosub dis5 ' RSSI - radio strenght
    Case 6
    gosub dis6 ' output memory - 9600b - same line as GPS is on
    Case 7
    gosub dis7 ' erase memory, reset address to 0
    Case 8
    gosub dis8 ' Start Recorder - set stflag to 1
    Case 9
    gosub dis9 ' Stop Recorder - set stflag to 0, write last address to EEPROM on 18F
    End Select

    ' --------- Interrupt Handler ------------------------------------------------------------

    IF PIR1.0 THEN ' IF Timer1 has over-flowed then
    Timer = Timer + 1 ' Increment Timer variable
    PIR1.0 = 0 ' Clear over-flow/int flag
    ' @20MHz 200nS * 65,536 * 8 = 0.1048576 seconds per over-flow
    ' 0.1048576 * 48 = ~5.033 seconds before jump to NextStage
    IF Timer >= 48 THEN NextStage
    ENDIF


    goto Main

    return

    NextStage: ' Dont really know what you need here. Just a visual test
    T1CON.0 = 0 ' Turn off Timer1 if you need to here
    Timer = 0 ' Clear Timer var on entry here
    TMR1H = 0
    TMR1L = 0 ' CLear timer count registers as required

    GOTO ReStart ' When you're ready to start all over

    ' Interrupt handler stuff here
    '
    Disable ' Disable interrupts in handler
    ProcedureSwitcher:
    Bmenu = Bmenu + 1 ' Changing tasks only
    ' I need to be able to do more here... A 'select' button?

    If Bmenu = 10 Then Bmenu=1
    serout2 ALCDout, LCDbd, [I,CLR]
    serout2 ALCDout, LCDbd,[I,L1_C1]
    serout2 ALCDout, LCDbd, ["Using Menu #: ",#Bmenu]
    pause 500

    Here:
    While SWITCH = 0 ' waiting until
    wend ' push-button is release
    pause 100 ' debounce time
    If switch = 0 then here
    PIR1.0 = 0 ' Clear Timer1 over-flow flag
    Timer = 0 ' Clear Timer counts before return
    INTCON.1=0 ' reset RB0 interrupt flag
    Resume ' Return to main program

    Enable ' Enable interrupts after
    ' handler

    The 18F2525 supports multiple interrupts, and even priorities of interupt (which I think I turned off) - EG there is INT on RB0, RB1, RB2... If necessary, I can move the incoming serial data from RB1 to RB5 or so to make space for multiple interrupts.

    Anyone have any really good Interrupt/menu experience for such an application? I am sure this is a common type of activity - scroll through menus, then select the one you want, hopefully while something is still happening in the background....

    Thanks,

    Tom

  2. #2
    Join Date
    Feb 2003
    Location
    Delaware
    Posts
    30


    Did you find this post helpful? Yes | No

    Default I use a pot hooked to an analog port for scrolling.

    That's right my secrets out. I have done a few projects that involve user interfaces and I like to use a pot to scroll through menu items. I also use a single button and assign it different funtions based on how long its held down. You see I like to use a timer to debounce my switch. I set a timer to run free with a 1 mS period. Then when I service its interrupt I check to see if the button is pressed and if it is I increment a counter. Back in my main loop I check the value of the counter and if it is > then say 1000 I toggle an output, if it is > then 3000 I enter the menu screens. If the button is not pressed I zero the counter.

    Hope this helps,

    Joe Kupcha.

    P.S. Consider using a harware UART so that you won't need to wait and you won't miss any characters.

    Edit: If you want to use buttons for navigation you can save I/O by using an analog port and setting up a resistor network with the switches shorting out indivdual resistors.
    Last edited by cupajoe; - 27th March 2005 at 19:53. Reason: Forgot about buttons and analog ports.

  3. #3
    Join Date
    Feb 2005
    Location
    Bellevue
    Posts
    125


    Did you find this post helpful? Yes | No

    Question Great idea.. reading with POT?

    So, a few questions:

    1. What a 10k pot or something? Then setup a scale from 1-?? and convert this to X number of menu items? Hmmm..

    2. My menu system is broken with my current interrupt system - for example, if I want to go PAST menu 5 to menu 6, I can't do it because menu 5 is already happening.. It will show me that I selected 'Menu 6', but then goes back to Menu 5 --

    I need a way to SKIP menus I don't want to use and only dive in on the ones I want.. I think they way I have it set up, I HAVE TO go to each one.. no good..

    Do I have a SECOND button which does the selecting? I've never made a menu system like this before that chooses basically Gosubs...

    Tom

  4. #4
    Join Date
    Feb 2004
    Location
    Germany
    Posts
    762


    Did you find this post helpful? Yes | No

    Default

    Tom,

    the trick with menu systems is to structure them as far as possible.

    i.e.
    if you are in a menu to set the clock you don't want to see an item "set LCD contrast", do you ?

    A good example are mobile phones

    You might remember the early motorola phones:
    it was almost impossible to change anything without having the manual next to you.

    Today (with almost any phone) you can do everything with only two or three buttons without having had a look at the manual at all.

    What I'm trying to say is:
    The work starts ways before you start writing your first line of code.
    regards

    Ralph

    _______________________________________________
    There are only 10 types of people:
    Those who understand binary, and those who don't ...
    _______________________________________________



  5. #5
    Join Date
    Feb 2005
    Location
    Bellevue
    Posts
    125


    Did you find this post helpful? Yes | No

    Default Not 'menu creative yet'..

    I agree the hard part is keeping it usable!

    My problem is that this is my first 'LCD Navigation' project with buttons. What I want and what I can do are not in alignment...

    I WANT the program to behave like this:

    Initialize:
    - warm up LCD, etc.
    - Ready interrupt buttons on RB0 and RB1 (menu & select)
    - set counters to zero

    main:
    while no buttons are pressed
    - go get data
    - If recordflag=1 then
    gosub recorddata
    endif
    - covert data to info
    - show data view on LCD
    If Menu=1: Gosub view1
    If Menu=2: Gosub View2
    If Menu=3: Gosub view3
    Goto main

    If main interrupt menu (B0) is pressed cycle through 3 options:
    - Main Menu View - Explans to press B0 to move to next menu B1 to select
    - pressing B1 here does nothing. Pressing B0 moves to next view

    - Change View (BO/B1)
    - If I press the B1 button while looking at this view, it selects it
    - Select Menu1 - If I press B1, it selects it and returns to main
    - If I press B0, it shows the next menu ->
    - Select Menu2 - If I press B1, it selects it and retunrs to main
    - If I press B0, it shows the next menu ->
    - Select Menu3 - If I press B1, it selects it and retunrs to main
    - If I press B0, it shows the next menu ->
    - Select Exit - If I press B1, it selects it and goes to change view
    - If I press B0, it shows Menu1 ->

    - Start Recording(or stop recording if it is already on) (B0/B1)
    - If I press the B1 button while looking at this view
    - set recordflag to (on/off) depending on what current state is
    - If I press the B0 button while looking at this view, it moves next view

    - Playback recorded data(B0/B1)
    - If I press the B1 button while looking at this view, it selects it
    - takes me to a view that shows a warning that data will be dumped
    - if I press BO/B1 it will cancel this and return to top
    - If I press the B0 button while looking at this view, it moves next view

    - Exit (go back to where I was)
    - If I press the B1 button while looking at this view, it selects it
    - If I press the B0 button while looking at this view, it moves first view

    DURING this menu 'viewing', I want the processor to continue to take data in on the serial port.... If I DON'T click any BO/B1, after a certain amount of time, it should just COME BACK to the last menu# it was on...

    My problem is that I can only seem to trap for B0, then cycle through one menu at a time, and ALWAYS select that one (can't skip it). Pressing B1 is not doing anything, and I am not sure how to turn it on as an interrupt.. (18F2525 supporst multiple INT, and I THOUGHT I turned them on..)

    Any hints?

    Thanks,

    Tom

  6. #6
    Join Date
    Sep 2004
    Location
    montreal, canada
    Posts
    6,898


    Did you find this post helpful? Yes | No

    Default

    My suggestion, use the interrupt on PORTB change. Have a look to the datasheet.

    Once you jump to the interrupt routine, check the state of your push-buttons and do the according stuff or set some specific flags and do your stuff in the MAINLOOP.
    Steve

    It's not a bug, it's a random feature.
    There's no problem, only learning opportunities.

  7. #7
    Join Date
    Feb 2005
    Location
    Bellevue
    Posts
    125


    Did you find this post helpful? Yes | No

    Default

    OK - Once I am in the interrupt routine I need it to WAIT for a few seconds for the user to either click the BO again (in which case I'd do one thing), or click the B1, in which case I'd do something different.

    My problem is I can't find a way to WAIT... Is it some sort of loop?

    while RB0 <> pressed then do (do main routine stuff - read from port/convert)
    * time out after 5 seconds and return
    If RB1 is pressed then do (something)
    if RB0 is pressed then do (something else)

    wend

    ??

  8. #8
    Join Date
    Feb 2005
    Location
    Bellevue
    Posts
    125


    Did you find this post helpful? Yes | No

    Default

    With the 18F2525, there is an INT setting for external interrupts on RB0-2. From the sheet:
    -----------------------------------------------
    9.6 INTn Pin Interrupts
    External interrupts on the RB0/INT0, RB1/INT1 and
    RB2/INT2 pins are edge-triggered. If the corresponding
    INTEDGx bit in the INTCON2 register is set (= 1), the
    interrupt is triggered by a rising edge; if the bit is clear,
    the trigger is on the falling edge. When a valid edge
    appears on the RBx/INTx pin, the corresponding flag
    bit, INTxF, is set. This interrupt can be disabled by
    clearing the corresponding enable bit, INTxE. Flag bit,
    INTxF, must be cleared in software in the Interrupt
    Service Routine before re-enabling the interrupt.
    All external interrupts (INT0, INT1 and INT2) can wakeup
    the processor from Idle or Sleep modes if bit INTxE
    was set prior to going into those modes. If the Global
    Interrupt Enable bit, GIE, is set, the processor will
    branch to the interrupt vector following wake-up.
    Interrupt priority for INT1 and INT2 is determined by the
    value contained in the interrupt priority bits, INT1IP
    (INTCON3<6>) and INT2IP (INTCON3<7>). There is
    no priority bit associated with INT0. It is always a high
    priority interrupt source.

    ----------------------------------------------------
    I have set (I think) the appropriate bits for B0 and B1 to be interrupts. How can I tell the difference in an interrupt routine tho?? Since I am not watching for B1 to go high.... ????

    Tom

  9. #9
    Join Date
    Feb 2003
    Location
    Delaware
    Posts
    30


    Did you find this post helpful? Yes | No

    Default Ok more on the pot.

    Tom,

    The value of the pot doesn't really matter as long as its over say 5k. You see you are going to set up a voltage divider across Vcc and ground with the wiper going to the A/D pin. Then I simply read the value of the A/D (0 -1023) and I divide it to give me the number of selections I need. Here is an example. Note the tmr1cnt variable. TMR1 is free running with a 1mS period and tmr1cnt is a variable that is incremented every 1mS. This is compared to mud(menu update) to provide the timing to smoothly update the display. The other timing is provided by the variable "I". It is updated every 1mS if a button is pressed. It is cleared if the button is released. This variable is compared to MBP(menu button press) to debounce the button and ensure that it was held in for a bit.

    read_pot:
    adcin 3, adval3
    y = adval3 / 204
    return

    SETUP_MENU:
    if tmr1cnt > mud then
    tmr1cnt = 0
    gosub read_pot
    x = x + 1
    endif
    select case y
    case 0
    lcdout $FE,$C0,"->Reset Counters"
    case 1
    lcdout $FE,$C0,"->Set Rej. Dwell"
    case 2
    lcdout $FE,$C0,"->Set Threshold "
    case 3
    lcdout $FE,$C0,"->Prog. Scanner "
    case 4,5
    lcdout $FE,$C0,"->Exit Setup "
    end select
    if i > MBP then
    select case y
    case 0
    tmr1cnt = 0
    i = 0
    gosub reset_counters
    case 1
    tmr1cnt = 0
    i = 0
    gosub set_dwell
    case 2
    tmr1cnt = 0
    i = 0
    gosub set_thrsh
    case 3
    tmr1cnt = 0
    i = 0
    gosub prog_scan
    case 4,5
    @ BSF 0x06,1 ;SCANNER Off
    gosub SETUP_LCD
    goto main
    end select
    endif
    goto SETUP_MENU


    Hope this helps

    Joe

Members who have read this thread : 1

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