Using Pic18 Interrupts.

Pommie

Well-Known Member
Most Helpful Member
I had a 4x4 LED matrix setup using a Pic16F873A and swapped the chip to a (same pinout) Pic18F2620. I wanted to see how difficult it would be to run the matrix completely on interrupts.

I setup a 5mS interrupt using Timer 2.
Code:
    //setup 5mS interrupt = 8,000,000/16 = 500,000/10 = 50,000 set PR2=249 = 200 = 5mS 
    T2CON=0b01001110;       //pre=16 post=10
    PR2=249;
    TMR2IE=1;               //timer2 interrupts enable
    GIE=1;
    PEIE=1;
And an ISR to multiplex the LED - stored in a 16 bit variable called LEDs
Code:
//row 0 is RC7 (to RC4) and Anode (+)
//col 0 is RC0 (to RC3) and Cathode (-)
void  __interrupt(high_priority) myHighIsr(void){
    if(TMR2IE && TMR2IF){
        uint16_t temp=LEDs;     //make copy of LED variable
        col++;                  //increment column 
        col&=3;                 //and wrap around to zero
        temp<<=(col*4);         //get 4 LEDs in top bits
        temp&=0xf000;           //get rid of unwanted LEDs
        temp>>=8;               //shift to bits 4 to 7
        temp|=(0x0f-(1<<col));  //turn off unwanted columns
        LATC|=0x0f;             //turn all columns off
        LATC=(uint8_t)temp;     //turn on relevant LEDs
        TMR2IF=0;
    }
}
In the main lood I did a simple scrolling LED routine,
Code:
    while (1){
        __delay_ms(50);         //short delay
        if(dir) LEDs>>=1;       //if dir = 1 then move right
        else LEDs<<=1;          //else move left
        if(LEDs&1) dir=0;       //if we reached the right end then go left
        if(LEDs&0x8000) dir=1;  //if we reached the left end then go right
    }
And this is what it looked like,

Here's the complete code for anyone wanting to know about interrupts. The config statements are longer than the actual code!!!
Code:
// CONFIG1H
#pragma config OSC = INTIO67    // Oscillator Selection bits (Internal oscillator block, port function on RA6 and RA7)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor enabled)
#pragma config IESO = ON        // Internal/External Oscillator Switchover bit (Oscillator Switchover mode enabled)

// CONFIG2L
#pragma config PWRT = ON        // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = SBORDIS  // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
#pragma config BORV = 3         // Brown Out Reset Voltage bits (Minimum setting)

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

// CONFIG3H
#pragma config CCP2MX = PORTC   // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = ON      // PORTB A/D Enable bit (PORTB<4:0> pins are configured as analog input channels on Reset)
#pragma config LPT1OSC = OFF    // Low-Power Timer1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config MCLRE = ON       // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF        // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

// CONFIG5L
#pragma config CP0 = OFF        // Code Protection bit (Block 0 (000800-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)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block (000000-0007FFh) 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 (000800-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)

// 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-0007FFh) 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 (000800-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)

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

#include <xc.h>
#include <stdint.h>
#define _XTAL_FREQ 32000000

volatile uint8_t col=0,dir;
uint16_t LEDs;

//row 0 is RC7 (to RC4) and Anode (+)
//col 0 is RC0 (to RC3) and Cathode (-)
void  __interrupt(high_priority) myHighIsr(void){
    if(TMR2IE && TMR2IF){
        uint16_t temp=LEDs;     //make copy of LED variable
        col++;                  //increment column 
        col&=3;                 //and wrap around to zero
        temp<<=(col*4);         //get 4 LEDs in top bits
        temp&=0xf000;           //get rid of unwanted LEDs
        temp>>=8;               //shift to bits 4 to 7
        temp|=(0x0f-(1<<col));  //turn off unwanted columns
        LATC|=0x0f;             //turn all columns off
        LATC=(uint8_t)temp;     //turn on relevant LEDs
        TMR2IF=0;
    }
}

void main(void){
    OSCCON=0b01110000;      //8MHz
    PLLEN=1;                //x4=32MHz
    //setup 5mS interrupt = 8,000,000/16 = 500,000/10 = 50,000 set PR2=249 = 200 = 5mS 
    T2CON=0b01001110;       //pre=16 post=10
    PR2=249;
    TMR2IE=1;               //timer2 interrupts enable
    GIE=1;
    PEIE=1;
    TRISC=0;                //all output
    LEDs=0xf000;
    dir=1;
    while (1){
        __delay_ms(50);         //short delay
        if(dir) LEDs>>=1;       //if dir = 1 then move right
        else LEDs<<=1;          //else move left
        if(LEDs&1) dir=0;       //if we reached the right end then go left
        if(LEDs&0x8000) dir=1;  //if we reached the left end then go right
    }
}

Mike.
A question for knowledgeable people,
The two instructions
Code:
        col++;                  //increment column 
        col&=3;                 //and wrap around to zero
Can't be combined into
Code:
        ++col&=3;
I can't think why it isn't permitted. There must be a simple reason that I'm not seeing.
 
Code:
 ++col &= 3;

The error that generates is "error: (202) only lvalues can be assigned to or modified"

'lvalue' means an object that has a location in memory (i.e. it has an address).
An lvalue cannot be a function, an expression (like ++col) or a constant (like 3 , 4 , etc.).
 
Interestingly,
Code:
  col=++col&3;
only produces a warning,
main.c:71:13: warning: multiple unsequenced modifications to 'col' [-Wunsequenced]
I don't even know what that is warning about.
What's an "unsequenced" modification?

Mike.
 
It's warning you that the result is unspecified and may not be what you expect.

Statements like
Code:
col = ++col;
produce undefined behavior. It all has to do with "sequence points" and the language spec..
 
I thought precedence took care of that with ++ having a precedence of 2 and &= a precedence of 14.

I don't understand how there can be undefined behaviour.

Mike.
 
oogle
"c increment operator multiple unsequenced modifications" and/or "c increment operator undefined behavior" for lengthy discussions from the language lawyers.
 
Mike. Please forgive me. I can't help myself. I always wonder how I might do things differently (not necessarily better)...

Code:
  void  __interrupt(high_priority) myHighIsr(void)
  { static uint8_t col = 8;          // value; 1, 2, 4, 8
    static uint16_t temp = 0;        //
    if(TMR2IE && TMR2IF)
    { LATC = col ^ 0x0F;             // display off, select column
      LATC |= (hi(temp) & 0xF0);     // display new column
      col <<= 1; temp <<= 4;         // prep for next column
      if(col & 16)                   // if last column
      { col = 1;                     //   reset 'column'
        temp = led;                  //   refresh 'temp'
      }                              //
      TMR2IF = 0;                    //
    }                                //
  }                                  //
And <off topic>, I know, but, have you ever done anything with Charlieplexing?

Happy Holidays. Cheerful regards, Mike

 
Ahhh, I see the equals and the increment are both modifying it, hence confusion.

It also explains why col=col+1&3 works (+ is higher precedence).

I still think precedence takes away the unsequenced part as precedence gives it sequence - increment first then AND and assign. Made me think, is equals given a precedent? Yes it is, it's assigned 14 the lowest.
I'm trying to get my head around why e = a < d ? a++ : a = d can't be parsed.

Mike, yes, I've used charlieplexing many times in the past. If you remember, I used it to read a 4x3 keyboard using just 5 pins - keeping one pin free (of an 8 pin pic) to transmit RS232.

Mike.
 
Was trying to remember how I did this all those years ago. Turns out GP0, 1 & 3 have WPUs so these were the column inputs. GP2 and 4 went to the 4 rows via diodes (2 one way, two reversed). So no WPUs on columns float low unless pulled high by the rows via a switch. WPUs on columns float high unless pulled low ......

Mike.
 
Last edited:
Off topic question: what compiler did you use here to write this code?
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…