microcontroller Pin Interrupt circuit - Page 1
Forum section: electronics / general

author: yalect
author_rank: Regular Contributor
timestamp: May 17, 2024, 12:05:45 am
content: Hi,I would like to ask you that I want to write code inC languageusing the microcontrollerPIC16F84, when I applicate a voltage onRA4/T0CKIofPORTAan interrupt hapens making the program switchs or jumps to second sub function or loopvoid interrupt()doing some instructions and back after it has finished or done to the main programvoid main()that means switching or moving between two functions by interrupt.is it possible?.thank you.

author: Doctorandus_P
author_rank: Super Contributor
timestamp: May 17, 2024, 12:25:51 am
content: Usually there are a lot of ways in which ISR's can be triggered by software, but they tend to have various side effects. With your method, you loos an I/O pin, and when it's shorted it does not work at all. Another method is to pre-load a timer and let it overflow after command.

author: DavidAlfa
author_rank: Super Contributor
timestamp: May 17, 2024, 01:48:46 am
content: In that PIC only RB7:RB4 pins have interrupt on change.Which compiler? XC8?

author: yalect
author_rank: Regular Contributor
timestamp: May 17, 2024, 05:40:05 am
content: thank you for your replies.you mean we can't use interrupts onPORTAwithPIC16F84? to switch or move to sub function or routine for exampleinterrupt ()by interrupt, maybe withTMR0timer and How?.

author: woofy
author_rank: Frequent Contributor
timestamp: May 17, 2024, 08:09:58 am
content: First, unless yo have a good reason to use this ancient device, you should choose something newer with more features for less money.If you do have to use it then yes, you can use the timer to generate the interrupt from a change on RA4. You should set T0CS to 1 to select external clk, PSA to 0 to bypass the prescaler and TMR0 to 0xFF. Now a clk input will cause the timer to rollover to 0x00 and set T0IF. Remember to set TMR0 back to 0xFF in your interrupt routine.

author: woody
author_rank: Frequent Contributor
timestamp: May 17, 2024, 08:19:47 am
content: Quote from: yalect on May 17, 2024, 05:40:05 amNo you cannot. See datasheet page 48Quote from: yalect on May 17, 2024, 05:40:05 amIn principle you first select the chip frequency and timer0 settings to fire every x ms. x depending on how often you need to check the state of the input pin. For the 16F84 this is done in hardware (crystal/resonator or RC) and in an init() routine that precedes main(), where you set fuses and timer.Then you write a (maybe empty) main() and an interrupt() routine that handles (reads) the input pin every time the interrupt fires. If you only want to light a led or switch a relay depending on the input state you can do that in the interrupt routine. For more complicated reactions you need signaling to main() to keep the interrupt() routine short.

author: jpanhalt
author_rank: Super Contributor
timestamp: May 17, 2024, 08:28:13 am
content: On the 16F84A (I didn't check the plain 16F84):1) Poll the pin and make a software interrupt or even a branch. No interrupt needed.2) That pin is T0CLKI (TMR0 input) and TMR0 is writable. Set TMR0 to 255. On first pulse TMR0 will overflow and can be made to cause an interrupt. You can also select the edge to cause increment. Of course, on return from the ISR, you need to re-arm TMR0.Not knowing how complex your project is, if it is relatively simple, I would just poll the pin and not use an interrupt.

author: yalect
author_rank: Regular Contributor
timestamp: May 27, 2024, 09:32:27 am
content: Hi, thank you for your reply.but Can I know how is interrupt this Pic microcontroller?.thanks.

author: jpanhalt
author_rank: Super Contributor
timestamp: May 27, 2024, 09:44:01 am
content: It's been 10 days since your last post. Several posts have told you how to create an interrupt with that chip. Do you understand the principle? What don't you understand? Why do you even need an interrupt? Why not use polling?Maybe most important, do you know how write code in C? Several contributors have asked questions. You have not answered a single one. Addressing those questions would be a good place to start.

author: yalect
author_rank: Regular Contributor
timestamp: May 27, 2024, 02:09:50 pm
content: Sorry, that it was mistake, yes I know about to put 255 value in the timer to make it overflow after, I meant how is it's fast is, that interrupts or speed of response, maybe there are a ways to make it more response?.Thank you in advance.

author: DavidAlfa
author_rank: Super Contributor
timestamp: May 27, 2024, 02:31:41 pm
content: Thats it. It will take a single clock cycle, almost instant response (1-4us maybe).

author: jpanhalt
author_rank: Super Contributor
timestamp: May 27, 2024, 02:56:58 pm
content: I agree with David. It is quite fast relative to anything else you do. The datasheet for the 16F84A in Section 6 describes interrupt latency. For an IOC on PORTB, it is 3 to 4 instruction cycles (Tcy). An instruction cycle is 4 oscillator cycles. Thus, at 8 MHz, an instruction cycle is 2 MHz (500 ns). I didn't see a specific latency for reading Timer 0 overflow which sets TOIF. I suspect it is at least that fast.That chip does not save "context," i.e., WREG, STATUS and other important working values. It does save the return point on the STACK. Depending on your program and the ISR, you may and probably do want to save context, then restore context before returning from the interrupt. Saving context will take several more Tcy and there are efficient examples of how to do that in the datasheet. That may be somewhat automatic in C, I don't know.

author: yalect
author_rank: Regular Contributor
timestamp: May 29, 2024, 11:36:24 am
content: Hi, thank you for replies.Is it correct when we read the timer or tmr0 directlly?.for example :Timer or tmr0 = 132;orif (tmr0 = 132);shortly, is that affect on the timer fonction?.Thanks.

author: jpanhalt
author_rank: Super Contributor
timestamp: May 29, 2024, 12:16:08 pm
content: Please read the datasheet for the device you are using. Here's an excerpt from the 16F84A datasheet:QuoteFirst, it rolls over from 255 (0xFF) on the next count. It can count from the RA4/T0CK1 pin and create an interrupt. It's not the easiest way to do it, but since you wanted an interrupt by a pin on PORTA, in theory, it can do that. I cannot help you with C code. I don't know why you apparently want to preset to 132. Note, Timer0 also has prescaler, so you have to set a few things up in code, including edge. I believe if you set it as a timer based on the instruction clock, it runs continuously after you do that. That is, you cannot turn it on and off easily. Look at the requirement for synchronization.An easier way would be to use PORTB and IOC as other have said.

author: Ian.M
author_rank: Super Contributor
timestamp: May 29, 2024, 03:31:28 pm
content: However Port B IOC on older PIC16 and PIC18 parts including the PIC16F84 & PIC16F84A is buggy. It can loose edges due to a race condition in the change detection logic. Seebug detailsat the old xargs.com site (via Internet Archive).Its OK for waking from SLEEP, but if running, makes it very difficult to use any other pins on port B without risking missing a change on the IOC capable pin you are interested in.Your best bet for an easy to use external interrupt on that PIC is the RB0/INT pin as that pin has a simple edge triggered interrupt, with the edge selectable by OPTION_REG.INTEDG, and the usual enable and interrupt flags in INTCON.

author: yalect
author_rank: Regular Contributor
timestamp: May 30, 2024, 06:11:06 pm
content: Hi,we can set TMR0 to 255. On first pulse TMR0 will overflow and can be made to cause an interrupt.as they response above and we can read the statuse of the flag in the register INTCON TOIF to detectThat.is there a way to read TOIF or carry its value and clear it again in software in the same way maybe with (and) logic or (or) in one instruction instead read and clear frequently?.Thank you.

author: jpanhalt
author_rank: Super Contributor
timestamp: May 30, 2024, 06:33:23 pm
content: Look on page 10 of the datasheet. The T0IF bit of INTCON is readable and writable. If that doesn't convince you , then this section will:QuoteNot only can you clear it, but you must clear it in software.I feel like we are going in circles. You wanted an interrupt and didn't want to poll a bit. Yes, you can poll it (if T0IE is clear), but why go such a circuitous route if you do not want an interrupt?As a general rule, with PICs, interrupt flags are set regardless of whether the corresponding interrupt is enabled. That can be an important consideration when re-enabling interrupts.

author: yalect
author_rank: Regular Contributor
timestamp: June 01, 2024, 12:42:29 pm
content: Hi,yes, maybe in such microcontroller or PIC 16F84 we can't make intrruptions for changes happen on Pin RA4/T0CKI or voltage causes the Pic do some special fonctions like calculate some numbers for example or like output Portb......?Thank you.

author: DavidAlfa
author_rank: Super Contributor
timestamp: June 01, 2024, 01:51:20 pm
content: Of course you can - That's what an interrupt stands for!I suggest you get some PIC programming book!https://deepbluembedded.com/interrupts-in-pic-microcontrollers/https://class.ece.uw.edu/475/peckol/doc/8976457-Programming-8Bit-PIC-Micro-Controllers-in-C.pdf#page=112You must configure the peripheral or interrupt source first (The timer), clear any pending flags, enable global interrupts (GIE) and also peripheral interrupts (PEI) depending on the peripheral.This is all explained in the datasheet.Also, check the datasheet for the "TCKEZTMR1" parameter.(TABLE 17-8: TIMER0 AND TIMER1 EXTERNAL CLOCK REQUIREMENTS)It takes about 7 cpu clock cycles for the timer0 to increment when selecting external clock, so it won't be as instant as you might think.I simulated it, the best I got was about 12-15uS delay.- 7 clock cycles for the timer to "read" the clock pulse.- Another 3-4 clocks of interrupt latency (The time it needs to trigger and jump).- Few more clocks to save context (W and STATUS registers).- Actual interrut code starts executing.Then depending on the compiler you must declare a function as an interrupt.In XC this is done adding the preamble "__interrupt()" to a void function:Code:void __interrupt() function_name (void)So for XC8:Code:void __interrupt() ISR(void){ // This will be called when an interrupt happensif(TMR0IF){ // Check if TMR0IF is setTMR0IF=0; // TMR0 interrupt active, clear TMR0IF//blah // Do something. Don't make any complex, long operations here.}if(other_IF){ // This function must check all the enabled interrupts.other_IF=0;//other_blah}}Also, make clear the compiler you're using. "C language" means nothing here, PIC compilers are very different to each other.Also, still, why you MUST use RA0? Why not any of the PORTB pins that have native interrupt-on-change?You're basically wasting the timer in this basic function.Some basic code:Code:#include <xc.h>#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)#pragma config MCLRE = ON // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is MCLR)#pragma config BOREN = ON // Brown-out Detect Enable bit (BOD enabled)#pragma config LVP = ON // Low-Voltage Programming Enable bit (RB4/PGM pin has PGM function, low-voltage programming enabled)#pragma config CPD = OFF // Data EE Memory Code Protection bit (Data memory code protection off)#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)void __interrupt() Interrupt(void){if (INTCONbits.TMR0IF) {INTCONbits.TMR0IF = 0;TMR0 = 255; // Preload timer with 255, so it overflows on next input clockPORTAbits.RA1 = PORTAbits.RA1; // Toggle RA1}}void main() {TRISAbits.TRISA1=0; // RA1 as outputTRISAbits.TRISA2=0; // RA2 as outputTRISAbits.TRISA4=1; // RA4 (TOCK1) as inputTMR0 = 255; // Preload timer with 255, so it overflows on next input clockOPTION_REGbits.T0CS = 1; // Timer0 clock source = TOCK1 pin.OPTION_REGbits.T0SE = 0; // Clock edge = low-to-highOPTION_REGbits.PSA = 1; // Prescaler assigned to WDTINTCONbits.T0IF = 0; // Clear flagINTCONbits.T0IE = 1; // Enable Timer 0 interruptINTCONbits.GIE = 1; // Enable Global interruptswhile(1) {for(uint16_t i=0; i<10000L; i++); // Small delayPORTAbits.RA2 = !PORTAbits.RA2; // Toggle RA2 all the time}}

author: jpanhalt
author_rank: Super Contributor
timestamp: June 01, 2024, 02:04:30 pm
content: Quote from: yalect on June 01, 2024, 12:42:29 pmYou have another thread on that very subject. Repeating the questions here will cause confusion. TOIF is set by rollover of Timer0, not a change on the pin per se. It detects a count that causes a rollover of Timer0 from 255 to 0. Timer0 must be configured as a counter for this workaround to cause an interrupt or for the flag to be set. It's in the datasheet.EDIT: See duplicate post here:https://www.eevblog.com/forum/programming/instruction-programming-in-c-language/msg5526073/#msg5526073

author: yalect
author_rank: Regular Contributor
timestamp: July 05, 2024, 11:24:08 am
content: Thank you for your replies.For DavidAlfa you talked about MPLAB XC8 compiler but I can't find the file of executer after I install or Please, can led me to its name exactlly or its directory maybe it's different?.Thanks

author: DavidAlfa
author_rank: Super Contributor
timestamp: July 06, 2024, 03:06:34 pm
content: Mplab X IDE:https://www.microchip.com/en-us/tools-resources/develop/mplab-x-ideXC8 compiler:https://www.microchip.com/en-us/tools-resources/develop/mplab-xc-compilersYou install the IDE, then the compiler.Then open the IDE and create a new project, selecting your MCU and the compiler.

author: @rt
author_rank: Super Contributor
timestamp: July 07, 2024, 12:22:22 pm
content: 16F84?I'm surprised you can buy one.16F628A is better in every way, has more memory, extra peripherals, analogue pins.. probably an internal R/C clock, etc.I hope the 16F84 was cheap or free.You can set cmcon register to 7 to set analogue pins as digital, and use 16F84 code with 16F628 immediately.