Interrupts on pic18f452 not shooting in mplab X, help? C language

In summary, the problem is that the code will not stop at 4 seconds even though the timer has been set to that time. The code will continue running even after the button has been released.
  • #1
Maniac_XOX
86
5
Homework Statement
Im trying to make an interrupt in my program happen at 4 seconds
Relevant Equations
(as below)
I am using MPLAB X, everything is working great when I work on examples that require smaller or no preload at all, I do not understand why that is the case, is there a limit to the TMR0L?

Hello please help asap,

my specific case I have:

4MHz crystal -----> 1 / (4MHz / 4) = 1MHz timer

I Need to make interrupts happen after 4 seconds

1MHz * 4s = 4,000,000 counts

Therefore i decided to use a 16-bit with a 1:64 Prescaler setting.
4,000,000 / 64 = 62,500 counts

The difference would therefore be: 65,536 - 62,500 = 3,036 as preload

the problem arises when I use a breakpoint and stopwatch in MPLAB X IDE to know if the program stops at that specific time ( 4 seconds ) when I initialise the timer function, but the interrupt just never happens.

Any help? it does not work in PROTEUS either, i have tried before understanding the reason being the preloading, after testing it out with different examples.

APPENDIX (code is in c language):
Edit by mentor -- added code tags.
C:
#include "LED.h"
#include "Timer.h"
#include "Button.h"

#define _XTAL_FREQ 4MHZ

void InitialiseTimer(void)         // 4 seconds TIMER
{
    T0CONbits.TMR0ON = 1;    //timer enabled
    T0CONbits.T08BIT = 0;       // 16-bit set
    T0CONbits.T0CS = 0;         // internal clock
    T0CONbits.T0SE = 1;         // high to low transition
    T0CONbits.PSA = 0;         // 1:64 prescale enabled (101)
    T0CONbits.T0PS2 = 1;
    T0CONbits.T0PS1 = 0;
    T0CONbits.T0PS0 = 1;
}

void main(void)
{
    InitialiseLED();                         // this is from another header file
    InitialiseTimer();
   
    while(1)                                 // loop to check every run stops at the same time ( 4 seconds)
    {
        if(TimerOverflow())
        {
            LEDToggle(LED1);
        }   
    }   
}
 
Last edited by a moderator:
Physics news on Phys.org
  • #2
You have this preprocessor directive --
#define _XTAL_FREQ 4MHZ

1. I don't see that you have used this anywhere in your code.
2. Even worse, I don't see how it could possibly be used. Assuming that _XTAL_FREQ appears somewhere in your code, all that will happen is that this string of characters will be replaced by the string "4MHZ". This isn't a valid numeric value that the code can use.
 
  • #3
Mark44 said:
You have this preprocessor directive --
#define _XTAL_FREQ 4MHZ

1. I don't see that you have used this anywhere in your code.
2. Even worse, I don't see how it could possibly be used. Assuming that _XTAL_FREQ appears somewhere in your code, all that will happen is that this string of characters will be replaced by the string "4MHZ". This isn't a valid numeric value that the code can use.
lol sorry that was a typo in the code i actually write it as 4000000 so it would be 4MHz, but the problem persists
 
  • #4
Multipe thread starts merged into original thread
PLease help, I am fairly new to proteus and mplabx so I am trying to udnerstand how it all works. I am using PIC18F452 microcontroller.

I have this circuit in proteus shown at the bottom of the text.

The code:
Code:
#define _XTAL_FREQ  4000000
//Set the config bits
#pragma config WDT = OFF, BOR = OFF, LVP = OFF, OSC = XT

// setting up BUTTONS
void InitialiseButtons(void);
unsigned char ReadButton(void);

#define UP           0
#define DOWN         1

#define BUTTON_S2          0x01
#define BUTTON_S3          0x10
#define BUTTON_S2_S3     0x00

void InitialiseButtons(void)
{
    TRISA |= 0x10;

    TRISB |= 0x01;
}//Detects a change of state of buttons
// Buttons are active low
unsigned char ReadButton(void)
{
    char ButtonState;
    static char ButtonFlag = 0x11;
 
    //Read State of both buttons
    ButtonState = (PORTA & 0x10) | (PORTB & 0x01);
 
    if(ButtonFlag != ButtonState)    //there has been a change
    {
        ButtonFlag = ButtonState;
        return ButtonFlag;
    }
 
    return 0x11;
}

// setting up LEDs
#define LED0    0x01
#define LED1    0x02
#define LED2    0x04
#define LED3    0x08

void InitialiseLED(void);   //prototype functions
void LEDOn(unsigned char TheLED);
void LEDOff(unsigned char TheLED);
void LEDToggle(unsigned char TheLED);
void LEDWrite(unsigned char LEDValue);

void InitialiseLED(void)
{
    TRISB = 0xF0;    //Set the port direction register
    LATB = 0x00;    //Clear the port
}
 
void LEDOn(unsigned char TheLED)
{
    LATB |= TheLED; //Set the required bit on PORTB
}

void LEDOff(unsigned char TheLED)
{
    LATB &= (~TheLED); //Clear the required bit on PORTB
}

void LEDToggle(unsigned char TheLED)
{
    LATB ^= TheLED;   //XOR the required bit on PORTB
}

void LEDWrite(unsigned char LEDValue)
{
    LATB = LEDValue;  //Store a value on PORTB
}

// setting up TIMER

void ResetSeconds(void)
{
    seconds = 0;
}

unsigned char TimerOverflow(void)
{
    char flag = 0;
 
    if(INTCONbits.TMR0IF)
    {
        INTCONbits.TMR0IF = 0;
        //flag = 1;
        seconds++;
    }
 
    //return flag;
    return seconds;

// setting up STATEMACHINE with TIMER
enum
{
    S_OFF
    S_STATE1
    S_STATE2
}States;

enum
{
    E_T1,
    E_T2,
    E_BUTTON
}Events;

#define T3s 3
#define T5s 5

unsigned char GetEvent(void);
unsigned char State = S_OFF;

void DoStateMachine(void)
{
    unsigned char Event;
    Event = GetEvent();

    switch(State)
    {
        case S_OFF:
            LEDOff(LED3);
            LEDOff(LED2);
            if(Event == E_BUTTON)
            {
                ResetSeconds();
                State = S_STATE1;
            }
            break;

        case S_STATE1:
            LEDOn(LED3);
            LEDOff(LED2);
            if(Event == E_T1)
            {
                ResetSeconds();
                State = S_STATE2;
            }

            if(Event == E_BUTTON)
                State = S_OFF;
            break;

        case S_STATE2:
            LEDOff(LED3);
            LEDOn(LED2);
            if(Event == E_T2)
            {
                ResetSeconds();
                State = S_STATE1;
            }

            if(Event == E_BUTTON)
                State = S_OFF;

            break;
    }
}unsigned char GetEvent(void)
{
    if(TimerOverflow() == T3s)
        return E_T1;

    if(TimerOverflow() == T5s)
        return E_T2;

    if(ReadButton() == BUTTON_S2)
        return E_BUTTON;void main(void)
{
    InitialiseLED();
    InitialiseButtons();
    InitialiseTimer();
    Lcd_Init();
 
    while(1)
    {
        DoStateMachine();
    }
}

When Switch RA4 is pressed, the system flashes the 2nd and 3rd LEDs intermittently.

RA4 is the activate/deactivate switch as i understand, but since I changed it to RD4, as well as the settings that involve PORT/TRIS/LAT A to PORT/TRIS/LAT D, the LEDs keep flashing and the switch stops working. How do I fix that?

It's also requested that my RESET switch is connected to RC4, not sure how that works either as I am aware the MCLR pin is the one that resets the MCU? How can the RC4 pin reset the system?

Final issue, the first LED should only be on when the system is on, but if the power terminal isn't pesent they won't turn on at all..

Appreciate your help a real lot!

1651419602366.png
 
  • #5
I don't think I'll be able to give much help. My expertise is more with full-size processors rather than PIC-type devices. The best I can do is to point out things that you wrote that aren't clear to me.
Maniac_XOX said:
my specific case I have:

4MHz crystal -----> 1 / (4MHz / 4) = 1MHz timer

I Need to make interrupts happen after 4 seconds
I don't know what you're doing in your line above with 4MHz crystal and 1MHz timer.
1 / (4MHz / 4) = 1/1MHz = (1/1,000,000) sec./cycle or 1 microsec/cycle.
What's the meaning of the 4 divisor in 4MHz/4?

Maniac_XOX said:
1MHz * 4s = 4,000,000 counts

Therefore i decided to use a 16-bit with a 1:64 Prescaler setting.
4,000,000 / 64 = 62,500 counts

The difference would therefore be: 65,536 - 62,500 = 3,036 as preload
I don't understand how this preload gets set in your code for InitialiseTimer()...
 
  • #6
Mark44 said:
I don't know what you're doing in your line above with 4MHz crystal and 1MHz timer.
1 / (4MHz / 4) = 1/1MHz = (1/1,000,000) sec./cycle or 1 microsec/cycle.
What's the meaning of the 4 divisor in 4MHz/4?
4MHz is the the frequency of the oscillator (Fosc), to find the the frequency of the internal instructions (set in the timer0 control register, TMR0CON) you divide Fosc by 4. So the time for one instuction takes 1/frequency = 1/(4/4)

Mark44 said:
I don't understand how this preload gets set in your code for InitialiseTimer()...
So far i have used TMR0L = any integer to preload the timer and it worked, not sure why it does not work with bigger numbers though, it confuses me
 
Last edited:
  • #7
I would look at the code for TimerOverflow(). If the 16 bit variable is a short (AKA short int), it's almost certainly signed, so its largest positive value is 32, 767, so it will never get up to 65,535 to overflow. You said that things were working correctly for smaller numbers, so maybe this is what you're running into. Not seeing the code makes it much more difficult to give helpful advice for a fix, but I would suggest changing things up so that you're dealing with numbers that are in the range of signed 16 bits.
 
  • #8
Maniac_XOX said:
Appreciate your help a real lot!
Microcontroller code is NOT an essay that seems to work. You must get inside the machine and make sure that absolutely everything must always work.

Bigger numbers that cause instability are almost always due to container size and range. If you do a binary search for the maximum size before onset of failure, you will have a clue to the size of the register that is too small for the task assigned. A real time clock in software, that fails after 18 hours, 12 minutes and 15 seconds, is a dead give away.

I wrote a real time operating system from scratch in assembly for the PIC16F84. You have an advantage and a disadvantage here, because you are separated from the critical details of the internal machine by the C language. Code productivity will be greater, but things can fall through the hidden cracks between assembly and C.
You will need to write separate minimum size test sequences for the modules, to verify and debug, before rolling it all together.
 
  • #9
Baluncore said:
Microcontroller code is NOT an essay that seems to work. You must get inside the machine and make sure that absolutely everything must always work.

Bigger numbers that cause instability are almost always due to container size and range. If you do a binary search for the maximum size before onset of failure, you will have a clue to the size of the register that is too small for the task assigned. A real time clock in software, that fails after 18 hours, 12 minutes and 15 seconds, is a dead give away.

I wrote a real time operating system from scratch in assembly for the PIC16F84. You have an advantage and a disadvantage here, because you are separated from the critical details of the internal machine by the C language. Code productivity will be greater, but things can fall through the hidden cracks between assembly and C.
You will need to write separate minimum size test sequences for the modules, to verify and debug, before rolling it all together.
I have actually managed to get the seconds right with the right calculations and settings finally!

Would you mind taking a look at the merged thread that is on reply #4? I have a couple questions on there regarding my proteus design and things i need to change in it, here it is below:

Code:
#define _XTAL_FREQ  4000000
//Set the config bits
#pragma config WDT = OFF, BOR = OFF, LVP = OFF, OSC = XT

// setting up BUTTONS
void InitialiseButtons(void);
unsigned char ReadButton(void);

#define UP           0
#define DOWN         1

#define BUTTON_S2          0x01
#define BUTTON_S3          0x10
#define BUTTON_S2_S3     0x00

void InitialiseButtons(void)
{
    TRISA |= 0x10;

    TRISB |= 0x01;
}//Detects a change of state of buttons
// Buttons are active low
unsigned char ReadButton(void)
{
    char ButtonState;
    static char ButtonFlag = 0x11;
 
    //Read State of both buttons
    ButtonState = (PORTA & 0x10) | (PORTB & 0x01);
 
    if(ButtonFlag != ButtonState)    //there has been a change
    {
        ButtonFlag = ButtonState;
        return ButtonFlag;
    }
 
    return 0x11;
}

// setting up LEDs
#define LED0    0x01
#define LED1    0x02
#define LED2    0x04
#define LED3    0x08

void InitialiseLED(void);   //prototype functions
void LEDOn(unsigned char TheLED);
void LEDOff(unsigned char TheLED);
void LEDToggle(unsigned char TheLED);
void LEDWrite(unsigned char LEDValue);

void InitialiseLED(void)
{
    TRISB = 0xF0;    //Set the port direction register
    LATB = 0x00;    //Clear the port
}
 
void LEDOn(unsigned char TheLED)
{
    LATB |= TheLED; //Set the required bit on PORTB
}

void LEDOff(unsigned char TheLED)
{
    LATB &= (~TheLED); //Clear the required bit on PORTB
}

void LEDToggle(unsigned char TheLED)
{
    LATB ^= TheLED;   //XOR the required bit on PORTB
}

void LEDWrite(unsigned char LEDValue)
{
    LATB = LEDValue;  //Store a value on PORTB
}

// setting up TIMER

void ResetSeconds(void)
{
    seconds = 0;
}

unsigned char TimerOverflow(void)
{
    char flag = 0;
 
    if(INTCONbits.TMR0IF)
    {
        INTCONbits.TMR0IF = 0;
        //flag = 1;
        seconds++;
    }
 
    //return flag;
    return seconds;

// setting up STATEMACHINE with TIMER
enum
{
    S_OFF
    S_STATE1
    S_STATE2
}States;

enum
{
    E_T1,
    E_T2,
    E_BUTTON
}Events;

#define T3s 3
#define T5s 5

unsigned char GetEvent(void);
unsigned char State = S_OFF;

void DoStateMachine(void)
{
    unsigned char Event;
    Event = GetEvent();

    switch(State)
    {
        case S_OFF:
            LEDOff(LED3);
            LEDOff(LED2);
            if(Event == E_BUTTON)
            {
                ResetSeconds();
                State = S_STATE1;
            }
            break;

        case S_STATE1:
            LEDOn(LED3);
            LEDOff(LED2);
            if(Event == E_T1)
            {
                ResetSeconds();
                State = S_STATE2;
            }

            if(Event == E_BUTTON)
                State = S_OFF;
            break;

        case S_STATE2:
            LEDOff(LED3);
            LEDOn(LED2);
            if(Event == E_T2)
            {
                ResetSeconds();
                State = S_STATE1;
            }

            if(Event == E_BUTTON)
                State = S_OFF;

            break;
    }
}unsigned char GetEvent(void)
{
    if(TimerOverflow() == T3s)
        return E_T1;

    if(TimerOverflow() == T5s)
        return E_T2;

    if(ReadButton() == BUTTON_S2)
        return E_BUTTON;void main(void)
{
    InitialiseLED();
    InitialiseButtons();
    InitialiseTimer();
    Lcd_Init();
 
    while(1)
    {
        DoStateMachine();
    }
}

When Switch RA4 is pressed, the system flashes the 2nd and 3rd LEDs intermittently.

RA4 is the activate/deactivate switch as i understand, but since I changed it to RD4, as well as the settings that involve PORT/TRIS/LAT A to PORT/TRIS/LAT D, the LEDs keep flashing and the switch stops working. How do I fix that?

It's also requested that my RESET switch is connected to RC4, not sure how that works either as I am aware the MCLR pin is the one that resets the MCU? How can the RC4 pin reset the system?

Final issue, the first LED should only be on when the system is on, but if the power terminal isn't pesent they won't turn on at all..

Appreciate your help a real lot!

View attachment 300883
 

1. Why are my interrupts not functioning on my PIC18F452 microcontroller when using MPLAB X?

There could be several reasons why your interrupts are not working. Some common causes include incorrect interrupt configuration, incorrect code syntax, or hardware issues. Double check your interrupt configuration settings and make sure your code is properly written and compiled. If the issue persists, check your hardware connections and make sure they are correct and functioning properly.

2. How do I enable interrupts on my PIC18F452 microcontroller in MPLAB X?

To enable interrupts on your PIC18F452, you need to set the GIE (Global Interrupt Enable) bit in the INTCON register and also set the specific interrupt enable bit for the desired interrupt source. This can be done using the appropriate C language syntax for your specific microcontroller. Refer to your microcontroller's datasheet for more detailed instructions.

3. Can I use multiple interrupts on my PIC18F452 microcontroller in MPLAB X?

Yes, the PIC18F452 microcontroller supports multiple interrupts. However, it is important to properly prioritize the interrupts to ensure that the most important ones are handled first. This can be done by setting the appropriate priority bits in the INTCON register. Refer to your microcontroller's datasheet for more information on interrupt prioritization.

4. How do I handle interrupts in my C code for the PIC18F452 microcontroller in MPLAB X?

To handle interrupts in your C code, you need to define an interrupt service routine (ISR) for each interrupt source. This ISR should contain the necessary code to handle the interrupt and clear the interrupt flag. Additionally, you may need to disable other interrupts during the execution of the ISR to prevent conflicts. Refer to your microcontroller's datasheet for more information on how to properly handle interrupts in your C code.

5. My interrupts were working before, but now they have stopped. What could be the problem?

If your interrupts were previously functioning but have suddenly stopped, it is likely due to a change in your code or hardware. Double check any recent changes you have made to your code and make sure they have not affected the interrupt functionality. Also, check your hardware connections and make sure they are still intact and functioning properly. If the issue persists, try debugging your code to identify any potential errors.

Back
Top