Positron8 - PIC18F27Q43 Timer0 Overflow Interrupt Demonstration

Started by top204, Apr 13, 2023, 11:50 AM

Previous topic - Next topic

top204

Thanks to the Positron8 compiler, the Q43 devices operate the same as other 18F types, but their SFR names may change and the bits within them will change, so it is important to check in the datasheet what SFRs and bits are required for a particular peripheral on a particular device. The PIC18F46Q43 device should be the same as the PIC18F27Q43 device I used for the demonatration program listing below, but with microchip, you can never guarantee that, so it "may" need some changes in the Timer0_Init procedure. :-)

The program listing below shows a simple Timer0 overflow interrupt demonstration. It has the interrupt set for 50ms. It also shows a more clear layout of a program listing, so it is easy to follow and change when required:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' A simple demonstration of a Timer0 overflow interrupt, operating on a PIC18F27Q43 device.
' The interrupt is set for a 50ms interval, which is 20Hz.
'
' It will flash an LED when the interrupt occurs and transmit an incrementing value to a serial terminal.
'
' Written for the Positron8 BASIC compiler by Les Johnson.
'
    Device = 18F27Q43                               ' Tell the compiler what device to compile for
    Declare Xtal = 64                               ' Tell the compiler what frequency the device is operating at (in MHz)
    On_Hardware_Interrupt Goto ISR_Handler          ' Tell the compiler that interrupts are being used and point to its handler routine
'
' Setup USART1
'
    Declare Hserial_Baud = 9600
    Declare HRSOut1_Pin = PORTC.6
    Declare HRSIn1_Pin = PORTC.7
'
' Create some constants and alias'
'
    Symbol LED_Pin = PORTB.0                        ' The LED is attached to this pin
    Symbol Timer0_cValue = $F3CB                    ' Set for Timer0 interval at 50ms with a 256 prescaler and the device operating at 64MHz
'
' Create a variable for the demonstration
'
    Dim wCounter As Word                            ' Increments every interrupt

'----------------------------------------------------
' Create some preprocessor meta-macros to make the program easier to follow and change
'----------------------------------------------------
$define Int_Global_Enable() INTCON0bits_GIE = 1     ' Enable global interrupts
$define Int_Global_Disable() INTCON0bits_GIE = 0    ' Disable global interrupts

$define Timer0_Enable() T0CON0bits_T0EN = 1         ' Enable Timer0
$define Timer0_Disable() T0CON0bits_T0EN = 0        ' Disable Timer0

'----------------------------------------------------
' Write a 16-bit value to the Timer0 SFRs
' Input     : pValue holds the value to write to TMR0L\H
' Output    : None
' Notes     : None
'
$define Timer0_Write16(pValue) '
    TMR0H = pValue.Byte1       '
    TMR0L = pValue.Byte0

'--------------------------------------------------------------------------------------------
' The main program starts here
' Initialise a Timer0 overflow interrupt.
' Every 20ms, the interrupt will flash an LED on PORTB.0
' And transmit the value of an incrementing counter variable to a serial terminal
'
Main:
    Int_Osc64MHz()                                  ' Set the device to use its internal 64MHz oscillator

    HRsoutLn "Started"                              ' Transmit to a serial terminal to make sure the program is initialised at 64MHz

    wCounter = 0                                    ' Reset the wCounter variable
    PinLow LED_Pin                                  ' Make the LED pin and output low to extinguish it
    Timer0_Init()                                   ' Initialise Timer0 for the interrupt required
    Int_Global_Enable()                             ' Enable global interrupts

    Do : Loop                                       ' Stop here because the interrupt will do its thing in the background

'--------------------------------------------------------------------------------------------
' Initialise Timer0
' Input     : None
' Output    : None
' Notes     : Timer0 is set up for a 50ms duration (20 Hz)
'
Proc Timer0_Init()
    Dim wTimer0 As TMR0L.Word                       ' Create a 16-bit SFR from TMR0L\H

    T0CON1 = 0b01011000                             ' Clock is FOSC/4, Prescaler is 1:256, Not Synchronised
    wTimer0 = Timer0_cValue                         ' Set Timer0 value
    PIR3bits_TMR0IF = 0                             ' Clear the interrupt flag before enabling the interrupt
    PIE3bits_TMR0IE = 1                             ' Enable a Timer0 interrupt
    T0CON0 = 0b10010000                             ' Postscaler is 1:1, Timer0 enabled, 16-bit operation
EndProc

'--------------------------------------------------------------------------------------------
' Read the 16-bit Timer0
' Input     : None
' Output    : Returns the 16-bit value held in TMR0L\H
' Notes     : None
'
Proc Timer0_Read16(), Word
    Result.Byte0 = TMR0L
    Result.Byte1 = TMR0H
EndProc

'--------------------------------------------------------------------------------------------
' Setup the internal oscillator for 64MHz
' Input     : None
' Output    : None
' Notes     : None
'
Proc Int_Osc64MHz()
    OSCCON1 = ob00000000
    OSCFRQ = 0b00001000                             ' Setup for 64MHz
    OSCENbits_HFOEN = 1                             ' HFINTOSC is enabled and operating as set by OSCFRQ
    DelayMs 100
EndProc

'--------------------------------------------------------------------------------------------
' Interrupt handler routine
' Input     : None
' Output    : None
' Notes     : A Timer0 overflow interrupt is tested for,
'             and this flashes an LED and transmits an incrementing value to a serial terminal
'
ISR_Handler:
    Context Save                                    ' Save any SFRs and compiler system variables used within the interrupt handler

    If PIR3bits_TMR0IF = 1 Then                     ' Was it a Timer0 overflow that triggered the interrupt?
        PIR3bits_TMR0IF = 0                         ' Yes. So clear its flag
        Timer0_Write16(Timer0_cValue)               ' Reload Timer0 for the same timing of the next interrupt
        Toggle LED_Pin                              ' Flash the LED
        HRsoutLn "From Interrupt: ", Dec wCounter   ' Transmit the value of wCounter to a serial terminal
        Inc wCounter                                ' Increment the wCounter variable
    EndIf

    Context Restore                                 ' Restore any SFRs and compiler system variables and exit the interrupt

'--------------------------------------------------------------------------------------------
' Set the config fuses to use the internal oscillator at 64MHz on a PICxxQ43 device
'
Config_Start
    FEXTOSC = Off                 ' Oscillator not enabled
    RSTOSC = HFINTOSC_64MHZ       ' HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1
    CLKOUTEN = Off                ' CLKOUT function is disabled
    PR1WAY = Off                  ' PRLOCKED bit can be set and cleared repeatedly
    CSWEN = On                    ' Writing to NOSC and NDIV is allowed
    FCMEN = On                    ' Fail-Safe Clock Monitor enabled
    MCLRE = INTMCLR               ' MCLR pin enabled
    PWRTS = PWRT_64               ' PWRT set at 64ms
    MVECEN = Off                  ' Interrupt contoller does not use vector table to prioritze interrupts
    IVT1WAY = Off                 ' IVTLOCKED bit can be cleared and set repeatedly
    LPBOREN = On                  ' Low-Power BOR enabled
    BOREN = SBORDIS               ' Brown-out Reset enabled. SBOREN bit is ignored
    BORV = VBOR_2P85              ' Brown-out Reset Voltage (VBOR) set to 2.8V
    ZCD = Off                     ' ZCD module is disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
    PPS1WAY = Off                 ' PPSLOCKED bit can be set and cleared repeatedly (subject to the unlock sequence)
    STVREN = On                   ' Stack full/underflow will cause Reset
    LVP = Off                     ' HV on MCLR/VPP must be used for programming
    XINST = Off                   ' Extended Instruction Set and Indexed Addressing Mode disabled
    WDTCPS = WDTCPS_31            ' Divider ratio 1:65536. software control of WDTPS
    WDTE = Off                    ' WDT Disabled. SWDTEN is ignored
    WDTCWS = WDTCWS_7             ' Window always open (100%). Software control. Keyed access not required
    WDTCCS = SC                   ' Software Control
    BBSIZE = BBSIZE_512           ' Boot Block size is 512 words
    BBEN = Off                    ' Boot block disabled
    SAFEN = Off                   ' SAF disabled
    DEBUG = Off                   ' Background Debugger disabled
    WRTB = Off                    ' Boot Block not Write protected
    WRTC = Off                    ' Configuration registers not Write protected
    WRTD = Off                    ' Data EEPROM not Write protected
    WRTSAF = Off                  ' SAF not Write Protected
    WRTAPP = Off                  ' Application Block not write protected
    CP = Off                      ' PFM and Data EEPROM code protection disabled
Config_End

Below is a screenshot of the above program operating on an Amicus18 board that contains a PIC18F27Q43 device, instead of its PIC18F25K20 device:
Timer0_Interrupt.jpg