Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

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.
 

tumbleweed

Active Member
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.).
 

Pommie

Well-Known Member
Most Helpful Member
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.
 

tumbleweed

Active Member
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..
 

Pommie

Well-Known Member
Most Helpful Member
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.
 

tumbleweed

Active Member
oogle
"c increment operator multiple unsequenced modifications" and/or "c increment operator undefined behavior" for lengthy discussions from the language lawyers.
 

Mike - K8LH

Well-Known Member
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

Knight Rider Charlie.png
 

Pommie

Well-Known Member
Most Helpful Member
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.
 

Pommie

Well-Known Member
Most Helpful Member
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:

tepalia02

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.
Off topic question: what compiler did you use here to write this code?
 

Latest threads

New Articles From Microcontroller Tips

Top