CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

External Interrupt problem

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
oxxyfx



Joined: 24 May 2007
Posts: 97

View user's profile Send private message

External Interrupt problem
PostPosted: Sun May 17, 2009 9:29 am     Reply with quote

Hello,

my nephew asked me nicely to build him an intelligent traffic light. How can you say no to him? Smile

So I decided to use a 16F88 (little overkill I know) but hey, it is a one time deal.

I started testing the below program and I see some issues around the external interrupt.

First let me give you a brief description of the project:

There are 3 LED lights these are large(20mm) 12 LED arrays driven by a transistor from the pin of the PIC. There are also 4 buttons beside the obvious On/Off power button. The function of each button is the following:

- MRED - once pushed it will turn all lights off and turn on the red
- MYELLOW - same as above for the Yellow
- MGREEN - same as above for the Green
- MAUTO - multifunction button:
--- When pressed once it will start an automatic routine - Green, Yellow Red as on real traffic lights.
--- When pressed twice it will do the same routine but with longer wait times
--- When pressed 3 times it should flash all 3 lights together as a defective traffic light
--- When pressed the fourth time it should turn all lights on - again as a defective traffic light.

Additional functionalities not implemented yet - For the first 3 buttons when pressed twice it will flash the respective color only.

So with all the above I have the following problem:

The first 3 buttons work great, the moment it is pressed it will go turn the respective color on.

The Auto button does not work as expected. When pressed it will continue the routine and at the beginning of the next cycle will perhaps change the sequence. This is not good, because a child as it does not see the reaction right away will keep punching the button again and again and that is already a different functionality.

Can you please tell me what is wrong with this code? I thought it is simple enough but it seems nothing is that simple any more...
Code:

#include "...\Semaphore\semaphore.h"

#define Green     Pin_A0
#define Yellow    Pin_A1
#define Red       Pin_A2
#define MAuto     Pin_B4
#define MGreen    Pin_B7
#define MYellow   Pin_B6
#define MRed      Pin_B5

int16 mtimer, seconds, dtime;
int Mode, APcount, Color;

Void Runauto(int i){

      dtime = 1000;
      Output_High(Green);
      If (i == 1)Delay_ms(dtime);
      If (i == 2){
         Delay_ms(dtime);
         Delay_ms(dtime);
         Delay_ms(dtime);
      }
      Output_low(Green);
      Output_High(Yellow);
      If (i == 1) Delay_ms(dtime);
      If (i == 2) {
         Delay_ms(dtime);
         Delay_ms(dtime);
      }

      Output_low(Yellow);
      Output_High(Red);
      If (i == 1)Delay_ms(dtime);
      If (i == 2){
         Delay_ms(dtime);
         Delay_ms(dtime);
         Delay_ms(dtime);
      }
      Output_Low(Red);
}

Void Allon(){
               Output_high(Red);
               Output_high(Yellow);
               Output_high(Green);
}

Void Flashall(){
         Output_Low(Red);
         Output_low(Yellow);
         Output_low(Green);
         Delay_ms(dtime);
         Output_High(Green);
         Output_High(Yellow);
         Output_High(Red);
         Delay_ms(dtime);

}

Void Flashgreen(){
         Output_Low(Green);
         Output_Low(Yellow);
         Output_Low(Red);
         Delay_ms(dtime);
         Output_high(Green);
         Delay_ms(1000);
}

Void Flashyellow(){
         Output_Low(Green);
         Output_Low(Yellow);
         Output_Low(Red);
         Delay_ms(dtime);
         Output_high(Yellow);
         Delay_ms(dtime);
}
Void Flashred(){
         Output_Low(Green);
         Output_Low(Yellow);
         Output_Low(Red);
         Delay_ms(dtime);
         Output_high(Red);
         Delay_ms(dtime);
}


#int_RB
Void int_RB_isr(){
int8 prt;

      prt = Input_b();
      If (prt == 16){
            APCount++;
            Mode = 1;
            If (APCount == 5) APCount = 1;
            If (APCount == 1){
               Output_Low(Green);
               Output_low(Yellow);
               Output_Low(Red);

               Output_High(Green);
               Delay_ms(dtime);
               Output_low(Green);
               Output_High(Yellow);
               Delay_ms(dtime);
               Output_low(Yellow);
               Output_High(Red);
               Delay_ms(dtime);
               Output_Low(Red);
            }
            If (APCount == 2){
               Output_Low(Green);
               Output_low(Yellow);
               Output_low(Red);
               dtime = 1000;
               Output_High(Green);
               Delay_ms(dtime);
               Delay_ms(dtime);
               Delay_ms(dtime);
               Output_low(Green);
               Output_High(Yellow);
               Delay_ms(dtime);
               Delay_ms(dtime);
               Output_low(Yellow);
               Output_High(Red);
               Delay_ms(dtime);
               Delay_ms(dtime);
               Delay_ms(dtime);
               Output_Low(Red);
            }
            If (APCount == 3) {
               Output_Low(Green);
               Output_low(Yellow);
               Output_Low(Red);
               Output_Low(Red);
               Output_low(Yellow);
               Output_low(Green);
               Delay_ms(dtime);
               Output_High(Green);
               Output_High(Yellow);
               Output_High(Red);
               Delay_ms(dtime);           
            }

            If (APCount == 4) {
               Output_Low(Green);
               Output_low(Yellow);
               Output_Low(Red);
               Output_high(Red);
               Output_high(Yellow);
               Output_high(Green);
            }
           
      }

      If (prt == 128){
            Mode = 2;
            Color = 1;
      }
      If (prt == 64){
            Mode = 2;
            Color = 2;
      }
      If (prt == 32){
            Mode = 2;
            Color = 3;
      }
}



void main()
{
   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_OFF);
   setup_spi(FALSE);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   setup_oscillator(OSC_8MHZ|OSC_INTRC);
   enable_interrupts(GLOBAL);
   clear_interrupt(INT_RB);
   enable_interrupts(INT_RB);

   APCount = 1;
   Mode = 1;
   dtime = 75;
   
   While(true){
 
      Switch(Mode){
         Case 1:
                  If (APCount == 5) APCount = 1;
                  If (APCount == 1) Runauto(1);
                  If (APCount == 2) Runauto(2);
                  If (APCount == 3) Flashall();
                  If (APCount == 4) Allon();
                  Break;
         Case 2:
                  If (Color == 1){
                     Output_Low(Red);
                     Output_low(Yellow);
                     Output_high(Green);
                  }
                  If (Color == 2){
                     Output_Low(Red);
                     Output_High(Yellow);
                     Output_Low(Green);
                  }
                  If (Color == 3){
                     Output_High(Red);
                     Output_Low(Yellow);
                     Output_Low(Green);
                  }
                  Break;

         Case 5:
               Delay_ms(100);
               Break;

      }

   }
}


There might be unnecessary routines in this code, I have not touched it in weeks, please excuse me for that.

Thanks,

Oxy
bungee-



Joined: 27 Jun 2007
Posts: 206

View user's profile Send private message

PostPosted: Sun May 17, 2009 3:56 pm     Reply with quote

Just a quick observation. Don't use delay's in the interrupt routine. That can lead to unpredictive states. Wink
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Mon May 18, 2009 1:43 am     Reply with quote

Switch bouncing might be another issue. Search this forum for 'debounce' for several solutions to this problem.

Code:
   enable_interrupts(GLOBAL);
   clear_interrupt(INT_RB);
   enable_interrupts(INT_RB);

   APCount = 1;
   Mode = 1;
   dtime = 75;
Here the interrupt is enabled before the variables it uses are initialized. Revert the sequence.
oxxyfx



Joined: 24 May 2007
Posts: 97

View user's profile Send private message

PostPosted: Wed May 27, 2009 9:27 am     Reply with quote

Thanks folks,

I completely forgot I posted this question.

bungee: Originally the delays were in a subroutine and the subroutine got called by the interrupt routine. That didn't work either since it was called by the interrupt routine...

How can I avoid using delays here when I have to time the flashing of the lights?

ckielstra: I will try this however I doubt it will make any difference. I will search for "debounce" after I posted this

Thanks. If you folks have any other ideas please let me know.
Ttelmah
Guest







PostPosted: Wed May 27, 2009 9:38 am     Reply with quote

Approach things completely differentlty.
Have a timer interrupt, at some fastish interval. Perhaps 10msec. Have this check the keys, and if it 'sees' a key pressed, set a flag to say this has been seen. Then on the next call, if the flag is seen, check again, and if the key is still 'true', set an external global variable, to say the particular key has been recorded. Otherwise turn off the flag. This gives the debounce needed for any mechanical key. Also have a 'tick' decremented in the routine, if it is non zero.
Then the main code, sits in a 'state machine', looping as fast as you can. First, check if a key has been recorded. If so, change the 'light state' to reflect this, and set the 'tick', to correspond to the new time required. Then, check the 'tick', and if it reaches zero, change to the next required light state, and set the new tick time for this state. Then loop.

Basically, the main code, sits, timed by the 'tick', changing lights whenever this reaches zero. It is overriden, if a button is pushed, jumping immediately to the new required state. All light changes are done in the 'main', but are timed by the hardware timer interrupt, or triggered by the buttons if required.

Best Wishes
oxxyfx



Joined: 24 May 2007
Posts: 97

View user's profile Send private message

PostPosted: Wed May 27, 2009 9:47 am     Reply with quote

Thank you, that is really nice way of doing this. I will try to rewrite the code to reflect this.

Thanks again.
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

using timer0
PostPosted: Wed May 27, 2009 4:28 pm     Reply with quote

I discovered and have done exactly what Ttelmah suggests - for multiple push button blocks - where I want only the highest PRIORITY button press by reading a 74HC148 3 bit output into 3 bits of PORTB and handling 7 buttons with the LOWEST priority button ( #7 ) always asserted in hardware by tying the input pin.

THEN
on an 18f886 using int 8 mhz clock and
setup timer 0 for RTC/int clockas DIV_64
(prescalar=256 )

this gives an appx 8.192 mSec 'tick' -

define T0IF ( timer zero interupt flag )

simply test for:
If (T0IF) {
T0IF=0; // clear it
see if the masked bit of portb has a change
if so record it
and if THE SAME state on NEXT TICK
it is valid

}

use of the external priority encoder makes the job of sort out multiple
button press 's very easy - if that is your desire as only the highest priority one is reported




}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group