Problem with PIC18F Timer0 (Counter Mode) in Interrupt.

Thread Starter

Noah96

Joined Apr 3, 2023
5
The code I shared is intended to control a two-story elevator using a microcontroller. It utilizes the microcontroller's Timer0 to perform the counting of rising edges.

  1. Update State Function:

The function mettreAJourEtat() is defined to update the elevator's state based on the current conditions. It uses switch statements to perform specific actions depending on the current state and inputs.

  1. Main Function:

The main() function is the program's main function. It initializes the necessary variables and ports, then enters an infinite loop where it updates the elevator's state by calling the mettreAJourEtat() function. It also handles the logic for Timer0 counting.

  1. Timer0 Interrupt Function:

The Timer0_ISR() function is an interrupt function for Timer0. It is called when the Timer0 interrupt flag is triggered. In this function, the frontCount counter is incremented on each rising edge detected, and then the interrupt flag is cleared.

This code utilizes the inputs from RG0 and RG1 ports to detect the states of the elevator buttons or sensors. Based on the current state and inputs, the outputs of RF0 to RF3 ports are controlled to activate relays or other elevator devices.


am experiencing an issue with the Timer0 counter not incrementing. I suspect there might be a problem with either my interrupt or configuration. Can you help me identify the issue?

I have bundled the main.c file, the .hex file, and the Proteus simulation into a RAR archive.




1684887699426.png

C:
/*
* File:   newmain.c
* Author: nader Noomen
* Project For my Master degree
* Created on 25 avril 2023, 17:54
*/
// CONFIG1H
#pragma config OSC = XT       // Oscillator Selection bits (RC oscillator w/ OSC2 configured as RA6)
#pragma config OSCS = OFF       // Oscillator System Clock Switch Enable bit (Oscillator system clock switch option is disabled (main oscillator is source))

// CONFIG2L
#pragma config PWRT = OFF       // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOR = OFF         // Brown-out Reset Enable bit (Brown-out Reset enabled)
#pragma config BORV = 25        // Brown-out Reset Voltage bits (VBOR set to 2.5V)

// CONFIG2H
#pragma config WDT = OFF        // Watchdog Timer Enable bit (WDT enabled)
#pragma config WDTPS = 128      // Watchdog Timer Postscale Select bits (1:128)

// CONFIG3L
#pragma config MODE = MC        // Processor Mode Select bits (Microcontroller mode)
#pragma config WAIT = OFF       // External Bus Data Wait Enable bit (Wait selections unavailable for table reads and table writes)

// CONFIG3H
#pragma config CCP2MUX = ON     // CCP2 Mux bit (CCP2 input/output is multiplexed with RC1)

// CONFIG4L
#pragma config STVR = OFF       // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF       // Low-Voltage ICSP Enable bit (Low-voltage ICSP enabled)

// CONFIG5L
#pragma config CP0 = OFF        // Code Protection bit (Block 0 (000200-003FFFh) not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 (004000-007FFFh) not code-protected)
#pragma config CP2 = OFF        // Code Protection bit (Block 2 (008000-00BFFFh) not code-protected)
#pragma config CP3 = OFF        // Code Protection bit (Block 3 (00C000-00FFFFh) not code-protected)
#pragma config CP4 = OFF        // Code Protection bit (Block 4 (010000-013FFFh) not code-protected)
#pragma config CP5 = OFF        // Code Protection bit (Block 5 (014000-017FFFh) not code-protected)
#pragma config CP6 = OFF        // Code Protection bit (Block 6 (018000-01BFFFh) not code-protected)
#pragma config CP7 = OFF        // Code Protection bit (Block 7 (01C000-01FFFFh) not code-protected)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot Block (000000-0001FFh) not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 (000200-003FFFh) not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 (004000-007FFFh) not write-protected)
#pragma config WRT2 = OFF       // Write Protection bit (Block 2 (008000-00BFFFh) not write-protected)
#pragma config WRT3 = OFF       // Write Protection bit (Block 3 (00C000-00FFFFh) not write-protected)
#pragma config WRT4 = OFF       // Write Protection bit (Block 4 (010000-013FFFh) not write-protected)
#pragma config WRT5 = OFF       // Write Protection bit (Block 5 (014000-017FFFh) not write-protected)
#pragma config WRT6 = OFF       // Write Protection bit (Block 6 (018000-01BFFFh) not write-protected)
#pragma config WRT7 = OFF       // Write Protection bit (Block 7 (01C000-01FFFFh) not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot Block (000000-0001FFh) not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 (000200-003FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 (004000-007FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF      // Table Read Protection bit (Block 2 (008000-00BFFFh) not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF      // Table Read Protection bit (Block 3 (00C000-00FFFFh) not protected from table reads executed in other blocks)
#pragma config EBTR4 = OFF      // Table Read Protection bit (Block 4 (010000-013FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR5 = OFF      // Table Read Protection bit (Block 5 (014000-017FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR6 = OFF      // Table Read Protection bit (Block 6 (018000-01BFFFh) not protected from table reads executed in other blocks)
#pragma config EBTR7 = OFF      // Table Read Protection bit (Block 7 (01C000-01FFFFh) not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot Block (000000-0001FFh) not protected from table reads executed in other blocks)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
// Flash Program Memory Code Protection bit (All program memory code-protected)

#include <xc.h>


#define TRUE  0x01
#define FALSE 0x00


void Config_Param_Timer() // Configure le module Timer pour fonctionner en mode compteur
{
    INTCONbits.TMR0IF = 0; // Efface le drapeau de dépassement du Timer0
    INTCONbits.TMR0IE = 1;
   
    T0CONbits.T08BIT = 1;
    T0CONbits.T0CS = 1;
    T0CONbits.PSA = 0;
    T0CONbits.T0SE =1;
    INTCON2bits.TMR0IP = 1;
   T0CONbits.T0PS2 = 1;
   T0CONbits.T0PS1 = 1;
   T0CONbits.T0PS0 = 1;
   
    T0CONbits.TMR0ON = 1;
   
    INTCONbits.GIE = 1; // Active les interruptions globales
}

int position_actuel;
int frontCount;
unsigned int etatActuel;


typedef enum {
    Etage_0_vers_Etage_0,
    Etage_0_vers_Etage_1,
    Etage_1_vers_Etage_0,
    Etage_1_vers_Etage_1,
} EtatAscenseur;



EtatAscenseur mettreAJourEtat(EtatAscenseur etatCourant) {
    switch (etatCourant) {
        case Etage_0_vers_Etage_0:
            if (PORTGbits.RG0 == 1 && frontCount <= 0 && position_actuel == 0) {
                PORTFbits.RF0 = 1;
                PORTFbits.RF1 = 1;
                PORTFbits.RF2 = 1;
                PORTFbits.RF3 = 1;
                position_actuel = 0;
                frontCount = 0;
            }
            break;

        case Etage_0_vers_Etage_1:
            if (PORTGbits.RG1 == 1 && frontCount <= 1 && position_actuel == 0) {
                PORTFbits.RF0 = 1;
                PORTFbits.RF1 = 0;
                PORTFbits.RF2 = 0;
                PORTFbits.RF3 = 0;

                if (frontCount == 2) {
                    PORTFbits.RF0 = 1;
                    PORTFbits.RF1 = 1;
                    PORTFbits.RF2 = 0;
                    PORTFbits.RF3 = 0;

                    if (frontCount == 3) {
                        PORTFbits.RF0 = 1;
                        PORTFbits.RF1 = 1;
                        PORTFbits.RF2 = 1;
                        PORTFbits.RF3 = 0;

                        if (frontCount == 4) {
                            PORTFbits.RF0 = 1;
                            PORTFbits.RF1 = 1;
                            PORTFbits.RF2 = 1;
                            PORTFbits.RF3 = 1;

                            position_actuel = 1;
                            frontCount = 0;
                        }
                    }
                }
            }
            break;

        case Etage_1_vers_Etage_0:
            if (PORTGbits.RG1 == 1 && frontCount <= 1 && position_actuel == 1) {
                PORTFbits.RF0 = 1;
                PORTFbits.RF1 = 0;
                PORTFbits.RF2 = 0;
                PORTFbits.RF3 = 0;

                if (frontCount == 2) {
                    PORTFbits.RF0 = 1;
                    PORTFbits.RF1 = 1;
                    PORTFbits.RF2 = 0;
                    PORTFbits.RF3 = 0;

                    if (frontCount == 3) {
                        PORTFbits.RF0 = 1;
                        PORTFbits.RF1 = 1;
                        PORTFbits.RF2 = 1;
                        PORTFbits.RF3 = 0;

                        if (frontCount == 4) {
                            PORTFbits.RF0 = 1;
                            PORTFbits.RF1 = 1;
                            PORTFbits.RF2 = 1;
                            PORTFbits.RF3 = 1;
                            position_actuel = 0;
                            frontCount = 0;
                        }
                    }
                }
            }
            break;

        case Etage_1_vers_Etage_1:
            if (PORTGbits.RG1 == 1 && frontCount <= 1 && position_actuel == 1) {
                PORTFbits.RF0 = 1;
                PORTFbits.RF1 = 1;
                PORTFbits.RF2 = 1;
                PORTFbits.RF3 = 1;
                position_actuel = 1;
            }
            break;
    }
   
    return etatCourant; // Retourne l'état courant si aucune transition ne se produit
}

void main(void) {
   

EtatAscenseur etatCourant;


    Config_Param_Timer();
    TRISF = 0;
    PORTFbits.RF0 = 0;
    PORTFbits.RF1 = 0;
    PORTFbits.RF2 = 0;
    PORTFbits.RF3 = 0;

    TRISG = 0b00000011; // Configure RG0 et RG1 en tant qu'entrées
    PORTGbits.RG0 = 0;
    PORTGbits.RG1 = 0;

     frontCount= TMR0;
     
    TMR0 = 0;
   
    position_actuel = 0;

    while (1) {
        etatActuel = mettreAJourEtat(etatCourant);
        // Ajoutez ici la logique pour effectuer le comptage du timer
    }
}

// Déclaration de la fonction d'interruption pour le Timer0
void __interrupt() Timer0_ISR(void)
{
    if (INTCONbits.TMR0IF) // Vérifie le drapeau d'interruption du Timer0
    {
        frontCount++; // Incrémente le compteur à chaque front montant
        INTCONbits.TMR0IF = 0; // Efface le drapeau d'interruption du Timer0
    }
}
Mod edit: Present attached C code using code tags - JohnInTX
 

Attachments

Last edited by a moderator:

bidrohini

Joined Jul 29, 2022
190
I could not figure out if anything is wrong with your code. But in your proteus file, I can see that the MCLR pin is directly connected to the ground. You're supposed to pull up the pin with a 10K resistor. I request you to check and double-check your code with the datasheet. Please check if you are setting all the registers associated with the timer and your desired configuration correctly. If needed, try with a smaller and simpler code to see if you are configuring the timer correctly.
 

MIS42N

Joined Jan 25, 2013
22
You have set up a prescaler (T0CONbits.PSA = 0; ) with a divisor of 256. (T0CONbits.T0PS2 = 1; T0CONbits.T0PS1 = 1; T0CONbits.T0PS0 = 1; ). Is that the problem?

You realise that the Timer0 interrupt occurs when the timer overflows (from 256 to 0)? So as set up it will increment frontcount every 65536 leading edges. Maybe what you need to do is set up a Port B pin as your input, with interrupt on change enabled and an ISR. That would allow frontcount to increment on every leading edge. But I don't know the details of what you are measuring so this may be wrong.

On examining the code further, I don't think it can work. There are nested IF statements if (frontCount == 2) etc. that cannot be executed because because they are inside an if block that has && frontCount <= 1.

Yes, start simple then build.
 
Last edited:

Thread Starter

Noah96

Joined Apr 3, 2023
5
thank you for your response. Let me explain the purpose of my code: I am trying to control an elevator (a motor) between each floor. There are 4 magnets, which means that in order for the elevator to move from one floor to another, the magnet sensor must receive 4 signals. Within each signal, there are specific commands. For example, in the 3rd signal, the speed should decrease.

What I want is for the timer (TMR0) to count the edges. I'm not sure if I need to use an interrupt input or if I should use TMR0 in counter mode.

I hope this explanation clarifies the purpose of my code.
 

Thread Starter

Noah96

Joined Apr 3, 2023
5
I could not figure out if anything is wrong with your code. But in your proteus file, I can see that the MCLR pin is directly connected to the ground. You're supposed to pull up the pin with a 10K resistor. I request you to check and double-check your code with the datasheet. Please check if you are setting all the registers associated with the timer and your desired configuration correctly. If needed, try with a smaller and simpler code to see if you are configuring the timer correctly.
You have set up a prescaler (T0CONbits.PSA = 0; ) with a divisor of 256. (T0CONbits.T0PS2 = 1; T0CONbits.T0PS1 = 1; T0CONbits.T0PS0 = 1; ). Is that the problem?

You realise that the Timer0 interrupt occurs when the timer overflows (from 256 to 0)? So as set up it will increment frontcount every 65536 leading edges. Maybe what you need to do is set up a Port B pin as your input, with interrupt on change enabled and an ISR. That would allow frontcount to increment on every leading edge. But I don't know the details of what you are measuring so this may be wrong.

On examining the code further, I don't think it can work. There are nested IF statements if (frontCount == 2) etc. that cannot be executed because because they are inside an if block that has && frontCount <= 1.

Yes, start simple then build.
Thank you for your response. Let me explain the purpose of my code: I am trying to control an elevator (a motor) between each floor. There are 4 magnets, which means that in order for the elevator to move from one floor to another, the magnet sensor must receive 4 signals. Within each signal, there are specific commands. For example, in the 3rd signal, the speed should decrease.
What I want is for the timer (TMR0) to count the edges. I'm not sure if I need to use an interrupt input or if I should use TMR0 in counter mode.
I hope this explanation clarifies the purpose of my code.
 

Ian Rogers

Joined Dec 12, 2012
1,136
Just be wary about your port writes.. I would use LATG and LATF as that may give you problems.
Or write all pins in a single port in one go.
 

MIS42N

Joined Jan 25, 2013
22
thank you for your response. Let me explain the purpose of my code: I am trying to control an elevator (a motor) between each floor. There are 4 magnets, which means that in order for the elevator to move from one floor to another, the magnet sensor must receive 4 signals. Within each signal, there are specific commands. For example, in the 3rd signal, the speed should decrease.

What I want is for the timer (TMR0) to count the edges. I'm not sure if I need to use an interrupt input or if I should use TMR0 in counter mode.

I hope this explanation clarifies the purpose of my code.
Like many problems, there are multiple solutions. The choice between interrupts, using TMR0 in count mode, or direct interrogation of the input is one of them.

In this case, once the program is initialised, it enters an infinite loop. There are no wait states in the loop so it is likely to be looping hundreds or thousands of times a second. In that case polling (repeated reading) of an input is usually the way to go. It is not necessary to use interrupts.

Now the decision is to monitor the input directly or allow the input to be counted by TMR0. Since what is being programmed is a state machine, monitoring directly would be satisfactory.

So now assume the loop is started when the input is low. This is a rough pseudo code idea that might work.

Code:
while(1)
  if input is 0 then count = 0 else count++ ; make sure the switch is closed, no false signal
     if count > 3 then ; we have three (or however many is reliable) successive closed signals
         case state
             state=1 [code], state = <next state>
             state=2 ... etc
        end case
        while input = 1 [] ; waiting for the input to go back to zero
    end if
end while
Note that it is just one way of doing it. If it were me designing this I'd worry about things like where the lift starts, what happens if a magnet is missed, does it cater for up and down. I may think of using (for example) up to 3 magnets at each point. That way by giving the magnets a pattern you could determine where the lift is, what direction (after passing two groups), and if a magnet is missing (by knowing the pattern to expect).

But this is an exercise and not designing for a real lift. So it is up to the designer.

And to answer the original question - don't use the prescaler. Set T0CONbits.PSA = 1;
Don't use interrupts. Just examine TMR0 directly.
 
Top