Interrupts using PIC18f46k20 microcontroller

Discussion in 'The Projects Forum' started by iamtobey, Apr 3, 2013.

  1. iamtobey

    Thread Starter New Member

    Apr 3, 2013
    3
    0
    I am new fairly new to C++ and i'm having problems Initializing the required resisters needed for my project on motor speed control. I have used the data sheet(link below) but cannot get around the problem.http://ww1.microchip.com/downloads/en/devicedoc/41303g.pdf

    The two problems I am encountering

    interrupts not occurring. Code for interrupts process is below

    when I enable global interrupts i.e. 'INCONbits.GIE =1' nothing displays on the pic (leds and screen) as if it where in sleep mode.

    Initialization.
    Code ( (Unknown Language)):
    1.  
    2.  void InitializeSystem(void)
    3. {
    4.  
    5. OSCCON = 0b01110000;
    6. OSCTUNEbits.PLLEN = 0;                  // turn off the PLL
    7.  
    8. // Setup I/O Ports.
    9.  
    10.     ANSEL = 0x00;                          // all digital   check if needed*
    11. TRISA = 0;              // TRISA outputs
    12. LATA = 0b11110000;        // drive PORTA pins low
    13.  
    14. oled_res = 1;               // do not reset LCD yet
    15. oled_cs = 1;                // do not select the LCD
    16.  
    17. TRISB = 0b11111111;
    18.  
    19.  
    20. LATC = 0b00101000;
    21. TRISC = 0b00000000;
    22.  
    23. TRISD = 0;              // TRISD is LED output
    24. LATD = 0;               // turn off LEDS
    25.  
    26. TRISE = 0b00000111;
    27.  
    28. // Set up global interrupts
    29.     RCONbits.IPEN = 1;          // Enable priority levels on interrupts
    30. INTCONbits.GIE = 1;    
    31. INTCONbits.RBIE = 1;
    32. INTCONbits.RBIF = 0;
    33.  
    34.  
    35. //configure buttons
    36. WPUB = 0b00001111;
    37. INTCON2bits.RBPU = 0;       // turn on weak pull ups for RB0-RB3
    38.  
    39. INTCONbits.INT0IF = 0;                  // clear RB0 INT
    40. INTCONbits.INT0IE = 1;                  // enable RB0 INT
    41. INTCON2bits.INTEDG0 = 0;        // interrupt on falling edge
    42.  
    43. INTCON3bits.INT1IF = 0;                 // clear RB1 INT
    44. INTCON3bits.INT1IE = 1;                 // enable RB1 INT  
    45. INTCON2bits.INTEDG1 = 0;            // interrupt on falling edge
    46.  
    47.  
    48. INTCON3bits.INT2IF = 0;                 // clear RB2 INT
    49. INTCON3bits.INT2IE = 1;                 // enable RB2 INT
    50. INTCON2bits.INTEDG2 = 0;            // interrupt on falling edge
    51.  
    52.  
    53.  
    54.  
    55. // Setup TMR1
    56. // Configure Timer 1
    57. T1CON   = 0b11111101;
    58. INTCONbits.TMR0IE=1;
    59. INTCONbits.TMR0IF=0;
    60. INTCON2bits.TMR0IP=0;
    61.  
    62. // Configure MSSP for SPI master mode
    63. SSPCON1 = 0b00110010;                   // clock idle high, Clk /64
    64.  
    65. SSPSTAT = 0b00000000;
    66.  
    67. PIR1bits.TMR1IF = 0;
    68. PIE1bits.TMR1IE = 1;
    69.  
    70.  
    71.  
    72. OSCCON = 0b01110000;
    73. OSCTUNEbits.PLLEN = 1;  // Puts the PIC at 64MHz
    74. CCP1CON = 0b00001100;
    75. PSTRCON = 0b00010001;
    76.  
    77.     // setup timer 2 for pwm
    78.     T2CON = 0b00000111;// Prescale = 1:16, timer on, postscale not used with CCP module
    79. PR2 = 255;     // Configure the Timer2 period
    80. TRISCbits.TRISC2  = 0;              // Make CCP1 pin as output
    81. CCP1CON = 0x0C;           // Configure CCP1 module in PWM mode
    82. T2CON = 0x01;    // Set Prescaler to be 4, hence PWM frequency is set to 4.88KHz.                
    83. T2CON |= 0x04;            // Enable the Timer2, hence enable the PWM.
    84. SetPWMDutyCycle(pwm);       // Intialize the PWM to 0.5 duty cycle
    85.  
    86.  
    87.  
    88.      } // end InitializeSystem
    89. void SetPWMDutyCycle(unsigned int DutyCycle)      // Give a value in between 0 and
    90.                                                       // 1024 for DutyCycle    
    91. {
    92. CCPR1L   = DutyCycle>>2;            // Put MSB 8 bits in CCPR1L
    93. CCP1CON &= 0xCF;                    // Make bit4 and 5 zero
    94. CCP1CON |= (0x30&(DutyCycle<<4));   // Assign Last 2 LSBs to CCP1CON
    95. }
    96.  
    Interrupt Service
    Code ( (Unknown Language)):
    1.  
    2. #pragma code InterruptVectorLow = 0x18
    3. void InterruptVectorLow (void)
    4. {
    5.   _asm  
    6.      goto InterruptServiceLow //jump to interrupt routine
    7.   _endasm
    8. }
    9.  
    10. //----------Interrupt Service Routine-------------------------------------
    11. #pragma interrupt InterruptServiceHigh
    12. void InterruptServiceHigh(void)
    13. {
    14.  
    15. if(INTCONbits.RBIF)
    16. {
    17.     INTCONbits.RBIF = 0;
    18.  
    19.     if(PORTBbits.RB6!=0)                                        
    20.         {
    21.             UpperCounter++; //increment UpperCounter if RB6 goes high                          
    22.             speed_counter++; // increment the counter used to calculate  
    23.                                               //speed                                              
    24.             LATDbits.LATD7=~LATDbits.LATD7;  // LED7 changes state each  
    25.                                                              //rising edge                      
    26.             Delay10TCYx(1);        
    27.         }
    28.  
    29.  
    30.  
    31.    else if(PORTBbits.RB7!=0)    
    32.              //count pulses from ch B                                      
    33.         {
    34.             LowerCounter++; //increment LowerCounter if RB7 goes high                                                                    
    35.             speed_counter++;                                    
    36.                     LATDbits.LATD0=~LATDbits.LATD0; //LED0 changes state each  
    37.                                                             //rising edge                  
    38.             Delay10TCYx(1);            
    39.         }
    40.  
    41.  
    42.  
    43.      else if(PORTBbits.RB5 != 0)
    44.                    //count pulses from ch Z                                                                  
    45.         {
    46.             LowerCounter=0;  //reset LowerCounter                          
    47.                     UpperCounter=0;   //reset UpperCounter                          
    48.             Delay10TCYx(1);            
    49.         }
    50. }
    51. }
    52.  
    53. #pragma interruptlow InterruptServiceLow// "interruptlow" pragma for low priority
    54. void InterruptServiceLow(void)
    55. {
    56.  
    57. if(INTCONbits.TMR0IF)
    58.        {
    59.     position2=speed_counter;                                            
    60.  
    61.     speed=((((position2-position1)/64)*60)/2.1);        
    62.         //calculate speed. TMR0 on 16bit prescalar1:8    
    63.     TMR0H = 0;    
    64.             //  clear timer - always write upper byte first                                        
    65.     TMR0L = 0;
    66.             INTCONbits.TMR0IF = 0;    
    67.              // clear (reset) flag                                  
    68.     LATDbits.LATD2=~LATDbits.LATD2;
    69.     position1=speed_counter;
    70.  }
    71. }
    72.  
     
  2. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    You are never setting up IOCB for your interrupt-on-change, though that shouldn't result in what you are setting, unless you aren't doing anything in main (). Posting the test of the code may help.

    You should never enable interrupts before you are ready to handle them, so your global interrupt enable is not set until the end of the initialize code.

    Additionally, you haven't enabled low priority interrupts and have not set up TMR0.
     
    iamtobey likes this.
  3. iamtobey

    Thread Starter New Member

    Apr 3, 2013
    3
    0
    thanks for your reply.

    full code with observations corrected below
    Code ( (Unknown Language)):
    1.  
    2.  
    3. // High priority interrupt vector
    4.  
    5. #pragma code InterruptVectorHigh = 0x08
    6. void InterruptVectorHigh (void)
    7. {
    8.   _asm
    9.     goto InterruptServiceHigh //jump to interrupt routine
    10.   _endasm
    11. }
    12.  
    13. //----------------------------------------------------------------------------
    14. //----------------------------------------------------------------------------
    15. // Low priority interrupt vector
    16.  
    17. #pragma code InterruptVectorLow = 0x18
    18. void InterruptVectorLow (void)
    19. {
    20.   _asm
    21.     goto InterruptServiceLow //jump to interrupt routine
    22.   _endasm
    23. }
    24.  
    25. //----------Interrupt Service Routine-------------------------------------
    26. #pragma interrupt InterruptServiceHigh
    27. void InterruptServiceHigh(void)
    28. {
    29.  
    30.     if(INTCONbits.RBIF)
    31.     {
    32.         INTCONbits.RBIF = 0;
    33.        
    34.         if(PORTBbits.RB6!=0)                                        //count pulses from ch A
    35.             {
    36.                 UpperCounter++;                                     //increment UpperCounter if RB6 goes high
    37.                 speed_counter++;                                            // increment the counter used to calculate speed
    38.                 LATDbits.LATD7=~LATDbits.LATD7;                     // LED7 changes state each rising edge
    39.                 Delay10TCYx(1);        
    40.             }
    41.  
    42.    
    43.  
    44.        else if(PORTBbits.RB7!=0)                                            //count pulses from ch B
    45.             {
    46.                 LowerCounter++;                                     //increment LowerCounter if RB7 goes high
    47.                 speed_counter++;                                   
    48.                 LATDbits.LATD0=~LATDbits.LATD0;                     //LED0 changes state each rising edge
    49.                 Delay10TCYx(1);            
    50.             }
    51.  
    52.                
    53.  
    54.          else if(PORTBbits.RB5 != 0)                                            //count pulses from ch Z
    55.             {
    56.                 LowerCounter=0;                             //reset LowerCounter
    57.                 UpperCounter=0;                             //reset UpperCounter
    58.                 Delay10TCYx(1);            
    59.             }
    60.     }
    61. }
    62.  
    63. #pragma interruptlow InterruptServiceLow// "interruptlow" pragma for low priority
    64. void InterruptServiceLow(void)
    65. {
    66.  
    67.     if(INTCONbits.TMR0IF)
    68.     {
    69.         position2=speed_counter;                                           
    70.  
    71.         speed=((((position2-position1)/64)*60)/2.1);                // calculate speed. TMR0 on 16bit prescalar1:8
    72.         // calculation shows  -> rpm = (FREQ_out*60)/N                //N= number of slots at disc
    73.         TMR0H = 0;                                                  // clear timer - always write upper byte first
    74.         TMR0L = 0;
    75.         INTCONbits.TMR0IF = 0;                                      // clear (reset) flag
    76.         LATDbits.LATD2=~LATDbits.LATD2;
    77.         position1=speed_counter;
    78.     }
    79. }
    80. /**** E N D   I N T E R R U P T   S E R V I C E ******************************************/
    81.  
    82.  
    83. void PressMe (unsigned char *ptrButtonPressed) // this function waits for a button press
    84. {
    85.     *ptrButtonPressed = 0;
    86.     Delay10KTCYx(90); //Debounce switch
    87.  
    88.     while(*ptrButtonPressed == 0)
    89.     {
    90.         if(PORTBbits.RB0 != 1)
    91.         {
    92.             *ptrButtonPressed = 1;
    93.         }
    94.         else if(PORTBbits.RB1 != 1)
    95.         {
    96.             *ptrButtonPressed = 2;
    97.         }
    98.         else if(PORTBbits.RB2 != 1)
    99.         {
    100.             *ptrButtonPressed = 3;
    101.         }
    102.         else if(PORTBbits.RB3 != 1)
    103.         {
    104.             *ptrButtonPressed = 4;
    105.         }
    106.         else
    107.         *ptrButtonPressed = 0;
    108.     }
    109. }
    110.  
    111.  
    112.  
    113.  
    114.  
    115.     void main(void){
    116.  
    117.     char Sbuffer[90];
    118.     unsigned char ButtonPressed = 0;                        /*This variable is  is used to tell the programme whether RB0, RB1, RB2 or RB3 has been pressed*/                      
    119.     unsigned char *ptrButtonPressed;                        //Pointers to pass to functions
    120.     ptrButtonPressed = &ButtonPressed;
    121.  
    122.     InitializeSystem();
    123.  
    124.     // These are the functions you need to use to initialise the display
    125.     oled_init();
    126.     oled_clear();
    127.     oled_refresh();
    128.     Delay10KTCYx(250); 
    129.     sprintf(Sbuffer,"\nHello Friend, \n\nWelcome to our MOTOR");    // Print to string buffer
    130.     oled_puts_2x(Sbuffer);                  // double height
    131.     oled_refresh();                         // And refresh the display so we can see things!
    132.     Delay10KTCYx(500);
    133.     Delay10KTCYx(500);
    134.     Delay10KTCYx(500);
    135.     Delay10KTCYx(500);
    136.     Delay10KTCYx(500);
    137.     Delay10KTCYx(500);
    138.     Delay10KTCYx(500);
    139.     Delay10KTCYx(500);
    140.  
    141.  
    142.         while (1)
    143.         {
    144.                
    145.         MainMenu(ptrButtonPressed);
    146.        
    147.         }      
    148.     }
    149.    
    150.  
    151.  
    152.  
    153.  
    154. void InitializeSystem(void)
    155. {
    156.  
    157.     OSCCON = 0b01110000;
    158.     OSCTUNEbits.PLLEN = 0;                  // turn off the PLL
    159.  
    160.     // Setup I/O Ports.
    161.    
    162.     ANSEL = 0x00;                          // all digital   check if needed*
    163.     TRISA = 0;                              // TRISA outputs
    164.     LATA = 0b11110000;                      // drive PORTA pins low
    165.  
    166.     oled_res = 1;                           // do not reset LCD yet
    167.     oled_cs = 1;                            // do not select the LCD
    168.  
    169.     TRISB = 0b11111111;
    170.  
    171.  
    172.     LATC = 0b00101000;
    173.     TRISC = 0b00000000;
    174.  
    175.     TRISD = 0;                              // TRISD is LED output
    176.     LATD = 0;                               // turn off LEDS
    177.  
    178.     TRISE = 0b00000111;
    179.  
    180.  
    181.  
    182.     //configure buttons
    183.     WPUB = 0b00001111;
    184.     INTCON2bits.RBPU = 0;                   // turn on weak pull ups for RB0-RB3
    185.  
    186.     INTCONbits.INT0IF = 0;                  // clear RB0 INT
    187.     INTCONbits.INT0IE = 1;                  // enable RB0 INT
    188.     INTCON2bits.INTEDG0 = 0;                // interrupt on falling edge
    189.  
    190.     INTCON3bits.INT1IF = 0;                 // clear RB1 INT
    191.     INTCON3bits.INT1IE = 1;                 // enable RB1 INT  
    192.     INTCON2bits.INTEDG1 = 0;                // interrupt on falling edge
    193.  
    194.  
    195.     INTCON3bits.INT2IF = 0;                 // clear RB2 INT
    196.     INTCON3bits.INT2IE = 1;                 // enable RB2 INT
    197.     INTCON2bits.INTEDG2 = 0;                // interrupt on falling edge
    198.          
    199.  
    200.    
    201.  
    202.     // Setup TMR0
    203.     T0CON = 0b00000010;          // 16- bit prescaller 1:8
    204.     INTCONbits.TMR0IE=1;
    205.     INTCONbits.TMR0IF=0;
    206.     INTCON2bits.TMR0IP=0;
    207.  
    208.     // Configure Timer 1
    209.     T1CON   = 0b11111101;
    210.  
    211.  
    212.  
    213.     // Configure MSSP for SPI master mode
    214.     SSPCON1 = 0b00110010;                   // clock idle high,   Clk /64
    215.  
    216.     SSPSTAT = 0b00000000;
    217.  
    218.     PIR1bits.TMR1IF = 0;
    219.     PIE1bits.TMR1IE = 1;
    220.  
    221.  
    222.  
    223.     OSCCON = 0b01110000;
    224.     OSCTUNEbits.PLLEN = 1;  // Puts the PIC at 64MHz
    225.     CCP1CON = 0b00001100;
    226.     PSTRCON = 0b00010001;
    227.  
    228.     // setup timer 2 for pwm
    229.     T2CON = 0b00000111;// Prescale = 1:16, timer on, postscale not used with CCP module
    230.     PR2 = 255;     // Configure the Timer2 period
    231.     TRISCbits.TRISC2  = 0;              // Make CCP1 pin as output
    232.     CCP1CON = 0x0C;           // Configure CCP1 module in PWM mode
    233.     T2CON = 0x01;             // Set Prescaler to be 4, hence PWM frequency is set to 4.88KHz.
    234.     T2CON |= 0x04;            // Enable the Timer2, hence enable the PWM.
    235.     SetPWMDutyCycle(pwm);       // Intialize the PWM to 0.5 duty cycle
    236.  
    237.     // Set up global interrupts
    238.     IOCB = 1;  
    239.     RCONbits.IPEN = 1;                      // Enable priority levels on interrupts
    240.     INTCONbits.RBIE = 1;
    241.     INTCONbits.RBIF = 0;
    242.     INTCONbits.GIE = 1;
    243.     INTCONbits.PEIE = 1;
    244.    
    245.    T0CONbits.TMR0ON = 1;   // START TIMER0
    246.  
    247.  
    248.     } // end InitializeSystem
    249.     void SetPWMDutyCycle(unsigned int DutyCycle)      // Give a value in between 0 and 1024 for DutyCycle
    250.     {
    251.     CCPR1L   = DutyCycle>>2;            // Put MSB 8 bits in CCPR1L
    252.     CCP1CON &= 0xCF;                    // Make bit4 and 5 zero
    253.     CCP1CON |= (0x30&(DutyCycle<<4));   // Assign Last 2 LSBs to CCP1CON
    254.     }
    255.  
     
    Last edited: Apr 3, 2013
  4. nsaspook

    AAC Fanatic!

    Aug 27, 2009
    2,907
    2,166
    Just make sure you understand that the meaning of .GIE and .PEIE change when priority levels are enabled. Another thing to think about when using both low and high ISRs is the interaction of non-ATOMIC (multi-instruction) operations on variables. For example: The value of speed_counter (if it's more than 8 bits) is assigned to another variable in the LOW ISR but speed_counter is changed in the HIGH ISR. There is a small window during the assignment of speed_counter if it's not ATOMIC to the HIGH ISR that the value might change in the middle of the code because the HIGH ISR changed the value mid-step. To be sure the operations are handled correctly you should use a memory barrier to protect those operations that might be affected by asynchronous timing. Using 'volatile' to be sure we don't cache the value, adding the 'near' modifier (Access RAM no banking) and/or just disabling HIGH interrupts during operations of a shared variable within the LOW ISR or main.
     
  5. iamtobey

    Thread Starter New Member

    Apr 3, 2013
    3
    0
    Ahh. I didn't even think off that. That is a problem that i will try to deal with when i get there. For now, the interrupts don't seem to be occurring so the Speed_counter aint counting nothing. Thank you for your observations though, I will have a look and try tomake appropriate corrections.
     
  6. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    I oft use "bigger than byte" quantities inside C18 C code where the value is changed inside an ISR. I insure I copy it correctly by this code snippet:

    Code ( (Unknown Language)):
    1.    while (A != B) A = B;
    I made a small macro to write this code for me but don't have it handy at the moment on this iPad. I will post again later if I remember.

    Here's the macro. I only use 1 variable inside the ISR so it's a bit non-general, but you can fix that easily:

    Code ( (Unknown Language)):
    1.   // "thread safe" macro to read current Ticks
    2.   #define GetTicks(Dest) while(Dest != Ticks) Dest = Ticks
    3.   #define ResetTicks()   while(Ticks != 0) Ticks = 0
    4.  
     
    Last edited: Apr 4, 2013
  7. nsaspook

    AAC Fanatic!

    Aug 27, 2009
    2,907
    2,166
    Maybe "thread safer" :) but with C18 without mutual-exclusion during the multi-instruction sequence compare there are still some cases where a ISR could cause problems. (mainly during byte rollover) If the increase in interrupt latency is not a problem disabling interrupts is usually more robust and quicker.

    C18 -Opa- optimized generated code using long A,B;.

    while (A != B) A = B;

    INTCONbits.GIE = 0;
    A = B;
    INTCONbits.GIE = 1;

    Code ( (Unknown Language)):
    1. 5:             void main(void)
    2. 6:             {
    3. 7:                 while (A != B) A = B;
    4. 00A6  0E0A     MOVLW 0xA
    5. 00A8  6EE9     MOVWF FSR0L, ACCESS
    6. 00AA  0E0F     MOVLW 0xF
    7. 00AC  6EEA     MOVWF FSR0H, ACCESS
    8. 00AE  50EE     MOVF POSTINC0, W, ACCESS
    9. 00B0  010F     MOVLB 0xF
    10. 00B2  190E     XORWF 0xE, W, BANKED
    11. 00B4  E10C     BNZ 0xCE
    12. 00B6  50EE     MOVF POSTINC0, W, ACCESS
    13. 00B8  010F     MOVLB 0xF
    14. 00BA  190F     XORWF 0xF, W, BANKED
    15. 00BC  E108     BNZ 0xCE
    16. 00BE  50EE     MOVF POSTINC0, W, ACCESS
    17. 00C0  010F     MOVLB 0xF
    18. 00C2  1910     XORWF 0x10, W, BANKED
    19. 00C4  E104     BNZ 0xCE
    20. 00C6  50EE     MOVF POSTINC0, W, ACCESS
    21. 00C8  010F     MOVLB 0xF
    22. 00CA  1911     XORWF 0x11, W, BANKED
    23. 00CC  E100     BNZ 0xCE
    24. 00CE  E009     BZ 0xE2
    25. 00D0  CF0E     MOVFF B, A
    26. 00D2  FF0A     NOP
    27. 00D4  CF0F     MOVFF 0xF0F, 0xF0B
    28. 00D6  FF0B     NOP
    29. 00D8  CF10     MOVFF 0xF10, 0xF0C
    30. 00DA  FF0C     NOP
    31. 00DC  CF11     MOVFF 0xF11, 0xF0D
    32. 00DE  FF0D     NOP
    33. 00E0  D7E2     BRA main
    34. 8:            
    35. 9:                 INTCONbits.GIE = 0;
    36. 00E2  9EF2     BCF INTCON, 7, ACCESS
    37. 10:                A = B;
    38. 00E4  CF0E     MOVFF B, A
    39. 00E6  FF0A     NOP
    40. 00E8  CF0F     MOVFF 0xF0F, 0xF0B
    41. 00EA  FF0B     NOP
    42. 00EC  CF10     MOVFF 0xF10, 0xF0C
    43. 00EE  FF0C     NOP
    44. 00F0  CF11     MOVFF 0xF11, 0xF0D
    45. 00F2  FF0D     NOP
    46. 11:                INTCONbits.GIE = 1;
    47. 00F4  8EF2     BSF INTCON, 7, ACCESS
    48. 12:            
    49. 13:            }
    50. 00F6  0012     RETURN 0
     
Loading...