News:

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

Main Menu

timer interrupt

Started by hitronics, May 17, 2021, 06:57 AM

Previous topic - Next topic

hitronics

Hi, Guys
I am looking for example of timer1 & timer0 interrupt example for blinking led
all your efforts are appreciated :)

Giuseppe


okmn

#2
there are few sample codes in positron studio menu(from Les)

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Demonstrate the use of the interrupt manager
'
' Create and handle two timer overflow interrupts
'
    Include "Amicus18.inc"                      ' Configure the compiler to use the Amicus18 hardware (18F25K20, 64MHz)
$define Handle_TMR0                             ' Handle a Timer0 overflow interrupt
$define Handle_TMR1                             ' Handle a Timer1 overflow interrupt

    Include "Interrupt Manager.inc"             ' Load the interrupt manager into the program
    Include "Amicus18_Timers.inc"               ' Load the Amicus18 Timer macros into the program

    'GoTo Main                                   ' Jump over the interrupt handlers
'--------------------------------------------------------------------
' High Priority Hardware Interrupt Handler
' Interrupt's on a Timer0 Overflow
' Display on the serial terminal
'
ISR_TMR0(Start)
    HRSOut "Timer0\r"                           ' Display text
ISR_TMR0(Exit)                                  ' Exit the interrupt, clearing the Timer0 flag

'--------------------------------------------------------------------
' High Priority Hardware Interrupt Handler
' Interrupt's on a Timer1 Overflow
' Display on the serial terminal
'
ISR_TMR1(Start)
    HRSOut "Timer1\r"                           ' Display text
ISR_TMR1(Exit)                                  ' Exit the interrupt, clearing the Timer1 flag

'--------------------------------------------------------------------
' Main Program Loop
'
Main:
'
' Configure Timer0 for:
'                       Clear TMR0L\H registers
'                       16-bit operation
'                       Internal clock source
'                       1:128 Prescaler
'
    OpenTimer0(TIMER_INT_OFF & T0_16BIT & T0_SOURCE_INT & T0_PS_1_128)
'
' Configure Timer1 for:
'                        Clear TMR1L and TMR1H registers
'                        16-bit read/write mode
'                        Internal clock source
'                        1:8 Prescaler
'
    OpenTimer1(TIMER_INT_OFF & T1_16BIT_RW & T1_SOURCE_INT & T1_PS_1_8)

    Int_TMR0(Enable)                        ' Enable a Timer0 overflow interrupt
    Int_TMR1(Enable)                        ' Enable a Timer1 overflow interrupt
    Int_Global(Enable)                      ' Enable global interrupts

    Stop

'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Demonstrate the use of the interrupt manager
'
' Create and handle two timer overflow interrupts
'
    Include "Amicus18.inc"                      ' Configure the compiler to use the Amicus18 hardware (18F25K20, 64MHz)
$define Handle_TMR0                             ' Handle a Timer0 overflow interrupt
$define Handle_TMR1                             ' Handle a Timer1 overflow interrupt

    Include "Interrupt Manager.inc"             ' Load the interrupt manager into the program
    Include "Amicus18_Timers.inc"               ' Load the Amicus18 Timer macros into the program

    GoTo Main                                   ' Jump over the interrupt handlers
'--------------------------------------------------------------------
' High Priority Hardware Interrupt Handler
' Interrupt's on a Timer0 Overflow
' Display on the serial terminal
'
ISR_TMR0(Start)
    HRSOut "Timer0\r"                           ' Display text
ISR_TMR0(Exit)                                  ' Exit the interrupt, clearing the Timer0 flag
'--------------------------------------------------------------------
' High Priority Hardware Interrupt Handler
' Interrupt's on a Timer1 Overflow
' Display on the serial terminal
'
ISR_TMR1(Start)
    HRSOut "Timer1\r"                           ' Display text
ISR_TMR1(Exit)                                  ' Exit the interrupt, clearing the Timer1 flag
'--------------------------------------------------------------------
' Main Program Loop
'
Main:
'
' Configure Timer0 for:
'                       Clear TMR0L\H registers
'                       16-bit operation
'                       Internal clock source
'                       1:128 Prescaler
'
    OpenTimer0(TIMER_INT_OFF & T0_16BIT & T0_SOURCE_INT & T0_PS_1_128)
'
' Configure Timer1 for:
'                        Clear TMR1L and TMR1H registers
'                        16-bit read/write mode
'                        Internal clock source
'                        1:8 Prescaler
'
    OpenTimer1(TIMER_INT_OFF & T1_16BIT_RW & T1_SOURCE_INT & T1_PS_1_8)

    Int_TMR0(Enable)                        ' Enable a Timer0 overflow interrupt
    Int_TMR1(Enable)                        ' Enable a Timer1 overflow interrupt
    Int_Global(Enable)                      ' Enable global interrupts

    Stop

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Timer1 Interrupt Demo
'
' Flash an LED with a Timer1 overflow interrupt, while flashing another LED in the foreground
'
' Written by Les Johnson for the Positron8 BASIC compiler.
' https://sites.google.com/view/rosetta-tech/home
'
    Device = 18F25K20                       ' We'll use the same chip as used with Amicus18
    Declare Xtal = 64
    On_Hardware_Interrupt GoTo ISR_Handler ' Point to the interrupt handler

    Include "Amicus18_Timers.inc"           ' Load the Amicus18 Timer macros into the program

    Symbol LED1 = PORTB.0           ' Led attachement pin
    Symbol LED2 = PORTB.2           ' Led attachement pin

'-------------------------------------------------------
' Main Program loop
Main:
    Low LED1                        ' \ Extinguish both LEDs
    Low LED2                        ' /
'
' Configure Timer1 for:
'                        Clear TMR1L and TMR1H registers
'                        Interrupt on Timer1
'                        16-bit read/write mode
'                        Internal clock source
'                        1:8 Prescaler
'
'
    OpenTimer1(TIMER_INT_ON & T1_16BIT_RW & T1_SOURCE_INT & T1_PS_1_8)

    INTCONbits_PEIE = 1             ' Enable peripheral interrupts
    INTCONbits_GIE = 1              ' Enable global interrupts
'
' Flash an LED attached to PortB.2 slowly in the foreground
' Display the current value of Timer1 on the serial terminal
'
    Do                              ' Create an infinite loop
        HRSOutLn Dec ReadTimer1()   ' Display Timer1 value
        High LED2                   ' Illuminate the LED
        DelayMS 500                 ' Wait for 500 milliseconds
        Low LED2                    ' Extinguish the LED
        DelayMS 500                 ' Wait for 500 milliseconds
    Loop                            ' Do it forever

'-------------------------------------------------------
' Timer1 Interrupt Handler
' Flash an LED on PortB.0
'
ISR_Handler:
    Context Save
    If PIR1bits_TMR1IF = 1 Then     ' Was it a Timer1 overflow that triggered the interrupt ?
        Toggle LED1                 ' Yes. So. Toggle the LED
        Clear PIR1bits_TMR1IF       ' Clear the Timer1 overflow flag
    EndIf
    Context Restore                 ' Exit the interrupt, restoring registers

'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Flash an LED with a Timer0 overflow interrupt
' While flashing another LED in the foreground
'
' Written by Les Johnson for the Positron8 BASIC compiler.
' https://sites.google.com/view/rosetta-tech/home
'
    Device = 18F25K20                       ' We'll use the same chip as used with Amicus18
    Declare Xtal = 64
    On_Hardware_Interrupt GoTo ISR_Handler ' Point to interrupt handler

    Include "Amicus18_Timers.inc"           ' Load the Amicus18 Timer macros into the program

    Symbol LED1 = PORTB.0                   ' LED attachement pin
    Symbol LED2 = PORTB.2                   ' LED attachement pin

'-------------------------------------------------------
' Main Program loop
Main:
    Low LED1                                ' \ Extinguish both LEDs
    Low LED2                                ' /
'
' Configure Timer 0 for:
'                           Clear TMR0L and TMR0H registers
'                           Interrupt on Timer0
'                           16-bit operation
'                           Internal clock source
'                           1:16 Prescaler
'
    OpenTimer0(TIMER_INT_ON & T0_16BIT & T0_SOURCE_INT & T0_PS_1_16)

    INTCONbits_GIE = 1 ' Enable global interrupts
'
' Flash an LED attached to PortB.2 slowly in the foreground
' Display the current value of Timer0 on the serial terminal
'
    Do                                              ' Create an infinite loop
        HRSOutLn "Timer0 = ", Dec ReadTimer0()      ' Display Timer0 value
        High LED2                                   ' Illuminate the LED
        DelayMS 500                                 ' Wait for 500 milliseconds
        Low LED2                                    ' Extinguish the LED
        DelayMS 500                                 ' Wait for 500 milliseconds
    Loop                                            ' Do it forever

'------------------------------------------------------
' Timer 0 Interrupt Handler
' Flash an LED on PORTB.0
ISR_Handler:
    Context Save
    If INTCONbits_T0IF = 1 Then             ' Was it a Timer0 overflow that triggered the interrupt?
        Toggle LED1                         ' Yes. So. Toggle the LED
        Clear INTCONbits_T0IF               ' Clear the Timer0 overflow flag
    EndIf
    Context Restore                         ' Exit the interrupt, restoring registers
   


hitronics


Giuseppe

By activating or not the initial defines you can make the led blink every 500mS or for
interrupt of timer 0 or for interrupt of timer1


Device = 16F628

Xtal = 4

$define set_timer0 0  'set to 1 to enable timer 0
$define set_timer1 1  'set to 1 to enable timer 1

Config FOSC_INTOSCIO, WDTE_OFF, PWRTE_ON, MCLRE_OFF, BOREN_ON, LVP_OFF, CPD_OFF, CP_OFF

;**** End of Fuse Configurator Settings ****
;-------------------------------------------------------------------------------

All_Digital True                                   


OPTION_REG = %11000000
INTCON = %00100000

TRISB = %00000000                                       
TRISA = %00000000

CMCON = 7  '
VRCON = 0  '


Dim tic As Word

Symbol led = PORTB.0
Symbol GIE = INTCON.7

$if set_timer0
Symbol TMR0IE = INTCON.5
Symbol TMR0IF = INTCON.1
OPTION_REG.5 = 0 ; TMR0 Clock Source Select bit...0 = Internal Clock (CLKO) 1 = Transition on T0CKI pin
OPTION_REG.4 = 0 ; TMR0 Source Edge Select bit 0 = low/high 1 = high/low
OPTION_REG.3 = 0 ; Prescaler Assignment bit...0 = Prescaler is assigned to the Timer0
OPTION_REG.2 = 1 ; PS2:PS0: Prescaler Rate Select bits 1:64
OPTION_REG.1 = 0 ;
OPTION_REG.0 = 1 ;
TMR0 = 100
$endif

$if set_timer1
Symbol PEIE = INTCON.6
Symbol TMR1IE = PIE1.0
Symbol TMR1IF = PIR1.0
T1CON.5 = 0   ;bits 5-4  Prescaler Rate Select bits
T1CON.4 = 0   ;bit 4
T1CON.3 = 1   ;bit 3 Timer1 Oscillator Enable Control bit 1 = on
T1CON.2 = 1   ;bit 2 Timer1 External Clock Input Synchronization Control bit...1 = Do not synchronize external clock input
T1CON.1 = 0   ;bit 1 Timer1 Clock Source Select bit...0 = Internal clock (FOSC/4)
T1CON.0 = 1   ;bit 0 enables timer
TMR1H = 216   ;preset for timer1 MSB register
TMR1L = 242;  ;preset for timer1 LSB register
$endif

Low led
Clear tic

DelayMS 200

$if set_timer0
Set TMR0IE
Clear TMR0IF
$endif

$if set_timer1
 Set PEIE
 Set TMR1IE
 Clear TMR1IF
$endif

Set GIE
'------------------------------------------------------------
On_Interrupt GoTo int_routine

GoTo main

int_routine:     ' interrupt every 1mS

Context Save

$if set_timer0
If TMR0IF = 1 Then
   TMR0 = 100
   Clear TMR0IF
   tic = tic + 1               
EndIf   
$endif


$if set_timer1
If TMR1IF = 1 Then     
   TMR1H = 216   
   TMR1L = 242   
   Clear TMR1IF     
   tic = tic + 1
EndIf
$endif

Context Restore


'-----------------------------------------------------------
main:

If tic > 499 Then   'LED flashes every 500mS
   Clear tic
   Toggle led
EndIf   


GoTo main

hitronics

#5
all efforts are appreciated
by the way I want to go to subroutine inside interrupt can use gosub?
note: inside subroutine just read adc input

RGV250

Hi,
Quoteby the way I want to go to subroutine inside interrupt can use gosub?
It is best to keep the interrupt as small as possible, what I do in this situation is set a bit and then use that in the main program to call the subroutine and reset the bit at the end.

Bob

hitronics

I have some chips 12F675 I want to read analog at pin GPIO.0 then I want after some delay want to use same pin as digital output
then how to switch pin as analog then switch it as digital output ?

TimB


Yes you can use a gosub in the interrupt routine. Just remember to add up all the possible subs you may be in, in your main code and add on 2 more. I doubt you would overflow the stack in an 18 series, 16 is limited to 8 at least the old ones I used. Also keep the sub for use only via the interrupt. You cannot call a sub used in main code or a command eg ADCIN

ADC sampling takes time. What I do is start the sample using the Go/Done bit and then read it next interrupt. Then start the conversion again.


TimB

Quote from: hitronics on May 23, 2021, 01:56 PMI have some chips 12F675 I want to read analog at pin GPIO.0 then I want after some delay want to use same pin as digital output
then how to switch pin as analog then switch it as digital output ?

Yes it can be done. But you will need to read up on messing with the Pic reg's to handle the pin type swapping

hitronics

Quote from: TimB on May 23, 2021, 02:05 PMYes it can be done. But you will need to read up on messing with the Pic reg's to handle the pin type swapping

do you have example please :)

top204

#11
Sorry Tim, but a call to a subroutine should "never" be performed from within an interrupt, and the compiler will give a Warning message if a call to a standard subroutine is used within the interrupt handler.

The compiler, at compile time, scans the code of the interrupt handler between Context Save and Context Restore and stores any SFRs used and the compilers system variables used within it, in an internal array, so it can restore them when the interrupt is finished.

Remember, an interrupt can happen at any time within a program, even between assembler mnemonic loadings, and the compiler cannot scan the code between the called subroutine because it has no internal reference to its start and end, so all sorts of anomalies will happen within the code's operation. The Sub-EndSub directives were introduced to the compiler before I created true procedures, so they do not have any internal data structures to them, and will, eventually, be removed from the compilers because they are no longer required.

I have created a 'beta' mechanism in the latest Positron8 compiler that will allow a procedure to be called from an interrupt handler, because the compiler has reference as to the start and end of the procedure's block, and each procedure has an internal sctructure table containing its details, so the compiler can scan its internals. But it is still in beta, so cannot be 100% relied upon yet, and if used, the assembler code should be scanned for validity, just in case.

The principle sounds simple, but, internally, it is a complex piece of coding because the procedure needs to be marked as "called from interrupt", and any procedures it calls are also marked, and any procedures they call are marked and scanned etc... So the internal context storage array will increase with more procedures calling more procedures etc...

Also, a call to a procedure from an interrupt handler should be totally avoided because it adds more time to the handling of the interrupt. An interrupt should be as fast as is possible and "no" high level commands used within it, unless it is a demo, or nothing is really happening in the main program so slowness will not be a problem.

RayEllam

Better to set a flag in the ISR then run whatever sub/procedure from within the main code loop dependant on the flag setting.

Stephen Moss

Quote from: hitronics on May 23, 2021, 12:54 PMall efforts are appreciated
by the way I want to go to subroutine inside interrupt can use gosub?
note: inside subroutine just read adc input
Not really a good idea to jump out of an ISR and back again. If you really feel the need to read the ADC while in the ISR you would be better simply putting the ADC read code in the ISR
However, as ISR's (Interrupt Service Routines) should be kept as short a possible to minimise the chances of missing an interrupt events you would be better setting a flag, i.e. DIM ReadADC as Bit, then inside your ISR have ReadADC  = 1 and in your main code loop have If ReadADC = 1 then Jump_to_ADC_Subroutine, remember to reset you ReadADC flag to 0 somewhere in you ADC read subroutine. 

Quote from: hitronics on May 23, 2021, 01:56 PMI have some chips 12F675 I want to read analog at pin GPIO.0 then I want after some delay want to use same pin as digital output
then how to switch pin as analog then switch it as digital output ?
You will need write to several of the PIC registers....
TRISx
where x is the port letter, if you have read the data sheet you will know that setting a bit to 0 = output and 1 = input so if your signal is was connected to pin 1 of Port D your would need PORTD.1 = 0, to set it to an output.

ADCON/ADSEL
In some devices the ADCON register may contain the bits that determine if an I/O pin is analogue or digital, in larger devices it will normally be the ADSEL register, again you will need to read the datasheet to determine which Registers/Register Bits to manipulate.
The first time you write to such a register you will normally have to write to most if not all of the bits so it would be better to write to the entire at once, i.e.
ADSEL = Applicable_Value (saves writing 1 commands for each bit)
after that if you only need to change the analogue/digital status of a single you can change the individual bit as per the TRIS example above.

I think it would be better to change the analogue/digital status of the I/O before changing its Input/Output status.

I do not know what your are planning but normally when using a pin and both an analogue input and a digital output you will need to isolate (disconnect) the analogue signal from the pin when you want to use it as a digital output. Otherwise the analogue and digital signals will interfere with each other and may damage the source of the analogue signal or the I/O pin.
Generally, I would suggest avoiding such dual usage unless there is no other option.