Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Problem with PIC interrupt loop

Status
Not open for further replies.

shsn

Junior Member level 3
Junior Member level 3
Joined
Nov 28, 2012
Messages
26
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,523
Hi,

After reading bits of information on interrupt routine I decided to implement this to test it out. My current program has following routine:

  1. check and load ADC value into variable 'adc_value'.
  2. go through IF statement that matches conditions
  3. if a match is found turn LEDs
  4. if no match is found, flash all LEDs

So what I wanted to do was trigger a hardware interrupt on pin RB0 to flash all the LEDs UNTIL RB0 goes low. To achieve this (according to my assumption), I need a loop to keep the LEDs flash but I can't seem to do this or it is not possible to do this with interrupts.

Code:
unsigned int adc_val;

void checkMode() {
     if (RA2_bit == 0) {
        PORTB = 0b00000010;
     }
     else {
          PORTB = 0b00000100;
     }
}

void driveLED(unsigned int adc_val) {
     if (adc_val >= 0 && adc_val <= 40) {
        PORTD  = 0b00000000;
        PORTC = 0;
     }
     else if (adc_val > 41 && adc_val <= 91) {
        PORTD  = 0b10000000;
        PORTC = 0;
     }
     else if (adc_val > 92 && adc_val <= 153) {
        PORTD  = 0b11000000;
        PORTC = 0;
     }
     else if (adc_val > 154 && adc_val <= 215) {
        PORTD  = 0b11100000;
        PORTC = 0;
     }
     else if (adc_val > 216 && adc_val <= 276) {
        PORTD  = 0b11110000;
        PORTC = 0;
     }
     else if (adc_val > 277 && adc_val <= 337) {
        PORTD  = 0b11111000;
        PORTC = 0;
     }
     else if (adc_val > 338 && adc_val <= 399) {
        PORTD  = 0b11111100;
        PORTC = 0;
     }
     else if (adc_val > 400 && adc_val <= 460) {
        PORTD  = 0b11111110;
        PORTC = 0;
     }
     else if (adc_val > 461 && adc_val <= 521) {
        PORTD  = 0b11111111;
        PORTC = 0;
     }
     else if (adc_val > 522 && adc_val <= 582) {
        PORTD  = 0b11111111;
        PORTC = 0b10000000;
     }
     else if (adc_val > 583 && adc_val <= 644) {
        PORTD  = 0b11111111;
        PORTC = 0b11000000;
     }
     else if (adc_val > 645 && adc_val <= 705) {
        PORTD  = 0b11111111;
        PORTC = 0b11100000;
     }
     else if (adc_val > 706 && adc_val <= 767) {
        PORTD  = 0b11111111;
        PORTC = 0b11110000;
     }
     else if (adc_val > 768 && adc_val <= 828) {
        PORTD  = 0b11111111;
        PORTC = 0b11111000;
     }
     else if (adc_val > 829 && adc_val <= 890) {
        PORTD  = 0b11111111;
        PORTC = 0b11111100;
     }
     else if (adc_val > 891 && adc_val <= 951) {
        PORTD  = 0b11111111;
        PORTC = 0b11111110;
     }
     else {
        PORTD = 0;
        PORTC = 0;
        delay_ms(30);
        PORTD  = 0b11111111;
        PORTC = 0b11111110;
        delay_ms(30);
     }
}

void main() {
     TRISA = 0b000111;
     PORTA = 0b000000;
     ADCON1 = 0b111110; // varying voltage input
     
     TRISD = 0;
     PORTD = 0;
     
     TRISC = 0;
     PORTC = 0;

     TRISB = 0;
     PORTB = 0;

     TRISE = 0b000;
     PORTE = 0b000;

     INTCON.GIE = 1;
     INTCON.INTE =1 ;
     INTCON.INTF = 0;
     TRISB0_bit = 1;
     OPTION_REG.INTEDG = 1;

     checkMode();

     do {
          adc_val = ADC_read(0);
          driveLED(adc_val);
     }
     while(1);
}

void interrupt(void) {
     do {
          PORTD = 0;
          PORTC = 0;
          delay_ms(30);
          PORTD = 0b11111111;
          PORTC = 0b11111111;
          delay_ms(30);
     }
     while(INTCON.INTF==0);
}

If I load this program onto the PIC and run it, the external interrupt works (when RB0 pin goes to high, triggered by tactile switch) but letting go of the switch (despite the voltage going to 0V) it does not exit the interrupt routine -- it stays in the interrupt routine unless powered down.

If anyone could point me to the right direction or perhaps another topic related to interrupt I'm happy to dig more. Any help is appreciated.

Thank you.

Eric.
 

Try with this code:

Code:
unsigned int adc_val;

unsigned char FlagReg;
sbit Turn at FlagReg.B0;

void checkMode() {
     if (RA2_bit == 0) {
        PORTB = 0b00000010;
     }
     else {
          PORTB = 0b00000100;
     }
}

void driveLED(unsigned int adc_val) {
     if (adc_val >= 0 && adc_val <= 40) {
        PORTD  = 0b00000000;
        PORTC = 0;
     }
     else if (adc_val > 41 && adc_val <= 91) {
        PORTD  = 0b10000000;
        PORTC = 0;
     }
     else if (adc_val > 92 && adc_val <= 153) {
        PORTD  = 0b11000000;
        PORTC = 0;
     }
     else if (adc_val > 154 && adc_val <= 215) {
        PORTD  = 0b11100000;
        PORTC = 0;
     }
     else if (adc_val > 216 && adc_val <= 276) {
        PORTD  = 0b11110000;
        PORTC = 0;
     }
     else if (adc_val > 277 && adc_val <= 337) {
        PORTD  = 0b11111000;
        PORTC = 0;
     }
     else if (adc_val > 338 && adc_val <= 399) {
        PORTD  = 0b11111100;
        PORTC = 0;
     }
     else if (adc_val > 400 && adc_val <= 460) {
        PORTD  = 0b11111110;
        PORTC = 0;
     }
     else if (adc_val > 461 && adc_val <= 521) {
        PORTD  = 0b11111111;
        PORTC = 0;
     }
     else if (adc_val > 522 && adc_val <= 582) {
        PORTD  = 0b11111111;
        PORTC = 0b10000000;
     }
     else if (adc_val > 583 && adc_val <= 644) {
        PORTD  = 0b11111111;
        PORTC = 0b11000000;
     }
     else if (adc_val > 645 && adc_val <= 705) {
        PORTD  = 0b11111111;
        PORTC = 0b11100000;
     }
     else if (adc_val > 706 && adc_val <= 767) {
        PORTD  = 0b11111111;
        PORTC = 0b11110000;
     }
     else if (adc_val > 768 && adc_val <= 828) {
        PORTD  = 0b11111111;
        PORTC = 0b11111000;
     }
     else if (adc_val > 829 && adc_val <= 890) {
        PORTD  = 0b11111111;
        PORTC = 0b11111100;
     }
     else if (adc_val > 891 && adc_val <= 951) {
        PORTD  = 0b11111111;
        PORTC = 0b11111110;
     }
     else {
        PORTD = 0;
        PORTC = 0;
        delay_ms(30);
        PORTD  = 0b11111111;
        PORTC = 0b11111110;
        delay_ms(30);
     }
}

void main() {
     TRISA = 0b000111;
     PORTA = 0b000000;
     ADCON1 = 0b111110; // varying voltage input

     TRISD = 0;
     PORTD = 0;

     TRISC = 0;
     PORTC = 0;

     TRISB = 0;
     PORTB = 0;

     TRISE = 0b000;
     PORTE = 0b000;

     INTCON.GIE = 1;
     INTCON.INTE = 1 ;
     INTCON.INTF = 0;
     TRISB0_bit = 1;
     OPTION_REG.INTEDG = 1;

     checkMode();
     
     Turn = 0;

     do {
        if (Turn == 0){
          adc_val = ADC_read(0);
          driveLED(adc_val);
        }
        else{
          PORTD = 0;
          PORTC = 0;
          delay_ms(30);
          PORTD = 0b11111111;
          PORTC = 0b11111111;
          delay_ms(30);
        }
     }
     while(1);
}

void interrupt(void) {
     if (RB0_bit == 1){
        Turn = 1;
        INTEDG_bit = 0;
     }
     else{
          Turn = 0;
          INTEDG_bit = 1;
     }
     
     INTF_bit = 0;
}

The code should be easy to understand. If you have any problem understanding something, feel free to ask.

Hope this helps.
Tahmid.
 
  • Like
Reactions: shsn

    shsn

    Points: 2
    Helpful Answer Positive Rating
Hi Tahmid, thank you for your solution. The code you provided works as expected but I figured out an alternative solution that also works.

Code:
void interrupt(void) {
     while (RB0_bit == 1) {
        PORTC = 0;
        PORTD = 0b11111110;
        delay_ms(20);
        PORTD = 0b00000001;
        PORTC = 0b11111111;
        delay_ms(20);
        INTCON.INTF=0;
     }
}

This too keeps the interrupt loop going as long as the RB0 is set to high. Not sure which might be more efficient though :')
Thanks again, it's good to have multiple ways to achieve things.

Eric,
 

This too keeps the interrupt loop going as long as the RB0 is set to high. Not sure which might be more efficient though :')

My code frees the interrupt and does all the work in the main code. Yours keeps looping in the interrupt service routing and stays there instead of going to the main code. For your purpose both are okay as you have tested. One situation your code may be problematic is when you have other tasks to be carried out alongside the current task that is being done in the interrupt service routine. In that case, one is stopped to do the other, but both do not run simultaneously. Attempting to do so would be very inefficient.

Hope this helps.
Tahmid.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top