MPLABICDCode

The main program code should be under "Source File" in MPLAB. Your main Swordfish program file should always reside in the same folder as you MPLAB project file. That is, the program in "Source Files" must be in the same folder as the MPLAB *.mcp and *.mcw files.

' select device and clock...
Device = 18F1320
Clock = 8

' enable ICD - always set before including the Junebug module - if
' you are not using the ICD, you must disable or remove this option
' in order for your program to work correctly...
#option ICD = true     

' include the Junebug module - this module will manage LEDs and
' button presses for you. It will also correctly configure for internal
' oscillator, based on the 'clock' value above (4 or 8MHz only)
Include "junebug.bas"

' local variables...
Dim Index As Byte
Dim Delay As Word
Dim DoCount As Boolean

' program start...
Index = 0
DoCount = false
Delay = 100
While true
   LED = Index

   ' press button 1 to start and stop counting...
   If IsPressed(Btn1) Then
      DoCount = Not DoCount

   ' if button 2 is pressed, slow down the count speed...
   ElseIf IsPressed(Btn2) Then
      Inc(Delay, 10)
      If Delay > 500 Then
         Delay = 500
      EndIf

   ' if button 3 is pressed, speed up the count speed...
   ElseIf IsPressed(Btn3) Then
      Dec(Delay, 10)
      If Delay < 10 Then
         Delay = 10
      EndIf
   EndIf

   ' if counting is enabled, increment the counter and
   ' delayms(Delay) - Delay will vary depending on how
   ' much you have decreased or increased using Btn2 or Btn3
   ' respectively...
   If DoCount Then
      Inc(Index)
      DelayMS(Delay)
   EndIf
Wend

Module Code

Here is the module code, which should be under "Other Files"

Module Junebug

// default configuration fuses...
Config 
   OSC = INTIO2, 
   WDT = OFF, 
   LVP = OFF

// if you want to use ICD, then set '#option ICD = true' in your main program
// before you include this module...
#if IsOption(ICD) And ICD
#option ISR_SHADOW = false
#variable _maxram = _maxram - $C    // constrain RAM
#variable _maxrom = _maxrom - $1C0  // constrain ROM
Config DEBUG = ON                   // DEBUG fuse ON
#endif

// private module constants...
Const 
   TIMER_REFRESH          = 500,                            // 500 = 2 ms, 250 = 1ms
   TIMER_RELOAD As Word   = 65536 - _clock * TIMER_REFRESH, // calculate reload constant
   TIMER_DEBOUNCE As Byte = 2500 / TIMER_REFRESH            // button debounce (10ms)

// private module variables...
Dim 
   TMR1 As TMR1L.AsWord,   // timer 1 as a word
   TMR1IF As PIR1.0,       // timer 1 interrupt flag
   TMR1IE As PIE1.0,       // timer 1 interrupt enable
   smState As Byte,        // LED state machine variable
   LastButton As Byte,     // holds the state of the last PORTB button press
   Debounce As Byte        // debounce counter variable

// public module constants...
Public Const
   Btn1 = 1,
   Btn2 = 2,
   Btn3 = 4

// public module variables...
Public Dim                 
   LED As Byte,            // LED, bits 0..5
   Button As Byte          // button press, bits 0..2
{
****************************************************************************
* Name    : ISR (PRIVATE)                                                  *
* Notes   : High priority interrupt handler for Timer 1 events. The ISR is *
*         : fired every 1 or 2ms (depending on TIMER_REFRESH, see above)   *
*         : LED HANDLING                                                   *
*         : As the LEDs on the Junebug are 'charlieplexed', you can only   *
*         : normally have one LED on at a time. However, by time slicing   *
*         : very quickly between each LED state, you can give the illusion * 
*         : that all LEDs are on at the same time. Just set LED.0..5 in    *
*         : main program to switch on                                      *
*         : BUTTON HANDLING                                                *
*         : PORTB is scanned and if a button is pressed, the ISR will      *
*         : manage debouncing (10ms). Using an ISR to scan for a button    *
*         : ensure that no button press events are ever missed, even if    *
*         : your main program is performing another task. Use either       *
*         : Button.0..2 in your main program to test for a button press.   *
*         : alternatively, make a call to IsPressed() - see below          *
****************************************************************************
}
Public Interrupt ISR()
   Dim PortState As Byte

   // clear timer 1 interrupt flag and reload timer counter...
   TMR1 = TMR1 + TIMER_RELOAD
   TMR1IF = 0

   // disable all LEDS, then check each LED bit in turn - if set to
   // one, the LED is switched on
   TRISA = TRISA Or %11000001
   If (smState And LED) <> 0 Then
      Select smState
         Case 1
            High(PORTA.0)
            Low (PORTA.6) 
         Case 2     
            Low (PORTA.0)
            High(PORTA.6)      
         Case 4     
            High(PORTA.6)
            Low (PORTA.7)      
         Case 8     
            Low (PORTA.6)
            High(PORTA.7)      
         Case 16      
            Low (PORTA.0)
            High(PORTA.7)      
         Case 32      
            High(PORTA.0)
            Low (PORTA.7)      
      End Select
   EndIf

   // next LED state...
   smState = smState << 1
   If smState.6 = 1 Then
      smState = 1
   EndIf  

   // read PORTB and mask non-button pins...
   PortState = PORTB And %00100101

   // check for button debounce...
   If Debounce > 0 Then
      Dec(Debounce)

      // if debounce has expired and the button press state remains the same,
      // we need to set the correct bits for our public 'button' variable
      If (Debounce = 0) And (PortState = LastButton) Then
         If PortState.0 = 0 Then
            Button.0 = 1
         EndIf
         If PortState.2 = 0 Then
            Button.1 = 1
         EndIf
         If PortState.5 = 0 Then
            Button.2 = 1
         EndIf
      EndIf

   // no debounce, see if a button has been pressed...   
   ElseIf PortState <> LastButton Then
      Debounce = TIMER_DEBOUNCE
      LastButton = PortState
   EndIf
End Interrupt
{
****************************************************************************
* Name    : IsPressed (PUBLIC)                                             *
* Notes   : Returns true if a button has been pressed. You should pass     *
*         : the pre-defined constants Btn1, Btn2 or Btn3 to this routine.  *
*         : The 'Button' bit is automatically cleared whan a call is made  *
*         : this routine. If you use the 'Button' variable directly in     *
*         : your program, you will need to clear its state flag manually   *                                                   *
****************************************************************************
}
Public Function IsPressed(pButton As Byte) As Boolean
   Disable(ISR)
   result = (Button And pButton) > 0
   Button = Button And Not pButton
   Enable(ISR)
End Function

// the first piece of code we must always execute is to select
// either internal 4 or 8Mhz clock - this depends on the 'clock' value
// set in the main program...
#if _clock = 4
OSCCON = $62        
#elseif _clock = 8
OSCCON = $72 
#endif

// initialise the module...
smState = 1         // initialise LED state machine
LED = 0             // all LEDs are off
Button = 0          // no buttons pressed
INTCON2.7 = 0       // enable weak pullups on PORTB
Debounce = 0        // clear debounce
ADCON1 = %11110101  // all digital, except RA1 and RA3
TMR1 = TIMER_RELOAD // initialise timer 1
TMR1IF = 0          // clear timer interrupt flag
TMR1IE = 1          // enable timer 1 interrupts
T1CON = $01         // prescale 1:1, switch timer on
Enable(ISR)         // enable interrupt handler