I've been tinkering a little with the compiler and have run into some issues with interrupts. I've got an LAB-X1 from MELabs, setup with a bit of additional harware items, all of which runs without a hitch using code from another compiler. Starting from the standard "Hello World" type of program, I've worked up to what I've listed below. It will probably look a little familiar, since most of it was based on Help file examples.
Here are the issues:
- Both interrupts run as expected when only 1 of them is enabled (by commenting out one or the other "activate" subroutine calls). But, when both are enabled, a change on PortB (by turning the encoder) causes the Pic to hang. I took a quick look at the .lst file to see if I had the priority numbers correct, and saw that address 8h and 18h have the bra's to the correct subs, but didn't look into it any deeper.
- Using SAVE(anything meaningful)...RESTORE causes irratic operation when used in either of the interrupt routines. Most noticable is garbage on the LCD in the position just to the right of either of the numeric outputs.
Code: Select all
// Device Setup
DEVICE = 18f4620
CLOCK = 40
PUBLIC CONFIG
OSC = HSPLL
// LCD
#option LCD_DATA = PORTD.4
#option LCD_RS = PORTD.0
#option LCD_EN = PORTD.1
// Base Module Includes
INCLUDE "LCD.bas"
INCLUDE "utils.bas"
INCLUDE "USART.bas"
INCLUDE "Convert.bas"
// Alias
DIM LCDOut AS LCD.Write
DIM HSEROut AS USART.Write
// Constants
CONST
TransDelayMulti = 10,
UpdateMS = 10,
BASE_BAR = 0, // ASCII value of 0 bar (blank)
FULL_BAR = 3, // ASCII value of ||| bar
BAR_WIDTH = 5, // Max width in characters of bar
MAX_BAR_COUNT = BAR_WIDTH * FULL_BAR // Max bar counts
// initialise bit patterns...
// programmable characters are available that use codes $00 to $07.
// Create the bit patterns that make up the bars in the LCD's CGRAM.
// The vertical bars are made up of 8 identical bit patterns
CONST CGRAM(8*(FULL_BAR+1)) AS BYTE = ($00,$00,$00,$00,$00,$00,$00,$00, // base bar
$10,$10,$10,$10,$10,$10,$10,$00, // 8 x %10000 = |
$14,$14,$14,$14,$14,$14,$14,$00, // 8 x %10100 = | |
$15,$15,$15,$15,$15,$15,$15,$00) // 8 x %10101 = | | |
'--------------------------------------------------------------------------------
' Subroutines
'--------------------------------------------------------------------------------
' ---=== output byte pRepValue times ===---
NOINLINE SUB Rep(pValue, pRepValue AS BYTE)
DIM Index AS BYTE
Index = 0
WHILE Index < pRepValue
LCDOut(pValue)
INC(Index)
WEND
END SUB
' ---=== display the bar ===---
NOINLINE SUB Bargraph(pLine, pBarValue AS BYTE)
DIM NumberOfBars AS BYTE
DIM Balance AS BYTE
' ---=== Dim BalanceChar As Byte ===---
NumberOfBars = pBarValue / FULL_BAR
Balance = pBarValue MOD FULL_BAR
MoveCursor(pLine,1)
Rep(FULL_BAR,NumberOfBars)
LCDOut(Balance)
Rep(BASE_BAR,BAR_WIDTH - (NumberOfBars + Min(Balance,1)))
END SUB
' ---=== Timer Interrupt Setup ===---
CONST TimerReloadValue = 10
CONST TimerValue = 15536 'Aprrox every 10 msec
DIM Timer0 AS TMR0L.AsWord
DIM Timer0IF AS INTCON.2
DIM Timer0IE AS INTCON.5
DIM Timer0On AS T0CON.7
DIM TimerCounter AS BYTE
DIM ElapsedCounter AS LONGWORD
'#option ISR_SHADOW = false
interrupt OnTimer(2)
Timer0On = 0
Timer0 = TimerValue
DEC(TimerCounter)
IF TimerCounter = 0 THEN
TimerCounter = TimerReloadValue
ENDIF
INC(ElapsedCounter)
Timer0On = 1
Timer0IF = 0
END interrupt
SUB ActivateTimer()
TimerCounter = TimerReloadValue
Timer0 = TimerValue
T0CON = %00001000
Timer0IF = 0
Timer0IE = 1
Timer0On = 1
ENABLE(OnTimer)
END SUB
' ---=== Rotary Encoder Interrupt Setup ===---
CONST Rot_Count_Max = 64
CONST Rot_Count_Min = 0
DIM Old_Bits AS BYTE
DIM Rot_Count AS WORD
DIM RBIF AS INTCON.0
DIM RBIE AS INTCON.3
interrupt OnChgB(1)
DIM New_Bits AS BYTE
RBIE = 0 ' (RBIE) Disable Interrupts
' save(0)
New_Bits = PORTB AND (%00110000)
IF New_Bits = Old_Bits GOTO No_Change_Rot1
IF (New_Bits.4 XOR Old_Bits.5) = 1 THEN
Rot_Count = Rot_Count + 1
IF Rot_Count = Rot_Count_Max+1 THEN
Rot_Count = Rot_Count_Max
ENDIF
ELSE
Rot_Count = Rot_Count - 1
IF (Rot_Count = Rot_Count_Min - 1) OR (Rot_Count = $FFFF) THEN
Rot_Count = Rot_Count_Min
ENDIF
ENDIF
Old_Bits = New_Bits
No_Change_Rot1:
RBIF = 0 ' (RBIF) Clear Flag
' restore
RBIE = 1 ' (RBIE) Enable Interrupts
END interrupt
SUB ActivateOnChgB()
Rot_Count = (Rot_Count_Min + Rot_Count_Max)>>1
INPUT (PORTB.4)
INPUT (PORTB.5)
Old_Bits = PORTB AND %00110000
'---=== Initialize Interrupt ===---
RBIF = 0 ' (RBIF) Clear Flag
RBIE = 1 ' (RBIE) Enable Interrupts
ENABLE(OnChgB)
END SUB
'--------------------------------------------------------------------------------
' Main Program
'--------------------------------------------------------------------------------
// Variables
DIM Index AS BYTE
' ---=== Add Custom Characters ===--
LCDOut(CGRAM)
' ---=== Setup Serial ===---
SetBaudrate(br115200)
HSEROut(10,13)
ElapsedCounter = 0
ActivateTimer
ActivateOnChgB
' ---=== Main Loop ===---
WHILE true
FOR Index = 0 TO MAX_BAR_COUNT
Bargraph(1,Index)
Bargraph(2,MAX_BAR_COUNT - Index)
DELAYMS(UpdateMS)
LCD.WriteAt(1,8,DecToStr(ElapsedCounter,10," "))
LCD.WriteAt(2,8,DecToStr(Rot_Count,10," "))
NEXT
HSEROut("Up ")
DELAYMS(UpdateMS*TransDelayMulti)
FOR Index = MAX_BAR_COUNT TO 0 STEP -1
Bargraph(1,Index)
Bargraph(2,MAX_BAR_COUNT - Index)
DELAYMS(UpdateMS)
LCD.WriteAt(1,8,DecToStr(ElapsedCounter,10," "))
LCD.WriteAt(2,8,DecToStr(Rot_Count,10," "))
NEXT
HSEROut("Down",10,13)
DELAYMS(UpdateMS*TransDelayMulti)
WEND
Looking forward to hearing some ideas, especially if I've overlooked something which is causing the problems.
Steve